2017-11-14 23:35:42 +00:00
|
|
|
//===- Stmt.cpp - Statement AST Node Implementation -----------------------===//
|
2006-10-25 04:09:21 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2006-10-25 04:09:21 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Stmt class and statement subclasses.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-04-03 00:11:50 +00:00
|
|
|
#include "clang/AST/Stmt.h"
|
2012-12-01 17:12:56 +00:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/ASTDiagnostic.h"
|
2020-09-09 19:12:32 +02:00
|
|
|
#include "clang/AST/Attr.h"
|
2017-11-14 23:35:42 +00:00
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/DeclGroup.h"
|
2018-04-03 00:11:50 +00:00
|
|
|
#include "clang/AST/Expr.h"
|
2006-12-04 18:06:35 +00:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2020-09-09 19:12:32 +02:00
|
|
|
#include "clang/AST/ExprConcepts.h"
|
2008-05-29 21:12:08 +00:00
|
|
|
#include "clang/AST/ExprObjC.h"
|
2015-08-25 14:24:04 +00:00
|
|
|
#include "clang/AST/ExprOpenMP.h"
|
2009-04-26 01:32:48 +00:00
|
|
|
#include "clang/AST/StmtCXX.h"
|
|
|
|
#include "clang/AST/StmtObjC.h"
|
[OpenACC] Implement AST for OpenACC Compute Constructs (#81188)
'serial', 'parallel', and 'kernel' constructs are all considered
'Compute' constructs. This patch creates the AST type, plus the required
infrastructure for such a type, plus some base types that will be useful
in the future for breaking this up.
The only difference between the three is the 'kind'( plus some minor
clause legalization rules, but those can be differentiated easily
enough), so rather than representing them as separate AST nodes, it
seems
to make sense to make them the same.
Additionally, no clause AST functionality is being implemented yet, as
that fits better in a separate patch, and this is enough to get the
'naked' constructs implemented.
This is otherwise an 'NFC' patch, as it doesn't alter execution at all,
so there aren't any tests. I did this to break up the review workload
and to get feedback on the layout.
2024-02-13 06:02:13 -08:00
|
|
|
#include "clang/AST/StmtOpenACC.h"
|
2013-07-19 03:13:43 +00:00
|
|
|
#include "clang/AST/StmtOpenMP.h"
|
[SYCL] AST support for SYCL kernel entry point functions. (#122379)
A SYCL kernel entry point function is a non-member function or a static
member function declared with the `sycl_kernel_entry_point` attribute.
Such functions define a pattern for an offload kernel entry point
function to be generated to enable execution of a SYCL kernel on a
device. A SYCL library implementation orchestrates the invocation of
these functions with corresponding SYCL kernel arguments in response to
calls to SYCL kernel invocation functions specified by the SYCL 2020
specification.
The offload kernel entry point function (sometimes referred to as the
SYCL kernel caller function) is generated from the SYCL kernel entry
point function by a transformation of the function parameters followed
by a transformation of the function body to replace references to the
original parameters with references to the transformed ones. Exactly how
parameters are transformed will be explained in a future change that
implements non-trivial transformations. For now, it suffices to state
that a given parameter of the SYCL kernel entry point function may be
transformed to multiple parameters of the offload kernel entry point as
needed to satisfy offload kernel argument passing requirements.
Parameters that are decomposed in this way are reconstituted as local
variables in the body of the generated offload kernel entry point
function.
For example, given the following SYCL kernel entry point function
definition:
```
template<typename KernelNameType, typename KernelType>
[[clang::sycl_kernel_entry_point(KernelNameType)]]
void sycl_kernel_entry_point(KernelType kernel) {
kernel();
}
```
and the following call:
```
struct Kernel {
int dm1;
int dm2;
void operator()() const;
};
Kernel k;
sycl_kernel_entry_point<class kernel_name>(k);
```
the corresponding offload kernel entry point function that is generated
might look as follows (assuming `Kernel` is a type that requires
decomposition):
```
void offload_kernel_entry_point_for_kernel_name(int dm1, int dm2) {
Kernel kernel{dm1, dm2};
kernel();
}
```
Other details of the generated offload kernel entry point function, such
as its name and calling convention, are implementation details that need
not be reflected in the AST and may differ across target devices. For
that reason, only the transformation described above is represented in
the AST; other details will be filled in during code generation.
These transformations are represented using new AST nodes introduced
with this change. `OutlinedFunctionDecl` holds a sequence of
`ImplicitParamDecl` nodes and a sequence of statement nodes that
correspond to the transformed parameters and function body.
`SYCLKernelCallStmt` wraps the original function body and associates it
with an `OutlinedFunctionDecl` instance. For the example above, the AST
generated for the `sycl_kernel_entry_point<kernel_name>` specialization
would look as follows:
```
FunctionDecl 'sycl_kernel_entry_point<kernel_name>(Kernel)'
TemplateArgument type 'kernel_name'
TemplateArgument type 'Kernel'
ParmVarDecl kernel 'Kernel'
SYCLKernelCallStmt
CompoundStmt
<original statements>
OutlinedFunctionDecl
ImplicitParamDecl 'dm1' 'int'
ImplicitParamDecl 'dm2' 'int'
CompoundStmt
VarDecl 'kernel' 'Kernel'
<initialization of 'kernel' with 'dm1' and 'dm2'>
<transformed statements with redirected references of 'kernel'>
```
Any ODR-use of the SYCL kernel entry point function will (with future
changes) suffice for the offload kernel entry point to be emitted. An
actual call to the SYCL kernel entry point function will result in a
call to the function. However, evaluation of a `SYCLKernelCallStmt`
statement is a no-op, so such calls will have no effect other than to
trigger emission of the offload kernel entry point.
Additionally, as a related change inspired by code review feedback,
these changes disallow use of the `sycl_kernel_entry_point` attribute
with functions defined with a _function-try-block_. The SYCL 2020
specification prohibits the use of C++ exceptions in device functions.
Even if exceptions were not prohibited, it is unclear what the semantics
would be for an exception that escapes the SYCL kernel entry point
function; the boundary between host and device code could be an implicit
noexcept boundary that results in program termination if violated, or
the exception could perhaps be propagated to host code via the SYCL
library. Pending support for C++ exceptions in device code and clear
semantics for handling them at the host-device boundary, this change
makes use of the `sycl_kernel_entry_point` attribute with a function
defined with a _function-try-block_ an error.
2025-01-22 16:39:08 -05:00
|
|
|
#include "clang/AST/StmtSYCL.h"
|
2008-12-22 19:15:10 +00:00
|
|
|
#include "clang/AST/Type.h"
|
2013-02-08 22:30:41 +00:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2017-11-14 23:35:42 +00:00
|
|
|
#include "clang/Basic/LLVM.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
2010-04-23 16:29:58 +00:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2012-12-01 17:12:56 +00:00
|
|
|
#include "clang/Lex/Token.h"
|
2017-11-14 23:35:42 +00:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-08-24 17:05:45 +00:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-11-14 23:35:42 +00:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
2011-07-04 06:13:27 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-11-14 23:35:42 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
2023-01-14 11:07:21 -08:00
|
|
|
#include <optional>
|
2017-11-14 23:35:42 +00:00
|
|
|
#include <string>
|
2020-09-09 19:12:32 +02:00
|
|
|
#include <utility>
|
2017-11-14 23:35:42 +00:00
|
|
|
|
2006-10-25 04:09:21 +00:00
|
|
|
using namespace clang;
|
|
|
|
|
2024-12-20 12:29:33 -08:00
|
|
|
#define STMT(CLASS, PARENT)
|
|
|
|
#define STMT_RANGE(BASE, FIRST, LAST)
|
|
|
|
#define LAST_STMT_RANGE(BASE, FIRST, LAST) \
|
|
|
|
static_assert(llvm::isUInt<NumStmtBits>(Stmt::StmtClass::LAST##Class), \
|
|
|
|
"The number of 'StmtClass'es is strictly bound " \
|
|
|
|
"by a bitfield of width NumStmtBits");
|
|
|
|
#define ABSTRACT_STMT(STMT)
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
|
2007-05-23 21:48:04 +00:00
|
|
|
static struct StmtClassNameTable {
|
2007-08-25 01:42:24 +00:00
|
|
|
const char *Name;
|
|
|
|
unsigned Counter;
|
|
|
|
unsigned Size;
|
2010-05-05 15:24:00 +00:00
|
|
|
} StmtClassInfo[Stmt::lastStmtConstant+1];
|
2007-08-25 01:42:24 +00:00
|
|
|
|
|
|
|
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
|
|
|
|
static bool Initialized = false;
|
|
|
|
if (Initialized)
|
|
|
|
return StmtClassInfo[E];
|
|
|
|
|
2018-04-06 15:14:32 +00:00
|
|
|
// Initialize the table on the first use.
|
2007-08-25 01:42:24 +00:00
|
|
|
Initialized = true;
|
2010-05-18 06:22:21 +00:00
|
|
|
#define ABSTRACT_STMT(STMT)
|
2008-11-14 12:46:07 +00:00
|
|
|
#define STMT(CLASS, PARENT) \
|
|
|
|
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
|
|
|
|
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
|
2010-05-05 15:24:00 +00:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
2008-08-05 23:15:29 +00:00
|
|
|
|
2007-08-25 01:42:24 +00:00
|
|
|
return StmtClassInfo[E];
|
|
|
|
}
|
|
|
|
|
2013-08-18 10:09:15 +00:00
|
|
|
void *Stmt::operator new(size_t bytes, const ASTContext& C,
|
2013-08-18 17:45:38 +00:00
|
|
|
unsigned alignment) {
|
2012-12-01 15:09:41 +00:00
|
|
|
return ::operator new(bytes, C, alignment);
|
|
|
|
}
|
|
|
|
|
2007-03-23 22:27:02 +00:00
|
|
|
const char *Stmt::getStmtClassName() const {
|
2010-10-26 08:39:16 +00:00
|
|
|
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
|
2007-03-23 22:27:02 +00:00
|
|
|
}
|
2007-05-23 21:48:04 +00:00
|
|
|
|
2018-12-04 16:04:19 +00:00
|
|
|
// Check that no statement / expression class is polymorphic. LLVM style RTTI
|
|
|
|
// should be used instead. If absolutely needed an exception can still be added
|
|
|
|
// here by defining the appropriate macro (but please don't do this).
|
|
|
|
#define STMT(CLASS, PARENT) \
|
|
|
|
static_assert(!std::is_polymorphic<CLASS>::value, \
|
|
|
|
#CLASS " should not be polymorphic!");
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
|
2019-08-27 11:35:49 +00:00
|
|
|
// Check that no statement / expression class has a non-trival destructor.
|
|
|
|
// Statements and expressions are allocated with the BumpPtrAllocator from
|
|
|
|
// ASTContext and therefore their destructor is not executed.
|
|
|
|
#define STMT(CLASS, PARENT) \
|
|
|
|
static_assert(std::is_trivially_destructible<CLASS>::value, \
|
|
|
|
#CLASS " should be trivially destructible!");
|
|
|
|
// FIXME: InitListExpr is not trivially destructible due to its ASTVector.
|
|
|
|
#define INITLISTEXPR(CLASS, PARENT)
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
|
2007-05-23 21:48:04 +00:00
|
|
|
void Stmt::PrintStats() {
|
2007-08-25 01:42:24 +00:00
|
|
|
// Ensure the table is primed.
|
|
|
|
getStmtInfoTableEntry(Stmt::NullStmtClass);
|
2008-08-05 23:15:29 +00:00
|
|
|
|
2007-05-23 21:48:04 +00:00
|
|
|
unsigned sum = 0;
|
2011-07-04 06:13:27 +00:00
|
|
|
llvm::errs() << "\n*** Stmt/Expr Stats:\n";
|
2010-05-05 15:24:00 +00:00
|
|
|
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
|
2014-05-12 05:36:57 +00:00
|
|
|
if (StmtClassInfo[i].Name == nullptr) continue;
|
2007-08-25 01:42:24 +00:00
|
|
|
sum += StmtClassInfo[i].Counter;
|
2007-05-23 21:48:04 +00:00
|
|
|
}
|
2011-07-04 06:13:27 +00:00
|
|
|
llvm::errs() << " " << sum << " stmts/exprs total.\n";
|
2007-05-23 21:48:04 +00:00
|
|
|
sum = 0;
|
2010-05-05 15:24:00 +00:00
|
|
|
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
|
2014-05-12 05:36:57 +00:00
|
|
|
if (StmtClassInfo[i].Name == nullptr) continue;
|
2009-05-26 14:40:08 +00:00
|
|
|
if (StmtClassInfo[i].Counter == 0) continue;
|
2011-07-04 06:13:27 +00:00
|
|
|
llvm::errs() << " " << StmtClassInfo[i].Counter << " "
|
|
|
|
<< StmtClassInfo[i].Name << ", " << StmtClassInfo[i].Size
|
|
|
|
<< " each (" << StmtClassInfo[i].Counter*StmtClassInfo[i].Size
|
|
|
|
<< " bytes)\n";
|
2007-08-25 01:42:24 +00:00
|
|
|
sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
|
2007-05-23 21:48:04 +00:00
|
|
|
}
|
2011-07-04 06:13:27 +00:00
|
|
|
|
|
|
|
llvm::errs() << "Total bytes = " << sum << "\n";
|
2007-05-23 21:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Stmt::addStmtClass(StmtClass s) {
|
2007-08-25 01:42:24 +00:00
|
|
|
++getStmtInfoTableEntry(s).Counter;
|
2007-05-23 21:48:04 +00:00
|
|
|
}
|
|
|
|
|
2012-03-05 21:42:49 +00:00
|
|
|
bool Stmt::StatisticsEnabled = false;
|
|
|
|
void Stmt::EnableStatistics() {
|
|
|
|
StatisticsEnabled = true;
|
2007-05-23 21:48:04 +00:00
|
|
|
}
|
|
|
|
|
2020-10-18 13:34:41 +02:00
|
|
|
static std::pair<Stmt::Likelihood, const Attr *>
|
|
|
|
getLikelihood(ArrayRef<const Attr *> Attrs) {
|
|
|
|
for (const auto *A : Attrs) {
|
|
|
|
if (isa<LikelyAttr>(A))
|
|
|
|
return std::make_pair(Stmt::LH_Likely, A);
|
|
|
|
|
|
|
|
if (isa<UnlikelyAttr>(A))
|
|
|
|
return std::make_pair(Stmt::LH_Unlikely, A);
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_pair(Stmt::LH_None, nullptr);
|
|
|
|
}
|
|
|
|
|
2020-09-09 19:12:32 +02:00
|
|
|
static std::pair<Stmt::Likelihood, const Attr *> getLikelihood(const Stmt *S) {
|
|
|
|
if (const auto *AS = dyn_cast_or_null<AttributedStmt>(S))
|
2020-10-18 13:34:41 +02:00
|
|
|
return getLikelihood(AS->getAttrs());
|
2020-09-09 19:12:32 +02:00
|
|
|
|
|
|
|
return std::make_pair(Stmt::LH_None, nullptr);
|
|
|
|
}
|
|
|
|
|
2020-10-18 13:34:41 +02:00
|
|
|
Stmt::Likelihood Stmt::getLikelihood(ArrayRef<const Attr *> Attrs) {
|
|
|
|
return ::getLikelihood(Attrs).first;
|
|
|
|
}
|
|
|
|
|
2020-09-09 19:12:32 +02:00
|
|
|
Stmt::Likelihood Stmt::getLikelihood(const Stmt *S) {
|
|
|
|
return ::getLikelihood(S).first;
|
|
|
|
}
|
|
|
|
|
2020-10-31 13:07:06 +01:00
|
|
|
const Attr *Stmt::getLikelihoodAttr(const Stmt *S) {
|
|
|
|
return ::getLikelihood(S).second;
|
|
|
|
}
|
|
|
|
|
2020-09-09 19:12:32 +02:00
|
|
|
Stmt::Likelihood Stmt::getLikelihood(const Stmt *Then, const Stmt *Else) {
|
|
|
|
Likelihood LHT = ::getLikelihood(Then).first;
|
|
|
|
Likelihood LHE = ::getLikelihood(Else).first;
|
|
|
|
if (LHE == LH_None)
|
|
|
|
return LHT;
|
|
|
|
|
|
|
|
// If the same attribute is used on both branches there's a conflict.
|
|
|
|
if (LHT == LHE)
|
|
|
|
return LH_None;
|
|
|
|
|
|
|
|
if (LHT != LH_None)
|
|
|
|
return LHT;
|
|
|
|
|
|
|
|
// Invert the value of Else to get the value for Then.
|
|
|
|
return LHE == LH_Likely ? LH_Unlikely : LH_Likely;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::tuple<bool, const Attr *, const Attr *>
|
|
|
|
Stmt::determineLikelihoodConflict(const Stmt *Then, const Stmt *Else) {
|
|
|
|
std::pair<Likelihood, const Attr *> LHT = ::getLikelihood(Then);
|
|
|
|
std::pair<Likelihood, const Attr *> LHE = ::getLikelihood(Else);
|
|
|
|
// If the same attribute is used on both branches there's a conflict.
|
|
|
|
if (LHT.first != LH_None && LHT.first == LHE.first)
|
|
|
|
return std::make_tuple(true, LHT.second, LHE.second);
|
|
|
|
|
|
|
|
return std::make_tuple(false, nullptr, nullptr);
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Skip no-op (attributed, compound) container stmts and skip captured
|
2014-10-01 06:03:56 +00:00
|
|
|
/// stmt at the top, if \a IgnoreCaptured is true.
|
|
|
|
Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) {
|
|
|
|
Stmt *S = this;
|
|
|
|
if (IgnoreCaptured)
|
|
|
|
if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
|
|
|
|
S = CapS->getCapturedStmt();
|
|
|
|
while (true) {
|
|
|
|
if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
|
|
|
|
S = AS->getSubStmt();
|
|
|
|
else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) {
|
|
|
|
if (CS->size() != 1)
|
|
|
|
break;
|
|
|
|
S = CS->body_back();
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Strip off all label-like statements.
|
2011-09-10 00:02:34 +00:00
|
|
|
///
|
2012-04-14 00:33:13 +00:00
|
|
|
/// This will strip off label statements, case statements, attributed
|
|
|
|
/// statements and default statements recursively.
|
2011-09-10 00:02:34 +00:00
|
|
|
const Stmt *Stmt::stripLabelLikeStatements() const {
|
|
|
|
const Stmt *S = this;
|
|
|
|
while (true) {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *LS = dyn_cast<LabelStmt>(S))
|
2011-09-10 00:02:34 +00:00
|
|
|
S = LS->getSubStmt();
|
2018-04-03 00:11:50 +00:00
|
|
|
else if (const auto *SC = dyn_cast<SwitchCase>(S))
|
2011-09-10 00:02:34 +00:00
|
|
|
S = SC->getSubStmt();
|
2018-04-03 00:11:50 +00:00
|
|
|
else if (const auto *AS = dyn_cast<AttributedStmt>(S))
|
2012-04-14 00:33:13 +00:00
|
|
|
S = AS->getSubStmt();
|
2011-09-10 00:02:34 +00:00
|
|
|
else
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-09 08:16:59 +00:00
|
|
|
namespace {
|
2017-11-14 23:35:42 +00:00
|
|
|
|
2011-02-09 08:16:59 +00:00
|
|
|
struct good {};
|
|
|
|
struct bad {};
|
2011-02-09 08:31:17 +00:00
|
|
|
|
|
|
|
// These silly little functions have to be static inline to suppress
|
|
|
|
// unused warnings, and they have to be defined to suppress other
|
|
|
|
// warnings.
|
2018-04-03 00:11:50 +00:00
|
|
|
static good is_good(good) { return good(); }
|
2011-02-09 08:16:59 +00:00
|
|
|
|
|
|
|
typedef Stmt::child_range children_t();
|
2011-02-09 08:42:57 +00:00
|
|
|
template <class T> good implements_children(children_t T::*) {
|
|
|
|
return good();
|
|
|
|
}
|
2013-09-10 22:57:15 +00:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2018-04-03 00:11:50 +00:00
|
|
|
static bad implements_children(children_t Stmt::*) {
|
2011-02-09 08:42:57 +00:00
|
|
|
return bad();
|
|
|
|
}
|
2011-02-09 08:16:59 +00:00
|
|
|
|
2018-08-09 21:08:08 +00:00
|
|
|
typedef SourceLocation getBeginLoc_t() const;
|
|
|
|
template <class T> good implements_getBeginLoc(getBeginLoc_t T::*) {
|
2011-02-09 08:42:57 +00:00
|
|
|
return good();
|
|
|
|
}
|
2013-09-10 22:57:15 +00:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2018-08-09 21:08:08 +00:00
|
|
|
static bad implements_getBeginLoc(getBeginLoc_t Stmt::*) { return bad(); }
|
2012-12-25 14:51:39 +00:00
|
|
|
|
|
|
|
typedef SourceLocation getLocEnd_t() const;
|
2018-08-09 21:09:38 +00:00
|
|
|
template <class T> good implements_getEndLoc(getLocEnd_t T::*) {
|
2012-12-25 14:51:39 +00:00
|
|
|
return good();
|
|
|
|
}
|
2013-09-10 22:57:15 +00:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2018-08-09 21:09:38 +00:00
|
|
|
static bad implements_getEndLoc(getLocEnd_t Stmt::*) { return bad(); }
|
2011-02-09 08:16:59 +00:00
|
|
|
|
|
|
|
#define ASSERT_IMPLEMENTS_children(type) \
|
2013-09-10 22:57:15 +00:00
|
|
|
(void) is_good(implements_children(&type::children))
|
2018-08-09 21:08:08 +00:00
|
|
|
#define ASSERT_IMPLEMENTS_getBeginLoc(type) \
|
|
|
|
(void)is_good(implements_getBeginLoc(&type::getBeginLoc))
|
2018-08-09 21:09:38 +00:00
|
|
|
#define ASSERT_IMPLEMENTS_getEndLoc(type) \
|
|
|
|
(void)is_good(implements_getEndLoc(&type::getEndLoc))
|
2017-11-14 23:35:42 +00:00
|
|
|
|
|
|
|
} // namespace
|
2011-02-09 08:16:59 +00:00
|
|
|
|
|
|
|
/// Check whether the various Stmt classes implement their member
|
|
|
|
/// functions.
|
2013-09-10 22:57:15 +00:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2011-02-09 08:16:59 +00:00
|
|
|
static inline void check_implementations() {
|
|
|
|
#define ABSTRACT_STMT(type)
|
2018-08-09 21:08:08 +00:00
|
|
|
#define STMT(type, base) \
|
|
|
|
ASSERT_IMPLEMENTS_children(type); \
|
|
|
|
ASSERT_IMPLEMENTS_getBeginLoc(type); \
|
2018-08-09 21:09:38 +00:00
|
|
|
ASSERT_IMPLEMENTS_getEndLoc(type);
|
2011-02-09 08:16:59 +00:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_range Stmt::children() {
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
|
|
|
#define STMT(type, base) \
|
|
|
|
case Stmt::type##Class: \
|
|
|
|
return static_cast<type*>(this)->children();
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown statement kind!");
|
|
|
|
}
|
|
|
|
|
2012-03-09 15:39:19 +00:00
|
|
|
// Amusing macro metaprogramming hack: check whether a class provides
|
2012-12-25 14:51:39 +00:00
|
|
|
// a more specific implementation of getSourceRange.
|
2012-03-09 15:39:19 +00:00
|
|
|
//
|
|
|
|
// See also Expr.cpp:getExprLoc().
|
|
|
|
namespace {
|
2017-11-14 23:35:42 +00:00
|
|
|
|
2012-03-09 15:39:19 +00:00
|
|
|
/// This implementation is used when a class provides a custom
|
2012-12-25 14:51:39 +00:00
|
|
|
/// implementation of getSourceRange.
|
2012-03-09 15:39:19 +00:00
|
|
|
template <class S, class T>
|
2012-12-25 14:51:39 +00:00
|
|
|
SourceRange getSourceRangeImpl(const Stmt *stmt,
|
|
|
|
SourceRange (T::*v)() const) {
|
|
|
|
return static_cast<const S*>(stmt)->getSourceRange();
|
2012-03-09 15:39:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This implementation is used when a class doesn't provide a custom
|
2012-12-25 14:51:39 +00:00
|
|
|
/// implementation of getSourceRange. Overload resolution should pick it over
|
2012-03-09 15:39:19 +00:00
|
|
|
/// the implementation above because it's more specialized according to
|
|
|
|
/// function template partial ordering.
|
|
|
|
template <class S>
|
2012-12-25 14:51:39 +00:00
|
|
|
SourceRange getSourceRangeImpl(const Stmt *stmt,
|
|
|
|
SourceRange (Stmt::*v)() const) {
|
2018-08-09 21:08:08 +00:00
|
|
|
return SourceRange(static_cast<const S *>(stmt)->getBeginLoc(),
|
2018-08-09 21:09:38 +00:00
|
|
|
static_cast<const S *>(stmt)->getEndLoc());
|
2012-03-09 15:39:19 +00:00
|
|
|
}
|
2017-11-14 23:35:42 +00:00
|
|
|
|
|
|
|
} // namespace
|
2012-03-09 15:39:19 +00:00
|
|
|
|
2012-12-25 14:51:39 +00:00
|
|
|
SourceRange Stmt::getSourceRange() const {
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
|
|
|
#define STMT(type, base) \
|
|
|
|
case Stmt::type##Class: \
|
|
|
|
return getSourceRangeImpl<type>(this, &type::getSourceRange);
|
|
|
|
#include "clang/AST/StmtNodes.inc"
|
2012-03-09 15:39:19 +00:00
|
|
|
}
|
2012-12-25 14:51:39 +00:00
|
|
|
llvm_unreachable("unknown statement kind!");
|
2012-03-09 15:39:19 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 20:05:03 +00:00
|
|
|
SourceLocation Stmt::getBeginLoc() const {
|
2012-03-09 15:39:19 +00:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
2018-08-09 21:08:08 +00:00
|
|
|
#define STMT(type, base) \
|
|
|
|
case Stmt::type##Class: \
|
|
|
|
return static_cast<const type *>(this)->getBeginLoc();
|
2012-03-09 15:39:19 +00:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown statement kind");
|
|
|
|
}
|
|
|
|
|
2018-08-09 20:05:47 +00:00
|
|
|
SourceLocation Stmt::getEndLoc() const {
|
2012-03-09 15:39:19 +00:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
2018-08-09 21:09:38 +00:00
|
|
|
#define STMT(type, base) \
|
|
|
|
case Stmt::type##Class: \
|
|
|
|
return static_cast<const type *>(this)->getEndLoc();
|
2012-03-09 15:39:19 +00:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown statement kind");
|
|
|
|
}
|
|
|
|
|
2018-09-15 02:01:47 +00:00
|
|
|
int64_t Stmt::getID(const ASTContext &Context) const {
|
2018-12-03 22:19:05 +00:00
|
|
|
return Context.getAllocator().identifyKnownAlignedObject<Stmt>(this);
|
2018-09-15 02:01:47 +00:00
|
|
|
}
|
|
|
|
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
CompoundStmt::CompoundStmt(ArrayRef<Stmt *> Stmts, FPOptionsOverride FPFeatures,
|
|
|
|
SourceLocation LB, SourceLocation RB)
|
2022-05-15 22:35:46 +07:00
|
|
|
: Stmt(CompoundStmtClass), LBraceLoc(LB), RBraceLoc(RB) {
|
2012-12-29 20:03:39 +00:00
|
|
|
CompoundStmtBits.NumStmts = Stmts.size();
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
CompoundStmtBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
|
2017-12-24 16:24:20 +00:00
|
|
|
setStmts(Stmts);
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
if (hasStoredFPFeatures())
|
|
|
|
setStoredFPFeatures(FPFeatures);
|
2017-12-24 16:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CompoundStmt::setStmts(ArrayRef<Stmt *> Stmts) {
|
2012-12-29 20:03:39 +00:00
|
|
|
assert(CompoundStmtBits.NumStmts == Stmts.size() &&
|
2012-07-04 17:03:41 +00:00
|
|
|
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
|
|
|
|
|
2017-12-24 16:24:20 +00:00
|
|
|
std::copy(Stmts.begin(), Stmts.end(), body_begin());
|
2012-07-04 17:03:41 +00:00
|
|
|
}
|
|
|
|
|
2017-12-24 16:24:20 +00:00
|
|
|
CompoundStmt *CompoundStmt::Create(const ASTContext &C, ArrayRef<Stmt *> Stmts,
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
FPOptionsOverride FPFeatures,
|
2017-12-24 16:24:20 +00:00
|
|
|
SourceLocation LB, SourceLocation RB) {
|
|
|
|
void *Mem =
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
C.Allocate(totalSizeToAlloc<Stmt *, FPOptionsOverride>(
|
|
|
|
Stmts.size(), FPFeatures.requiresTrailingStorage()),
|
|
|
|
alignof(CompoundStmt));
|
|
|
|
return new (Mem) CompoundStmt(Stmts, FPFeatures, LB, RB);
|
2017-12-24 16:24:20 +00:00
|
|
|
}
|
2009-04-17 00:04:06 +00:00
|
|
|
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
CompoundStmt *CompoundStmt::CreateEmpty(const ASTContext &C, unsigned NumStmts,
|
|
|
|
bool HasFPFeatures) {
|
|
|
|
void *Mem = C.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, FPOptionsOverride>(NumStmts, HasFPFeatures),
|
|
|
|
alignof(CompoundStmt));
|
2017-12-24 16:24:20 +00:00
|
|
|
CompoundStmt *New = new (Mem) CompoundStmt(EmptyShell());
|
|
|
|
New->CompoundStmtBits.NumStmts = NumStmts;
|
[FPEnv] Allow CompoundStmt to keep FP options
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2,
reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused
fails because the test ast-print-fp-pragmas.c did not specify particular
target, and it failed on targets which do not support constrained
intrinsics. The original commit message is below.
AST does not have special nodes for pragmas. Instead a pragma modifies
some state variables of Sema, which in turn results in modified
attributes of AST nodes. This technique applies to floating point
operations as well. Every AST node that can depend on FP options keeps
current set of them.
This technique works well for options like exception behavior or fast
math options. They represent instructions to the compiler how to modify
code generation for the affected nodes. However treatment of FP control
modes has problems with this technique. Modifying FP control mode
(like rounding direction) usually requires operations on hardware, like
writing to control registers. It must be done prior to the first
operation that depends on the control mode. In particular, such
operations are required for implementation of `pragma STDC FENV_ROUND`,
compiler should set up necessary rounding direction at the beginning of
compound statement where the pragma occurs. As there is no representation
for pragmas in AST, the code generation becomes a complicated task in
this case.
To solve this issue FP options are kept inside CompoundStmt. Unlike to FP
options in expressions, these does not affect any operation on FP values,
but only inform the codegen about the FP options that act in the body of
the statement. As all pragmas that modify FP environment may occurs only
at the start of compound statement or at global level, such solution
works for all relevant pragmas. The options are kept as a difference
from the options in the enclosing compound statement or default options,
it helps codegen to set only changed control modes.
Differential Revision: https://reviews.llvm.org/D123952
2022-07-01 18:32:26 +07:00
|
|
|
New->CompoundStmtBits.HasFPFeatures = HasFPFeatures;
|
2017-12-24 16:24:20 +00:00
|
|
|
return New;
|
2009-04-17 00:04:06 +00:00
|
|
|
}
|
2007-05-23 21:48:04 +00:00
|
|
|
|
2019-02-15 00:27:53 +00:00
|
|
|
const Expr *ValueStmt::getExprStmt() const {
|
|
|
|
const Stmt *S = this;
|
|
|
|
do {
|
|
|
|
if (const auto *E = dyn_cast<Expr>(S))
|
|
|
|
return E;
|
|
|
|
|
|
|
|
if (const auto *LS = dyn_cast<LabelStmt>(S))
|
|
|
|
S = LS->getSubStmt();
|
|
|
|
else if (const auto *AS = dyn_cast<AttributedStmt>(S))
|
|
|
|
S = AS->getSubStmt();
|
|
|
|
else
|
|
|
|
llvm_unreachable("unknown kind of ValueStmt");
|
|
|
|
} while (isa<ValueStmt>(S));
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2007-05-28 06:56:27 +00:00
|
|
|
const char *LabelStmt::getName() const {
|
2011-02-17 07:39:24 +00:00
|
|
|
return getDecl()->getIdentifier()->getNameStart();
|
2007-05-28 06:56:27 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc,
|
2012-07-09 10:04:07 +00:00
|
|
|
ArrayRef<const Attr*> Attrs,
|
|
|
|
Stmt *SubStmt) {
|
2014-05-13 14:55:01 +00:00
|
|
|
assert(!Attrs.empty() && "Attrs should not be empty");
|
2017-12-24 16:24:11 +00:00
|
|
|
void *Mem = C.Allocate(totalSizeToAlloc<const Attr *>(Attrs.size()),
|
2016-10-20 14:27:22 +00:00
|
|
|
alignof(AttributedStmt));
|
2012-07-09 10:04:07 +00:00
|
|
|
return new (Mem) AttributedStmt(Loc, Attrs, SubStmt);
|
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C,
|
|
|
|
unsigned NumAttrs) {
|
2012-07-09 10:04:07 +00:00
|
|
|
assert(NumAttrs > 0 && "NumAttrs should be greater than zero");
|
2017-12-24 16:24:11 +00:00
|
|
|
void *Mem = C.Allocate(totalSizeToAlloc<const Attr *>(NumAttrs),
|
2016-10-20 14:27:22 +00:00
|
|
|
alignof(AttributedStmt));
|
2012-07-09 10:04:07 +00:00
|
|
|
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
|
|
|
|
}
|
|
|
|
|
2013-08-22 06:02:26 +00:00
|
|
|
std::string AsmStmt::generateAsmString(const ASTContext &C) const {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return gccAsmStmt->generateAsmString(C);
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return msAsmStmt->generateAsmString(C);
|
2012-08-28 17:43:23 +00:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
2025-03-17 20:10:46 +01:00
|
|
|
std::string AsmStmt::getOutputConstraint(unsigned i) const {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return gccAsmStmt->getOutputConstraint(i);
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2025-03-17 20:10:46 +01:00
|
|
|
return msAsmStmt->getOutputConstraint(i).str();
|
2012-08-28 17:43:23 +00:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
const Expr *AsmStmt::getOutputExpr(unsigned i) const {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return gccAsmStmt->getOutputExpr(i);
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return msAsmStmt->getOutputExpr(i);
|
2012-08-28 17:43:23 +00:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
2025-03-17 20:10:46 +01:00
|
|
|
std::string AsmStmt::getInputConstraint(unsigned i) const {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return gccAsmStmt->getInputConstraint(i);
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2025-03-17 20:10:46 +01:00
|
|
|
return msAsmStmt->getInputConstraint(i).str();
|
2012-08-28 17:43:23 +00:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
const Expr *AsmStmt::getInputExpr(unsigned i) const {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return gccAsmStmt->getInputExpr(i);
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return msAsmStmt->getInputExpr(i);
|
2012-08-28 17:43:23 +00:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
2025-03-17 20:10:46 +01:00
|
|
|
std::string AsmStmt::getClobber(unsigned i) const {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-28 18:21:14 +00:00
|
|
|
return gccAsmStmt->getClobber(i);
|
2018-04-03 00:11:50 +00:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2025-03-17 20:10:46 +01:00
|
|
|
return msAsmStmt->getClobber(i).str();
|
2012-08-28 17:43:23 +00:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
2012-08-28 00:24:05 +00:00
|
|
|
/// getNumPlusOperands - Return the number of output operands that have a "+"
|
|
|
|
/// constraint.
|
|
|
|
unsigned AsmStmt::getNumPlusOperands() const {
|
|
|
|
unsigned Res = 0;
|
|
|
|
for (unsigned i = 0, e = getNumOutputs(); i != e; ++i)
|
|
|
|
if (isOutputPlusConstraint(i))
|
|
|
|
++Res;
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2014-08-22 06:05:21 +00:00
|
|
|
char GCCAsmStmt::AsmStringPiece::getModifier() const {
|
|
|
|
assert(isOperand() && "Only Operands can have modifiers.");
|
|
|
|
return isLetter(Str[0]) ? Str[0] : '\0';
|
|
|
|
}
|
|
|
|
|
2025-03-17 20:10:46 +01:00
|
|
|
std::string GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(const Expr *E) {
|
|
|
|
if (auto *SL = llvm::dyn_cast<StringLiteral>(E))
|
|
|
|
return SL->getString().str();
|
|
|
|
assert(E->getDependence() == ExprDependence::None &&
|
|
|
|
"cannot extract a string from a dependent expression");
|
|
|
|
auto *CE = cast<ConstantExpr>(E);
|
|
|
|
APValue Res = CE->getAPValueResult();
|
|
|
|
assert(Res.isArray() && "expected an array");
|
|
|
|
|
|
|
|
std::string Out;
|
|
|
|
Out.reserve(Res.getArraySize());
|
|
|
|
for (unsigned I = 0; I < Res.getArraySize(); ++I) {
|
|
|
|
APValue C = Res.getArrayInitializedElt(I);
|
|
|
|
assert(C.isInt());
|
|
|
|
auto Ch = static_cast<char>(C.getInt().getExtValue());
|
|
|
|
Out.push_back(Ch);
|
|
|
|
}
|
|
|
|
return Out;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GCCAsmStmt::getAsmString() const {
|
|
|
|
return ExtractStringFromGCCAsmStmtComponent(getAsmStringExpr());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GCCAsmStmt::getClobber(unsigned i) const {
|
|
|
|
return ExtractStringFromGCCAsmStmtComponent(getClobberExpr(i));
|
2012-08-27 23:47:56 +00:00
|
|
|
}
|
|
|
|
|
2012-08-25 00:11:56 +00:00
|
|
|
Expr *GCCAsmStmt::getOutputExpr(unsigned i) {
|
2008-10-27 18:40:21 +00:00
|
|
|
return cast<Expr>(Exprs[i]);
|
|
|
|
}
|
2009-03-10 04:59:06 +00:00
|
|
|
|
|
|
|
/// getOutputConstraint - Return the constraint string for the specified
|
|
|
|
/// output operand. All output constraints are known to be non-empty (either
|
|
|
|
/// '=' or '+').
|
2025-03-17 20:10:46 +01:00
|
|
|
std::string GCCAsmStmt::getOutputConstraint(unsigned i) const {
|
|
|
|
return ExtractStringFromGCCAsmStmtComponent(getOutputConstraintExpr(i));
|
2008-10-27 18:40:21 +00:00
|
|
|
}
|
2009-03-10 04:59:06 +00:00
|
|
|
|
2012-08-25 00:11:56 +00:00
|
|
|
Expr *GCCAsmStmt::getInputExpr(unsigned i) {
|
2008-10-27 18:40:21 +00:00
|
|
|
return cast<Expr>(Exprs[i + NumOutputs]);
|
|
|
|
}
|
2017-11-14 23:35:42 +00:00
|
|
|
|
2012-08-25 00:11:56 +00:00
|
|
|
void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
|
2011-02-21 22:09:29 +00:00
|
|
|
Exprs[i + NumOutputs] = E;
|
|
|
|
}
|
|
|
|
|
2019-06-03 15:57:25 +00:00
|
|
|
AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const {
|
Support output constraints on "asm goto"
Summary:
Clang's "asm goto" feature didn't initially support outputs constraints. That
was the same behavior as gcc's implementation. The decision by gcc not to
support outputs was based on a restriction in their IR regarding terminators.
LLVM doesn't restrict terminators from returning values (e.g. 'invoke'), so
it made sense to support this feature.
Output values are valid only on the 'fallthrough' path. If an output value's used
on an indirect branch, then it's 'poisoned'.
In theory, outputs *could* be valid on the 'indirect' paths, but it's very
difficult to guarantee that the original semantics would be retained. E.g.
because indirect labels could be used as data, we wouldn't be able to split
critical edges in situations where two 'callbr' instructions have the same
indirect label, because the indirect branch's destination would no longer be
the same.
Reviewers: jyknight, nickdesaulniers, hfinkel
Reviewed By: jyknight, nickdesaulniers
Subscribers: MaskRay, rsmith, hiraditya, llvm-commits, cfe-commits, craig.topper, rnk
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D69876
2020-02-24 18:32:50 -08:00
|
|
|
return cast<AddrLabelExpr>(Exprs[i + NumOutputs + NumInputs]);
|
2019-06-03 15:57:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef GCCAsmStmt::getLabelName(unsigned i) const {
|
|
|
|
return getLabelExpr(i)->getLabel()->getName();
|
|
|
|
}
|
|
|
|
|
2009-03-10 04:59:06 +00:00
|
|
|
/// getInputConstraint - Return the specified input constraint. Unlike output
|
|
|
|
/// constraints, these can be empty.
|
2025-03-17 20:10:46 +01:00
|
|
|
std::string GCCAsmStmt::getInputConstraint(unsigned i) const {
|
|
|
|
return ExtractStringFromGCCAsmStmtComponent(getInputConstraintExpr(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GCCAsmStmt::setOutputsAndInputsAndClobbers(
|
|
|
|
const ASTContext &C, IdentifierInfo **Names, Expr **Constraints,
|
|
|
|
Stmt **Exprs, unsigned NumOutputs, unsigned NumInputs, unsigned NumLabels,
|
|
|
|
Expr **Clobbers, unsigned NumClobbers) {
|
2009-04-17 20:57:14 +00:00
|
|
|
this->NumOutputs = NumOutputs;
|
|
|
|
this->NumInputs = NumInputs;
|
2010-01-30 23:19:41 +00:00
|
|
|
this->NumClobbers = NumClobbers;
|
2019-06-03 15:57:25 +00:00
|
|
|
this->NumLabels = NumLabels;
|
2010-01-30 23:19:41 +00:00
|
|
|
|
2019-06-03 15:57:25 +00:00
|
|
|
unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2010-01-30 23:19:41 +00:00
|
|
|
C.Deallocate(this->Names);
|
|
|
|
this->Names = new (C) IdentifierInfo*[NumExprs];
|
|
|
|
std::copy(Names, Names + NumExprs, this->Names);
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2010-01-30 23:19:41 +00:00
|
|
|
C.Deallocate(this->Exprs);
|
|
|
|
this->Exprs = new (C) Stmt*[NumExprs];
|
|
|
|
std::copy(Exprs, Exprs + NumExprs, this->Exprs);
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2019-05-30 07:21:08 +00:00
|
|
|
unsigned NumConstraints = NumOutputs + NumInputs;
|
2010-01-30 23:19:41 +00:00
|
|
|
C.Deallocate(this->Constraints);
|
2025-03-17 20:10:46 +01:00
|
|
|
this->Constraints = new (C) Expr *[NumConstraints];
|
2019-05-30 07:21:08 +00:00
|
|
|
std::copy(Constraints, Constraints + NumConstraints, this->Constraints);
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2010-01-30 23:19:41 +00:00
|
|
|
C.Deallocate(this->Clobbers);
|
2025-03-17 20:10:46 +01:00
|
|
|
this->Clobbers = new (C) Expr *[NumClobbers];
|
2010-01-30 23:19:41 +00:00
|
|
|
std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
|
2009-04-17 20:57:14 +00:00
|
|
|
}
|
|
|
|
|
2009-03-10 06:33:24 +00:00
|
|
|
/// getNamedOperand - Given a symbolic operand reference like %[foo],
|
|
|
|
/// translate this into a numeric value needed to reference the same operand.
|
|
|
|
/// This returns -1 if the operand name is invalid.
|
2012-08-25 00:11:56 +00:00
|
|
|
int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
|
2009-03-10 06:33:24 +00:00
|
|
|
// Check if this is an output operand.
|
2022-01-11 11:51:22 -08:00
|
|
|
unsigned NumOutputs = getNumOutputs();
|
|
|
|
for (unsigned i = 0; i != NumOutputs; ++i)
|
2009-03-10 06:33:24 +00:00
|
|
|
if (getOutputName(i) == SymbolicName)
|
|
|
|
return i;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2022-01-11 11:51:22 -08:00
|
|
|
unsigned NumInputs = getNumInputs();
|
|
|
|
for (unsigned i = 0; i != NumInputs; ++i)
|
2009-03-10 06:33:24 +00:00
|
|
|
if (getInputName(i) == SymbolicName)
|
2022-01-11 11:51:22 -08:00
|
|
|
return NumOutputs + i;
|
2009-03-10 06:33:24 +00:00
|
|
|
|
2019-06-03 15:57:25 +00:00
|
|
|
for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
|
|
|
|
if (getLabelName(i) == SymbolicName)
|
2022-01-11 11:51:22 -08:00
|
|
|
return NumOutputs + NumInputs + getNumPlusOperands() + i;
|
2019-06-03 15:57:25 +00:00
|
|
|
|
2009-03-10 06:33:24 +00:00
|
|
|
// Not found.
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-03-10 23:21:44 +00:00
|
|
|
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
|
|
|
|
/// it into pieces. If the asm string is erroneous, emit errors and return
|
|
|
|
/// true, otherwise return false.
|
2012-08-25 00:11:56 +00:00
|
|
|
unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
|
2013-08-22 06:02:26 +00:00
|
|
|
const ASTContext &C, unsigned &DiagOffs) const {
|
2025-03-17 20:10:46 +01:00
|
|
|
|
|
|
|
std::string Str = getAsmString();
|
|
|
|
const char *StrStart = Str.data();
|
|
|
|
const char *StrEnd = Str.data() + Str.size();
|
2009-03-10 23:51:40 +00:00
|
|
|
const char *CurPtr = StrStart;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-10 23:21:44 +00:00
|
|
|
// "Simple" inline asms have no constraints or operands, just convert the asm
|
|
|
|
// string to escape $'s.
|
|
|
|
if (isSimple()) {
|
|
|
|
std::string Result;
|
2009-03-10 23:51:40 +00:00
|
|
|
for (; CurPtr != StrEnd; ++CurPtr) {
|
|
|
|
switch (*CurPtr) {
|
2009-03-10 23:21:44 +00:00
|
|
|
case '$':
|
|
|
|
Result += "$$";
|
|
|
|
break;
|
|
|
|
default:
|
2009-03-10 23:51:40 +00:00
|
|
|
Result += *CurPtr;
|
2009-03-10 23:21:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Pieces.push_back(AsmStringPiece(Result));
|
2009-03-10 23:51:40 +00:00
|
|
|
return 0;
|
2009-03-10 23:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CurStringPiece - The current string that we are building up as we scan the
|
|
|
|
// asm string.
|
|
|
|
std::string CurStringPiece;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2011-09-02 00:18:52 +00:00
|
|
|
bool HasVariants = !C.getTargetInfo().hasNoAsmVariants();
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2016-05-16 22:52:23 +00:00
|
|
|
unsigned LastAsmStringToken = 0;
|
|
|
|
unsigned LastAsmStringOffset = 0;
|
|
|
|
|
2017-11-14 23:35:42 +00:00
|
|
|
while (true) {
|
2009-03-10 23:21:44 +00:00
|
|
|
// Done with the string?
|
2009-03-10 23:51:40 +00:00
|
|
|
if (CurPtr == StrEnd) {
|
2009-03-10 23:21:44 +00:00
|
|
|
if (!CurStringPiece.empty())
|
|
|
|
Pieces.push_back(AsmStringPiece(CurStringPiece));
|
2009-03-10 23:51:40 +00:00
|
|
|
return 0;
|
2009-03-10 23:21:44 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-10 23:51:40 +00:00
|
|
|
char CurChar = *CurPtr++;
|
2010-04-05 18:44:00 +00:00
|
|
|
switch (CurChar) {
|
|
|
|
case '$': CurStringPiece += "$$"; continue;
|
2010-04-23 16:29:58 +00:00
|
|
|
case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
|
|
|
|
case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
|
|
|
|
case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
|
2010-04-05 18:44:00 +00:00
|
|
|
case '%':
|
|
|
|
break;
|
|
|
|
default:
|
2009-03-10 23:21:44 +00:00
|
|
|
CurStringPiece += CurChar;
|
|
|
|
continue;
|
|
|
|
}
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2021-05-21 15:15:11 -07:00
|
|
|
const TargetInfo &TI = C.getTargetInfo();
|
|
|
|
|
2009-03-10 23:21:44 +00:00
|
|
|
// Escaped "%" character in asm string.
|
2009-03-11 00:06:36 +00:00
|
|
|
if (CurPtr == StrEnd) {
|
|
|
|
// % at end of string is invalid (no escape).
|
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
|
|
|
return diag::err_asm_invalid_escape;
|
|
|
|
}
|
2016-10-31 15:27:54 +00:00
|
|
|
// Handle escaped char and continue looping over the asm string.
|
2009-03-10 23:51:40 +00:00
|
|
|
char EscapedChar = *CurPtr++;
|
2016-10-31 15:27:54 +00:00
|
|
|
switch (EscapedChar) {
|
|
|
|
default:
|
2021-05-21 15:15:11 -07:00
|
|
|
// Handle target-specific escaped characters.
|
|
|
|
if (auto MaybeReplaceStr = TI.handleAsmEscapedChar(EscapedChar)) {
|
|
|
|
CurStringPiece += *MaybeReplaceStr;
|
|
|
|
continue;
|
|
|
|
}
|
2016-10-31 15:27:54 +00:00
|
|
|
break;
|
|
|
|
case '%': // %% -> %
|
|
|
|
case '{': // %{ -> {
|
|
|
|
case '}': // %} -> }
|
|
|
|
CurStringPiece += EscapedChar;
|
2009-03-10 23:21:44 +00:00
|
|
|
continue;
|
2016-10-31 15:27:54 +00:00
|
|
|
case '=': // %= -> Generate a unique ID.
|
2009-03-10 23:21:44 +00:00
|
|
|
CurStringPiece += "${:uid}";
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-10 23:21:44 +00:00
|
|
|
// Otherwise, we have an operand. If we have accumulated a string so far,
|
|
|
|
// add it to the Pieces list.
|
|
|
|
if (!CurStringPiece.empty()) {
|
|
|
|
Pieces.push_back(AsmStringPiece(CurStringPiece));
|
|
|
|
CurStringPiece.clear();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2014-08-22 06:05:21 +00:00
|
|
|
// Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that
|
|
|
|
// don't (e.g., %x4). 'x' following the '%' is the constraint modifier.
|
|
|
|
|
|
|
|
const char *Begin = CurPtr - 1; // Points to the character following '%'.
|
|
|
|
const char *Percent = Begin - 1; // Points to '%'.
|
|
|
|
|
2013-02-08 22:30:41 +00:00
|
|
|
if (isLetter(EscapedChar)) {
|
2011-07-05 11:13:37 +00:00
|
|
|
if (CurPtr == StrEnd) { // Premature end.
|
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
|
|
|
return diag::err_asm_invalid_escape;
|
|
|
|
}
|
2025-02-27 11:34:16 -08:00
|
|
|
|
|
|
|
// Specifically handle `cc` which we will alias to `c`.
|
|
|
|
// Note this is the only operand modifier that exists which has two
|
|
|
|
// characters.
|
|
|
|
if (EscapedChar == 'c' && *CurPtr == 'c')
|
|
|
|
CurPtr++;
|
|
|
|
|
2009-03-10 23:51:40 +00:00
|
|
|
EscapedChar = *CurPtr++;
|
2009-03-10 23:21:44 +00:00
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2014-08-22 06:05:21 +00:00
|
|
|
const SourceManager &SM = C.getSourceManager();
|
|
|
|
const LangOptions &LO = C.getLangOpts();
|
|
|
|
|
|
|
|
// Handle operands that don't have asmSymbolicName (e.g., %x4).
|
2013-02-08 22:30:41 +00:00
|
|
|
if (isDigit(EscapedChar)) {
|
2009-03-10 23:21:44 +00:00
|
|
|
// %n - Assembler operand n
|
2009-03-11 22:52:17 +00:00
|
|
|
unsigned N = 0;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-11 22:52:17 +00:00
|
|
|
--CurPtr;
|
2013-02-08 22:30:41 +00:00
|
|
|
while (CurPtr != StrEnd && isDigit(*CurPtr))
|
2009-03-11 23:09:16 +00:00
|
|
|
N = N*10 + ((*CurPtr++)-'0');
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2019-06-03 15:57:25 +00:00
|
|
|
unsigned NumOperands = getNumOutputs() + getNumPlusOperands() +
|
|
|
|
getNumInputs() + getNumLabels();
|
2009-03-11 00:23:13 +00:00
|
|
|
if (N >= NumOperands) {
|
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
|
|
|
return diag::err_asm_invalid_operand_number;
|
|
|
|
}
|
|
|
|
|
2014-08-22 06:05:21 +00:00
|
|
|
// Str contains "x4" (Operand without the leading %).
|
|
|
|
std::string Str(Begin, CurPtr - Begin);
|
|
|
|
// (BeginLoc, EndLoc) represents the range of the operand we are currently
|
|
|
|
// processing. Unlike Str, the range includes the leading '%'.
|
2025-03-17 20:10:46 +01:00
|
|
|
SourceLocation BeginLoc, EndLoc;
|
|
|
|
if (auto *SL = dyn_cast<StringLiteral>(getAsmStringExpr())) {
|
|
|
|
BeginLoc =
|
|
|
|
SL->getLocationOfByte(Percent - StrStart, SM, LO, TI,
|
|
|
|
&LastAsmStringToken, &LastAsmStringOffset);
|
|
|
|
EndLoc =
|
|
|
|
SL->getLocationOfByte(CurPtr - StrStart, SM, LO, TI,
|
|
|
|
&LastAsmStringToken, &LastAsmStringOffset);
|
|
|
|
} else {
|
|
|
|
BeginLoc = getAsmStringExpr()->getBeginLoc();
|
|
|
|
EndLoc = getAsmStringExpr()->getEndLoc();
|
|
|
|
}
|
2014-08-22 06:05:21 +00:00
|
|
|
|
2015-05-29 19:42:19 +00:00
|
|
|
Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc);
|
2009-03-10 23:21:44 +00:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2014-08-22 06:05:21 +00:00
|
|
|
// Handle operands that have asmSymbolicName (e.g., %x[foo]).
|
2009-03-10 23:21:44 +00:00
|
|
|
if (EscapedChar == '[') {
|
2009-03-11 00:06:36 +00:00
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-11 00:06:36 +00:00
|
|
|
// Find the ']'.
|
2009-03-10 23:51:40 +00:00
|
|
|
const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
|
2014-05-12 05:36:57 +00:00
|
|
|
if (NameEnd == nullptr)
|
2009-03-11 00:06:36 +00:00
|
|
|
return diag::err_asm_unterminated_symbolic_operand_name;
|
|
|
|
if (NameEnd == CurPtr)
|
|
|
|
return diag::err_asm_empty_symbolic_operand_name;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2011-07-23 10:55:15 +00:00
|
|
|
StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-10 23:21:44 +00:00
|
|
|
int N = getNamedOperand(SymbolicName);
|
2009-03-11 00:06:36 +00:00
|
|
|
if (N == -1) {
|
|
|
|
// Verify that an operand with that name exists.
|
|
|
|
DiagOffs = CurPtr-StrStart;
|
|
|
|
return diag::err_asm_unknown_symbolic_operand_name;
|
|
|
|
}
|
2014-08-22 06:05:21 +00:00
|
|
|
|
|
|
|
// Str contains "x[foo]" (Operand without the leading %).
|
|
|
|
std::string Str(Begin, NameEnd + 1 - Begin);
|
|
|
|
|
|
|
|
// (BeginLoc, EndLoc) represents the range of the operand we are currently
|
|
|
|
// processing. Unlike Str, the range includes the leading '%'.
|
2025-03-17 20:10:46 +01:00
|
|
|
SourceLocation BeginLoc, EndLoc;
|
|
|
|
if (auto *SL = dyn_cast<StringLiteral>(getAsmStringExpr())) {
|
|
|
|
BeginLoc =
|
|
|
|
SL->getLocationOfByte(Percent - StrStart, SM, LO, TI,
|
|
|
|
&LastAsmStringToken, &LastAsmStringOffset);
|
|
|
|
EndLoc =
|
|
|
|
SL->getLocationOfByte(NameEnd + 1 - StrStart, SM, LO, TI,
|
|
|
|
&LastAsmStringToken, &LastAsmStringOffset);
|
|
|
|
} else {
|
|
|
|
BeginLoc = getAsmStringExpr()->getBeginLoc();
|
|
|
|
EndLoc = getAsmStringExpr()->getEndLoc();
|
|
|
|
}
|
2014-08-22 06:05:21 +00:00
|
|
|
|
2015-05-29 19:42:19 +00:00
|
|
|
Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-11 00:06:36 +00:00
|
|
|
CurPtr = NameEnd+1;
|
2009-03-10 23:21:44 +00:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-10 23:57:07 +00:00
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
2009-03-10 23:51:40 +00:00
|
|
|
return diag::err_asm_invalid_escape;
|
2009-03-10 23:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-27 20:23:31 +00:00
|
|
|
|
|
|
|
/// Assemble final IR asm string (GCC-style).
|
2013-08-22 06:02:26 +00:00
|
|
|
std::string GCCAsmStmt::generateAsmString(const ASTContext &C) const {
|
2012-08-24 17:05:45 +00:00
|
|
|
// Analyze the asm string to decompose it into its pieces. We know that Sema
|
|
|
|
// has already done this, so it is guaranteed to be successful.
|
2012-08-25 00:11:56 +00:00
|
|
|
SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces;
|
2012-08-24 17:05:45 +00:00
|
|
|
unsigned DiagOffs;
|
|
|
|
AnalyzeAsmString(Pieces, C, DiagOffs);
|
|
|
|
|
|
|
|
std::string AsmString;
|
2018-04-03 00:11:50 +00:00
|
|
|
for (const auto &Piece : Pieces) {
|
|
|
|
if (Piece.isString())
|
|
|
|
AsmString += Piece.getString();
|
|
|
|
else if (Piece.getModifier() == '\0')
|
|
|
|
AsmString += '$' + llvm::utostr(Piece.getOperandNo());
|
2012-08-24 17:05:45 +00:00
|
|
|
else
|
2018-04-03 00:11:50 +00:00
|
|
|
AsmString += "${" + llvm::utostr(Piece.getOperandNo()) + ':' +
|
|
|
|
Piece.getModifier() + '}';
|
2012-08-24 17:05:45 +00:00
|
|
|
}
|
|
|
|
return AsmString;
|
|
|
|
}
|
2009-03-10 23:21:44 +00:00
|
|
|
|
2012-08-27 20:23:31 +00:00
|
|
|
/// Assemble final IR asm string (MS-style).
|
2013-08-22 06:02:26 +00:00
|
|
|
std::string MSAsmStmt::generateAsmString(const ASTContext &C) const {
|
2012-08-27 20:23:31 +00:00
|
|
|
// FIXME: This needs to be translated into the IR string representation.
|
2020-10-30 11:11:35 +08:00
|
|
|
SmallVector<StringRef, 8> Pieces;
|
|
|
|
AsmStr.split(Pieces, "\n\t");
|
|
|
|
std::string MSAsmString;
|
|
|
|
for (size_t I = 0, E = Pieces.size(); I < E; ++I) {
|
|
|
|
StringRef Instruction = Pieces[I];
|
|
|
|
// For vex/vex2/vex3/evex masm style prefix, convert it to att style
|
|
|
|
// since we don't support masm style prefix in backend.
|
2023-12-13 08:54:13 -08:00
|
|
|
if (Instruction.starts_with("vex "))
|
2020-10-30 11:11:35 +08:00
|
|
|
MSAsmString += '{' + Instruction.substr(0, 3).str() + '}' +
|
|
|
|
Instruction.substr(3).str();
|
2023-12-13 08:54:13 -08:00
|
|
|
else if (Instruction.starts_with("vex2 ") ||
|
|
|
|
Instruction.starts_with("vex3 ") ||
|
|
|
|
Instruction.starts_with("evex "))
|
2020-10-30 11:11:35 +08:00
|
|
|
MSAsmString += '{' + Instruction.substr(0, 4).str() + '}' +
|
|
|
|
Instruction.substr(4).str();
|
|
|
|
else
|
|
|
|
MSAsmString += Instruction.str();
|
|
|
|
// If this is not the last instruction, adding back the '\n\t'.
|
|
|
|
if (I < E - 1)
|
|
|
|
MSAsmString += "\n\t";
|
|
|
|
}
|
|
|
|
return MSAsmString;
|
2012-08-27 20:23:31 +00:00
|
|
|
}
|
|
|
|
|
2012-08-24 00:07:09 +00:00
|
|
|
Expr *MSAsmStmt::getOutputExpr(unsigned i) {
|
|
|
|
return cast<Expr>(Exprs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *MSAsmStmt::getInputExpr(unsigned i) {
|
|
|
|
return cast<Expr>(Exprs[i + NumOutputs]);
|
|
|
|
}
|
2017-11-14 23:35:42 +00:00
|
|
|
|
2012-08-24 00:07:09 +00:00
|
|
|
void MSAsmStmt::setInputExpr(unsigned i, Expr *E) {
|
|
|
|
Exprs[i + NumOutputs] = E;
|
|
|
|
}
|
|
|
|
|
2008-01-30 05:01:46 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Constructors
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
|
|
|
|
bool issimple, bool isvolatile, unsigned numoutputs,
|
|
|
|
unsigned numinputs, IdentifierInfo **names,
|
2025-03-17 20:10:46 +01:00
|
|
|
Expr **constraints, Expr **exprs, Expr *asmstr,
|
|
|
|
unsigned numclobbers, Expr **clobbers,
|
|
|
|
unsigned numlabels, SourceLocation rparenloc)
|
2017-11-14 23:35:42 +00:00
|
|
|
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
|
2019-06-03 15:57:25 +00:00
|
|
|
numinputs, numclobbers),
|
2025-03-17 20:10:46 +01:00
|
|
|
RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) {
|
2019-06-03 15:57:25 +00:00
|
|
|
unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2010-01-30 23:19:41 +00:00
|
|
|
Names = new (C) IdentifierInfo*[NumExprs];
|
|
|
|
std::copy(names, names + NumExprs, Names);
|
|
|
|
|
|
|
|
Exprs = new (C) Stmt*[NumExprs];
|
|
|
|
std::copy(exprs, exprs + NumExprs, Exprs);
|
|
|
|
|
2019-05-30 07:21:08 +00:00
|
|
|
unsigned NumConstraints = NumOutputs + NumInputs;
|
2025-03-17 20:10:46 +01:00
|
|
|
Constraints = new (C) Expr *[NumConstraints];
|
2019-05-30 07:21:08 +00:00
|
|
|
std::copy(constraints, constraints + NumConstraints, Constraints);
|
2008-08-05 23:15:29 +00:00
|
|
|
|
2025-03-17 20:10:46 +01:00
|
|
|
Clobbers = new (C) Expr *[NumClobbers];
|
2010-01-30 23:19:41 +00:00
|
|
|
std::copy(clobbers, clobbers + NumClobbers, Clobbers);
|
2007-11-22 01:36:19 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
|
2012-08-16 00:06:53 +00:00
|
|
|
SourceLocation lbraceloc, bool issimple, bool isvolatile,
|
2012-10-16 21:55:39 +00:00
|
|
|
ArrayRef<Token> asmtoks, unsigned numoutputs,
|
2013-05-03 00:10:13 +00:00
|
|
|
unsigned numinputs,
|
2012-10-16 21:55:39 +00:00
|
|
|
ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs,
|
|
|
|
StringRef asmstr, ArrayRef<StringRef> clobbers,
|
|
|
|
SourceLocation endloc)
|
2017-11-14 23:35:42 +00:00
|
|
|
: AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
|
|
|
|
numinputs, clobbers.size()), LBraceLoc(lbraceloc),
|
|
|
|
EndLoc(endloc), NumAsmToks(asmtoks.size()) {
|
2013-05-03 00:10:13 +00:00
|
|
|
initialize(C, asmstr, asmtoks, constraints, exprs, clobbers);
|
|
|
|
}
|
2012-08-16 00:06:53 +00:00
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
static StringRef copyIntoContext(const ASTContext &C, StringRef str) {
|
2015-08-04 12:34:23 +00:00
|
|
|
return str.copy(C);
|
2013-05-03 00:10:13 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr,
|
2013-05-03 00:10:13 +00:00
|
|
|
ArrayRef<Token> asmtoks,
|
|
|
|
ArrayRef<StringRef> constraints,
|
|
|
|
ArrayRef<Expr*> exprs,
|
|
|
|
ArrayRef<StringRef> clobbers) {
|
|
|
|
assert(NumAsmToks == asmtoks.size());
|
|
|
|
assert(NumClobbers == clobbers.size());
|
|
|
|
|
2015-12-05 07:41:42 +00:00
|
|
|
assert(exprs.size() == NumOutputs + NumInputs);
|
|
|
|
assert(exprs.size() == constraints.size());
|
2013-05-03 00:10:13 +00:00
|
|
|
|
|
|
|
AsmStr = copyIntoContext(C, asmstr);
|
2012-08-07 00:29:06 +00:00
|
|
|
|
2015-12-05 07:41:42 +00:00
|
|
|
Exprs = new (C) Stmt*[exprs.size()];
|
|
|
|
std::copy(exprs.begin(), exprs.end(), Exprs);
|
2012-08-24 00:07:09 +00:00
|
|
|
|
2015-12-05 07:41:42 +00:00
|
|
|
AsmToks = new (C) Token[asmtoks.size()];
|
|
|
|
std::copy(asmtoks.begin(), asmtoks.end(), AsmToks);
|
2012-08-08 19:48:07 +00:00
|
|
|
|
2015-12-05 07:41:42 +00:00
|
|
|
Constraints = new (C) StringRef[exprs.size()];
|
|
|
|
std::transform(constraints.begin(), constraints.end(), Constraints,
|
|
|
|
[&](StringRef Constraint) {
|
|
|
|
return copyIntoContext(C, Constraint);
|
|
|
|
});
|
2012-08-28 20:28:20 +00:00
|
|
|
|
2012-08-10 21:36:25 +00:00
|
|
|
Clobbers = new (C) StringRef[NumClobbers];
|
2015-12-05 07:41:42 +00:00
|
|
|
// FIXME: Avoid the allocation/copy if at all possible.
|
|
|
|
std::transform(clobbers.begin(), clobbers.end(), Clobbers,
|
|
|
|
[&](StringRef Clobber) {
|
|
|
|
return copyIntoContext(C, Clobber);
|
|
|
|
});
|
2012-06-11 20:47:18 +00:00
|
|
|
}
|
|
|
|
|
2021-10-05 08:02:53 -04:00
|
|
|
IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, IfStatementKind Kind,
|
2020-08-10 16:29:33 -07:00
|
|
|
Stmt *Init, VarDecl *Var, Expr *Cond, SourceLocation LPL,
|
|
|
|
SourceLocation RPL, Stmt *Then, SourceLocation EL, Stmt *Else)
|
|
|
|
: Stmt(IfStmtClass), LParenLoc(LPL), RParenLoc(RPL) {
|
2018-10-27 21:12:20 +00:00
|
|
|
bool HasElse = Else != nullptr;
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
bool HasInit = Init != nullptr;
|
|
|
|
IfStmtBits.HasElse = HasElse;
|
|
|
|
IfStmtBits.HasVar = HasVar;
|
|
|
|
IfStmtBits.HasInit = HasInit;
|
|
|
|
|
2021-10-05 08:02:53 -04:00
|
|
|
setStatementKind(Kind);
|
2010-06-21 23:44:13 +00:00
|
|
|
|
2018-10-27 21:12:20 +00:00
|
|
|
setCond(Cond);
|
|
|
|
setThen(Then);
|
|
|
|
if (HasElse)
|
|
|
|
setElse(Else);
|
|
|
|
if (HasVar)
|
|
|
|
setConditionVariable(Ctx, Var);
|
|
|
|
if (HasInit)
|
|
|
|
setInit(Init);
|
|
|
|
|
|
|
|
setIfLoc(IL);
|
|
|
|
if (HasElse)
|
|
|
|
setElseLoc(EL);
|
|
|
|
}
|
|
|
|
|
|
|
|
IfStmt::IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit)
|
|
|
|
: Stmt(IfStmtClass, Empty) {
|
|
|
|
IfStmtBits.HasElse = HasElse;
|
|
|
|
IfStmtBits.HasVar = HasVar;
|
|
|
|
IfStmtBits.HasInit = HasInit;
|
|
|
|
}
|
|
|
|
|
|
|
|
IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL,
|
2021-10-05 08:02:53 -04:00
|
|
|
IfStatementKind Kind, Stmt *Init, VarDecl *Var,
|
|
|
|
Expr *Cond, SourceLocation LPL, SourceLocation RPL,
|
|
|
|
Stmt *Then, SourceLocation EL, Stmt *Else) {
|
2018-10-27 21:12:20 +00:00
|
|
|
bool HasElse = Else != nullptr;
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
bool HasInit = Init != nullptr;
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, SourceLocation>(
|
|
|
|
NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse),
|
|
|
|
alignof(IfStmt));
|
|
|
|
return new (Mem)
|
2021-10-05 08:02:53 -04:00
|
|
|
IfStmt(Ctx, IL, Kind, Init, Var, Cond, LPL, RPL, Then, EL, Else);
|
2018-10-27 21:12:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar,
|
|
|
|
bool HasInit) {
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, SourceLocation>(
|
|
|
|
NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse),
|
|
|
|
alignof(IfStmt));
|
|
|
|
return new (Mem) IfStmt(EmptyShell(), HasElse, HasVar, HasInit);
|
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *IfStmt::getConditionVariable() {
|
|
|
|
auto *DS = getConditionVariableDeclStmt();
|
|
|
|
if (!DS)
|
2014-05-12 05:36:57 +00:00
|
|
|
return nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2018-10-27 21:12:20 +00:00
|
|
|
void IfStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
|
|
|
|
assert(hasVarStorage() &&
|
|
|
|
"This if statement has no storage for a condition variable!");
|
|
|
|
|
2010-06-21 23:44:13 +00:00
|
|
|
if (!V) {
|
2018-10-27 21:12:20 +00:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2012-03-09 18:35:03 +00:00
|
|
|
SourceRange VarRange = V->getSourceRange();
|
2018-10-27 21:12:20 +00:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
|
|
|
|
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
2016-08-16 17:44:11 +00:00
|
|
|
bool IfStmt::isObjCAvailabilityCheck() const {
|
2018-10-27 21:12:20 +00:00
|
|
|
return isa<ObjCAvailabilityCheckExpr>(getCond());
|
2016-08-16 17:44:11 +00:00
|
|
|
}
|
|
|
|
|
2023-01-14 12:31:01 -08:00
|
|
|
std::optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
|
2019-12-13 14:10:13 -08:00
|
|
|
if (!isConstexpr() || getCond()->isValueDependent())
|
2022-12-03 11:13:41 -08:00
|
|
|
return std::nullopt;
|
2019-12-13 14:10:13 -08:00
|
|
|
return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
|
|
|
|
}
|
|
|
|
|
2023-01-14 12:31:01 -08:00
|
|
|
std::optional<const Stmt *>
|
2021-05-11 06:40:48 -07:00
|
|
|
IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
|
2023-01-14 12:31:01 -08:00
|
|
|
if (std::optional<Stmt *> Result =
|
2021-05-11 06:40:48 -07:00
|
|
|
const_cast<IfStmt *>(this)->getNondiscardedCase(Ctx))
|
|
|
|
return *Result;
|
2022-12-03 11:13:41 -08:00
|
|
|
return std::nullopt;
|
2021-05-11 06:40:48 -07:00
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
|
2012-08-07 23:12:23 +00:00
|
|
|
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
|
2010-06-21 23:44:13 +00:00
|
|
|
SourceLocation RP)
|
[AST] Widen the bit-fields of Stmt to 8 bytes.
Although some classes are using the tail padding of Stmt, most of
them are not. In particular the expression classes are not using it
since there is Expr in between, and Expr contains a single pointer.
This patch widen the bit-fields to Stmt to 8 bytes and move some
data from NullStmt, CompoundStmt, LabelStmt, AttributedStmt, SwitchStmt,
WhileStmt, DoStmt, ForStmt, GotoStmt, ContinueStmt, BreakStmt
and ReturnStmt to the newly available space.
In itself this patch do not achieve much but I plan to go through each of
the classes in the statement/expression hierarchy and use this newly
available space. A quick estimation gives me that this should shrink the
size of the statement/expression hierarchy by >10% when parsing all of Boost.
Differential Revision: https://reviews.llvm.org/D53604
Reviewed By: rjmccall
llvm-svn: 345459
2018-10-27 18:43:27 +00:00
|
|
|
: Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP)
|
2010-06-21 23:44:13 +00:00
|
|
|
{
|
|
|
|
SubExprs[INIT] = Init;
|
|
|
|
setConditionVariable(C, condVar);
|
2013-09-03 14:41:16 +00:00
|
|
|
SubExprs[COND] = Cond;
|
|
|
|
SubExprs[INC] = Inc;
|
2010-06-21 23:44:13 +00:00
|
|
|
SubExprs[BODY] = Body;
|
[AST] Widen the bit-fields of Stmt to 8 bytes.
Although some classes are using the tail padding of Stmt, most of
them are not. In particular the expression classes are not using it
since there is Expr in between, and Expr contains a single pointer.
This patch widen the bit-fields to Stmt to 8 bytes and move some
data from NullStmt, CompoundStmt, LabelStmt, AttributedStmt, SwitchStmt,
WhileStmt, DoStmt, ForStmt, GotoStmt, ContinueStmt, BreakStmt
and ReturnStmt to the newly available space.
In itself this patch do not achieve much but I plan to go through each of
the classes in the statement/expression hierarchy and use this newly
available space. A quick estimation gives me that this should shrink the
size of the statement/expression hierarchy by >10% when parsing all of Boost.
Differential Revision: https://reviews.llvm.org/D53604
Reviewed By: rjmccall
llvm-svn: 345459
2018-10-27 18:43:27 +00:00
|
|
|
ForStmtBits.ForLoc = FL;
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *ForStmt::getConditionVariable() const {
|
|
|
|
if (!SubExprs[CONDVAR])
|
2014-05-12 05:36:57 +00:00
|
|
|
return nullptr;
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2018-04-03 00:11:50 +00:00
|
|
|
auto *DS = cast<DeclStmt>(SubExprs[CONDVAR]);
|
2010-06-21 23:44:13 +00:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
|
2010-06-21 23:44:13 +00:00
|
|
|
if (!V) {
|
2014-05-12 05:36:57 +00:00
|
|
|
SubExprs[CONDVAR] = nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2012-03-09 18:35:03 +00:00
|
|
|
SourceRange VarRange = V->getSourceRange();
|
|
|
|
SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
|
|
|
|
VarRange.getEnd());
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 16:12:37 +00:00
|
|
|
SwitchStmt::SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var,
|
2020-08-10 16:29:33 -07:00
|
|
|
Expr *Cond, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc)
|
|
|
|
: Stmt(SwitchStmtClass), FirstCase(nullptr), LParenLoc(LParenLoc),
|
|
|
|
RParenLoc(RParenLoc) {
|
2018-10-29 16:12:37 +00:00
|
|
|
bool HasInit = Init != nullptr;
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
SwitchStmtBits.HasInit = HasInit;
|
|
|
|
SwitchStmtBits.HasVar = HasVar;
|
|
|
|
SwitchStmtBits.AllEnumCasesCovered = false;
|
|
|
|
|
|
|
|
setCond(Cond);
|
|
|
|
setBody(nullptr);
|
|
|
|
if (HasInit)
|
|
|
|
setInit(Init);
|
|
|
|
if (HasVar)
|
|
|
|
setConditionVariable(Ctx, Var);
|
|
|
|
|
|
|
|
setSwitchLoc(SourceLocation{});
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 16:12:37 +00:00
|
|
|
SwitchStmt::SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar)
|
|
|
|
: Stmt(SwitchStmtClass, Empty) {
|
|
|
|
SwitchStmtBits.HasInit = HasInit;
|
|
|
|
SwitchStmtBits.HasVar = HasVar;
|
|
|
|
SwitchStmtBits.AllEnumCasesCovered = false;
|
|
|
|
}
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2018-10-29 16:12:37 +00:00
|
|
|
SwitchStmt *SwitchStmt::Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var,
|
2020-08-10 16:29:33 -07:00
|
|
|
Expr *Cond, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc) {
|
2018-10-29 16:12:37 +00:00
|
|
|
bool HasInit = Init != nullptr;
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar),
|
|
|
|
alignof(SwitchStmt));
|
2020-08-10 16:29:33 -07:00
|
|
|
return new (Mem) SwitchStmt(Ctx, Init, Var, Cond, LParenLoc, RParenLoc);
|
2018-10-29 16:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SwitchStmt *SwitchStmt::CreateEmpty(const ASTContext &Ctx, bool HasInit,
|
|
|
|
bool HasVar) {
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar),
|
|
|
|
alignof(SwitchStmt));
|
|
|
|
return new (Mem) SwitchStmt(EmptyShell(), HasInit, HasVar);
|
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *SwitchStmt::getConditionVariable() {
|
|
|
|
auto *DS = getConditionVariableDeclStmt();
|
|
|
|
if (!DS)
|
|
|
|
return nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2018-10-29 16:12:37 +00:00
|
|
|
void SwitchStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
|
|
|
|
assert(hasVarStorage() &&
|
|
|
|
"This switch statement has no storage for a condition variable!");
|
|
|
|
|
2010-06-21 23:44:13 +00:00
|
|
|
if (!V) {
|
2018-10-29 16:12:37 +00:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2012-03-09 18:35:03 +00:00
|
|
|
SourceRange VarRange = V->getSourceRange();
|
2018-10-29 16:12:37 +00:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
|
|
|
|
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-30 13:42:41 +00:00
|
|
|
WhileStmt::WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
|
2020-07-09 23:19:06 -04:00
|
|
|
Stmt *Body, SourceLocation WL, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc)
|
2018-10-30 13:42:41 +00:00
|
|
|
: Stmt(WhileStmtClass) {
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
WhileStmtBits.HasVar = HasVar;
|
|
|
|
|
|
|
|
setCond(Cond);
|
|
|
|
setBody(Body);
|
|
|
|
if (HasVar)
|
|
|
|
setConditionVariable(Ctx, Var);
|
|
|
|
|
|
|
|
setWhileLoc(WL);
|
2020-07-09 23:19:06 -04:00
|
|
|
setLParenLoc(LParenLoc);
|
|
|
|
setRParenLoc(RParenLoc);
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-30 13:42:41 +00:00
|
|
|
WhileStmt::WhileStmt(EmptyShell Empty, bool HasVar)
|
|
|
|
: Stmt(WhileStmtClass, Empty) {
|
|
|
|
WhileStmtBits.HasVar = HasVar;
|
|
|
|
}
|
|
|
|
|
|
|
|
WhileStmt *WhileStmt::Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
|
2020-07-09 23:19:06 -04:00
|
|
|
Stmt *Body, SourceLocation WL,
|
|
|
|
SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc) {
|
2018-10-30 13:42:41 +00:00
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
void *Mem =
|
|
|
|
Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar),
|
|
|
|
alignof(WhileStmt));
|
2020-07-09 23:19:06 -04:00
|
|
|
return new (Mem) WhileStmt(Ctx, Var, Cond, Body, WL, LParenLoc, RParenLoc);
|
2018-10-30 13:42:41 +00:00
|
|
|
}
|
2012-08-07 23:12:23 +00:00
|
|
|
|
2018-10-30 13:42:41 +00:00
|
|
|
WhileStmt *WhileStmt::CreateEmpty(const ASTContext &Ctx, bool HasVar) {
|
|
|
|
void *Mem =
|
|
|
|
Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar),
|
|
|
|
alignof(WhileStmt));
|
|
|
|
return new (Mem) WhileStmt(EmptyShell(), HasVar);
|
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *WhileStmt::getConditionVariable() {
|
|
|
|
auto *DS = getConditionVariableDeclStmt();
|
|
|
|
if (!DS)
|
|
|
|
return nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2018-10-30 13:42:41 +00:00
|
|
|
void WhileStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
|
|
|
|
assert(hasVarStorage() &&
|
|
|
|
"This while statement has no storage for a condition variable!");
|
|
|
|
|
2010-06-21 23:44:13 +00:00
|
|
|
if (!V) {
|
2018-10-30 13:42:41 +00:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
|
2010-06-21 23:44:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-03-09 18:35:03 +00:00
|
|
|
|
|
|
|
SourceRange VarRange = V->getSourceRange();
|
2018-10-30 13:42:41 +00:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
|
|
|
|
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
|
2010-06-21 23:44:13 +00:00
|
|
|
}
|
|
|
|
|
2007-08-24 21:09:09 +00:00
|
|
|
// IndirectGotoStmt
|
2011-02-17 07:39:24 +00:00
|
|
|
LabelDecl *IndirectGotoStmt::getConstantTarget() {
|
2018-04-03 00:11:50 +00:00
|
|
|
if (auto *E = dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
|
2010-10-28 08:53:48 +00:00
|
|
|
return E->getLabel();
|
2014-05-12 05:36:57 +00:00
|
|
|
return nullptr;
|
2010-10-28 08:53:48 +00:00
|
|
|
}
|
2007-08-24 21:09:09 +00:00
|
|
|
|
|
|
|
// ReturnStmt
|
2018-10-30 14:40:49 +00:00
|
|
|
ReturnStmt::ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
|
|
|
|
: Stmt(ReturnStmtClass), RetExpr(E) {
|
|
|
|
bool HasNRVOCandidate = NRVOCandidate != nullptr;
|
|
|
|
ReturnStmtBits.HasNRVOCandidate = HasNRVOCandidate;
|
|
|
|
if (HasNRVOCandidate)
|
|
|
|
setNRVOCandidate(NRVOCandidate);
|
|
|
|
setReturnLoc(RL);
|
2008-06-17 03:11:08 +00:00
|
|
|
}
|
2018-10-30 14:40:49 +00:00
|
|
|
|
|
|
|
ReturnStmt::ReturnStmt(EmptyShell Empty, bool HasNRVOCandidate)
|
|
|
|
: Stmt(ReturnStmtClass, Empty) {
|
|
|
|
ReturnStmtBits.HasNRVOCandidate = HasNRVOCandidate;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnStmt *ReturnStmt::Create(const ASTContext &Ctx, SourceLocation RL,
|
|
|
|
Expr *E, const VarDecl *NRVOCandidate) {
|
|
|
|
bool HasNRVOCandidate = NRVOCandidate != nullptr;
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<const VarDecl *>(HasNRVOCandidate),
|
|
|
|
alignof(ReturnStmt));
|
|
|
|
return new (Mem) ReturnStmt(RL, E, NRVOCandidate);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnStmt *ReturnStmt::CreateEmpty(const ASTContext &Ctx,
|
|
|
|
bool HasNRVOCandidate) {
|
|
|
|
void *Mem = Ctx.Allocate(totalSizeToAlloc<const VarDecl *>(HasNRVOCandidate),
|
|
|
|
alignof(ReturnStmt));
|
|
|
|
return new (Mem) ReturnStmt(EmptyShell(), HasNRVOCandidate);
|
2007-08-24 21:09:09 +00:00
|
|
|
}
|
2011-04-28 01:08:34 +00:00
|
|
|
|
2018-10-28 12:30:53 +00:00
|
|
|
// CaseStmt
|
|
|
|
CaseStmt *CaseStmt::Create(const ASTContext &Ctx, Expr *lhs, Expr *rhs,
|
|
|
|
SourceLocation caseLoc, SourceLocation ellipsisLoc,
|
|
|
|
SourceLocation colonLoc) {
|
|
|
|
bool CaseStmtIsGNURange = rhs != nullptr;
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, SourceLocation>(
|
|
|
|
NumMandatoryStmtPtr + CaseStmtIsGNURange, CaseStmtIsGNURange),
|
|
|
|
alignof(CaseStmt));
|
|
|
|
return new (Mem) CaseStmt(lhs, rhs, caseLoc, ellipsisLoc, colonLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
CaseStmt *CaseStmt::CreateEmpty(const ASTContext &Ctx,
|
|
|
|
bool CaseStmtIsGNURange) {
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *, SourceLocation>(
|
|
|
|
NumMandatoryStmtPtr + CaseStmtIsGNURange, CaseStmtIsGNURange),
|
|
|
|
alignof(CaseStmt));
|
|
|
|
return new (Mem) CaseStmt(EmptyShell(), CaseStmtIsGNURange);
|
|
|
|
}
|
|
|
|
|
2017-11-14 23:35:42 +00:00
|
|
|
SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock,
|
2014-07-25 20:52:51 +00:00
|
|
|
Stmt *Handler)
|
2017-11-14 23:35:42 +00:00
|
|
|
: Stmt(SEHTryStmtClass), IsCXXTry(IsCXXTry), TryLoc(TryLoc) {
|
2014-07-25 20:52:51 +00:00
|
|
|
Children[TRY] = TryBlock;
|
2011-04-28 01:08:34 +00:00
|
|
|
Children[HANDLER] = Handler;
|
|
|
|
}
|
|
|
|
|
2014-07-25 20:52:51 +00:00
|
|
|
SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
|
2013-08-22 05:28:54 +00:00
|
|
|
SourceLocation TryLoc, Stmt *TryBlock,
|
2014-07-25 20:52:51 +00:00
|
|
|
Stmt *Handler) {
|
|
|
|
return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
|
2011-04-28 01:08:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
|
|
|
|
return dyn_cast<SEHExceptStmt>(getHandler());
|
|
|
|
}
|
|
|
|
|
|
|
|
SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const {
|
|
|
|
return dyn_cast<SEHFinallyStmt>(getHandler());
|
|
|
|
}
|
|
|
|
|
2017-11-14 23:35:42 +00:00
|
|
|
SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block)
|
|
|
|
: Stmt(SEHExceptStmtClass), Loc(Loc) {
|
2013-09-03 14:41:16 +00:00
|
|
|
Children[FILTER_EXPR] = FilterExpr;
|
2011-04-28 01:08:34 +00:00
|
|
|
Children[BLOCK] = Block;
|
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
SEHExceptStmt* SEHExceptStmt::Create(const ASTContext &C, SourceLocation Loc,
|
|
|
|
Expr *FilterExpr, Stmt *Block) {
|
2011-04-28 01:08:34 +00:00
|
|
|
return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
|
|
|
|
}
|
|
|
|
|
2017-11-14 23:35:42 +00:00
|
|
|
SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, Stmt *Block)
|
|
|
|
: Stmt(SEHFinallyStmtClass), Loc(Loc), Block(Block) {}
|
2011-04-28 01:08:34 +00:00
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
SEHFinallyStmt* SEHFinallyStmt::Create(const ASTContext &C, SourceLocation Loc,
|
2011-04-28 01:08:34 +00:00
|
|
|
Stmt *Block) {
|
|
|
|
return new(C)SEHFinallyStmt(Loc,Block);
|
|
|
|
}
|
2013-04-16 18:53:08 +00:00
|
|
|
|
2015-12-02 17:44:43 +00:00
|
|
|
CapturedStmt::Capture::Capture(SourceLocation Loc, VariableCaptureKind Kind,
|
|
|
|
VarDecl *Var)
|
|
|
|
: VarAndKind(Var, Kind), Loc(Loc) {
|
|
|
|
switch (Kind) {
|
|
|
|
case VCK_This:
|
|
|
|
assert(!Var && "'this' capture cannot have a variable!");
|
|
|
|
break;
|
|
|
|
case VCK_ByRef:
|
|
|
|
assert(Var && "capturing by reference must have a variable!");
|
|
|
|
break;
|
|
|
|
case VCK_ByCopy:
|
|
|
|
assert(Var && "capturing by copy must have a variable!");
|
|
|
|
break;
|
|
|
|
case VCK_VLAType:
|
|
|
|
assert(!Var &&
|
|
|
|
"Variable-length array type capture cannot have a variable!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-30 03:24:14 +00:00
|
|
|
CapturedStmt::VariableCaptureKind
|
|
|
|
CapturedStmt::Capture::getCaptureKind() const {
|
|
|
|
return VarAndKind.getInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *CapturedStmt::Capture::getCapturedVar() const {
|
|
|
|
assert((capturesVariable() || capturesVariableByCopy()) &&
|
|
|
|
"No variable available for 'this' or VAT capture");
|
|
|
|
return VarAndKind.getPointer();
|
|
|
|
}
|
|
|
|
|
2013-04-16 18:53:08 +00:00
|
|
|
CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const {
|
|
|
|
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
|
|
|
|
|
|
|
|
// Offset of the first Capture object.
|
2016-10-20 14:27:22 +00:00
|
|
|
unsigned FirstCaptureOffset = llvm::alignTo(Size, alignof(Capture));
|
2013-04-16 18:53:08 +00:00
|
|
|
|
|
|
|
return reinterpret_cast<Capture *>(
|
|
|
|
reinterpret_cast<char *>(const_cast<CapturedStmt *>(this))
|
|
|
|
+ FirstCaptureOffset);
|
|
|
|
}
|
|
|
|
|
2013-05-04 03:59:06 +00:00
|
|
|
CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind,
|
|
|
|
ArrayRef<Capture> Captures,
|
2013-04-16 18:53:08 +00:00
|
|
|
ArrayRef<Expr *> CaptureInits,
|
2013-04-16 19:37:38 +00:00
|
|
|
CapturedDecl *CD,
|
2013-04-16 18:53:08 +00:00
|
|
|
RecordDecl *RD)
|
|
|
|
: Stmt(CapturedStmtClass), NumCaptures(Captures.size()),
|
2013-05-04 03:59:06 +00:00
|
|
|
CapDeclAndKind(CD, Kind), TheRecordDecl(RD) {
|
2013-04-16 18:53:08 +00:00
|
|
|
assert( S && "null captured statement");
|
2013-04-16 19:37:38 +00:00
|
|
|
assert(CD && "null captured declaration for captured statement");
|
2013-04-16 18:53:08 +00:00
|
|
|
assert(RD && "null record declaration for captured statement");
|
|
|
|
|
|
|
|
// Copy initialization expressions.
|
|
|
|
Stmt **Stored = getStoredStmts();
|
|
|
|
for (unsigned I = 0, N = NumCaptures; I != N; ++I)
|
|
|
|
*Stored++ = CaptureInits[I];
|
|
|
|
|
|
|
|
// Copy the statement being captured.
|
|
|
|
*Stored = S;
|
|
|
|
|
|
|
|
// Copy all Capture objects.
|
|
|
|
Capture *Buffer = getStoredCaptures();
|
|
|
|
std::copy(Captures.begin(), Captures.end(), Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
|
|
|
|
: Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures),
|
2017-11-14 23:35:42 +00:00
|
|
|
CapDeclAndKind(nullptr, CR_Default) {
|
2014-05-12 05:36:57 +00:00
|
|
|
getStoredStmts()[NumCaptures] = nullptr;
|
2023-05-12 18:43:53 -07:00
|
|
|
|
|
|
|
// Construct default capture objects.
|
|
|
|
Capture *Buffer = getStoredCaptures();
|
|
|
|
for (unsigned I = 0, N = NumCaptures; I != N; ++I)
|
|
|
|
new (Buffer++) Capture();
|
2013-04-16 18:53:08 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
CapturedStmt *CapturedStmt::Create(const ASTContext &Context, Stmt *S,
|
2013-05-04 03:59:06 +00:00
|
|
|
CapturedRegionKind Kind,
|
2013-04-16 18:53:08 +00:00
|
|
|
ArrayRef<Capture> Captures,
|
|
|
|
ArrayRef<Expr *> CaptureInits,
|
2013-04-16 19:37:38 +00:00
|
|
|
CapturedDecl *CD,
|
2013-04-16 18:53:08 +00:00
|
|
|
RecordDecl *RD) {
|
|
|
|
// The layout is
|
|
|
|
//
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
// | CapturedStmt, Init, ..., Init, S, Capture, ..., Capture |
|
|
|
|
// ----------------^-------------------^----------------------
|
|
|
|
// getStoredStmts() getStoredCaptures()
|
|
|
|
//
|
|
|
|
// where S is the statement being captured.
|
|
|
|
//
|
|
|
|
assert(CaptureInits.size() == Captures.size() && "wrong number of arguments");
|
|
|
|
|
|
|
|
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (Captures.size() + 1);
|
|
|
|
if (!Captures.empty()) {
|
|
|
|
// Realign for the following Capture array.
|
2016-10-20 14:27:22 +00:00
|
|
|
Size = llvm::alignTo(Size, alignof(Capture));
|
2013-04-16 18:53:08 +00:00
|
|
|
Size += sizeof(Capture) * Captures.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Mem = Context.Allocate(Size);
|
2013-05-04 03:59:06 +00:00
|
|
|
return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD);
|
2013-04-16 18:53:08 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 05:28:54 +00:00
|
|
|
CapturedStmt *CapturedStmt::CreateDeserialized(const ASTContext &Context,
|
2013-04-16 18:53:08 +00:00
|
|
|
unsigned NumCaptures) {
|
|
|
|
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
|
|
|
|
if (NumCaptures > 0) {
|
|
|
|
// Realign for the following Capture array.
|
2016-10-20 14:27:22 +00:00
|
|
|
Size = llvm::alignTo(Size, alignof(Capture));
|
2013-04-16 18:53:08 +00:00
|
|
|
Size += sizeof(Capture) * NumCaptures;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Mem = Context.Allocate(Size);
|
|
|
|
return new (Mem) CapturedStmt(EmptyShell(), NumCaptures);
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_range CapturedStmt::children() {
|
2017-03-30 14:13:19 +00:00
|
|
|
// Children are captured field initializers.
|
2013-04-16 19:37:38 +00:00
|
|
|
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
|
2013-04-16 18:53:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-12 15:36:02 +00:00
|
|
|
Stmt::const_child_range CapturedStmt::children() const {
|
|
|
|
return const_child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
|
|
|
|
}
|
|
|
|
|
2015-12-30 03:24:14 +00:00
|
|
|
CapturedDecl *CapturedStmt::getCapturedDecl() {
|
|
|
|
return CapDeclAndKind.getPointer();
|
|
|
|
}
|
2017-11-14 23:35:42 +00:00
|
|
|
|
2015-12-30 03:24:14 +00:00
|
|
|
const CapturedDecl *CapturedStmt::getCapturedDecl() const {
|
|
|
|
return CapDeclAndKind.getPointer();
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Set the outlined function declaration.
|
2015-12-30 03:24:14 +00:00
|
|
|
void CapturedStmt::setCapturedDecl(CapturedDecl *D) {
|
|
|
|
assert(D && "null CapturedDecl");
|
|
|
|
CapDeclAndKind.setPointer(D);
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Retrieve the captured region kind.
|
2015-12-30 03:24:14 +00:00
|
|
|
CapturedRegionKind CapturedStmt::getCapturedRegionKind() const {
|
|
|
|
return CapDeclAndKind.getInt();
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Set the captured region kind.
|
2015-12-30 03:24:14 +00:00
|
|
|
void CapturedStmt::setCapturedRegionKind(CapturedRegionKind Kind) {
|
|
|
|
CapDeclAndKind.setInt(Kind);
|
|
|
|
}
|
|
|
|
|
2013-04-16 18:53:08 +00:00
|
|
|
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
|
2014-03-14 18:08:33 +00:00
|
|
|
for (const auto &I : captures()) {
|
2017-05-15 16:26:15 +00:00
|
|
|
if (!I.capturesVariable() && !I.capturesVariableByCopy())
|
2013-04-16 18:53:08 +00:00
|
|
|
continue;
|
2017-09-20 20:11:31 +00:00
|
|
|
if (I.getCapturedVar()->getCanonicalDecl() == Var->getCanonicalDecl())
|
2013-04-16 18:53:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|