2017-11-15 07:35:42 +08:00
|
|
|
//===- Stmt.cpp - Statement AST Node Implementation -----------------------===//
|
2006-10-25 12:09:21 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08: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 12:09:21 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Stmt class and statement subclasses.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-04-03 08:11:50 +08:00
|
|
|
#include "clang/AST/Stmt.h"
|
2012-12-02 01:12:56 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/ASTDiagnostic.h"
|
2020-09-10 01:12:32 +08:00
|
|
|
#include "clang/AST/Attr.h"
|
2017-11-15 07:35:42 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/DeclGroup.h"
|
2018-04-03 08:11:50 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2006-12-05 02:06:35 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2020-09-10 01:12:32 +08:00
|
|
|
#include "clang/AST/ExprConcepts.h"
|
2008-05-30 05:12:08 +08:00
|
|
|
#include "clang/AST/ExprObjC.h"
|
2015-08-25 22:24:04 +08:00
|
|
|
#include "clang/AST/ExprOpenMP.h"
|
2009-04-26 09:32:48 +08:00
|
|
|
#include "clang/AST/StmtCXX.h"
|
|
|
|
#include "clang/AST/StmtObjC.h"
|
2013-07-19 11:13:43 +08:00
|
|
|
#include "clang/AST/StmtOpenMP.h"
|
2008-12-23 03:15:10 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2013-02-09 06:30:41 +08:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2017-11-15 07:35:42 +08:00
|
|
|
#include "clang/Basic/LLVM.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
2010-04-24 00:29:58 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2012-12-02 01:12:56 +08:00
|
|
|
#include "clang/Lex/Token.h"
|
2017-11-15 07:35:42 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-08-25 01:05:45 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-11-15 07:35:42 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
2011-07-04 14:13:27 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-11-15 07:35:42 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
|
|
|
#include <string>
|
2019-08-27 19:35:49 +08:00
|
|
|
#include <type_traits>
|
2020-09-10 01:12:32 +08:00
|
|
|
#include <utility>
|
2017-11-15 07:35:42 +08:00
|
|
|
|
2006-10-25 12:09:21 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2007-05-24 05:48:04 +08:00
|
|
|
static struct StmtClassNameTable {
|
2007-08-25 09:42:24 +08:00
|
|
|
const char *Name;
|
|
|
|
unsigned Counter;
|
|
|
|
unsigned Size;
|
2010-05-05 23:24:00 +08:00
|
|
|
} StmtClassInfo[Stmt::lastStmtConstant+1];
|
2007-08-25 09:42:24 +08:00
|
|
|
|
|
|
|
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
|
|
|
|
static bool Initialized = false;
|
|
|
|
if (Initialized)
|
|
|
|
return StmtClassInfo[E];
|
|
|
|
|
2018-04-06 23:14:32 +08:00
|
|
|
// Initialize the table on the first use.
|
2007-08-25 09:42:24 +08:00
|
|
|
Initialized = true;
|
2010-05-18 14:22:21 +08:00
|
|
|
#define ABSTRACT_STMT(STMT)
|
2008-11-14 20:46:07 +08:00
|
|
|
#define STMT(CLASS, PARENT) \
|
|
|
|
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
|
|
|
|
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
|
2010-05-05 23:24:00 +08:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
2008-08-06 07:15:29 +08:00
|
|
|
|
2007-08-25 09:42:24 +08:00
|
|
|
return StmtClassInfo[E];
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:09:15 +08:00
|
|
|
void *Stmt::operator new(size_t bytes, const ASTContext& C,
|
2013-08-19 01:45:38 +08:00
|
|
|
unsigned alignment) {
|
2012-12-01 23:09:41 +08:00
|
|
|
return ::operator new(bytes, C, alignment);
|
|
|
|
}
|
|
|
|
|
2007-03-24 06:27:02 +08:00
|
|
|
const char *Stmt::getStmtClassName() const {
|
2010-10-26 16:39:16 +08:00
|
|
|
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
|
2007-03-24 06:27:02 +08:00
|
|
|
}
|
2007-05-24 05:48:04 +08:00
|
|
|
|
2018-12-05 00:04:19 +08: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 19:35:49 +08: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-24 05:48:04 +08:00
|
|
|
void Stmt::PrintStats() {
|
2007-08-25 09:42:24 +08:00
|
|
|
// Ensure the table is primed.
|
|
|
|
getStmtInfoTableEntry(Stmt::NullStmtClass);
|
2008-08-06 07:15:29 +08:00
|
|
|
|
2007-05-24 05:48:04 +08:00
|
|
|
unsigned sum = 0;
|
2011-07-04 14:13:27 +08:00
|
|
|
llvm::errs() << "\n*** Stmt/Expr Stats:\n";
|
2010-05-05 23:24:00 +08:00
|
|
|
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
|
2014-05-12 13:36:57 +08:00
|
|
|
if (StmtClassInfo[i].Name == nullptr) continue;
|
2007-08-25 09:42:24 +08:00
|
|
|
sum += StmtClassInfo[i].Counter;
|
2007-05-24 05:48:04 +08:00
|
|
|
}
|
2011-07-04 14:13:27 +08:00
|
|
|
llvm::errs() << " " << sum << " stmts/exprs total.\n";
|
2007-05-24 05:48:04 +08:00
|
|
|
sum = 0;
|
2010-05-05 23:24:00 +08:00
|
|
|
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
|
2014-05-12 13:36:57 +08:00
|
|
|
if (StmtClassInfo[i].Name == nullptr) continue;
|
2009-05-26 22:40:08 +08:00
|
|
|
if (StmtClassInfo[i].Counter == 0) continue;
|
2011-07-04 14:13:27 +08:00
|
|
|
llvm::errs() << " " << StmtClassInfo[i].Counter << " "
|
|
|
|
<< StmtClassInfo[i].Name << ", " << StmtClassInfo[i].Size
|
|
|
|
<< " each (" << StmtClassInfo[i].Counter*StmtClassInfo[i].Size
|
|
|
|
<< " bytes)\n";
|
2007-08-25 09:42:24 +08:00
|
|
|
sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
|
2007-05-24 05:48:04 +08:00
|
|
|
}
|
2011-07-04 14:13:27 +08:00
|
|
|
|
|
|
|
llvm::errs() << "Total bytes = " << sum << "\n";
|
2007-05-24 05:48:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Stmt::addStmtClass(StmtClass s) {
|
2007-08-25 09:42:24 +08:00
|
|
|
++getStmtInfoTableEntry(s).Counter;
|
2007-05-24 05:48:04 +08:00
|
|
|
}
|
|
|
|
|
2012-03-06 05:42:49 +08:00
|
|
|
bool Stmt::StatisticsEnabled = false;
|
|
|
|
void Stmt::EnableStatistics() {
|
|
|
|
StatisticsEnabled = true;
|
2007-05-24 05:48:04 +08:00
|
|
|
}
|
|
|
|
|
2020-10-18 19:34:41 +08: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-10 01:12:32 +08: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 19:34:41 +08:00
|
|
|
return getLikelihood(AS->getAttrs());
|
2020-09-10 01:12:32 +08:00
|
|
|
|
|
|
|
return std::make_pair(Stmt::LH_None, nullptr);
|
|
|
|
}
|
|
|
|
|
2020-10-18 19:34:41 +08:00
|
|
|
Stmt::Likelihood Stmt::getLikelihood(ArrayRef<const Attr *> Attrs) {
|
|
|
|
return ::getLikelihood(Attrs).first;
|
|
|
|
}
|
|
|
|
|
2020-09-10 01:12:32 +08:00
|
|
|
Stmt::Likelihood Stmt::getLikelihood(const Stmt *S) {
|
|
|
|
return ::getLikelihood(S).first;
|
|
|
|
}
|
|
|
|
|
2020-10-31 20:07:06 +08:00
|
|
|
const Attr *Stmt::getLikelihoodAttr(const Stmt *S) {
|
|
|
|
return ::getLikelihood(S).second;
|
|
|
|
}
|
|
|
|
|
2020-09-10 01:12:32 +08: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 09:00:01 +08:00
|
|
|
/// Skip no-op (attributed, compound) container stmts and skip captured
|
2014-10-01 14:03:56 +08: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 09:00:01 +08:00
|
|
|
/// Strip off all label-like statements.
|
2011-09-10 08:02:34 +08:00
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
/// This will strip off label statements, case statements, attributed
|
|
|
|
/// statements and default statements recursively.
|
2011-09-10 08:02:34 +08:00
|
|
|
const Stmt *Stmt::stripLabelLikeStatements() const {
|
|
|
|
const Stmt *S = this;
|
|
|
|
while (true) {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *LS = dyn_cast<LabelStmt>(S))
|
2011-09-10 08:02:34 +08:00
|
|
|
S = LS->getSubStmt();
|
2018-04-03 08:11:50 +08:00
|
|
|
else if (const auto *SC = dyn_cast<SwitchCase>(S))
|
2011-09-10 08:02:34 +08:00
|
|
|
S = SC->getSubStmt();
|
2018-04-03 08:11:50 +08:00
|
|
|
else if (const auto *AS = dyn_cast<AttributedStmt>(S))
|
2012-04-14 08:33:13 +08:00
|
|
|
S = AS->getSubStmt();
|
2011-09-10 08:02:34 +08:00
|
|
|
else
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-09 16:16:59 +08:00
|
|
|
namespace {
|
2017-11-15 07:35:42 +08:00
|
|
|
|
2011-02-09 16:16:59 +08:00
|
|
|
struct good {};
|
|
|
|
struct bad {};
|
2011-02-09 16:31:17 +08: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 08:11:50 +08:00
|
|
|
static good is_good(good) { return good(); }
|
2011-02-09 16:16:59 +08:00
|
|
|
|
|
|
|
typedef Stmt::child_range children_t();
|
2011-02-09 16:42:57 +08:00
|
|
|
template <class T> good implements_children(children_t T::*) {
|
|
|
|
return good();
|
|
|
|
}
|
2013-09-11 06:57:15 +08:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2018-04-03 08:11:50 +08:00
|
|
|
static bad implements_children(children_t Stmt::*) {
|
2011-02-09 16:42:57 +08:00
|
|
|
return bad();
|
|
|
|
}
|
2011-02-09 16:16:59 +08:00
|
|
|
|
2018-08-10 05:08:08 +08:00
|
|
|
typedef SourceLocation getBeginLoc_t() const;
|
|
|
|
template <class T> good implements_getBeginLoc(getBeginLoc_t T::*) {
|
2011-02-09 16:42:57 +08:00
|
|
|
return good();
|
|
|
|
}
|
2013-09-11 06:57:15 +08:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2018-08-10 05:08:08 +08:00
|
|
|
static bad implements_getBeginLoc(getBeginLoc_t Stmt::*) { return bad(); }
|
2012-12-25 22:51:39 +08:00
|
|
|
|
|
|
|
typedef SourceLocation getLocEnd_t() const;
|
2018-08-10 05:09:38 +08:00
|
|
|
template <class T> good implements_getEndLoc(getLocEnd_t T::*) {
|
2012-12-25 22:51:39 +08:00
|
|
|
return good();
|
|
|
|
}
|
2013-09-11 06:57:15 +08:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2018-08-10 05:09:38 +08:00
|
|
|
static bad implements_getEndLoc(getLocEnd_t Stmt::*) { return bad(); }
|
2011-02-09 16:16:59 +08:00
|
|
|
|
|
|
|
#define ASSERT_IMPLEMENTS_children(type) \
|
2013-09-11 06:57:15 +08:00
|
|
|
(void) is_good(implements_children(&type::children))
|
2018-08-10 05:08:08 +08:00
|
|
|
#define ASSERT_IMPLEMENTS_getBeginLoc(type) \
|
|
|
|
(void)is_good(implements_getBeginLoc(&type::getBeginLoc))
|
2018-08-10 05:09:38 +08:00
|
|
|
#define ASSERT_IMPLEMENTS_getEndLoc(type) \
|
|
|
|
(void)is_good(implements_getEndLoc(&type::getEndLoc))
|
2017-11-15 07:35:42 +08:00
|
|
|
|
|
|
|
} // namespace
|
2011-02-09 16:16:59 +08:00
|
|
|
|
|
|
|
/// Check whether the various Stmt classes implement their member
|
|
|
|
/// functions.
|
2013-09-11 06:57:15 +08:00
|
|
|
LLVM_ATTRIBUTE_UNUSED
|
2011-02-09 16:16:59 +08:00
|
|
|
static inline void check_implementations() {
|
|
|
|
#define ABSTRACT_STMT(type)
|
2018-08-10 05:08:08 +08:00
|
|
|
#define STMT(type, base) \
|
|
|
|
ASSERT_IMPLEMENTS_children(type); \
|
|
|
|
ASSERT_IMPLEMENTS_getBeginLoc(type); \
|
2018-08-10 05:09:38 +08:00
|
|
|
ASSERT_IMPLEMENTS_getEndLoc(type);
|
2011-02-09 16:16:59 +08: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 23:39:19 +08:00
|
|
|
// Amusing macro metaprogramming hack: check whether a class provides
|
2012-12-25 22:51:39 +08:00
|
|
|
// a more specific implementation of getSourceRange.
|
2012-03-09 23:39:19 +08:00
|
|
|
//
|
|
|
|
// See also Expr.cpp:getExprLoc().
|
|
|
|
namespace {
|
2017-11-15 07:35:42 +08:00
|
|
|
|
2012-03-09 23:39:19 +08:00
|
|
|
/// This implementation is used when a class provides a custom
|
2012-12-25 22:51:39 +08:00
|
|
|
/// implementation of getSourceRange.
|
2012-03-09 23:39:19 +08:00
|
|
|
template <class S, class T>
|
2012-12-25 22:51:39 +08:00
|
|
|
SourceRange getSourceRangeImpl(const Stmt *stmt,
|
|
|
|
SourceRange (T::*v)() const) {
|
|
|
|
return static_cast<const S*>(stmt)->getSourceRange();
|
2012-03-09 23:39:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This implementation is used when a class doesn't provide a custom
|
2012-12-25 22:51:39 +08:00
|
|
|
/// implementation of getSourceRange. Overload resolution should pick it over
|
2012-03-09 23:39:19 +08:00
|
|
|
/// the implementation above because it's more specialized according to
|
|
|
|
/// function template partial ordering.
|
|
|
|
template <class S>
|
2012-12-25 22:51:39 +08:00
|
|
|
SourceRange getSourceRangeImpl(const Stmt *stmt,
|
|
|
|
SourceRange (Stmt::*v)() const) {
|
2018-08-10 05:08:08 +08:00
|
|
|
return SourceRange(static_cast<const S *>(stmt)->getBeginLoc(),
|
2018-08-10 05:09:38 +08:00
|
|
|
static_cast<const S *>(stmt)->getEndLoc());
|
2012-03-09 23:39:19 +08:00
|
|
|
}
|
2017-11-15 07:35:42 +08:00
|
|
|
|
|
|
|
} // namespace
|
2012-03-09 23:39:19 +08:00
|
|
|
|
2012-12-25 22:51:39 +08: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 23:39:19 +08:00
|
|
|
}
|
2012-12-25 22:51:39 +08:00
|
|
|
llvm_unreachable("unknown statement kind!");
|
2012-03-09 23:39:19 +08:00
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:03 +08:00
|
|
|
SourceLocation Stmt::getBeginLoc() const {
|
2012-03-09 23:39:19 +08:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
2018-08-10 05:08:08 +08:00
|
|
|
#define STMT(type, base) \
|
|
|
|
case Stmt::type##Class: \
|
|
|
|
return static_cast<const type *>(this)->getBeginLoc();
|
2012-03-09 23:39:19 +08:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown statement kind");
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation Stmt::getEndLoc() const {
|
2012-03-09 23:39:19 +08:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
|
|
|
|
#define ABSTRACT_STMT(type)
|
2018-08-10 05:09:38 +08:00
|
|
|
#define STMT(type, base) \
|
|
|
|
case Stmt::type##Class: \
|
|
|
|
return static_cast<const type *>(this)->getEndLoc();
|
2012-03-09 23:39:19 +08:00
|
|
|
#include "clang/AST/StmtNodes.inc"
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown statement kind");
|
|
|
|
}
|
|
|
|
|
2018-09-15 10:01:47 +08:00
|
|
|
int64_t Stmt::getID(const ASTContext &Context) const {
|
2018-12-04 06:19:05 +08:00
|
|
|
return Context.getAllocator().identifyKnownAlignedObject<Stmt>(this);
|
2018-09-15 10:01:47 +08:00
|
|
|
}
|
|
|
|
|
2017-12-25 00:24:20 +08:00
|
|
|
CompoundStmt::CompoundStmt(ArrayRef<Stmt *> Stmts, SourceLocation LB,
|
|
|
|
SourceLocation RB)
|
[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-28 02:43:27 +08:00
|
|
|
: Stmt(CompoundStmtClass), RBraceLoc(RB) {
|
2012-12-30 04:03:39 +08:00
|
|
|
CompoundStmtBits.NumStmts = Stmts.size();
|
2017-12-25 00:24:20 +08:00
|
|
|
setStmts(Stmts);
|
[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-28 02:43:27 +08:00
|
|
|
CompoundStmtBits.LBraceLoc = LB;
|
2017-12-25 00:24:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CompoundStmt::setStmts(ArrayRef<Stmt *> Stmts) {
|
2012-12-30 04:03:39 +08:00
|
|
|
assert(CompoundStmtBits.NumStmts == Stmts.size() &&
|
2012-07-05 01:03:41 +08:00
|
|
|
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
|
|
|
|
|
2017-12-25 00:24:20 +08:00
|
|
|
std::copy(Stmts.begin(), Stmts.end(), body_begin());
|
2012-07-05 01:03:41 +08:00
|
|
|
}
|
|
|
|
|
2017-12-25 00:24:20 +08:00
|
|
|
CompoundStmt *CompoundStmt::Create(const ASTContext &C, ArrayRef<Stmt *> Stmts,
|
|
|
|
SourceLocation LB, SourceLocation RB) {
|
|
|
|
void *Mem =
|
|
|
|
C.Allocate(totalSizeToAlloc<Stmt *>(Stmts.size()), alignof(CompoundStmt));
|
|
|
|
return new (Mem) CompoundStmt(Stmts, LB, RB);
|
|
|
|
}
|
2009-04-17 08:04:06 +08:00
|
|
|
|
2017-12-25 00:24:20 +08:00
|
|
|
CompoundStmt *CompoundStmt::CreateEmpty(const ASTContext &C,
|
|
|
|
unsigned NumStmts) {
|
|
|
|
void *Mem =
|
|
|
|
C.Allocate(totalSizeToAlloc<Stmt *>(NumStmts), alignof(CompoundStmt));
|
|
|
|
CompoundStmt *New = new (Mem) CompoundStmt(EmptyShell());
|
|
|
|
New->CompoundStmtBits.NumStmts = NumStmts;
|
|
|
|
return New;
|
2009-04-17 08:04:06 +08:00
|
|
|
}
|
2007-05-24 05:48:04 +08:00
|
|
|
|
2019-02-15 08:27:53 +08: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 14:56:27 +08:00
|
|
|
const char *LabelStmt::getName() const {
|
2011-02-17 15:39:24 +08:00
|
|
|
return getDecl()->getIdentifier()->getNameStart();
|
2007-05-28 14:56:27 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc,
|
2012-07-09 18:04:07 +08:00
|
|
|
ArrayRef<const Attr*> Attrs,
|
|
|
|
Stmt *SubStmt) {
|
2014-05-13 22:55:01 +08:00
|
|
|
assert(!Attrs.empty() && "Attrs should not be empty");
|
2017-12-25 00:24:11 +08:00
|
|
|
void *Mem = C.Allocate(totalSizeToAlloc<const Attr *>(Attrs.size()),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(AttributedStmt));
|
2012-07-09 18:04:07 +08:00
|
|
|
return new (Mem) AttributedStmt(Loc, Attrs, SubStmt);
|
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C,
|
|
|
|
unsigned NumAttrs) {
|
2012-07-09 18:04:07 +08:00
|
|
|
assert(NumAttrs > 0 && "NumAttrs should be greater than zero");
|
2017-12-25 00:24:11 +08:00
|
|
|
void *Mem = C.Allocate(totalSizeToAlloc<const Attr *>(NumAttrs),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(AttributedStmt));
|
2012-07-09 18:04:07 +08:00
|
|
|
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
|
|
|
|
}
|
|
|
|
|
2013-08-22 14:02:26 +08:00
|
|
|
std::string AsmStmt::generateAsmString(const ASTContext &C) const {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return gccAsmStmt->generateAsmString(C);
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return msAsmStmt->generateAsmString(C);
|
2012-08-29 01:43:23 +08:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef AsmStmt::getOutputConstraint(unsigned i) const {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return gccAsmStmt->getOutputConstraint(i);
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return msAsmStmt->getOutputConstraint(i);
|
2012-08-29 01:43:23 +08:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
const Expr *AsmStmt::getOutputExpr(unsigned i) const {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return gccAsmStmt->getOutputExpr(i);
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return msAsmStmt->getOutputExpr(i);
|
2012-08-29 01:43:23 +08:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef AsmStmt::getInputConstraint(unsigned i) const {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return gccAsmStmt->getInputConstraint(i);
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return msAsmStmt->getInputConstraint(i);
|
2012-08-29 01:43:23 +08:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
const Expr *AsmStmt::getInputExpr(unsigned i) const {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return gccAsmStmt->getInputExpr(i);
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return msAsmStmt->getInputExpr(i);
|
2012-08-29 01:43:23 +08:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef AsmStmt::getClobber(unsigned i) const {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return gccAsmStmt->getClobber(i);
|
2018-04-03 08:11:50 +08:00
|
|
|
if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this))
|
2012-08-29 02:21:14 +08:00
|
|
|
return msAsmStmt->getClobber(i);
|
2012-08-29 01:43:23 +08:00
|
|
|
llvm_unreachable("unknown asm statement kind!");
|
|
|
|
}
|
|
|
|
|
2012-08-28 08:24:05 +08: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 14:05:21 +08:00
|
|
|
char GCCAsmStmt::AsmStringPiece::getModifier() const {
|
|
|
|
assert(isOperand() && "Only Operands can have modifiers.");
|
|
|
|
return isLetter(Str[0]) ? Str[0] : '\0';
|
|
|
|
}
|
|
|
|
|
2012-08-28 07:47:56 +08:00
|
|
|
StringRef GCCAsmStmt::getClobber(unsigned i) const {
|
|
|
|
return getClobberStringLiteral(i)->getString();
|
|
|
|
}
|
|
|
|
|
2012-08-25 08:11:56 +08:00
|
|
|
Expr *GCCAsmStmt::getOutputExpr(unsigned i) {
|
2008-10-28 02:40:21 +08:00
|
|
|
return cast<Expr>(Exprs[i]);
|
|
|
|
}
|
2009-03-10 12:59:06 +08:00
|
|
|
|
|
|
|
/// getOutputConstraint - Return the constraint string for the specified
|
|
|
|
/// output operand. All output constraints are known to be non-empty (either
|
|
|
|
/// '=' or '+').
|
2012-08-25 08:11:56 +08:00
|
|
|
StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const {
|
2010-01-31 04:38:10 +08:00
|
|
|
return getOutputConstraintLiteral(i)->getString();
|
2008-10-28 02:40:21 +08:00
|
|
|
}
|
2009-03-10 12:59:06 +08:00
|
|
|
|
2012-08-25 08:11:56 +08:00
|
|
|
Expr *GCCAsmStmt::getInputExpr(unsigned i) {
|
2008-10-28 02:40:21 +08:00
|
|
|
return cast<Expr>(Exprs[i + NumOutputs]);
|
|
|
|
}
|
2017-11-15 07:35:42 +08:00
|
|
|
|
2012-08-25 08:11:56 +08:00
|
|
|
void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
|
2011-02-22 06:09:29 +08:00
|
|
|
Exprs[i + NumOutputs] = E;
|
|
|
|
}
|
|
|
|
|
2019-06-03 23:57:25 +08: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-25 10:32:50 +08:00
|
|
|
return cast<AddrLabelExpr>(Exprs[i + NumOutputs + NumInputs]);
|
2019-06-03 23:57:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef GCCAsmStmt::getLabelName(unsigned i) const {
|
|
|
|
return getLabelExpr(i)->getLabel()->getName();
|
|
|
|
}
|
|
|
|
|
2009-03-10 12:59:06 +08:00
|
|
|
/// getInputConstraint - Return the specified input constraint. Unlike output
|
|
|
|
/// constraints, these can be empty.
|
2012-08-25 08:11:56 +08:00
|
|
|
StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
|
2010-01-31 04:38:10 +08:00
|
|
|
return getInputConstraintLiteral(i)->getString();
|
2008-10-28 02:40:21 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 14:02:26 +08:00
|
|
|
void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
|
|
|
|
IdentifierInfo **Names,
|
|
|
|
StringLiteral **Constraints,
|
|
|
|
Stmt **Exprs,
|
|
|
|
unsigned NumOutputs,
|
|
|
|
unsigned NumInputs,
|
2019-06-03 23:57:25 +08:00
|
|
|
unsigned NumLabels,
|
2013-08-22 14:02:26 +08:00
|
|
|
StringLiteral **Clobbers,
|
|
|
|
unsigned NumClobbers) {
|
2009-04-18 04:57:14 +08:00
|
|
|
this->NumOutputs = NumOutputs;
|
|
|
|
this->NumInputs = NumInputs;
|
2010-01-31 07:19:41 +08:00
|
|
|
this->NumClobbers = NumClobbers;
|
2019-06-03 23:57:25 +08:00
|
|
|
this->NumLabels = NumLabels;
|
2010-01-31 07:19:41 +08:00
|
|
|
|
2019-06-03 23:57:25 +08:00
|
|
|
unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2010-01-31 07:19:41 +08:00
|
|
|
C.Deallocate(this->Names);
|
|
|
|
this->Names = new (C) IdentifierInfo*[NumExprs];
|
|
|
|
std::copy(Names, Names + NumExprs, this->Names);
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2010-01-31 07:19:41 +08:00
|
|
|
C.Deallocate(this->Exprs);
|
|
|
|
this->Exprs = new (C) Stmt*[NumExprs];
|
|
|
|
std::copy(Exprs, Exprs + NumExprs, this->Exprs);
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2019-05-30 15:21:08 +08:00
|
|
|
unsigned NumConstraints = NumOutputs + NumInputs;
|
2010-01-31 07:19:41 +08:00
|
|
|
C.Deallocate(this->Constraints);
|
2019-05-30 15:21:08 +08:00
|
|
|
this->Constraints = new (C) StringLiteral*[NumConstraints];
|
|
|
|
std::copy(Constraints, Constraints + NumConstraints, this->Constraints);
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2010-01-31 07:19:41 +08:00
|
|
|
C.Deallocate(this->Clobbers);
|
|
|
|
this->Clobbers = new (C) StringLiteral*[NumClobbers];
|
|
|
|
std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
|
2009-04-18 04:57:14 +08:00
|
|
|
}
|
|
|
|
|
2009-03-10 14:33:24 +08: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 08:11:56 +08:00
|
|
|
int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
|
2009-03-10 14:33:24 +08:00
|
|
|
unsigned NumPlusOperands = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 14:33:24 +08:00
|
|
|
// Check if this is an output operand.
|
|
|
|
for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) {
|
|
|
|
if (getOutputName(i) == SymbolicName)
|
|
|
|
return i;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 14:33:24 +08:00
|
|
|
for (unsigned i = 0, e = getNumInputs(); i != e; ++i)
|
|
|
|
if (getInputName(i) == SymbolicName)
|
|
|
|
return getNumOutputs() + NumPlusOperands + i;
|
|
|
|
|
2019-06-03 23:57:25 +08:00
|
|
|
for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
|
|
|
|
if (getLabelName(i) == SymbolicName)
|
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-25 10:32:50 +08:00
|
|
|
return i + getNumOutputs() + getNumInputs();
|
2019-06-03 23:57:25 +08:00
|
|
|
|
2009-03-10 14:33:24 +08:00
|
|
|
// Not found.
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-03-11 07:21:44 +08: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 08:11:56 +08:00
|
|
|
unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
|
2013-08-22 14:02:26 +08:00
|
|
|
const ASTContext &C, unsigned &DiagOffs) const {
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef Str = getAsmString()->getString();
|
2010-08-17 20:54:38 +08:00
|
|
|
const char *StrStart = Str.begin();
|
|
|
|
const char *StrEnd = Str.end();
|
2009-03-11 07:51:40 +08:00
|
|
|
const char *CurPtr = StrStart;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:21:44 +08:00
|
|
|
// "Simple" inline asms have no constraints or operands, just convert the asm
|
|
|
|
// string to escape $'s.
|
|
|
|
if (isSimple()) {
|
|
|
|
std::string Result;
|
2009-03-11 07:51:40 +08:00
|
|
|
for (; CurPtr != StrEnd; ++CurPtr) {
|
|
|
|
switch (*CurPtr) {
|
2009-03-11 07:21:44 +08:00
|
|
|
case '$':
|
|
|
|
Result += "$$";
|
|
|
|
break;
|
|
|
|
default:
|
2009-03-11 07:51:40 +08:00
|
|
|
Result += *CurPtr;
|
2009-03-11 07:21:44 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Pieces.push_back(AsmStringPiece(Result));
|
2009-03-11 07:51:40 +08:00
|
|
|
return 0;
|
2009-03-11 07:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// CurStringPiece - The current string that we are building up as we scan the
|
|
|
|
// asm string.
|
|
|
|
std::string CurStringPiece;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-09-02 08:18:52 +08:00
|
|
|
bool HasVariants = !C.getTargetInfo().hasNoAsmVariants();
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2016-05-17 06:52:23 +08:00
|
|
|
unsigned LastAsmStringToken = 0;
|
|
|
|
unsigned LastAsmStringOffset = 0;
|
|
|
|
|
2017-11-15 07:35:42 +08:00
|
|
|
while (true) {
|
2009-03-11 07:21:44 +08:00
|
|
|
// Done with the string?
|
2009-03-11 07:51:40 +08:00
|
|
|
if (CurPtr == StrEnd) {
|
2009-03-11 07:21:44 +08:00
|
|
|
if (!CurStringPiece.empty())
|
|
|
|
Pieces.push_back(AsmStringPiece(CurStringPiece));
|
2009-03-11 07:51:40 +08:00
|
|
|
return 0;
|
2009-03-11 07:21:44 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:51:40 +08:00
|
|
|
char CurChar = *CurPtr++;
|
2010-04-06 02:44:00 +08:00
|
|
|
switch (CurChar) {
|
|
|
|
case '$': CurStringPiece += "$$"; continue;
|
2010-04-24 00:29:58 +08:00
|
|
|
case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
|
|
|
|
case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
|
|
|
|
case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
|
2010-04-06 02:44:00 +08:00
|
|
|
case '%':
|
|
|
|
break;
|
|
|
|
default:
|
2009-03-11 07:21:44 +08:00
|
|
|
CurStringPiece += CurChar;
|
|
|
|
continue;
|
|
|
|
}
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2021-05-22 06:15:11 +08:00
|
|
|
const TargetInfo &TI = C.getTargetInfo();
|
|
|
|
|
2009-03-11 07:21:44 +08:00
|
|
|
// Escaped "%" character in asm string.
|
2009-03-11 08:06:36 +08: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 23:27:54 +08:00
|
|
|
// Handle escaped char and continue looping over the asm string.
|
2009-03-11 07:51:40 +08:00
|
|
|
char EscapedChar = *CurPtr++;
|
2016-10-31 23:27:54 +08:00
|
|
|
switch (EscapedChar) {
|
|
|
|
default:
|
2021-05-22 06:15:11 +08:00
|
|
|
// Handle target-specific escaped characters.
|
|
|
|
if (auto MaybeReplaceStr = TI.handleAsmEscapedChar(EscapedChar)) {
|
|
|
|
CurStringPiece += *MaybeReplaceStr;
|
|
|
|
continue;
|
|
|
|
}
|
2016-10-31 23:27:54 +08:00
|
|
|
break;
|
|
|
|
case '%': // %% -> %
|
|
|
|
case '{': // %{ -> {
|
|
|
|
case '}': // %} -> }
|
|
|
|
CurStringPiece += EscapedChar;
|
2009-03-11 07:21:44 +08:00
|
|
|
continue;
|
2016-10-31 23:27:54 +08:00
|
|
|
case '=': // %= -> Generate a unique ID.
|
2009-03-11 07:21:44 +08:00
|
|
|
CurStringPiece += "${:uid}";
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:21:44 +08: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 23:08:12 +08:00
|
|
|
|
2014-08-22 14:05:21 +08: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-09 06:30:41 +08:00
|
|
|
if (isLetter(EscapedChar)) {
|
2011-07-05 19:13:37 +08:00
|
|
|
if (CurPtr == StrEnd) { // Premature end.
|
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
|
|
|
return diag::err_asm_invalid_escape;
|
|
|
|
}
|
2009-03-11 07:51:40 +08:00
|
|
|
EscapedChar = *CurPtr++;
|
2009-03-11 07:21:44 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-08-22 14:05:21 +08:00
|
|
|
const SourceManager &SM = C.getSourceManager();
|
|
|
|
const LangOptions &LO = C.getLangOpts();
|
|
|
|
|
|
|
|
// Handle operands that don't have asmSymbolicName (e.g., %x4).
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isDigit(EscapedChar)) {
|
2009-03-11 07:21:44 +08:00
|
|
|
// %n - Assembler operand n
|
2009-03-12 06:52:17 +08:00
|
|
|
unsigned N = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-12 06:52:17 +08:00
|
|
|
--CurPtr;
|
2013-02-09 06:30:41 +08:00
|
|
|
while (CurPtr != StrEnd && isDigit(*CurPtr))
|
2009-03-12 07:09:16 +08:00
|
|
|
N = N*10 + ((*CurPtr++)-'0');
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2019-06-03 23:57:25 +08:00
|
|
|
unsigned NumOperands = getNumOutputs() + getNumPlusOperands() +
|
|
|
|
getNumInputs() + getNumLabels();
|
2009-03-11 08:23:13 +08:00
|
|
|
if (N >= NumOperands) {
|
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
|
|
|
return diag::err_asm_invalid_operand_number;
|
|
|
|
}
|
|
|
|
|
2014-08-22 14:05:21 +08: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 '%'.
|
2016-05-17 06:52:23 +08:00
|
|
|
SourceLocation BeginLoc = getAsmString()->getLocationOfByte(
|
|
|
|
Percent - StrStart, SM, LO, TI, &LastAsmStringToken,
|
|
|
|
&LastAsmStringOffset);
|
|
|
|
SourceLocation EndLoc = getAsmString()->getLocationOfByte(
|
|
|
|
CurPtr - StrStart, SM, LO, TI, &LastAsmStringToken,
|
|
|
|
&LastAsmStringOffset);
|
2014-08-22 14:05:21 +08:00
|
|
|
|
2015-05-30 03:42:19 +08:00
|
|
|
Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc);
|
2009-03-11 07:21:44 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-08-22 14:05:21 +08:00
|
|
|
// Handle operands that have asmSymbolicName (e.g., %x[foo]).
|
2009-03-11 07:21:44 +08:00
|
|
|
if (EscapedChar == '[') {
|
2009-03-11 08:06:36 +08:00
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 08:06:36 +08:00
|
|
|
// Find the ']'.
|
2009-03-11 07:51:40 +08:00
|
|
|
const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
|
2014-05-12 13:36:57 +08:00
|
|
|
if (NameEnd == nullptr)
|
2009-03-11 08:06:36 +08:00
|
|
|
return diag::err_asm_unterminated_symbolic_operand_name;
|
|
|
|
if (NameEnd == CurPtr)
|
|
|
|
return diag::err_asm_empty_symbolic_operand_name;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:21:44 +08:00
|
|
|
int N = getNamedOperand(SymbolicName);
|
2009-03-11 08:06:36 +08: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 14:05:21 +08: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 '%'.
|
2016-05-17 06:52:23 +08:00
|
|
|
SourceLocation BeginLoc = getAsmString()->getLocationOfByte(
|
|
|
|
Percent - StrStart, SM, LO, TI, &LastAsmStringToken,
|
|
|
|
&LastAsmStringOffset);
|
|
|
|
SourceLocation EndLoc = getAsmString()->getLocationOfByte(
|
|
|
|
NameEnd + 1 - StrStart, SM, LO, TI, &LastAsmStringToken,
|
|
|
|
&LastAsmStringOffset);
|
2014-08-22 14:05:21 +08:00
|
|
|
|
2015-05-30 03:42:19 +08:00
|
|
|
Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 08:06:36 +08:00
|
|
|
CurPtr = NameEnd+1;
|
2009-03-11 07:21:44 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-11 07:57:07 +08:00
|
|
|
DiagOffs = CurPtr-StrStart-1;
|
2009-03-11 07:51:40 +08:00
|
|
|
return diag::err_asm_invalid_escape;
|
2009-03-11 07:21:44 +08:00
|
|
|
}
|
|
|
|
}
|
2012-08-28 04:23:31 +08:00
|
|
|
|
|
|
|
/// Assemble final IR asm string (GCC-style).
|
2013-08-22 14:02:26 +08:00
|
|
|
std::string GCCAsmStmt::generateAsmString(const ASTContext &C) const {
|
2012-08-25 01:05:45 +08: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 08:11:56 +08:00
|
|
|
SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces;
|
2012-08-25 01:05:45 +08:00
|
|
|
unsigned DiagOffs;
|
|
|
|
AnalyzeAsmString(Pieces, C, DiagOffs);
|
|
|
|
|
|
|
|
std::string AsmString;
|
2018-04-03 08:11:50 +08:00
|
|
|
for (const auto &Piece : Pieces) {
|
|
|
|
if (Piece.isString())
|
|
|
|
AsmString += Piece.getString();
|
|
|
|
else if (Piece.getModifier() == '\0')
|
|
|
|
AsmString += '$' + llvm::utostr(Piece.getOperandNo());
|
2012-08-25 01:05:45 +08:00
|
|
|
else
|
2018-04-03 08:11:50 +08:00
|
|
|
AsmString += "${" + llvm::utostr(Piece.getOperandNo()) + ':' +
|
|
|
|
Piece.getModifier() + '}';
|
2012-08-25 01:05:45 +08:00
|
|
|
}
|
|
|
|
return AsmString;
|
|
|
|
}
|
2009-03-11 07:21:44 +08:00
|
|
|
|
2012-08-28 04:23:31 +08:00
|
|
|
/// Assemble final IR asm string (MS-style).
|
2013-08-22 14:02:26 +08:00
|
|
|
std::string MSAsmStmt::generateAsmString(const ASTContext &C) const {
|
2012-08-28 04:23:31 +08: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.
|
|
|
|
if (Instruction.startswith("vex "))
|
|
|
|
MSAsmString += '{' + Instruction.substr(0, 3).str() + '}' +
|
|
|
|
Instruction.substr(3).str();
|
|
|
|
else if (Instruction.startswith("vex2 ") ||
|
|
|
|
Instruction.startswith("vex3 ") || Instruction.startswith("evex "))
|
|
|
|
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-28 04:23:31 +08:00
|
|
|
}
|
|
|
|
|
2012-08-24 08:07:09 +08:00
|
|
|
Expr *MSAsmStmt::getOutputExpr(unsigned i) {
|
|
|
|
return cast<Expr>(Exprs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *MSAsmStmt::getInputExpr(unsigned i) {
|
|
|
|
return cast<Expr>(Exprs[i + NumOutputs]);
|
|
|
|
}
|
2017-11-15 07:35:42 +08:00
|
|
|
|
2012-08-24 08:07:09 +08:00
|
|
|
void MSAsmStmt::setInputExpr(unsigned i, Expr *E) {
|
|
|
|
Exprs[i + NumOutputs] = E;
|
|
|
|
}
|
|
|
|
|
2008-01-30 13:01:46 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Constructors
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
|
|
|
|
bool issimple, bool isvolatile, unsigned numoutputs,
|
|
|
|
unsigned numinputs, IdentifierInfo **names,
|
|
|
|
StringLiteral **constraints, Expr **exprs,
|
|
|
|
StringLiteral *asmstr, unsigned numclobbers,
|
2019-06-03 23:57:25 +08:00
|
|
|
StringLiteral **clobbers, unsigned numlabels,
|
|
|
|
SourceLocation rparenloc)
|
2017-11-15 07:35:42 +08:00
|
|
|
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
|
2019-06-03 23:57:25 +08:00
|
|
|
numinputs, numclobbers),
|
|
|
|
RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) {
|
|
|
|
unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2010-01-31 07:19:41 +08: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 15:21:08 +08:00
|
|
|
unsigned NumConstraints = NumOutputs + NumInputs;
|
|
|
|
Constraints = new (C) StringLiteral*[NumConstraints];
|
|
|
|
std::copy(constraints, constraints + NumConstraints, Constraints);
|
2008-08-06 07:15:29 +08:00
|
|
|
|
2010-01-31 07:19:41 +08:00
|
|
|
Clobbers = new (C) StringLiteral*[NumClobbers];
|
|
|
|
std::copy(clobbers, clobbers + NumClobbers, Clobbers);
|
2007-11-22 09:36:19 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
|
2012-08-16 08:06:53 +08:00
|
|
|
SourceLocation lbraceloc, bool issimple, bool isvolatile,
|
2012-10-17 05:55:39 +08:00
|
|
|
ArrayRef<Token> asmtoks, unsigned numoutputs,
|
2013-05-03 08:10:13 +08:00
|
|
|
unsigned numinputs,
|
2012-10-17 05:55:39 +08:00
|
|
|
ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs,
|
|
|
|
StringRef asmstr, ArrayRef<StringRef> clobbers,
|
|
|
|
SourceLocation endloc)
|
2017-11-15 07:35:42 +08:00
|
|
|
: AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
|
|
|
|
numinputs, clobbers.size()), LBraceLoc(lbraceloc),
|
|
|
|
EndLoc(endloc), NumAsmToks(asmtoks.size()) {
|
2013-05-03 08:10:13 +08:00
|
|
|
initialize(C, asmstr, asmtoks, constraints, exprs, clobbers);
|
|
|
|
}
|
2012-08-16 08:06:53 +08:00
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
static StringRef copyIntoContext(const ASTContext &C, StringRef str) {
|
2015-08-04 20:34:23 +08:00
|
|
|
return str.copy(C);
|
2013-05-03 08:10:13 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr,
|
2013-05-03 08:10:13 +08:00
|
|
|
ArrayRef<Token> asmtoks,
|
|
|
|
ArrayRef<StringRef> constraints,
|
|
|
|
ArrayRef<Expr*> exprs,
|
|
|
|
ArrayRef<StringRef> clobbers) {
|
|
|
|
assert(NumAsmToks == asmtoks.size());
|
|
|
|
assert(NumClobbers == clobbers.size());
|
|
|
|
|
2015-12-05 15:41:42 +08:00
|
|
|
assert(exprs.size() == NumOutputs + NumInputs);
|
|
|
|
assert(exprs.size() == constraints.size());
|
2013-05-03 08:10:13 +08:00
|
|
|
|
|
|
|
AsmStr = copyIntoContext(C, asmstr);
|
2012-08-07 08:29:06 +08:00
|
|
|
|
2015-12-05 15:41:42 +08:00
|
|
|
Exprs = new (C) Stmt*[exprs.size()];
|
|
|
|
std::copy(exprs.begin(), exprs.end(), Exprs);
|
2012-08-24 08:07:09 +08:00
|
|
|
|
2015-12-05 15:41:42 +08:00
|
|
|
AsmToks = new (C) Token[asmtoks.size()];
|
|
|
|
std::copy(asmtoks.begin(), asmtoks.end(), AsmToks);
|
2012-08-09 03:48:07 +08:00
|
|
|
|
2015-12-05 15:41:42 +08:00
|
|
|
Constraints = new (C) StringRef[exprs.size()];
|
|
|
|
std::transform(constraints.begin(), constraints.end(), Constraints,
|
|
|
|
[&](StringRef Constraint) {
|
|
|
|
return copyIntoContext(C, Constraint);
|
|
|
|
});
|
2012-08-29 04:28:20 +08:00
|
|
|
|
2012-08-11 05:36:25 +08:00
|
|
|
Clobbers = new (C) StringRef[NumClobbers];
|
2015-12-05 15:41:42 +08: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-12 04:47:18 +08:00
|
|
|
}
|
|
|
|
|
2018-10-28 05:12:20 +08:00
|
|
|
IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr,
|
2020-08-11 07:29:33 +08: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-28 05:12:20 +08:00
|
|
|
bool HasElse = Else != nullptr;
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
bool HasInit = Init != nullptr;
|
|
|
|
IfStmtBits.HasElse = HasElse;
|
|
|
|
IfStmtBits.HasVar = HasVar;
|
|
|
|
IfStmtBits.HasInit = HasInit;
|
|
|
|
|
2016-06-24 03:16:49 +08:00
|
|
|
setConstexpr(IsConstexpr);
|
2010-06-22 07:44:13 +08:00
|
|
|
|
2018-10-28 05:12:20 +08: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,
|
|
|
|
bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
|
2020-08-11 07:29:33 +08:00
|
|
|
SourceLocation LPL, SourceLocation RPL, Stmt *Then,
|
|
|
|
SourceLocation EL, Stmt *Else) {
|
2018-10-28 05:12:20 +08: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)
|
2020-08-11 07:29:33 +08:00
|
|
|
IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, LPL, RPL, Then, EL, Else);
|
2018-10-28 05:12:20 +08: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 13:36:57 +08:00
|
|
|
return nullptr;
|
2010-06-22 07:44:13 +08:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2018-10-28 05:12:20 +08:00
|
|
|
void IfStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
|
|
|
|
assert(hasVarStorage() &&
|
|
|
|
"This if statement has no storage for a condition variable!");
|
|
|
|
|
2010-06-22 07:44:13 +08:00
|
|
|
if (!V) {
|
2018-10-28 05:12:20 +08:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
|
2010-06-22 07:44:13 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2012-03-10 02:35:03 +08:00
|
|
|
SourceRange VarRange = V->getSourceRange();
|
2018-10-28 05:12:20 +08:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
|
|
|
|
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
|
2010-06-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
2016-08-17 01:44:11 +08:00
|
|
|
bool IfStmt::isObjCAvailabilityCheck() const {
|
2018-10-28 05:12:20 +08:00
|
|
|
return isa<ObjCAvailabilityCheckExpr>(getCond());
|
2016-08-17 01:44:11 +08:00
|
|
|
}
|
|
|
|
|
2021-05-11 21:40:48 +08:00
|
|
|
Optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
|
2019-12-14 06:10:13 +08:00
|
|
|
if (!isConstexpr() || getCond()->isValueDependent())
|
|
|
|
return None;
|
|
|
|
return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
|
|
|
|
}
|
|
|
|
|
2021-05-11 21:40:48 +08:00
|
|
|
Optional<const Stmt *>
|
|
|
|
IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
|
|
|
|
if (Optional<Stmt *> Result =
|
|
|
|
const_cast<IfStmt *>(this)->getNondiscardedCase(Ctx))
|
|
|
|
return *Result;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
|
2012-08-08 07:12:23 +08:00
|
|
|
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
|
2010-06-22 07:44:13 +08: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-28 02:43:27 +08:00
|
|
|
: Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP)
|
2010-06-22 07:44:13 +08:00
|
|
|
{
|
|
|
|
SubExprs[INIT] = Init;
|
|
|
|
setConditionVariable(C, condVar);
|
2013-09-03 22:41:16 +08:00
|
|
|
SubExprs[COND] = Cond;
|
|
|
|
SubExprs[INC] = Inc;
|
2010-06-22 07:44:13 +08: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-28 02:43:27 +08:00
|
|
|
ForStmtBits.ForLoc = FL;
|
2010-06-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl *ForStmt::getConditionVariable() const {
|
|
|
|
if (!SubExprs[CONDVAR])
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2018-04-03 08:11:50 +08:00
|
|
|
auto *DS = cast<DeclStmt>(SubExprs[CONDVAR]);
|
2010-06-22 07:44:13 +08:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
|
2010-06-22 07:44:13 +08:00
|
|
|
if (!V) {
|
2014-05-12 13:36:57 +08:00
|
|
|
SubExprs[CONDVAR] = nullptr;
|
2010-06-22 07:44:13 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2012-03-10 02:35:03 +08:00
|
|
|
SourceRange VarRange = V->getSourceRange();
|
|
|
|
SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
|
|
|
|
VarRange.getEnd());
|
2010-06-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
2018-10-30 00:12:37 +08:00
|
|
|
SwitchStmt::SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var,
|
2020-08-11 07:29:33 +08:00
|
|
|
Expr *Cond, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc)
|
|
|
|
: Stmt(SwitchStmtClass), FirstCase(nullptr), LParenLoc(LParenLoc),
|
|
|
|
RParenLoc(RParenLoc) {
|
2018-10-30 00:12:37 +08: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-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
2018-10-30 00:12:37 +08:00
|
|
|
SwitchStmt::SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar)
|
|
|
|
: Stmt(SwitchStmtClass, Empty) {
|
|
|
|
SwitchStmtBits.HasInit = HasInit;
|
|
|
|
SwitchStmtBits.HasVar = HasVar;
|
|
|
|
SwitchStmtBits.AllEnumCasesCovered = false;
|
|
|
|
}
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2018-10-30 00:12:37 +08:00
|
|
|
SwitchStmt *SwitchStmt::Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var,
|
2020-08-11 07:29:33 +08:00
|
|
|
Expr *Cond, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc) {
|
2018-10-30 00:12:37 +08:00
|
|
|
bool HasInit = Init != nullptr;
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
void *Mem = Ctx.Allocate(
|
|
|
|
totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar),
|
|
|
|
alignof(SwitchStmt));
|
2020-08-11 07:29:33 +08:00
|
|
|
return new (Mem) SwitchStmt(Ctx, Init, Var, Cond, LParenLoc, RParenLoc);
|
2018-10-30 00:12:37 +08: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-22 07:44:13 +08:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2018-10-30 00:12:37 +08:00
|
|
|
void SwitchStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
|
|
|
|
assert(hasVarStorage() &&
|
|
|
|
"This switch statement has no storage for a condition variable!");
|
|
|
|
|
2010-06-22 07:44:13 +08:00
|
|
|
if (!V) {
|
2018-10-30 00:12:37 +08:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
|
2010-06-22 07:44:13 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2012-03-10 02:35:03 +08:00
|
|
|
SourceRange VarRange = V->getSourceRange();
|
2018-10-30 00:12:37 +08:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
|
|
|
|
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
|
2010-06-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
2018-10-30 21:42:41 +08:00
|
|
|
WhileStmt::WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
|
2020-07-10 11:19:06 +08:00
|
|
|
Stmt *Body, SourceLocation WL, SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc)
|
2018-10-30 21:42:41 +08:00
|
|
|
: Stmt(WhileStmtClass) {
|
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
WhileStmtBits.HasVar = HasVar;
|
|
|
|
|
|
|
|
setCond(Cond);
|
|
|
|
setBody(Body);
|
|
|
|
if (HasVar)
|
|
|
|
setConditionVariable(Ctx, Var);
|
|
|
|
|
|
|
|
setWhileLoc(WL);
|
2020-07-10 11:19:06 +08:00
|
|
|
setLParenLoc(LParenLoc);
|
|
|
|
setRParenLoc(RParenLoc);
|
2010-06-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
2018-10-30 21:42:41 +08: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-10 11:19:06 +08:00
|
|
|
Stmt *Body, SourceLocation WL,
|
|
|
|
SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc) {
|
2018-10-30 21:42:41 +08:00
|
|
|
bool HasVar = Var != nullptr;
|
|
|
|
void *Mem =
|
|
|
|
Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar),
|
|
|
|
alignof(WhileStmt));
|
2020-07-10 11:19:06 +08:00
|
|
|
return new (Mem) WhileStmt(Ctx, Var, Cond, Body, WL, LParenLoc, RParenLoc);
|
2018-10-30 21:42:41 +08:00
|
|
|
}
|
2012-08-08 07:12:23 +08:00
|
|
|
|
2018-10-30 21:42:41 +08: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-22 07:44:13 +08:00
|
|
|
return cast<VarDecl>(DS->getSingleDecl());
|
|
|
|
}
|
|
|
|
|
2018-10-30 21:42:41 +08:00
|
|
|
void WhileStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
|
|
|
|
assert(hasVarStorage() &&
|
|
|
|
"This while statement has no storage for a condition variable!");
|
|
|
|
|
2010-06-22 07:44:13 +08:00
|
|
|
if (!V) {
|
2018-10-30 21:42:41 +08:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
|
2010-06-22 07:44:13 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-03-10 02:35:03 +08:00
|
|
|
|
|
|
|
SourceRange VarRange = V->getSourceRange();
|
2018-10-30 21:42:41 +08:00
|
|
|
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
|
|
|
|
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
|
2010-06-22 07:44:13 +08:00
|
|
|
}
|
|
|
|
|
2007-08-25 05:09:09 +08:00
|
|
|
// IndirectGotoStmt
|
2011-02-17 15:39:24 +08:00
|
|
|
LabelDecl *IndirectGotoStmt::getConstantTarget() {
|
2018-04-03 08:11:50 +08:00
|
|
|
if (auto *E = dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
|
2010-10-28 16:53:48 +08:00
|
|
|
return E->getLabel();
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2010-10-28 16:53:48 +08:00
|
|
|
}
|
2007-08-25 05:09:09 +08:00
|
|
|
|
|
|
|
// ReturnStmt
|
2018-10-30 22:40:49 +08: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 11:11:08 +08:00
|
|
|
}
|
2018-10-30 22:40:49 +08: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-25 05:09:09 +08:00
|
|
|
}
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2018-10-28 20:30:53 +08: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-15 07:35:42 +08:00
|
|
|
SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock,
|
2014-07-26 04:52:51 +08:00
|
|
|
Stmt *Handler)
|
2017-11-15 07:35:42 +08:00
|
|
|
: Stmt(SEHTryStmtClass), IsCXXTry(IsCXXTry), TryLoc(TryLoc) {
|
2014-07-26 04:52:51 +08:00
|
|
|
Children[TRY] = TryBlock;
|
2011-04-28 09:08:34 +08:00
|
|
|
Children[HANDLER] = Handler;
|
|
|
|
}
|
|
|
|
|
2014-07-26 04:52:51 +08:00
|
|
|
SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
|
2013-08-22 13:28:54 +08:00
|
|
|
SourceLocation TryLoc, Stmt *TryBlock,
|
2014-07-26 04:52:51 +08:00
|
|
|
Stmt *Handler) {
|
|
|
|
return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
|
|
|
|
return dyn_cast<SEHExceptStmt>(getHandler());
|
|
|
|
}
|
|
|
|
|
|
|
|
SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const {
|
|
|
|
return dyn_cast<SEHFinallyStmt>(getHandler());
|
|
|
|
}
|
|
|
|
|
2017-11-15 07:35:42 +08:00
|
|
|
SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block)
|
|
|
|
: Stmt(SEHExceptStmtClass), Loc(Loc) {
|
2013-09-03 22:41:16 +08:00
|
|
|
Children[FILTER_EXPR] = FilterExpr;
|
2011-04-28 09:08:34 +08:00
|
|
|
Children[BLOCK] = Block;
|
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
SEHExceptStmt* SEHExceptStmt::Create(const ASTContext &C, SourceLocation Loc,
|
|
|
|
Expr *FilterExpr, Stmt *Block) {
|
2011-04-28 09:08:34 +08:00
|
|
|
return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
|
|
|
|
}
|
|
|
|
|
2017-11-15 07:35:42 +08:00
|
|
|
SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, Stmt *Block)
|
|
|
|
: Stmt(SEHFinallyStmtClass), Loc(Loc), Block(Block) {}
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
SEHFinallyStmt* SEHFinallyStmt::Create(const ASTContext &C, SourceLocation Loc,
|
2011-04-28 09:08:34 +08:00
|
|
|
Stmt *Block) {
|
|
|
|
return new(C)SEHFinallyStmt(Loc,Block);
|
|
|
|
}
|
2013-04-17 02:53:08 +08:00
|
|
|
|
2015-12-03 01:44:43 +08: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 11:24:14 +08: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-17 02:53:08 +08:00
|
|
|
CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const {
|
|
|
|
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
|
|
|
|
|
|
|
|
// Offset of the first Capture object.
|
2016-10-20 22:27:22 +08:00
|
|
|
unsigned FirstCaptureOffset = llvm::alignTo(Size, alignof(Capture));
|
2013-04-17 02:53:08 +08:00
|
|
|
|
|
|
|
return reinterpret_cast<Capture *>(
|
|
|
|
reinterpret_cast<char *>(const_cast<CapturedStmt *>(this))
|
|
|
|
+ FirstCaptureOffset);
|
|
|
|
}
|
|
|
|
|
2013-05-04 11:59:06 +08:00
|
|
|
CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind,
|
|
|
|
ArrayRef<Capture> Captures,
|
2013-04-17 02:53:08 +08:00
|
|
|
ArrayRef<Expr *> CaptureInits,
|
2013-04-17 03:37:38 +08:00
|
|
|
CapturedDecl *CD,
|
2013-04-17 02:53:08 +08:00
|
|
|
RecordDecl *RD)
|
|
|
|
: Stmt(CapturedStmtClass), NumCaptures(Captures.size()),
|
2013-05-04 11:59:06 +08:00
|
|
|
CapDeclAndKind(CD, Kind), TheRecordDecl(RD) {
|
2013-04-17 02:53:08 +08:00
|
|
|
assert( S && "null captured statement");
|
2013-04-17 03:37:38 +08:00
|
|
|
assert(CD && "null captured declaration for captured statement");
|
2013-04-17 02:53:08 +08: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-15 07:35:42 +08:00
|
|
|
CapDeclAndKind(nullptr, CR_Default) {
|
2014-05-12 13:36:57 +08:00
|
|
|
getStoredStmts()[NumCaptures] = nullptr;
|
2013-04-17 02:53:08 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
CapturedStmt *CapturedStmt::Create(const ASTContext &Context, Stmt *S,
|
2013-05-04 11:59:06 +08:00
|
|
|
CapturedRegionKind Kind,
|
2013-04-17 02:53:08 +08:00
|
|
|
ArrayRef<Capture> Captures,
|
|
|
|
ArrayRef<Expr *> CaptureInits,
|
2013-04-17 03:37:38 +08:00
|
|
|
CapturedDecl *CD,
|
2013-04-17 02:53:08 +08: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 22:27:22 +08:00
|
|
|
Size = llvm::alignTo(Size, alignof(Capture));
|
2013-04-17 02:53:08 +08:00
|
|
|
Size += sizeof(Capture) * Captures.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Mem = Context.Allocate(Size);
|
2013-05-04 11:59:06 +08:00
|
|
|
return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD);
|
2013-04-17 02:53:08 +08:00
|
|
|
}
|
|
|
|
|
2013-08-22 13:28:54 +08:00
|
|
|
CapturedStmt *CapturedStmt::CreateDeserialized(const ASTContext &Context,
|
2013-04-17 02:53:08 +08:00
|
|
|
unsigned NumCaptures) {
|
|
|
|
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
|
|
|
|
if (NumCaptures > 0) {
|
|
|
|
// Realign for the following Capture array.
|
2016-10-20 22:27:22 +08:00
|
|
|
Size = llvm::alignTo(Size, alignof(Capture));
|
2013-04-17 02:53:08 +08:00
|
|
|
Size += sizeof(Capture) * NumCaptures;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Mem = Context.Allocate(Size);
|
|
|
|
return new (Mem) CapturedStmt(EmptyShell(), NumCaptures);
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_range CapturedStmt::children() {
|
2017-03-30 22:13:19 +08:00
|
|
|
// Children are captured field initializers.
|
2013-04-17 03:37:38 +08:00
|
|
|
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
|
2013-04-17 02:53:08 +08:00
|
|
|
}
|
|
|
|
|
2019-04-12 23:36:02 +08:00
|
|
|
Stmt::const_child_range CapturedStmt::children() const {
|
|
|
|
return const_child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
|
|
|
|
}
|
|
|
|
|
2015-12-30 11:24:14 +08:00
|
|
|
CapturedDecl *CapturedStmt::getCapturedDecl() {
|
|
|
|
return CapDeclAndKind.getPointer();
|
|
|
|
}
|
2017-11-15 07:35:42 +08:00
|
|
|
|
2015-12-30 11:24:14 +08:00
|
|
|
const CapturedDecl *CapturedStmt::getCapturedDecl() const {
|
|
|
|
return CapDeclAndKind.getPointer();
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Set the outlined function declaration.
|
2015-12-30 11:24:14 +08:00
|
|
|
void CapturedStmt::setCapturedDecl(CapturedDecl *D) {
|
|
|
|
assert(D && "null CapturedDecl");
|
|
|
|
CapDeclAndKind.setPointer(D);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Retrieve the captured region kind.
|
2015-12-30 11:24:14 +08:00
|
|
|
CapturedRegionKind CapturedStmt::getCapturedRegionKind() const {
|
|
|
|
return CapDeclAndKind.getInt();
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Set the captured region kind.
|
2015-12-30 11:24:14 +08:00
|
|
|
void CapturedStmt::setCapturedRegionKind(CapturedRegionKind Kind) {
|
|
|
|
CapDeclAndKind.setInt(Kind);
|
|
|
|
}
|
|
|
|
|
2013-04-17 02:53:08 +08:00
|
|
|
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
|
2014-03-15 02:08:33 +08:00
|
|
|
for (const auto &I : captures()) {
|
2017-05-16 00:26:15 +08:00
|
|
|
if (!I.capturesVariable() && !I.capturesVariableByCopy())
|
2013-04-17 02:53:08 +08:00
|
|
|
continue;
|
2017-09-21 04:11:31 +08:00
|
|
|
if (I.getCapturedVar()->getCanonicalDecl() == Var->getCanonicalDecl())
|
2013-04-17 02:53:08 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|