mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-28 08:02:54 +00:00
Merge llvm-project main llvmorg-15-init-17826-g1f8ae9d7e7e4
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvmorg-15-init-17826-g1f8ae9d7e7e4, the last commit before the upstream release/16.x branch was created. PR: 265425 MFC after: 2 weeks
This commit is contained in:
commit
972a253a57
@ -202,7 +202,8 @@ class CFGCXXRecordTypedCall : public CFGStmt {
|
||||
isa<ReturnedValueConstructionContext>(C) ||
|
||||
isa<VariableConstructionContext>(C) ||
|
||||
isa<ConstructorInitializerConstructionContext>(C) ||
|
||||
isa<ArgumentConstructionContext>(C)));
|
||||
isa<ArgumentConstructionContext>(C) ||
|
||||
isa<LambdaCaptureConstructionContext>(C)));
|
||||
Data2.setPointer(const_cast<ConstructionContext *>(C));
|
||||
}
|
||||
|
||||
|
@ -36,13 +36,14 @@ class ConstructionContextItem {
|
||||
ElidedDestructorKind,
|
||||
ElidableConstructorKind,
|
||||
ArgumentKind,
|
||||
STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind,
|
||||
STATEMENT_WITH_INDEX_KIND_END=ArgumentKind,
|
||||
LambdaCaptureKind,
|
||||
STATEMENT_WITH_INDEX_KIND_BEGIN = ArgumentKind,
|
||||
STATEMENT_WITH_INDEX_KIND_END = LambdaCaptureKind,
|
||||
STATEMENT_KIND_BEGIN = VariableKind,
|
||||
STATEMENT_KIND_END = ArgumentKind,
|
||||
STATEMENT_KIND_END = LambdaCaptureKind,
|
||||
InitializerKind,
|
||||
INITIALIZER_KIND_BEGIN=InitializerKind,
|
||||
INITIALIZER_KIND_END=InitializerKind
|
||||
INITIALIZER_KIND_BEGIN = InitializerKind,
|
||||
INITIALIZER_KIND_END = InitializerKind
|
||||
};
|
||||
|
||||
LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) {
|
||||
@ -55,6 +56,8 @@ class ConstructionContextItem {
|
||||
case ElidedDestructorKind: return "elide destructor";
|
||||
case ElidableConstructorKind: return "elide constructor";
|
||||
case ArgumentKind: return "construct into argument";
|
||||
case LambdaCaptureKind:
|
||||
return "construct into lambda captured variable";
|
||||
case InitializerKind: return "construct into member variable";
|
||||
};
|
||||
llvm_unreachable("Unknown ItemKind");
|
||||
@ -72,7 +75,7 @@ class ConstructionContextItem {
|
||||
|
||||
bool hasIndex() const {
|
||||
return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN &&
|
||||
Kind >= STATEMENT_WITH_INDEX_KIND_END;
|
||||
Kind <= STATEMENT_WITH_INDEX_KIND_END;
|
||||
}
|
||||
|
||||
bool hasInitializer() const {
|
||||
@ -127,6 +130,9 @@ class ConstructionContextItem {
|
||||
ConstructionContextItem(const CXXCtorInitializer *Init)
|
||||
: Data(Init), Kind(InitializerKind), Index(0) {}
|
||||
|
||||
ConstructionContextItem(const LambdaExpr *LE, unsigned Index)
|
||||
: Data(LE), Kind(LambdaCaptureKind), Index(Index) {}
|
||||
|
||||
ItemKind getKind() const { return Kind; }
|
||||
|
||||
LLVM_DUMP_METHOD StringRef getKindAsString() const {
|
||||
@ -254,7 +260,8 @@ class ConstructionContext {
|
||||
CXX17ElidedCopyReturnedValueKind,
|
||||
RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
|
||||
RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind,
|
||||
ArgumentKind
|
||||
ArgumentKind,
|
||||
LambdaCaptureKind
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -298,6 +305,11 @@ class ConstructionContext {
|
||||
const ConstructionContextLayer *TopLayer);
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
virtual const ArrayInitLoopExpr *getArrayInitLoop() const { return nullptr; }
|
||||
|
||||
// Only declared to silence -Wnon-virtual-dtor warnings.
|
||||
virtual ~ConstructionContext() = default;
|
||||
};
|
||||
|
||||
/// An abstract base class for local variable constructors.
|
||||
@ -314,6 +326,12 @@ class VariableConstructionContext : public ConstructionContext {
|
||||
public:
|
||||
const DeclStmt *getDeclStmt() const { return DS; }
|
||||
|
||||
const ArrayInitLoopExpr *getArrayInitLoop() const override {
|
||||
const auto *Var = cast<VarDecl>(DS->getSingleDecl());
|
||||
|
||||
return dyn_cast<ArrayInitLoopExpr>(Var->getInit());
|
||||
}
|
||||
|
||||
static bool classof(const ConstructionContext *CC) {
|
||||
return CC->getKind() >= VARIABLE_BEGIN &&
|
||||
CC->getKind() <= VARIABLE_END;
|
||||
@ -381,6 +399,10 @@ class ConstructorInitializerConstructionContext : public ConstructionContext {
|
||||
public:
|
||||
const CXXCtorInitializer *getCXXCtorInitializer() const { return I; }
|
||||
|
||||
const ArrayInitLoopExpr *getArrayInitLoop() const override {
|
||||
return dyn_cast<ArrayInitLoopExpr>(I->getInit());
|
||||
}
|
||||
|
||||
static bool classof(const ConstructionContext *CC) {
|
||||
return CC->getKind() >= INITIALIZER_BEGIN &&
|
||||
CC->getKind() <= INITIALIZER_END;
|
||||
@ -659,6 +681,42 @@ class ArgumentConstructionContext : public ConstructionContext {
|
||||
}
|
||||
};
|
||||
|
||||
class LambdaCaptureConstructionContext : public ConstructionContext {
|
||||
// The lambda of which the initializer we capture.
|
||||
const LambdaExpr *LE;
|
||||
|
||||
// Index of the captured element in the captured list.
|
||||
unsigned Index;
|
||||
|
||||
friend class ConstructionContext; // Allows to create<>() itself.
|
||||
|
||||
explicit LambdaCaptureConstructionContext(const LambdaExpr *LE,
|
||||
unsigned Index)
|
||||
: ConstructionContext(LambdaCaptureKind), LE(LE), Index(Index) {}
|
||||
|
||||
public:
|
||||
const LambdaExpr *getLambdaExpr() const { return LE; }
|
||||
unsigned getIndex() const { return Index; }
|
||||
|
||||
const Expr *getInitializer() const {
|
||||
return *(LE->capture_init_begin() + Index);
|
||||
}
|
||||
|
||||
const FieldDecl *getFieldDecl() const {
|
||||
auto It = LE->getLambdaClass()->field_begin();
|
||||
std::advance(It, Index);
|
||||
return *It;
|
||||
}
|
||||
|
||||
const ArrayInitLoopExpr *getArrayInitLoop() const override {
|
||||
return dyn_cast_or_null<ArrayInitLoopExpr>(getInitializer());
|
||||
}
|
||||
|
||||
static bool classof(const ConstructionContext *CC) {
|
||||
return CC->getKind() == LambdaCaptureKind;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
|
||||
|
@ -340,6 +340,10 @@ class DataflowAnalysisContext {
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *>
|
||||
DisjunctionVals;
|
||||
llvm::DenseMap<BoolValue *, NegationValue *> NegationVals;
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ImplicationValue *>
|
||||
ImplicationVals;
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, BiconditionalValue *>
|
||||
BiconditionalVals;
|
||||
|
||||
// Flow conditions are tracked symbolically: each unique flow condition is
|
||||
// associated with a fresh symbolic variable (token), bound to the clause that
|
||||
|
@ -128,6 +128,21 @@ class Environment {
|
||||
/// with a symbolic representation of the `this` pointee.
|
||||
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
|
||||
|
||||
/// Creates and returns an environment to use for an inline analysis of the
|
||||
/// callee. Uses the storage location from each argument in the `Call` as the
|
||||
/// storage location for the corresponding parameter in the callee.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// The callee of `Call` must be a `FunctionDecl` with a body.
|
||||
///
|
||||
/// The body of the callee must not reference globals.
|
||||
///
|
||||
/// The arguments of `Call` must map 1:1 to the callee's parameters.
|
||||
///
|
||||
/// Each argument of `Call` must already have a `StorageLocation`.
|
||||
Environment pushCall(const CallExpr *Call) const;
|
||||
|
||||
/// Returns true if and only if the environment is equivalent to `Other`, i.e
|
||||
/// the two environments:
|
||||
/// - have the same mappings from declarations to storage locations,
|
||||
|
@ -54,10 +54,13 @@ template <typename Key, typename ElementLattice> class MapLattice {
|
||||
// The `bottom` element is the empty map.
|
||||
static MapLattice bottom() { return MapLattice(); }
|
||||
|
||||
void insert(const std::pair<const key_type, mapped_type> &P) { C.insert(P); }
|
||||
std::pair<iterator, bool>
|
||||
insert(const std::pair<const key_type, mapped_type> &P) {
|
||||
return C.insert(P);
|
||||
}
|
||||
|
||||
void insert(std::pair<const key_type, mapped_type> &&P) {
|
||||
C.insert(std::move(P));
|
||||
std::pair<iterator, bool> insert(std::pair<const key_type, mapped_type> &&P) {
|
||||
return C.insert(std::move(P));
|
||||
}
|
||||
|
||||
unsigned size() const { return C.size(); }
|
||||
|
@ -20,6 +20,12 @@
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
||||
struct TransferOptions {
|
||||
/// Determines whether to analyze function bodies when present in the
|
||||
/// translation unit.
|
||||
bool ContextSensitive = false;
|
||||
};
|
||||
|
||||
/// Maps statements to the environments of basic blocks that contain them.
|
||||
class StmtToEnvMap {
|
||||
public:
|
||||
@ -36,7 +42,8 @@ class StmtToEnvMap {
|
||||
/// Requirements:
|
||||
///
|
||||
/// `S` must not be `ParenExpr` or `ExprWithCleanups`.
|
||||
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env);
|
||||
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
|
||||
TransferOptions Options);
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
|
||||
#include "clang/Analysis/FlowSensitive/Transfer.h"
|
||||
#include "llvm/ADT/Any.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
@ -36,6 +37,9 @@ struct DataflowAnalysisOptions {
|
||||
// (at which point the built-in transfer functions can be simply a standalone
|
||||
// analysis).
|
||||
bool ApplyBuiltinTransfer = true;
|
||||
|
||||
/// Only has an effect if `ApplyBuiltinTransfer` is true.
|
||||
TransferOptions BuiltinTransferOptions;
|
||||
};
|
||||
|
||||
/// Type-erased lattice element container.
|
||||
@ -57,7 +61,7 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel {
|
||||
|
||||
/// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
|
||||
TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer)
|
||||
: Options({ApplyBuiltinTransfer}) {}
|
||||
: Options({ApplyBuiltinTransfer, TransferOptions{}}) {}
|
||||
|
||||
TypeErasedDataflowAnalysis(DataflowAnalysisOptions Options)
|
||||
: Options(Options) {}
|
||||
@ -90,6 +94,11 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel {
|
||||
/// Determines whether to apply the built-in transfer functions, which model
|
||||
/// the heap and stack in the `Environment`.
|
||||
bool applyBuiltinTransfer() const { return Options.ApplyBuiltinTransfer; }
|
||||
|
||||
/// Returns the options to be passed to the built-in transfer functions.
|
||||
TransferOptions builtinTransferOptions() const {
|
||||
return Options.BuiltinTransferOptions;
|
||||
}
|
||||
};
|
||||
|
||||
/// Type-erased model of the program at a given program point.
|
||||
|
@ -37,12 +37,13 @@ class Value {
|
||||
Pointer,
|
||||
Struct,
|
||||
|
||||
// Synthetic boolean values are either atomic values or composites that
|
||||
// represent conjunctions, disjunctions, and negations.
|
||||
// Synthetic boolean values are either atomic values or logical connectives.
|
||||
AtomicBool,
|
||||
Conjunction,
|
||||
Disjunction,
|
||||
Negation
|
||||
Negation,
|
||||
Implication,
|
||||
Biconditional,
|
||||
};
|
||||
|
||||
explicit Value(Kind ValKind) : ValKind(ValKind) {}
|
||||
@ -84,7 +85,9 @@ class BoolValue : public Value {
|
||||
return Val->getKind() == Kind::AtomicBool ||
|
||||
Val->getKind() == Kind::Conjunction ||
|
||||
Val->getKind() == Kind::Disjunction ||
|
||||
Val->getKind() == Kind::Negation;
|
||||
Val->getKind() == Kind::Negation ||
|
||||
Val->getKind() == Kind::Implication ||
|
||||
Val->getKind() == Kind::Biconditional;
|
||||
}
|
||||
};
|
||||
|
||||
@ -162,6 +165,54 @@ class NegationValue : public BoolValue {
|
||||
BoolValue &SubVal;
|
||||
};
|
||||
|
||||
/// Models a boolean implication.
|
||||
///
|
||||
/// Equivalent to `!LHS v RHS`.
|
||||
class ImplicationValue : public BoolValue {
|
||||
public:
|
||||
explicit ImplicationValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
|
||||
: BoolValue(Kind::Implication), LeftSubVal(LeftSubVal),
|
||||
RightSubVal(RightSubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Implication;
|
||||
}
|
||||
|
||||
/// Returns the left sub-value of the implication.
|
||||
BoolValue &getLeftSubValue() const { return LeftSubVal; }
|
||||
|
||||
/// Returns the right sub-value of the implication.
|
||||
BoolValue &getRightSubValue() const { return RightSubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &LeftSubVal;
|
||||
BoolValue &RightSubVal;
|
||||
};
|
||||
|
||||
/// Models a boolean biconditional.
|
||||
///
|
||||
/// Equivalent to `(LHS ^ RHS) v (!LHS ^ !RHS)`.
|
||||
class BiconditionalValue : public BoolValue {
|
||||
public:
|
||||
explicit BiconditionalValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
|
||||
: BoolValue(Kind::Biconditional), LeftSubVal(LeftSubVal),
|
||||
RightSubVal(RightSubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Biconditional;
|
||||
}
|
||||
|
||||
/// Returns the left sub-value of the biconditional.
|
||||
BoolValue &getLeftSubValue() const { return LeftSubVal; }
|
||||
|
||||
/// Returns the right sub-value of the biconditional.
|
||||
BoolValue &getRightSubValue() const { return RightSubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &LeftSubVal;
|
||||
BoolValue &RightSubVal;
|
||||
};
|
||||
|
||||
/// Models an integer.
|
||||
class IntegerValue : public Value {
|
||||
public:
|
||||
|
@ -5040,6 +5040,12 @@ general this requires the template to be declared at least twice. For example:
|
||||
clang::preferred_name(wstring)]] basic_string {
|
||||
// ...
|
||||
};
|
||||
|
||||
|
||||
Note that the ``preferred_name`` attribute will be ignored when the compiler
|
||||
writes a C++20 Module interface now. This is due to a compiler issue
|
||||
(https://github.com/llvm/llvm-project/issues/56490) that blocks users to modularize
|
||||
declarations with `preferred_name`. This is intended to be fixed in the future.
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -45,18 +45,18 @@ namespace clang {
|
||||
// Start position for diagnostics.
|
||||
enum {
|
||||
DIAG_START_COMMON = 0,
|
||||
DIAG_START_DRIVER = DIAG_START_COMMON + DIAG_SIZE_COMMON,
|
||||
DIAG_START_FRONTEND = DIAG_START_DRIVER + DIAG_SIZE_DRIVER,
|
||||
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + DIAG_SIZE_FRONTEND,
|
||||
DIAG_START_LEX = DIAG_START_SERIALIZATION + DIAG_SIZE_SERIALIZATION,
|
||||
DIAG_START_PARSE = DIAG_START_LEX + DIAG_SIZE_LEX,
|
||||
DIAG_START_AST = DIAG_START_PARSE + DIAG_SIZE_PARSE,
|
||||
DIAG_START_COMMENT = DIAG_START_AST + DIAG_SIZE_AST,
|
||||
DIAG_START_CROSSTU = DIAG_START_COMMENT + DIAG_SIZE_COMMENT,
|
||||
DIAG_START_SEMA = DIAG_START_CROSSTU + DIAG_SIZE_CROSSTU,
|
||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + DIAG_SIZE_SEMA,
|
||||
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + DIAG_SIZE_ANALYSIS,
|
||||
DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + DIAG_SIZE_REFACTORING
|
||||
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
|
||||
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
|
||||
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
|
||||
DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
|
||||
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
|
||||
DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
|
||||
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
|
||||
DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
|
||||
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
|
||||
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
|
||||
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
|
||||
DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING)
|
||||
};
|
||||
|
||||
class CustomDiagInfo;
|
||||
|
@ -282,7 +282,7 @@ def err_inline_nested_namespace_definition : Error<
|
||||
def err_expected_semi_after_attribute_list : Error<
|
||||
"expected ';' after attribute list">;
|
||||
def err_expected_semi_after_static_assert : Error<
|
||||
"expected ';' after static_assert">;
|
||||
"expected ';' after '%0'">;
|
||||
def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
|
||||
def err_single_decl_assign_in_for_range : Error<
|
||||
"range-based 'for' statement uses ':', not '='">;
|
||||
@ -425,7 +425,7 @@ def err_unexpected_token_in_nested_name_spec : Error<
|
||||
def err_bool_redeclaration : Error<
|
||||
"redeclaration of C++ built-in type 'bool'">;
|
||||
def warn_cxx98_compat_static_assert : Warning<
|
||||
"static_assert declarations are incompatible with C++98">,
|
||||
"'static_assert' declarations are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def ext_ms_static_assert : ExtWarn<
|
||||
"use of 'static_assert' without inclusion of <assert.h> is a Microsoft "
|
||||
@ -538,6 +538,8 @@ def err_invalid_operator_on_type : Error<
|
||||
"cannot use %select{dot|arrow}0 operator on a type">;
|
||||
def err_expected_unqualified_id : Error<
|
||||
"expected %select{identifier|unqualified-id}0">;
|
||||
def err_while_loop_outside_of_a_function : Error<
|
||||
"while loop outside of a function">;
|
||||
def err_brackets_go_after_unqualified_id : Error<
|
||||
"brackets are not allowed here; to declare an array, "
|
||||
"place the brackets after the %select{identifier|name}0">;
|
||||
|
@ -1526,12 +1526,12 @@ def err_messaging_class_with_direct_method : Error<
|
||||
|
||||
// C++ declarations
|
||||
def err_static_assert_expression_is_not_constant : Error<
|
||||
"static_assert expression is not an integral constant expression">;
|
||||
"static assertion expression is not an integral constant expression">;
|
||||
def err_constexpr_if_condition_expression_is_not_constant : Error<
|
||||
"constexpr if condition is not a constant expression">;
|
||||
def err_static_assert_failed : Error<"static_assert failed%select{: %1|}0">;
|
||||
def err_static_assert_failed : Error<"static assertion failed%select{: %1|}0">;
|
||||
def err_static_assert_requirement_failed : Error<
|
||||
"static_assert failed due to requirement '%0'%select{: %2|}1">;
|
||||
"static assertion failed due to requirement '%0'%select{: %2|}1">;
|
||||
|
||||
def warn_consteval_if_always_true : Warning<
|
||||
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
|
||||
@ -5774,6 +5774,8 @@ def warn_forward_class_redefinition : Warning<
|
||||
def err_redefinition_different_typedef : Error<
|
||||
"%select{typedef|type alias|type alias template}0 "
|
||||
"redefinition with different types%diff{ ($ vs $)|}1,2">;
|
||||
def err_redefinition_different_concept : Error<
|
||||
"redefinition of concept %0 with different template parameters or requirements">;
|
||||
def err_tag_reference_non_tag : Error<
|
||||
"%select{non-struct type|non-class type|non-union type|non-enum "
|
||||
"type|typedef|type alias|template|type alias template|template "
|
||||
|
@ -195,6 +195,7 @@ VALUE_LANGOPT(DoubleSize , 32, 0, "width of double")
|
||||
VALUE_LANGOPT(LongDoubleSize , 32, 0, "width of long double")
|
||||
LANGOPT(PPCIEEELongDouble , 1, 0, "use IEEE 754 quadruple-precision for long double")
|
||||
LANGOPT(EnableAIXExtendedAltivecABI , 1, 0, "__EXTABI__ predefined macro")
|
||||
LANGOPT(EnableAIXQuadwordAtomicsABI , 1, 0, "Use 16-byte atomic lock free semantics")
|
||||
COMPATIBLE_VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
|
||||
COMPATIBLE_VALUE_LANGOPT(PIE , 1, 0, "is pie")
|
||||
LANGOPT(ROPI , 1, 0, "Read-only position independence")
|
||||
|
@ -908,6 +908,9 @@ PRAGMA_ANNOTATION(pragma_fp)
|
||||
// Annotation for the attribute pragma directives - #pragma clang attribute ...
|
||||
PRAGMA_ANNOTATION(pragma_attribute)
|
||||
|
||||
// Annotation for the riscv pragma directives - #pragma clang riscv intrinsic ...
|
||||
PRAGMA_ANNOTATION(pragma_riscv)
|
||||
|
||||
// Annotations for module import translated from #include etc.
|
||||
ANNOTATION(module_include)
|
||||
ANNOTATION(module_begin)
|
||||
|
@ -186,7 +186,7 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
|
||||
// HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is
|
||||
// tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The
|
||||
// policy operand is located at the last position.
|
||||
Policy MaskedPolicy = HasPolicyOperand;
|
||||
Policy MaskedPolicyScheme = HasPolicyOperand;
|
||||
|
||||
// The policy scheme for unmasked intrinsic IR.
|
||||
// It could be NonePolicy, HasPassthruOperand or HasPolicyOperand.
|
||||
@ -194,7 +194,7 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
|
||||
// undef, tail policy is tail agnostic, otherwise policy is tail undisturbed.
|
||||
// HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail
|
||||
// undisturbed.
|
||||
Policy UnMaskedPolicy = NonePolicy;
|
||||
Policy UnMaskedPolicyScheme = NonePolicy;
|
||||
|
||||
// This builtin supports non-masked function overloading api.
|
||||
// All masked operations support overloading api.
|
||||
@ -443,7 +443,7 @@ class RVVMaskOp0Builtin<string prototype> : RVVOp0Builtin<"m", prototype, "c"> {
|
||||
let HasMaskedOffOperand = false;
|
||||
}
|
||||
|
||||
let UnMaskedPolicy = HasPolicyOperand,
|
||||
let UnMaskedPolicyScheme = HasPolicyOperand,
|
||||
HasMaskedOffOperand = false in {
|
||||
multiclass RVVSlideBuiltinSet {
|
||||
defm "" : RVVOutBuiltinSet<NAME, "csilxfd",
|
||||
@ -582,7 +582,7 @@ class IsFloat<string type> {
|
||||
}
|
||||
|
||||
let HasUnMaskedOverloaded = false,
|
||||
MaskedPolicy = NonePolicy in {
|
||||
MaskedPolicyScheme = NonePolicy in {
|
||||
class RVVVLEMaskBuiltin : RVVOutBuiltin<"m", "mPCUe", "c"> {
|
||||
let Name = "vlm_v";
|
||||
let IRName = "vlm";
|
||||
@ -591,7 +591,7 @@ let HasUnMaskedOverloaded = false,
|
||||
}
|
||||
|
||||
let HasUnMaskedOverloaded = false,
|
||||
UnMaskedPolicy = HasPassthruOperand in {
|
||||
UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
multiclass RVVVLEBuiltin<list<string> types> {
|
||||
let Name = NAME # "_v",
|
||||
IRName = "vle",
|
||||
@ -664,7 +664,7 @@ multiclass RVVVLSEBuiltin<list<string> types> {
|
||||
IRName = "vlse",
|
||||
MaskedIRName ="vlse_mask",
|
||||
HasUnMaskedOverloaded = false,
|
||||
UnMaskedPolicy = HasPassthruOperand in {
|
||||
UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
foreach type = types in {
|
||||
def : RVVOutBuiltin<"v", "vPCet", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
@ -675,7 +675,7 @@ multiclass RVVVLSEBuiltin<list<string> types> {
|
||||
}
|
||||
|
||||
multiclass RVVIndexedLoad<string op> {
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
foreach type = TypeList in {
|
||||
foreach eew_list = EEWList[0-2] in {
|
||||
defvar eew = eew_list[0];
|
||||
@ -701,7 +701,7 @@ multiclass RVVIndexedLoad<string op> {
|
||||
}
|
||||
|
||||
let HasMaskedOffOperand = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
// Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl)
|
||||
std::swap(Ops[0], Ops[1]);
|
||||
@ -738,7 +738,7 @@ multiclass RVVVSSEBuiltin<list<string> types> {
|
||||
IRName = "vsse",
|
||||
MaskedIRName = "vsse_mask",
|
||||
HasMaskedOffOperand = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
// Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl)
|
||||
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
|
||||
@ -762,7 +762,7 @@ multiclass RVVVSSEBuiltin<list<string> types> {
|
||||
|
||||
multiclass RVVIndexedStore<string op> {
|
||||
let HasMaskedOffOperand = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
// Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl)
|
||||
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
|
||||
@ -1141,7 +1141,7 @@ multiclass RVVUnitStridedSegStore<string op> {
|
||||
MaskedIRName = op # nf # "_mask",
|
||||
NF = nf,
|
||||
HasMaskedOffOperand = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
// Builtin: (ptr, val0, val1, ..., vl)
|
||||
@ -1187,7 +1187,7 @@ multiclass RVVStridedSegStore<string op> {
|
||||
MaskedIRName = op # nf # "_mask",
|
||||
NF = nf,
|
||||
HasMaskedOffOperand = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
// Builtin: (ptr, stride, val0, val1, ..., vl).
|
||||
@ -1229,7 +1229,7 @@ multiclass RVVIndexedSegStore<string op> {
|
||||
MaskedIRName = op # nf # "_mask",
|
||||
NF = nf,
|
||||
HasMaskedOffOperand = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
// Builtin: (ptr, index, val0, val1, ..., vl)
|
||||
@ -1568,7 +1568,7 @@ def vsetvl_macro: RVVHeader;
|
||||
let HasBuiltinAlias = false,
|
||||
HasVL = false,
|
||||
HasMasked = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
Log2LMUL = [0],
|
||||
ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type
|
||||
{
|
||||
@ -1627,7 +1627,7 @@ defm : RVVIndexedSegStore<"vsoxseg">;
|
||||
|
||||
// 12. Vector Integer Arithmetic Instructions
|
||||
// 12.1. Vector Single-Width Integer Add and Subtract
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vadd : RVVIntBinBuiltinSet;
|
||||
defm vsub : RVVIntBinBuiltinSet;
|
||||
defm vrsub : RVVOutOp1BuiltinSet<"vrsub", "csil",
|
||||
@ -1638,7 +1638,7 @@ defm vneg_v : RVVPseudoUnaryBuiltin<"vrsub", "csil">;
|
||||
|
||||
// 12.2. Vector Widening Integer Add/Subtract
|
||||
// Widening unsigned integer add/subtract, 2*SEW = SEW +/- SEW
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vwaddu : RVVUnsignedWidenBinBuiltinSet;
|
||||
defm vwsubu : RVVUnsignedWidenBinBuiltinSet;
|
||||
// Widening signed integer add/subtract, 2*SEW = SEW +/- SEW
|
||||
@ -1657,7 +1657,7 @@ defm vwcvt_x_x_v : RVVPseudoVWCVTBuiltin<"vwadd", "vwcvt_x", "csi",
|
||||
[["w", "wv"]]>;
|
||||
|
||||
// 12.3. Vector Integer Extension
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
|
||||
def vsext_vf2 : RVVIntExt<"vsext", "w", "wv", "csi">;
|
||||
def vzext_vf2 : RVVIntExt<"vzext", "Uw", "UwUv", "csi">;
|
||||
@ -1673,8 +1673,8 @@ let Log2LMUL = [-3, -2, -1, 0] in {
|
||||
}
|
||||
|
||||
// 12.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions
|
||||
let HasMasked = false, MaskedPolicy = NonePolicy in {
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vadc : RVVCarryinBuiltinSet;
|
||||
defm vsbc : RVVCarryinBuiltinSet;
|
||||
}
|
||||
@ -1685,7 +1685,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy in {
|
||||
}
|
||||
|
||||
// 12.5. Vector Bitwise Logical Instructions
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vand : RVVIntBinBuiltinSet;
|
||||
defm vxor : RVVIntBinBuiltinSet;
|
||||
defm vor : RVVIntBinBuiltinSet;
|
||||
@ -1693,7 +1693,7 @@ defm vor : RVVIntBinBuiltinSet;
|
||||
defm vnot_v : RVVPseudoVNotBuiltin<"vxor", "csil">;
|
||||
|
||||
// 12.6. Vector Single-Width Bit Shift Instructions
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vsll : RVVShiftBuiltinSet;
|
||||
defm vsrl : RVVUnsignedShiftBuiltinSet;
|
||||
defm vsra : RVVSignedShiftBuiltinSet;
|
||||
@ -1707,7 +1707,7 @@ defm vncvt_x_x_w : RVVPseudoVNCVTBuiltin<"vnsrl", "vncvt_x", "csi",
|
||||
["Uv", "UvUw"]]>;
|
||||
|
||||
// 12.8. Vector Integer Comparison Instructions
|
||||
let MaskedPolicy = NonePolicy in {
|
||||
let MaskedPolicyScheme = NonePolicy in {
|
||||
defm vmseq : RVVIntMaskOutBuiltinSet;
|
||||
defm vmsne : RVVIntMaskOutBuiltinSet;
|
||||
defm vmsltu : RVVUnsignedMaskOutBuiltinSet;
|
||||
@ -1721,7 +1721,7 @@ defm vmsge : RVVSignedMaskOutBuiltinSet;
|
||||
}
|
||||
|
||||
// 12.9. Vector Integer Min/Max Instructions
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vminu : RVVUnsignedBinBuiltinSet;
|
||||
defm vmin : RVVSignedBinBuiltinSet;
|
||||
defm vmaxu : RVVUnsignedBinBuiltinSet;
|
||||
@ -1745,7 +1745,7 @@ defm vrem : RVVSignedBinBuiltinSet;
|
||||
}
|
||||
|
||||
// 12.12. Vector Widening Integer Multiply Instructions
|
||||
let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicy = HasPassthruOperand in {
|
||||
let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vwmul : RVVOutOp0Op1BuiltinSet<"vwmul", "csi",
|
||||
[["vv", "w", "wvv"],
|
||||
["vx", "w", "wve"]]>;
|
||||
@ -1758,7 +1758,7 @@ defm vwmulsu : RVVOutOp0Op1BuiltinSet<"vwmulsu", "csi",
|
||||
}
|
||||
|
||||
// 12.13. Vector Single-Width Integer Multiply-Add Instructions
|
||||
let UnMaskedPolicy = HasPolicyOperand in {
|
||||
let UnMaskedPolicyScheme = HasPolicyOperand in {
|
||||
defm vmacc : RVVIntTerBuiltinSet;
|
||||
defm vnmsac : RVVIntTerBuiltinSet;
|
||||
defm vmadd : RVVIntTerBuiltinSet;
|
||||
@ -1783,7 +1783,7 @@ defm vwmaccus : RVVOutOp1Op2BuiltinSet<"vwmaccus", "csi",
|
||||
|
||||
// 12.15. Vector Integer Merge Instructions
|
||||
// C/C++ Operand: (mask, op1, op2, vl), Intrinsic: (op1, op2, mask, vl)
|
||||
let HasMasked = false, MaskedPolicy = NonePolicy,
|
||||
let HasMasked = false, MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
|
||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()};
|
||||
@ -1798,7 +1798,9 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
|
||||
}
|
||||
|
||||
// 12.16. Vector Integer Move Instructions
|
||||
let HasMasked = false, UnMaskedPolicy = HasPassthruOperand, MaskedPolicy = NonePolicy in {
|
||||
let HasMasked = false,
|
||||
UnMaskedPolicyScheme = HasPassthruOperand,
|
||||
MaskedPolicyScheme = NonePolicy in {
|
||||
let OverloadedName = "vmv_v" in {
|
||||
defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csil",
|
||||
[["v", "Uv", "UvUv"]]>;
|
||||
@ -1813,7 +1815,7 @@ let HasMasked = false, UnMaskedPolicy = HasPassthruOperand, MaskedPolicy = NoneP
|
||||
|
||||
// 13. Vector Fixed-Point Arithmetic Instructions
|
||||
// 13.1. Vector Single-Width Saturating Add and Subtract
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vsaddu : RVVUnsignedBinBuiltinSet;
|
||||
defm vsadd : RVVSignedBinBuiltinSet;
|
||||
defm vssubu : RVVUnsignedBinBuiltinSet;
|
||||
@ -1866,7 +1868,7 @@ let Log2LMUL = [-2, -1, 0, 1, 2] in {
|
||||
}
|
||||
|
||||
// 14.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions
|
||||
let UnMaskedPolicy = HasPolicyOperand in {
|
||||
let UnMaskedPolicyScheme = HasPolicyOperand in {
|
||||
defm vfmacc : RVVFloatingTerBuiltinSet;
|
||||
defm vfnmacc : RVVFloatingTerBuiltinSet;
|
||||
defm vfmsac : RVVFloatingTerBuiltinSet;
|
||||
@ -1884,7 +1886,7 @@ defm vfwnmsac : RVVFloatingWidenTerBuiltinSet;
|
||||
}
|
||||
|
||||
// 14.8. Vector Floating-Point Square-Root Instruction
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
def vfsqrt : RVVFloatingUnaryVVBuiltin;
|
||||
|
||||
// 14.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction
|
||||
@ -1906,7 +1908,7 @@ defm vfneg_v : RVVPseudoVFUnaryBuiltin<"vfsgnjn", "xfd">;
|
||||
defm vfabs_v : RVVPseudoVFUnaryBuiltin<"vfsgnjx", "xfd">;
|
||||
|
||||
// 14.13. Vector Floating-Point Compare Instructions
|
||||
let MaskedPolicy = NonePolicy in {
|
||||
let MaskedPolicyScheme = NonePolicy in {
|
||||
defm vmfeq : RVVFloatingMaskOutBuiltinSet;
|
||||
defm vmfne : RVVFloatingMaskOutBuiltinSet;
|
||||
defm vmflt : RVVFloatingMaskOutBuiltinSet;
|
||||
@ -1916,12 +1918,12 @@ defm vmfge : RVVFloatingMaskOutBuiltinSet;
|
||||
}
|
||||
|
||||
// 14.14. Vector Floating-Point Classify Instruction
|
||||
let Name = "vfclass_v", UnMaskedPolicy = HasPassthruOperand in
|
||||
let Name = "vfclass_v", UnMaskedPolicyScheme = HasPassthruOperand in
|
||||
def vfclass : RVVOp0Builtin<"Uv", "Uvv", "xfd">;
|
||||
|
||||
// 14.15. Vector Floating-Point Merge Instructio
|
||||
// C/C++ Operand: (mask, op1, op2, vl), Builtin: (op1, op2, mask, vl)
|
||||
let HasMasked = false, MaskedPolicy = NonePolicy,
|
||||
let HasMasked = false, MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
|
||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()};
|
||||
@ -1935,13 +1937,13 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
|
||||
}
|
||||
|
||||
// 14.16. Vector Floating-Point Move Instruction
|
||||
let HasMasked = false, UnMaskedPolicy = HasPassthruOperand,
|
||||
HasUnMaskedOverloaded = false, MaskedPolicy = NonePolicy in
|
||||
let HasMasked = false, UnMaskedPolicyScheme = HasPassthruOperand,
|
||||
HasUnMaskedOverloaded = false, MaskedPolicyScheme = NonePolicy in
|
||||
defm vfmv_v : RVVOutBuiltinSet<"vfmv_v_f", "xfd",
|
||||
[["f", "v", "ve"]]>;
|
||||
|
||||
// 14.17. Single-Width Floating-Point/Integer Type-Convert Instructions
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
def vfcvt_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_xu">;
|
||||
def vfcvt_x_f_v : RVVConvToSignedBuiltin<"vfcvt_x">;
|
||||
def vfcvt_rtz_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_rtz_xu">;
|
||||
@ -1975,7 +1977,7 @@ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
|
||||
|
||||
// 15. Vector Reduction Operations
|
||||
// 15.1. Vector Single-Width Integer Reduction Instructions
|
||||
let MaskedPolicy = NonePolicy in {
|
||||
let MaskedPolicyScheme = NonePolicy in {
|
||||
defm vredsum : RVVIntReductionBuiltinSet;
|
||||
defm vredmaxu : RVVUnsignedReductionBuiltin;
|
||||
defm vredmax : RVVSignedReductionBuiltin;
|
||||
@ -2021,7 +2023,7 @@ def vmset : RVVMaskNullaryBuiltin;
|
||||
defm vmmv_m : RVVPseudoMaskBuiltin<"vmand", "c">;
|
||||
defm vmnot_m : RVVPseudoMaskBuiltin<"vmnand", "c">;
|
||||
|
||||
let MaskedPolicy = NonePolicy in {
|
||||
let MaskedPolicyScheme = NonePolicy in {
|
||||
// 16.2. Vector count population in mask vcpop.m
|
||||
def vcpop : RVVMaskOp0Builtin<"um">;
|
||||
|
||||
@ -2038,7 +2040,7 @@ def vmsif : RVVMaskUnaryBuiltin;
|
||||
def vmsof : RVVMaskUnaryBuiltin;
|
||||
}
|
||||
|
||||
let UnMaskedPolicy = HasPassthruOperand, HasUnMaskedOverloaded = false in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand, HasUnMaskedOverloaded = false in {
|
||||
// 16.8. Vector Iota Instruction
|
||||
defm viota : RVVOutBuiltinSet<"viota", "csil", [["m", "Uv", "Uvm"]]>;
|
||||
|
||||
@ -2049,7 +2051,7 @@ let UnMaskedPolicy = HasPassthruOperand, HasUnMaskedOverloaded = false in {
|
||||
|
||||
// 17. Vector Permutation Instructions
|
||||
// 17.1. Integer Scalar Move Instructions
|
||||
let HasMasked = false, MaskedPolicy = NonePolicy in {
|
||||
let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
|
||||
let HasVL = false, OverloadedName = "vmv_x" in
|
||||
defm vmv_x : RVVOp0BuiltinSet<"vmv_x_s", "csil",
|
||||
[["s", "ve", "ev"],
|
||||
@ -2061,7 +2063,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy in {
|
||||
}
|
||||
|
||||
// 17.2. Floating-Point Scalar Move Instructions
|
||||
let HasMasked = false, MaskedPolicy = NonePolicy in {
|
||||
let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
|
||||
let HasVL = false, OverloadedName = "vfmv_f" in
|
||||
defm vfmv_f : RVVOp0BuiltinSet<"vfmv_f_s", "xfd",
|
||||
[["s", "ve", "ev"]]>;
|
||||
@ -2078,7 +2080,7 @@ defm vslideup : RVVSlideBuiltinSet;
|
||||
defm vslidedown : RVVSlideBuiltinSet;
|
||||
|
||||
// 17.3.3. Vector Slide1up Instructions
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
let UnMaskedPolicyScheme = HasPassthruOperand in {
|
||||
defm vslide1up : RVVSlideOneBuiltinSet;
|
||||
defm vfslide1up : RVVFloatingBinVFBuiltinSet;
|
||||
|
||||
@ -2104,7 +2106,7 @@ defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csil",
|
||||
}
|
||||
|
||||
// 17.5. Vector Compress Instruction
|
||||
let HasMasked = false, MaskedPolicy = NonePolicy,
|
||||
let HasMasked = false, MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
|
||||
IntrinsicTypes = {ResultType, Ops[3]->getType()};
|
||||
@ -2119,7 +2121,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
|
||||
|
||||
// Miscellaneous
|
||||
let HasMasked = false, HasVL = false, IRName = "" in {
|
||||
let Name = "vreinterpret_v", MaskedPolicy = NonePolicy,
|
||||
let Name = "vreinterpret_v", MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
return Builder.CreateBitCast(Ops[0], ResultType);
|
||||
}] in {
|
||||
@ -2141,7 +2143,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
|
||||
}
|
||||
}
|
||||
|
||||
let Name = "vundefined", HasUnMaskedOverloaded = false, MaskedPolicy = NonePolicy,
|
||||
let Name = "vundefined", HasUnMaskedOverloaded = false,
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
return llvm::UndefValue::get(ResultType);
|
||||
}] in {
|
||||
@ -2151,7 +2154,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
|
||||
|
||||
// LMUL truncation
|
||||
// C/C++ Operand: VecTy, IR Operand: VecTy, Index
|
||||
let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc", MaskedPolicy = NonePolicy,
|
||||
let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc",
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{ {
|
||||
ID = Intrinsic::vector_extract;
|
||||
IntrinsicTypes = {ResultType, Ops[0]->getType()};
|
||||
@ -2169,7 +2173,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
|
||||
|
||||
// LMUL extension
|
||||
// C/C++ Operand: SubVecTy, IR Operand: VecTy, SubVecTy, Index
|
||||
let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext", MaskedPolicy = NonePolicy,
|
||||
let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext",
|
||||
MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
ID = Intrinsic::vector_insert;
|
||||
IntrinsicTypes = {ResultType, Ops[0]->getType()};
|
||||
@ -2187,7 +2192,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
|
||||
}
|
||||
}
|
||||
|
||||
let Name = "vget_v", MaskedPolicy = NonePolicy,
|
||||
let Name = "vget_v", MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
ID = Intrinsic::vector_extract;
|
||||
@ -2211,7 +2216,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
|
||||
}
|
||||
}
|
||||
|
||||
let Name = "vset_v", Log2LMUL = [0, 1, 2], MaskedPolicy = NonePolicy,
|
||||
let Name = "vset_v", Log2LMUL = [0, 1, 2], MaskedPolicyScheme = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
ID = Intrinsic::vector_insert;
|
||||
|
@ -14,12 +14,17 @@
|
||||
#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace llvm {
|
||||
class Constant;
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class StringRef;
|
||||
|
||||
namespace vfs {
|
||||
class FileSystem;
|
||||
}
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -98,10 +103,11 @@ class CodeGenerator : public ASTConsumer {
|
||||
/// the allocated CodeGenerator instance.
|
||||
CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
|
||||
llvm::StringRef ModuleName,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &HeaderSearchOpts,
|
||||
const PreprocessorOptions &PreprocessorOpts,
|
||||
const CodeGenOptions &CGO,
|
||||
llvm::LLVMContext& C,
|
||||
llvm::LLVMContext &C,
|
||||
CoverageSourceInfo *CoverageInfo = nullptr);
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -44,9 +44,7 @@ typedef SmallVector<InputInfo, 4> InputInfoList;
|
||||
|
||||
class Command;
|
||||
class Compilation;
|
||||
class JobList;
|
||||
class JobAction;
|
||||
class SanitizerArgs;
|
||||
class ToolChain;
|
||||
|
||||
/// Describes the kind of LTO mode selected via -f(no-)?lto(=.*)? options.
|
||||
|
@ -3679,6 +3679,10 @@ def mabi_EQ_vec_extabi : Flag<["-"], "mabi=vec-extabi">, Group<m_Group>, Flags<[
|
||||
MarshallingInfoFlag<LangOpts<"EnableAIXExtendedAltivecABI">>;
|
||||
def mabi_EQ_vec_default : Flag<["-"], "mabi=vec-default">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable the default Altivec ABI on AIX (AIX only). Uses only volatile vector registers.">;
|
||||
def mabi_EQ_quadword_atomics : Flag<["-"], "mabi=quadword-atomics">,
|
||||
Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable quadword atomics ABI on AIX (AIX PPC64 only). Uses lqarx/stqcx. instructions.">,
|
||||
MarshallingInfoFlag<LangOpts<"EnableAIXQuadwordAtomicsABI">>;
|
||||
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
|
||||
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
|
||||
def msecure_plt : Flag<["-"], "msecure-plt">, Group<m_ppc_Features_Group>;
|
||||
|
@ -107,10 +107,10 @@ class DependencyFileGenerator : public DependencyCollector {
|
||||
|
||||
void finishedMainFile(DiagnosticsEngine &Diags) override;
|
||||
|
||||
bool needSystemDependencies() final override { return IncludeSystemHeaders; }
|
||||
bool needSystemDependencies() final { return IncludeSystemHeaders; }
|
||||
|
||||
bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem,
|
||||
bool IsModuleFile, bool IsMissing) final override;
|
||||
bool IsModuleFile, bool IsMissing) final;
|
||||
|
||||
protected:
|
||||
void outputDependencyFile(llvm::raw_ostream &OS);
|
||||
|
@ -49,7 +49,6 @@ void operator delete(void *ptr, clang::PreprocessingRecord &PR,
|
||||
|
||||
namespace clang {
|
||||
|
||||
class FileEntry;
|
||||
class IdentifierInfo;
|
||||
class MacroInfo;
|
||||
class SourceManager;
|
||||
|
@ -67,7 +67,6 @@ namespace clang {
|
||||
class CodeCompletionHandler;
|
||||
class CommentHandler;
|
||||
class DirectoryEntry;
|
||||
class DirectoryLookup;
|
||||
class EmptylineHandler;
|
||||
class ExternalPreprocessorSource;
|
||||
class FileEntry;
|
||||
|
@ -215,6 +215,7 @@ class Parser : public CodeCompletionHandler {
|
||||
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
|
||||
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
|
||||
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
|
||||
std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
|
||||
|
||||
std::unique_ptr<CommentHandler> CommentSemaHandler;
|
||||
|
||||
@ -1043,7 +1044,7 @@ class Parser : public CodeCompletionHandler {
|
||||
/// If the next token is not a semicolon, this emits the specified diagnostic,
|
||||
/// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior
|
||||
/// to the semicolon, consumes that extra token.
|
||||
bool ExpectAndConsumeSemi(unsigned DiagID);
|
||||
bool ExpectAndConsumeSemi(unsigned DiagID , StringRef TokenUsed = "");
|
||||
|
||||
/// The kind of extra semi diagnostic to emit.
|
||||
enum ExtraSemiKind {
|
||||
|
@ -795,6 +795,10 @@ class Sema;
|
||||
/// This candidate was not viable because its associated constraints were
|
||||
/// not satisfied.
|
||||
ovl_fail_constraints_not_satisfied,
|
||||
|
||||
/// This candidate was not viable because it has internal linkage and is
|
||||
/// from a different module unit than the use.
|
||||
ovl_fail_module_mismatched,
|
||||
};
|
||||
|
||||
/// A list of implicit conversion sequences for the arguments of an
|
||||
|
@ -0,0 +1,36 @@
|
||||
//===- RISCVIntrinsicManager.h - RISC-V Intrinsic Handler -------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the RISCVIntrinsicManager, which handles RISC-V vector
|
||||
// intrinsic functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H
|
||||
#define LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H
|
||||
|
||||
namespace clang {
|
||||
class Sema;
|
||||
class LookupResult;
|
||||
class IdentifierInfo;
|
||||
class Preprocessor;
|
||||
|
||||
namespace sema {
|
||||
class RISCVIntrinsicManager {
|
||||
public:
|
||||
virtual ~RISCVIntrinsicManager() = default;
|
||||
|
||||
// Create RISC-V intrinsic and insert into symbol table and return true if
|
||||
// found, otherwise return false.
|
||||
virtual bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
|
||||
Preprocessor &PP) = 0;
|
||||
};
|
||||
} // end namespace sema
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -210,9 +210,19 @@ class Scope {
|
||||
/// Used to determine if errors occurred in this scope.
|
||||
DiagnosticErrorTrap ErrorTrap;
|
||||
|
||||
/// A lattice consisting of undefined, a single NRVO candidate variable in
|
||||
/// this scope, or over-defined. The bit is true when over-defined.
|
||||
llvm::PointerIntPair<VarDecl *, 1, bool> NRVO;
|
||||
/// A single NRVO candidate variable in this scope.
|
||||
/// There are three possible values:
|
||||
/// 1) pointer to VarDecl that denotes NRVO candidate itself.
|
||||
/// 2) nullptr value means that NRVO is not allowed in this scope
|
||||
/// (e.g. return a function parameter).
|
||||
/// 3) None value means that there is no NRVO candidate in this scope
|
||||
/// (i.e. there are no return statements in this scope).
|
||||
Optional<VarDecl *> NRVO;
|
||||
|
||||
/// Represents return slots for NRVO candidates in the current scope.
|
||||
/// If a variable is present in this set, it means that a return slot is
|
||||
/// available for this variable in the current scope.
|
||||
llvm::SmallPtrSet<VarDecl *, 8> ReturnSlots;
|
||||
|
||||
void setFlags(Scope *Parent, unsigned F);
|
||||
|
||||
@ -304,6 +314,10 @@ class Scope {
|
||||
bool decl_empty() const { return DeclsInScope.empty(); }
|
||||
|
||||
void AddDecl(Decl *D) {
|
||||
if (auto *VD = dyn_cast<VarDecl>(D))
|
||||
if (!isa<ParmVarDecl>(VD))
|
||||
ReturnSlots.insert(VD);
|
||||
|
||||
DeclsInScope.insert(D);
|
||||
}
|
||||
|
||||
@ -527,23 +541,9 @@ class Scope {
|
||||
UsingDirectives.end());
|
||||
}
|
||||
|
||||
void addNRVOCandidate(VarDecl *VD) {
|
||||
if (NRVO.getInt())
|
||||
return;
|
||||
if (NRVO.getPointer() == nullptr) {
|
||||
NRVO.setPointer(VD);
|
||||
return;
|
||||
}
|
||||
if (NRVO.getPointer() != VD)
|
||||
setNoNRVO();
|
||||
}
|
||||
void updateNRVOCandidate(VarDecl *VD);
|
||||
|
||||
void setNoNRVO() {
|
||||
NRVO.setInt(true);
|
||||
NRVO.setPointer(nullptr);
|
||||
}
|
||||
|
||||
void mergeNRVOIntoParent();
|
||||
void applyNRVO();
|
||||
|
||||
/// Init - This is used by the parser to implement scope caching.
|
||||
void Init(Scope *parent, unsigned flags);
|
||||
|
@ -226,6 +226,7 @@ namespace sema {
|
||||
class FunctionScopeInfo;
|
||||
class LambdaScopeInfo;
|
||||
class PossiblyUnreachableDiag;
|
||||
class RISCVIntrinsicManager;
|
||||
class SemaPPCallbacks;
|
||||
class TemplateDeductionInfo;
|
||||
}
|
||||
@ -1587,7 +1588,12 @@ class Sema final {
|
||||
/// assignment.
|
||||
llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments;
|
||||
|
||||
/// Indicate RISC-V vector builtin functions enabled or not.
|
||||
bool DeclareRISCVVBuiltins = false;
|
||||
|
||||
private:
|
||||
std::unique_ptr<sema::RISCVIntrinsicManager> RVIntrinsicManager;
|
||||
|
||||
Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
|
||||
|
||||
bool WarnedDarwinSDKInfoMissing = false;
|
||||
@ -8260,6 +8266,9 @@ class Sema final {
|
||||
Scope *S, MultiTemplateParamsArg TemplateParameterLists,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr);
|
||||
|
||||
void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
|
||||
bool &AddToScope);
|
||||
|
||||
RequiresExprBodyDecl *
|
||||
ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
|
||||
ArrayRef<ParmVarDecl *> LocalParameters,
|
||||
@ -12170,7 +12179,8 @@ class Sema final {
|
||||
// For simple assignment, pass both expressions and a null converted type.
|
||||
// For compound assignment, pass both expressions and the converted type.
|
||||
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
|
||||
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
|
||||
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType,
|
||||
BinaryOperatorKind Opc);
|
||||
|
||||
ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
|
||||
UnaryOperatorKind Opcode, Expr *Op);
|
||||
@ -13586,6 +13596,8 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
|
||||
llvm::StringRef StackSlotLabel,
|
||||
AlignPackInfo Value);
|
||||
|
||||
std::unique_ptr<sema::RISCVIntrinsicManager>
|
||||
CreateRISCVIntrinsicManager(Sema &S);
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
@ -75,6 +75,8 @@ enum class TemplateSubstitutionKind : char {
|
||||
class MultiLevelTemplateArgumentList {
|
||||
/// The template argument list at a certain template depth
|
||||
using ArgList = ArrayRef<TemplateArgument>;
|
||||
using ArgListsIterator = SmallVector<ArgList, 4>::iterator;
|
||||
using ConstArgListsIterator = SmallVector<ArgList, 4>::const_iterator;
|
||||
|
||||
/// The template argument lists, stored from the innermost template
|
||||
/// argument list (first) to the outermost template argument list (last).
|
||||
@ -121,6 +123,12 @@ enum class TemplateSubstitutionKind : char {
|
||||
return TemplateArgumentLists.size();
|
||||
}
|
||||
|
||||
// Determine the number of substituted args at 'Depth'.
|
||||
unsigned getNumSubsitutedArgs(unsigned Depth) const {
|
||||
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
|
||||
return TemplateArgumentLists[getNumLevels() - Depth - 1].size();
|
||||
}
|
||||
|
||||
unsigned getNumRetainedOuterLevels() const {
|
||||
return NumRetainedOuterLevels;
|
||||
}
|
||||
@ -158,6 +166,14 @@ enum class TemplateSubstitutionKind : char {
|
||||
return !(*this)(Depth, Index).isNull();
|
||||
}
|
||||
|
||||
bool isAnyArgInstantiationDependent() const {
|
||||
for (ArgList List : TemplateArgumentLists)
|
||||
for (const TemplateArgument &TA : List)
|
||||
if (TA.isInstantiationDependent())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Clear out a specific template argument.
|
||||
void setArgument(unsigned Depth, unsigned Index,
|
||||
TemplateArgument Arg) {
|
||||
@ -183,6 +199,14 @@ enum class TemplateSubstitutionKind : char {
|
||||
TemplateArgumentLists.push_back(Args);
|
||||
}
|
||||
|
||||
/// Replaces the current 'innermost' level with the provided argument list.
|
||||
/// This is useful for type deduction cases where we need to get the entire
|
||||
/// list from the AST, but then add the deduced innermost list.
|
||||
void replaceInnermostTemplateArguments(ArgList Args) {
|
||||
assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?");
|
||||
TemplateArgumentLists[0] = Args;
|
||||
}
|
||||
|
||||
/// Add an outermost level that we are not substituting. We have no
|
||||
/// arguments at this level, and do not remove it from the depth of inner
|
||||
/// template parameters that we instantiate.
|
||||
@ -197,6 +221,16 @@ enum class TemplateSubstitutionKind : char {
|
||||
const ArgList &getInnermost() const {
|
||||
return TemplateArgumentLists.front();
|
||||
}
|
||||
/// Retrieve the outermost template argument list.
|
||||
const ArgList &getOutermost() const {
|
||||
return TemplateArgumentLists.back();
|
||||
}
|
||||
ArgListsIterator begin() { return TemplateArgumentLists.begin(); }
|
||||
ConstArgListsIterator begin() const {
|
||||
return TemplateArgumentLists.begin();
|
||||
}
|
||||
ArgListsIterator end() { return TemplateArgumentLists.end(); }
|
||||
ConstArgListsIterator end() const { return TemplateArgumentLists.end(); }
|
||||
};
|
||||
|
||||
/// The context in which partial ordering of function templates occurs.
|
||||
|
@ -703,6 +703,10 @@ class ASTWriter : public ASTDeserializationListener,
|
||||
bool hasChain() const { return Chain; }
|
||||
ASTReader *getChain() const { return Chain; }
|
||||
|
||||
bool isWritingNamedModules() const {
|
||||
return WritingModule && WritingModule->isModulePurview();
|
||||
}
|
||||
|
||||
private:
|
||||
// ASTDeserializationListener implementation
|
||||
void ReaderInitialized(ASTReader *Reader) override;
|
||||
|
@ -731,7 +731,7 @@ class NoStateChangeFuncVisitor : public BugReporterVisitor {
|
||||
|
||||
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
|
||||
BugReporterContext &BR,
|
||||
PathSensitiveBugReport &R) override final;
|
||||
PathSensitiveBugReport &R) final;
|
||||
};
|
||||
|
||||
} // namespace ento
|
||||
|
@ -622,6 +622,11 @@ class ExprEngine {
|
||||
getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// Retreives the size of the array in the pending ArrayInitLoopExpr.
|
||||
static Optional<unsigned> getPendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// By looking at a certain item that may be potentially part of an object's
|
||||
/// ConstructionContext, retrieve such object's location. A particular
|
||||
/// statement can be transparently passed as \p Item in most cases.
|
||||
@ -816,7 +821,9 @@ class ExprEngine {
|
||||
|
||||
/// Checks whether our policies allow us to inline a non-POD type array
|
||||
/// construction.
|
||||
bool shouldInlineArrayConstruction(const ArrayType *Type);
|
||||
bool shouldInlineArrayConstruction(const ProgramStateRef State,
|
||||
const CXXConstructExpr *CE,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// Checks whether we construct an array of non-POD type, and decides if the
|
||||
/// constructor should be inkoved once again.
|
||||
@ -916,6 +923,16 @@ class ExprEngine {
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// Sets the size of the array in a pending ArrayInitLoopExpr.
|
||||
static ProgramStateRef setPendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx,
|
||||
unsigned Idx);
|
||||
|
||||
static ProgramStateRef removePendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// Store the location of a C++ object corresponding to a statement
|
||||
/// until the statement is actually encountered. For example, if a DeclStmt
|
||||
/// has CXXConstructExpr as its initializer, the object would be considered
|
||||
|
@ -55,8 +55,6 @@ template <typename T> struct ProgramStateTrait {
|
||||
}
|
||||
};
|
||||
|
||||
class RangeSet;
|
||||
|
||||
/// \class ProgramState
|
||||
/// ProgramState - This class encapsulates:
|
||||
///
|
||||
|
@ -40,7 +40,6 @@ class LabelDecl;
|
||||
|
||||
namespace ento {
|
||||
|
||||
class BasicValueFactory;
|
||||
class CompoundValData;
|
||||
class LazyCompoundValData;
|
||||
class MemRegion;
|
||||
|
@ -18,6 +18,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
} // end namespace llvm
|
||||
|
||||
namespace clang {
|
||||
namespace RISCV {
|
||||
|
||||
@ -104,12 +108,14 @@ struct PrototypeDescriptor {
|
||||
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
|
||||
|
||||
bool operator!=(const PrototypeDescriptor &PD) const {
|
||||
return PD.PT != PT || PD.VTM != VTM || PD.TM != TM;
|
||||
return !(*this == PD);
|
||||
}
|
||||
bool operator>(const PrototypeDescriptor &PD) const {
|
||||
return !(PD.PT <= PT && PD.VTM <= VTM && PD.TM <= TM);
|
||||
bool operator==(const PrototypeDescriptor &PD) const {
|
||||
return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
|
||||
}
|
||||
bool operator<(const PrototypeDescriptor &PD) const {
|
||||
return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
|
||||
}
|
||||
|
||||
static const PrototypeDescriptor Mask;
|
||||
static const PrototypeDescriptor Vector;
|
||||
static const PrototypeDescriptor VL;
|
||||
@ -224,8 +230,12 @@ class RVVType {
|
||||
bool isFloat(unsigned Width) const {
|
||||
return isFloat() && ElementBitwidth == Width;
|
||||
}
|
||||
|
||||
bool isConstant() const { return IsConstant; }
|
||||
bool isPointer() const { return IsPointer; }
|
||||
unsigned getElementBitwidth() const { return ElementBitwidth; }
|
||||
|
||||
ScalarTypeKind getScalarType() const { return ScalarType; }
|
||||
VScaleVal getScale() const { return Scale; }
|
||||
|
||||
private:
|
||||
// Verify RVV vector type and set Valid.
|
||||
@ -263,18 +273,6 @@ class RVVType {
|
||||
PrototypeDescriptor Proto);
|
||||
};
|
||||
|
||||
using RISCVPredefinedMacroT = uint8_t;
|
||||
|
||||
enum RISCVPredefinedMacro : RISCVPredefinedMacroT {
|
||||
Basic = 0,
|
||||
V = 1 << 1,
|
||||
Zvfh = 1 << 2,
|
||||
RV64 = 1 << 3,
|
||||
VectorMaxELen64 = 1 << 4,
|
||||
VectorMaxELenFp32 = 1 << 5,
|
||||
VectorMaxELenFp64 = 1 << 6,
|
||||
};
|
||||
|
||||
enum PolicyScheme : uint8_t {
|
||||
SchemeNone,
|
||||
HasPassthruOperand,
|
||||
@ -302,7 +300,6 @@ class RVVIntrinsic {
|
||||
// The types we use to obtain the specific LLVM intrinsic. They are index of
|
||||
// InputTypes. -1 means the return type.
|
||||
std::vector<int64_t> IntrinsicTypes;
|
||||
RISCVPredefinedMacroT RISCVPredefinedMacros = 0;
|
||||
unsigned NF = 1;
|
||||
|
||||
public:
|
||||
@ -333,9 +330,6 @@ class RVVIntrinsic {
|
||||
llvm::StringRef getIRName() const { return IRName; }
|
||||
llvm::StringRef getManualCodegen() const { return ManualCodegen; }
|
||||
PolicyScheme getPolicyScheme() const { return Scheme; }
|
||||
RISCVPredefinedMacroT getRISCVPredefinedMacros() const {
|
||||
return RISCVPredefinedMacros;
|
||||
}
|
||||
unsigned getNF() const { return NF; }
|
||||
const std::vector<int64_t> &getIntrinsicTypes() const {
|
||||
return IntrinsicTypes;
|
||||
@ -347,8 +341,72 @@ class RVVIntrinsic {
|
||||
static std::string
|
||||
getSuffixStr(BasicType Type, int Log2LMUL,
|
||||
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
|
||||
|
||||
static llvm::SmallVector<PrototypeDescriptor>
|
||||
computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
|
||||
bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
|
||||
unsigned NF);
|
||||
};
|
||||
|
||||
// RVVRequire should be sync'ed with target features, but only
|
||||
// required features used in riscv_vector.td.
|
||||
enum RVVRequire : uint8_t {
|
||||
RVV_REQ_None = 0,
|
||||
RVV_REQ_RV64 = 1 << 0,
|
||||
RVV_REQ_FullMultiply = 1 << 1,
|
||||
|
||||
LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply)
|
||||
};
|
||||
|
||||
// Raw RVV intrinsic info, used to expand later.
|
||||
// This struct is highly compact for minimized code size.
|
||||
struct RVVIntrinsicRecord {
|
||||
// Intrinsic name, e.g. vadd_vv
|
||||
const char *Name;
|
||||
|
||||
// Overloaded intrinsic name, could be empty if it can be computed from Name.
|
||||
// e.g. vadd
|
||||
const char *OverloadedName;
|
||||
|
||||
// Prototype for this intrinsic, index of RVVSignatureTable.
|
||||
uint16_t PrototypeIndex;
|
||||
|
||||
// Suffix of intrinsic name, index of RVVSignatureTable.
|
||||
uint16_t SuffixIndex;
|
||||
|
||||
// Suffix of overloaded intrinsic name, index of RVVSignatureTable.
|
||||
uint16_t OverloadedSuffixIndex;
|
||||
|
||||
// Length of the prototype.
|
||||
uint8_t PrototypeLength;
|
||||
|
||||
// Length of intrinsic name suffix.
|
||||
uint8_t SuffixLength;
|
||||
|
||||
// Length of overloaded intrinsic suffix.
|
||||
uint8_t OverloadedSuffixSize;
|
||||
|
||||
// Required target features for this intrinsic.
|
||||
uint8_t RequiredExtensions;
|
||||
|
||||
// Supported type, mask of BasicType.
|
||||
uint8_t TypeRangeMask;
|
||||
|
||||
// Supported LMUL.
|
||||
uint8_t Log2LMULMask;
|
||||
|
||||
// Number of fields, greater than 1 if it's segment load/store.
|
||||
uint8_t NF;
|
||||
|
||||
bool HasMasked : 1;
|
||||
bool HasVL : 1;
|
||||
bool HasMaskedOffOperand : 1;
|
||||
};
|
||||
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||
const RVVIntrinsicRecord &RVVInstrRecord);
|
||||
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
} // end namespace RISCV
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -98,7 +98,7 @@ class OptionRequirement : public RefactoringOptionsRequirement {
|
||||
OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {}
|
||||
|
||||
ArrayRef<std::shared_ptr<RefactoringOption>>
|
||||
getRefactoringOptions() const final override {
|
||||
getRefactoringOptions() const final {
|
||||
return Opt;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ using RefactoringActionRules =
|
||||
class SourceChangeRefactoringRule : public RefactoringActionRuleBase {
|
||||
public:
|
||||
void invoke(RefactoringResultConsumer &Consumer,
|
||||
RefactoringRuleContext &Context) final override {
|
||||
RefactoringRuleContext &Context) final {
|
||||
Expected<AtomicChanges> Changes = createSourceReplacements(Context);
|
||||
if (!Changes)
|
||||
Consumer.handleError(Changes.takeError());
|
||||
@ -74,7 +74,7 @@ class SourceChangeRefactoringRule : public RefactoringActionRuleBase {
|
||||
class FindSymbolOccurrencesRefactoringRule : public RefactoringActionRuleBase {
|
||||
public:
|
||||
void invoke(RefactoringResultConsumer &Consumer,
|
||||
RefactoringRuleContext &Context) final override {
|
||||
RefactoringRuleContext &Context) final {
|
||||
Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(Context);
|
||||
if (!Occurrences)
|
||||
Consumer.handleError(Occurrences.takeError());
|
||||
|
@ -24,7 +24,7 @@ template <typename T,
|
||||
typename = std::enable_if_t<traits::IsValidOptionType<T>::value>>
|
||||
class OptionalRefactoringOption : public RefactoringOption {
|
||||
public:
|
||||
void passToVisitor(RefactoringOptionVisitor &Visitor) final override {
|
||||
void passToVisitor(RefactoringOptionVisitor &Visitor) final {
|
||||
Visitor.visit(*this, Value);
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ class RequiredRefactoringOption : public OptionalRefactoringOption<T> {
|
||||
const ValueType &getValue() const {
|
||||
return *OptionalRefactoringOption<T>::Value;
|
||||
}
|
||||
bool isRequired() const final override { return true; }
|
||||
bool isRequired() const final { return true; }
|
||||
};
|
||||
|
||||
} // end namespace tooling
|
||||
|
@ -12,9 +12,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTImporter.h"
|
||||
#include "clang/AST/ASTImporterSharedState.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTDiagnostic.h"
|
||||
#include "clang/AST/ASTImporterSharedState.h"
|
||||
#include "clang/AST/ASTStructuralEquivalence.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
@ -34,6 +34,7 @@
|
||||
#include "clang/AST/LambdaCapture.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/ParentMapContext.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
@ -58,8 +59,8 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/ScopeExit.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -3219,9 +3220,12 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
|
||||
}
|
||||
|
||||
// Returns true if the given D has a DeclContext up to the TranslationUnitDecl
|
||||
// which is equal to the given DC.
|
||||
// which is equal to the given DC, or D is equal to DC.
|
||||
static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
|
||||
const DeclContext *DCi = D->getDeclContext();
|
||||
const DeclContext *DCi = dyn_cast<DeclContext>(D);
|
||||
if (!DCi)
|
||||
DCi = D->getDeclContext();
|
||||
assert(DCi && "Declaration should have a context");
|
||||
while (DCi != D->getTranslationUnitDecl()) {
|
||||
if (DCi == DC)
|
||||
return true;
|
||||
@ -3230,9 +3234,36 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the statement S has a parent declaration that has a
|
||||
// DeclContext that is inside (or equal to) DC. In a specific use case if DC is
|
||||
// a FunctionDecl, check if statement S resides in the body of the function.
|
||||
static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
|
||||
ParentMapContext &ParentC = DC->getParentASTContext().getParentMapContext();
|
||||
DynTypedNodeList Parents = ParentC.getParents(*S);
|
||||
while (!Parents.empty()) {
|
||||
if (const Decl *PD = Parents.begin()->get<Decl>())
|
||||
return isAncestorDeclContextOf(DC, PD);
|
||||
Parents = ParentC.getParents(*Parents.begin());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
|
||||
if (T.isNull())
|
||||
return false;
|
||||
|
||||
auto CheckTemplateArgument = [FD](const TemplateArgument &Arg) {
|
||||
switch (Arg.getKind()) {
|
||||
case TemplateArgument::Type:
|
||||
return hasTypeDeclaredInsideFunction(Arg.getAsType(), FD);
|
||||
case TemplateArgument::Expression:
|
||||
return isAncestorDeclContextOf(FD, Arg.getAsExpr());
|
||||
default:
|
||||
// FIXME: Handle other argument kinds.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (const auto *RecordT = T->getAs<RecordType>()) {
|
||||
const RecordDecl *RD = RecordT->getDecl();
|
||||
assert(RD);
|
||||
@ -3241,12 +3272,15 @@ static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
|
||||
return true;
|
||||
}
|
||||
if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
|
||||
return llvm::count_if(RDTempl->getTemplateArgs().asArray(),
|
||||
[FD](const TemplateArgument &Arg) {
|
||||
return hasTypeDeclaredInsideFunction(
|
||||
Arg.getAsType(), FD);
|
||||
});
|
||||
if (llvm::count_if(RDTempl->getTemplateArgs().asArray(),
|
||||
CheckTemplateArgument))
|
||||
return true;
|
||||
// Note: It is possible that T can be get as both a RecordType and a
|
||||
// TemplateSpecializationType.
|
||||
}
|
||||
if (const auto *TST = T->getAs<TemplateSpecializationType>())
|
||||
return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -394,7 +394,6 @@ void LinkageComputer::mergeTemplateLV(
|
||||
shouldConsiderTemplateVisibility(fn, specInfo);
|
||||
|
||||
FunctionTemplateDecl *temp = specInfo->getTemplate();
|
||||
|
||||
// Merge information from the template declaration.
|
||||
LinkageInfo tempLV = getLVForDecl(temp, computation);
|
||||
// The linkage of the specialization should be consistent with the
|
||||
@ -468,11 +467,16 @@ void LinkageComputer::mergeTemplateLV(
|
||||
|
||||
// Merge information from the template parameters, but ignore
|
||||
// visibility if we're only considering template arguments.
|
||||
|
||||
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
|
||||
LinkageInfo tempLV =
|
||||
// Merge information from the template declaration.
|
||||
LinkageInfo tempLV = getLVForDecl(temp, computation);
|
||||
// The linkage of the specialization should be consistent with the
|
||||
// template declaration.
|
||||
LV.setLinkage(tempLV.getLinkage());
|
||||
|
||||
LinkageInfo paramsLV =
|
||||
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
|
||||
LV.mergeMaybeWithVisibility(tempLV,
|
||||
LV.mergeMaybeWithVisibility(paramsLV,
|
||||
considerVisibility && !hasExplicitVisibilityAlready(computation));
|
||||
|
||||
// Merge information from the template arguments. We ignore
|
||||
@ -520,7 +524,6 @@ void LinkageComputer::mergeTemplateLV(LinkageInfo &LV,
|
||||
|
||||
// Merge information from the template parameters, but ignore
|
||||
// visibility if we're only considering template arguments.
|
||||
|
||||
VarTemplateDecl *temp = spec->getSpecializedTemplate();
|
||||
LinkageInfo tempLV =
|
||||
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
|
||||
@ -1077,7 +1080,6 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
|
||||
|
||||
// Finally, merge in information from the class.
|
||||
LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
|
||||
|
||||
return LV;
|
||||
}
|
||||
|
||||
|
@ -5269,10 +5269,14 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
|
||||
}
|
||||
}
|
||||
bool Cond;
|
||||
if (IS->isConsteval())
|
||||
if (IS->isConsteval()) {
|
||||
Cond = IS->isNonNegatedConsteval();
|
||||
else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(),
|
||||
Cond))
|
||||
// If we are not in a constant context, if consteval should not evaluate
|
||||
// to true.
|
||||
if (!Info.InConstantContext)
|
||||
Cond = !Cond;
|
||||
} else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(),
|
||||
Cond))
|
||||
return ESR_Failed;
|
||||
|
||||
if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {
|
||||
|
@ -1659,9 +1659,13 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
|
||||
appendInitializer(Block, I);
|
||||
|
||||
if (Init) {
|
||||
// If the initializer is an ArrayInitLoopExpr, we want to extract the
|
||||
// initializer, that's used for each element.
|
||||
const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
|
||||
|
||||
findConstructionContexts(
|
||||
ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
|
||||
Init);
|
||||
AILE ? AILE->getSubExpr() : Init);
|
||||
|
||||
if (HasTemporaries) {
|
||||
// For expression with temporaries go directly to subexpression to omit
|
||||
@ -2928,12 +2932,30 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we bind to a tuple-like type, we iterate over the HoldingVars, and
|
||||
// create a DeclStmt for each of them.
|
||||
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
|
||||
for (auto BD : llvm::reverse(DD->bindings())) {
|
||||
if (auto *VD = BD->getHoldingVar()) {
|
||||
DeclGroupRef DG(VD);
|
||||
DeclStmt *DSNew =
|
||||
new (Context) DeclStmt(DG, VD->getLocation(), GetEndLoc(VD));
|
||||
cfg->addSyntheticDeclStmt(DSNew, DS);
|
||||
Block = VisitDeclSubExpr(DSNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autoCreateBlock();
|
||||
appendStmt(Block, DS);
|
||||
|
||||
// If the initializer is an ArrayInitLoopExpr, we want to extract the
|
||||
// initializer, that's used for each element.
|
||||
const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
|
||||
|
||||
findConstructionContexts(
|
||||
ConstructionContextLayer::create(cfg->getBumpVectorContext(), DS),
|
||||
Init);
|
||||
AILE ? AILE->getSubExpr() : Init);
|
||||
|
||||
// Keep track of the last non-null block, as 'Block' can be nulled out
|
||||
// if the initializer expression is something like a 'while' in a
|
||||
@ -3340,9 +3362,20 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
|
||||
|
||||
CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
|
||||
CFGBlock *LastBlock = VisitNoRecurse(E, asc);
|
||||
|
||||
unsigned Idx = 0;
|
||||
for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
|
||||
et = E->capture_init_end(); it != et; ++it) {
|
||||
et = E->capture_init_end();
|
||||
it != et; ++it, ++Idx) {
|
||||
if (Expr *Init = *it) {
|
||||
// If the initializer is an ArrayInitLoopExpr, we want to extract the
|
||||
// initializer, that's used for each element.
|
||||
const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
|
||||
|
||||
findConstructionContexts(ConstructionContextLayer::create(
|
||||
cfg->getBumpVectorContext(), {E, Idx}),
|
||||
AILE ? AILE->getSubExpr() : Init);
|
||||
|
||||
CFGBlock *Tmp = Visit(Init);
|
||||
if (Tmp)
|
||||
LastBlock = Tmp;
|
||||
@ -5616,6 +5649,12 @@ static void print_construction_context(raw_ostream &OS,
|
||||
Stmts.push_back(TOCC->getConstructorAfterElision());
|
||||
break;
|
||||
}
|
||||
case ConstructionContext::LambdaCaptureKind: {
|
||||
const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
|
||||
Helper.handledStmt(const_cast<LambdaExpr *>(LCC->getLambdaExpr()), OS);
|
||||
OS << "+" << LCC->getIndex();
|
||||
return;
|
||||
}
|
||||
case ConstructionContext::ArgumentKind: {
|
||||
const auto *ACC = cast<ArgumentConstructionContext>(CC);
|
||||
if (const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
|
||||
|
@ -156,6 +156,12 @@ const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
|
||||
return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
|
||||
C, I, BTE);
|
||||
}
|
||||
case ConstructionContextItem::LambdaCaptureKind: {
|
||||
assert(ParentLayer->isLast());
|
||||
const auto *E = cast<LambdaExpr>(ParentItem.getStmt());
|
||||
return create<LambdaCaptureConstructionContext>(C, E,
|
||||
ParentItem.getIndex());
|
||||
}
|
||||
} // switch (ParentItem.getKind())
|
||||
|
||||
llvm_unreachable("Unexpected construction context with destructor!");
|
||||
@ -200,6 +206,11 @@ const ConstructionContext *ConstructionContext::createFromLayers(
|
||||
case ConstructionContextItem::ElidableConstructorKind: {
|
||||
llvm_unreachable("The argument needs to be materialized first!");
|
||||
}
|
||||
case ConstructionContextItem::LambdaCaptureKind: {
|
||||
assert(TopLayer->isLast());
|
||||
const auto *E = cast<LambdaExpr>(TopItem.getStmt());
|
||||
return create<LambdaCaptureConstructionContext>(C, E, TopItem.getIndex());
|
||||
}
|
||||
case ConstructionContextItem::InitializerKind: {
|
||||
assert(TopLayer->isLast());
|
||||
const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();
|
||||
|
@ -455,14 +455,16 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
|
||||
// array is considered modified if the loop-variable is a non-const reference.
|
||||
const auto DeclStmtToNonRefToArray = declStmt(hasSingleDecl(varDecl(hasType(
|
||||
hasUnqualifiedDesugaredType(referenceType(pointee(arrayType())))))));
|
||||
const auto RefToArrayRefToElements = match(
|
||||
findAll(stmt(cxxForRangeStmt(
|
||||
hasLoopVariable(varDecl(hasType(nonConstReferenceType()))
|
||||
.bind(NodeID<Decl>::value)),
|
||||
hasRangeStmt(DeclStmtToNonRefToArray),
|
||||
hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
|
||||
.bind("stmt")),
|
||||
Stm, Context);
|
||||
const auto RefToArrayRefToElements =
|
||||
match(findAll(stmt(cxxForRangeStmt(
|
||||
hasLoopVariable(
|
||||
varDecl(anyOf(hasType(nonConstReferenceType()),
|
||||
hasType(nonConstPointerType())))
|
||||
.bind(NodeID<Decl>::value)),
|
||||
hasRangeStmt(DeclStmtToNonRefToArray),
|
||||
hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
|
||||
.bind("stmt")),
|
||||
Stm, Context);
|
||||
|
||||
if (const auto *BadRangeInitFromArray =
|
||||
selectFirst<Stmt>("stmt", RefToArrayRefToElements))
|
||||
|
@ -113,16 +113,27 @@ BoolValue &DataflowAnalysisContext::getOrCreateNegation(BoolValue &Val) {
|
||||
|
||||
BoolValue &DataflowAnalysisContext::getOrCreateImplication(BoolValue &LHS,
|
||||
BoolValue &RHS) {
|
||||
return &LHS == &RHS ? getBoolLiteralValue(true)
|
||||
: getOrCreateDisjunction(getOrCreateNegation(LHS), RHS);
|
||||
if (&LHS == &RHS)
|
||||
return getBoolLiteralValue(true);
|
||||
|
||||
auto Res = ImplicationVals.try_emplace(std::make_pair(&LHS, &RHS), nullptr);
|
||||
if (Res.second)
|
||||
Res.first->second =
|
||||
&takeOwnership(std::make_unique<ImplicationValue>(LHS, RHS));
|
||||
return *Res.first->second;
|
||||
}
|
||||
|
||||
BoolValue &DataflowAnalysisContext::getOrCreateIff(BoolValue &LHS,
|
||||
BoolValue &RHS) {
|
||||
return &LHS == &RHS
|
||||
? getBoolLiteralValue(true)
|
||||
: getOrCreateConjunction(getOrCreateImplication(LHS, RHS),
|
||||
getOrCreateImplication(RHS, LHS));
|
||||
if (&LHS == &RHS)
|
||||
return getBoolLiteralValue(true);
|
||||
|
||||
auto Res = BiconditionalVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS),
|
||||
nullptr);
|
||||
if (Res.second)
|
||||
Res.first->second =
|
||||
&takeOwnership(std::make_unique<BiconditionalValue>(LHS, RHS));
|
||||
return *Res.first->second;
|
||||
}
|
||||
|
||||
AtomicBoolValue &DataflowAnalysisContext::makeFlowConditionToken() {
|
||||
@ -199,18 +210,18 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
|
||||
if (!Res.second)
|
||||
return;
|
||||
|
||||
auto ConstraintsIT = FlowConditionConstraints.find(&Token);
|
||||
if (ConstraintsIT == FlowConditionConstraints.end()) {
|
||||
auto ConstraintsIt = FlowConditionConstraints.find(&Token);
|
||||
if (ConstraintsIt == FlowConditionConstraints.end()) {
|
||||
Constraints.insert(&Token);
|
||||
} else {
|
||||
// Bind flow condition token via `iff` to its set of constraints:
|
||||
// FC <=> (C1 ^ C2 ^ ...), where Ci are constraints
|
||||
Constraints.insert(&getOrCreateIff(Token, *ConstraintsIT->second));
|
||||
Constraints.insert(&getOrCreateIff(Token, *ConstraintsIt->second));
|
||||
}
|
||||
|
||||
auto DepsIT = FlowConditionDeps.find(&Token);
|
||||
if (DepsIT != FlowConditionDeps.end()) {
|
||||
for (AtomicBoolValue *DepToken : DepsIT->second) {
|
||||
auto DepsIt = FlowConditionDeps.find(&Token);
|
||||
if (DepsIt != FlowConditionDeps.end()) {
|
||||
for (AtomicBoolValue *DepToken : DepsIt->second) {
|
||||
addTransitiveFlowConditionConstraints(*DepToken, Constraints,
|
||||
VisitedTokens);
|
||||
}
|
||||
@ -220,10 +231,10 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
|
||||
BoolValue &DataflowAnalysisContext::substituteBoolValue(
|
||||
BoolValue &Val,
|
||||
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
|
||||
auto IT = SubstitutionsCache.find(&Val);
|
||||
if (IT != SubstitutionsCache.end()) {
|
||||
auto It = SubstitutionsCache.find(&Val);
|
||||
if (It != SubstitutionsCache.end()) {
|
||||
// Return memoized result of substituting this boolean value.
|
||||
return *IT->second;
|
||||
return *It->second;
|
||||
}
|
||||
|
||||
// Handle substitution on the boolean value (and its subvalues), saving the
|
||||
@ -258,6 +269,24 @@ BoolValue &DataflowAnalysisContext::substituteBoolValue(
|
||||
Result = &getOrCreateConjunction(LeftSub, RightSub);
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Implication: {
|
||||
auto &IV = *cast<ImplicationValue>(&Val);
|
||||
auto &LeftSub =
|
||||
substituteBoolValue(IV.getLeftSubValue(), SubstitutionsCache);
|
||||
auto &RightSub =
|
||||
substituteBoolValue(IV.getRightSubValue(), SubstitutionsCache);
|
||||
Result = &getOrCreateImplication(LeftSub, RightSub);
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Biconditional: {
|
||||
auto &BV = *cast<BiconditionalValue>(&Val);
|
||||
auto &LeftSub =
|
||||
substituteBoolValue(BV.getLeftSubValue(), SubstitutionsCache);
|
||||
auto &RightSub =
|
||||
substituteBoolValue(BV.getRightSubValue(), SubstitutionsCache);
|
||||
Result = &getOrCreateIff(LeftSub, RightSub);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unhandled Value Kind");
|
||||
}
|
||||
@ -280,19 +309,19 @@ BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowCondition(
|
||||
BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache(
|
||||
AtomicBoolValue &Token,
|
||||
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
|
||||
auto ConstraintsIT = FlowConditionConstraints.find(&Token);
|
||||
if (ConstraintsIT == FlowConditionConstraints.end()) {
|
||||
auto ConstraintsIt = FlowConditionConstraints.find(&Token);
|
||||
if (ConstraintsIt == FlowConditionConstraints.end()) {
|
||||
return getBoolLiteralValue(true);
|
||||
}
|
||||
auto DepsIT = FlowConditionDeps.find(&Token);
|
||||
if (DepsIT != FlowConditionDeps.end()) {
|
||||
for (AtomicBoolValue *DepToken : DepsIT->second) {
|
||||
auto DepsIt = FlowConditionDeps.find(&Token);
|
||||
if (DepsIt != FlowConditionDeps.end()) {
|
||||
for (AtomicBoolValue *DepToken : DepsIt->second) {
|
||||
auto &NewDep = buildAndSubstituteFlowConditionWithCache(
|
||||
*DepToken, SubstitutionsCache);
|
||||
SubstitutionsCache[DepToken] = &NewDep;
|
||||
}
|
||||
}
|
||||
return substituteBoolValue(*ConstraintsIT->second, SubstitutionsCache);
|
||||
return substituteBoolValue(*ConstraintsIt->second, SubstitutionsCache);
|
||||
}
|
||||
|
||||
void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token) {
|
||||
|
@ -200,6 +200,42 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
|
||||
}
|
||||
}
|
||||
|
||||
Environment Environment::pushCall(const CallExpr *Call) const {
|
||||
Environment Env(*this);
|
||||
|
||||
// FIXME: Currently this only works if the callee is never a method and the
|
||||
// same callee is never analyzed from multiple separate callsites. To
|
||||
// generalize this, we'll need to store a "context" field (probably a stack of
|
||||
// `const CallExpr *`s) in the `Environment`, and then change the
|
||||
// `DataflowAnalysisContext` class to hold a map from contexts to "frames",
|
||||
// where each frame stores its own version of what are currently the
|
||||
// `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields.
|
||||
|
||||
const auto *FuncDecl = Call->getDirectCallee();
|
||||
assert(FuncDecl != nullptr);
|
||||
assert(FuncDecl->getBody() != nullptr);
|
||||
// FIXME: In order to allow the callee to reference globals, we probably need
|
||||
// to call `initGlobalVars` here in some way.
|
||||
|
||||
auto ParamIt = FuncDecl->param_begin();
|
||||
auto ArgIt = Call->arg_begin();
|
||||
auto ArgEnd = Call->arg_end();
|
||||
|
||||
// FIXME: Parameters don't always map to arguments 1:1; examples include
|
||||
// overloaded operators implemented as member functions, and parameter packs.
|
||||
for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) {
|
||||
assert(ParamIt != FuncDecl->param_end());
|
||||
|
||||
const VarDecl *Param = *ParamIt;
|
||||
const Expr *Arg = *ArgIt;
|
||||
auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
|
||||
assert(ArgLoc != nullptr);
|
||||
Env.setStorageLocation(*Param, *ArgLoc);
|
||||
}
|
||||
|
||||
return Env;
|
||||
}
|
||||
|
||||
bool Environment::equivalentTo(const Environment &Other,
|
||||
Environment::ValueModel &Model) const {
|
||||
assert(DACtx == Other.DACtx);
|
||||
@ -352,16 +388,16 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
|
||||
}
|
||||
}
|
||||
|
||||
auto IT = MemberLocToStruct.find(&Loc);
|
||||
if (IT != MemberLocToStruct.end()) {
|
||||
auto It = MemberLocToStruct.find(&Loc);
|
||||
if (It != MemberLocToStruct.end()) {
|
||||
// `Loc` is the location of a struct member so we need to also update the
|
||||
// value of the member in the corresponding `StructValue`.
|
||||
|
||||
assert(IT->second.first != nullptr);
|
||||
StructValue &StructVal = *IT->second.first;
|
||||
assert(It->second.first != nullptr);
|
||||
StructValue &StructVal = *It->second.first;
|
||||
|
||||
assert(IT->second.second != nullptr);
|
||||
const ValueDecl &Member = *IT->second.second;
|
||||
assert(It->second.second != nullptr);
|
||||
const ValueDecl &Member = *It->second.second;
|
||||
|
||||
StructVal.setChild(Member, Val);
|
||||
}
|
||||
|
@ -96,6 +96,20 @@ class DebugStringGenerator {
|
||||
S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1));
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Implication: {
|
||||
auto &IV = cast<ImplicationValue>(B);
|
||||
auto L = debugString(IV.getLeftSubValue(), Depth + 1);
|
||||
auto R = debugString(IV.getRightSubValue(), Depth + 1);
|
||||
S = formatv("(=>\n{0}\n{1})", L, R);
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Biconditional: {
|
||||
auto &BV = cast<BiconditionalValue>(B);
|
||||
auto L = debugString(BV.getLeftSubValue(), Depth + 1);
|
||||
auto R = debugString(BV.getRightSubValue(), Depth + 1);
|
||||
S = formatv("(=\n{0}\n{1})", L, R);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unhandled value kind");
|
||||
}
|
||||
|
@ -20,7 +20,9 @@
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
@ -46,8 +48,9 @@ static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
|
||||
|
||||
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
|
||||
public:
|
||||
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
|
||||
: StmtToEnv(StmtToEnv), Env(Env) {}
|
||||
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
|
||||
TransferOptions Options)
|
||||
: StmtToEnv(StmtToEnv), Env(Env), Options(Options) {}
|
||||
|
||||
void VisitBinaryOperator(const BinaryOperator *S) {
|
||||
const Expr *LHS = S->getLHS();
|
||||
@ -503,6 +506,35 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
|
||||
if (ArgLoc == nullptr)
|
||||
return;
|
||||
Env.setStorageLocation(*S, *ArgLoc);
|
||||
} else if (const FunctionDecl *F = S->getDirectCallee()) {
|
||||
// This case is for context-sensitive analysis, which we only do if we
|
||||
// have the callee body available in the translation unit.
|
||||
if (!Options.ContextSensitive || F->getBody() == nullptr)
|
||||
return;
|
||||
|
||||
auto &ASTCtx = F->getASTContext();
|
||||
|
||||
// FIXME: Cache these CFGs.
|
||||
auto CFCtx = ControlFlowContext::build(F, F->getBody(), &ASTCtx);
|
||||
// FIXME: Handle errors here and below.
|
||||
assert(CFCtx);
|
||||
auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
|
||||
|
||||
auto CalleeEnv = Env.pushCall(S);
|
||||
|
||||
// FIXME: Use the same analysis as the caller for the callee.
|
||||
DataflowAnalysisOptions Options;
|
||||
auto Analysis = NoopAnalysis(ASTCtx, Options);
|
||||
|
||||
auto BlockToOutputState =
|
||||
dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
|
||||
assert(BlockToOutputState);
|
||||
assert(ExitBlock < BlockToOutputState->size());
|
||||
|
||||
auto ExitState = (*BlockToOutputState)[ExitBlock];
|
||||
assert(ExitState);
|
||||
|
||||
Env = ExitState->Env;
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,11 +596,11 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
|
||||
Env.setValue(Loc, *Val);
|
||||
|
||||
if (Type->isStructureOrClassType()) {
|
||||
for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
|
||||
const FieldDecl *Field = std::get<0>(IT);
|
||||
for (auto It : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
|
||||
const FieldDecl *Field = std::get<0>(It);
|
||||
assert(Field != nullptr);
|
||||
|
||||
const Expr *Init = std::get<1>(IT);
|
||||
const Expr *Init = std::get<1>(It);
|
||||
assert(Init != nullptr);
|
||||
|
||||
if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
|
||||
@ -633,10 +665,12 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
|
||||
|
||||
const StmtToEnvMap &StmtToEnv;
|
||||
Environment &Env;
|
||||
TransferOptions Options;
|
||||
};
|
||||
|
||||
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
|
||||
TransferVisitor(StmtToEnv, Env).Visit(&S);
|
||||
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
|
||||
TransferOptions Options) {
|
||||
TransferVisitor(StmtToEnv, Env, Options).Visit(&S);
|
||||
}
|
||||
|
||||
} // namespace dataflow
|
||||
|
@ -47,9 +47,9 @@ class StmtToEnvMapImpl : public StmtToEnvMap {
|
||||
: CFCtx(CFCtx), BlockToState(BlockToState) {}
|
||||
|
||||
const Environment *getEnvironment(const Stmt &S) const override {
|
||||
auto BlockIT = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
|
||||
assert(BlockIT != CFCtx.getStmtToBlock().end());
|
||||
const auto &State = BlockToState[BlockIT->getSecond()->getBlockID()];
|
||||
auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
|
||||
assert(BlockIt != CFCtx.getStmtToBlock().end());
|
||||
const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
|
||||
assert(State);
|
||||
return &State.value().Env;
|
||||
}
|
||||
@ -74,8 +74,9 @@ static int blockIndexInPredecessor(const CFGBlock &Pred,
|
||||
class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
|
||||
public:
|
||||
TerminatorVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
|
||||
int BlockSuccIdx)
|
||||
: StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx) {}
|
||||
int BlockSuccIdx, TransferOptions TransferOpts)
|
||||
: StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx),
|
||||
TransferOpts(TransferOpts) {}
|
||||
|
||||
void VisitIfStmt(const IfStmt *S) {
|
||||
auto *Cond = S->getCond();
|
||||
@ -118,7 +119,7 @@ class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
|
||||
void extendFlowCondition(const Expr &Cond) {
|
||||
// The terminator sub-expression might not be evaluated.
|
||||
if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr)
|
||||
transfer(StmtToEnv, Cond, Env);
|
||||
transfer(StmtToEnv, Cond, Env, TransferOpts);
|
||||
|
||||
// FIXME: The flow condition must be an r-value, so `SkipPast::None` should
|
||||
// suffice.
|
||||
@ -150,6 +151,7 @@ class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
|
||||
const StmtToEnvMap &StmtToEnv;
|
||||
Environment &Env;
|
||||
int BlockSuccIdx;
|
||||
TransferOptions TransferOpts;
|
||||
};
|
||||
|
||||
/// Computes the input state for a given basic block by joining the output
|
||||
@ -217,7 +219,8 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
|
||||
if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
|
||||
const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates);
|
||||
TerminatorVisitor(StmtToEnv, PredState.Env,
|
||||
blockIndexInPredecessor(*Pred, Block))
|
||||
blockIndexInPredecessor(*Pred, Block),
|
||||
Analysis.builtinTransferOptions())
|
||||
.Visit(PredTerminatorStmt);
|
||||
}
|
||||
}
|
||||
@ -253,7 +256,8 @@ static void transferCFGStmt(
|
||||
assert(S != nullptr);
|
||||
|
||||
if (Analysis.applyBuiltinTransfer())
|
||||
transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env);
|
||||
transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env,
|
||||
Analysis.builtinTransferOptions());
|
||||
Analysis.transferTypeErased(S, State.Lattice, State.Env);
|
||||
|
||||
if (HandleTransferredStmt != nullptr)
|
||||
|
@ -221,6 +221,18 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
|
||||
UnprocessedSubVals.push(&N->getSubVal());
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Implication: {
|
||||
auto *I = cast<ImplicationValue>(Val);
|
||||
UnprocessedSubVals.push(&I->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&I->getRightSubValue());
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Biconditional: {
|
||||
auto *B = cast<BiconditionalValue>(Val);
|
||||
UnprocessedSubVals.push(&B->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&B->getRightSubValue());
|
||||
break;
|
||||
}
|
||||
case Value::Kind::AtomicBool: {
|
||||
Atomics[Var] = cast<AtomicBoolValue>(Val);
|
||||
break;
|
||||
@ -263,30 +275,52 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
|
||||
const Variable LeftSubVar = GetVar(&C->getLeftSubValue());
|
||||
const Variable RightSubVar = GetVar(&C->getRightSubValue());
|
||||
|
||||
// `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
|
||||
// which is already in conjunctive normal form. Below we add each of the
|
||||
// conjuncts of the latter expression to the result.
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar));
|
||||
Formula.addClause(negLit(Var), posLit(RightSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
|
||||
if (LeftSubVar == RightSubVar) {
|
||||
// `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is
|
||||
// already in conjunctive normal form. Below we add each of the
|
||||
// conjuncts of the latter expression to the result.
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar));
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&C->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&C->getRightSubValue());
|
||||
// Visit a sub-value of `Val` (pick any, they are identical).
|
||||
UnprocessedSubVals.push(&C->getLeftSubValue());
|
||||
} else {
|
||||
// `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
|
||||
// which is already in conjunctive normal form. Below we add each of the
|
||||
// conjuncts of the latter expression to the result.
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar));
|
||||
Formula.addClause(negLit(Var), posLit(RightSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&C->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&C->getRightSubValue());
|
||||
}
|
||||
} else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
|
||||
const Variable LeftSubVar = GetVar(&D->getLeftSubValue());
|
||||
const Variable RightSubVar = GetVar(&D->getRightSubValue());
|
||||
|
||||
// `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
|
||||
// which is already in conjunctive normal form. Below we add each of the
|
||||
// conjuncts of the latter expression to the result.
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(RightSubVar));
|
||||
if (LeftSubVar == RightSubVar) {
|
||||
// `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is
|
||||
// already in conjunctive normal form. Below we add each of the
|
||||
// conjuncts of the latter expression to the result.
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar));
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&D->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&D->getRightSubValue());
|
||||
// Visit a sub-value of `Val` (pick any, they are identical).
|
||||
UnprocessedSubVals.push(&D->getLeftSubValue());
|
||||
} else {
|
||||
// `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
|
||||
// which is already in conjunctive normal form. Below we add each of the
|
||||
// conjuncts of the latter expression to the result.
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(RightSubVar));
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&D->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&D->getRightSubValue());
|
||||
}
|
||||
} else if (auto *N = dyn_cast<NegationValue>(Val)) {
|
||||
const Variable SubVar = GetVar(&N->getSubVal());
|
||||
|
||||
@ -298,6 +332,46 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&N->getSubVal());
|
||||
} else if (auto *I = dyn_cast<ImplicationValue>(Val)) {
|
||||
const Variable LeftSubVar = GetVar(&I->getLeftSubValue());
|
||||
const Variable RightSubVar = GetVar(&I->getRightSubValue());
|
||||
|
||||
// `X <=> (A => B)` is equivalent to
|
||||
// `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in
|
||||
// conjunctive normal form. Below we add each of the conjuncts of the
|
||||
// latter expression to the result.
|
||||
Formula.addClause(posLit(Var), posLit(LeftSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(RightSubVar));
|
||||
Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&I->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&I->getRightSubValue());
|
||||
} else if (auto *B = dyn_cast<BiconditionalValue>(Val)) {
|
||||
const Variable LeftSubVar = GetVar(&B->getLeftSubValue());
|
||||
const Variable RightSubVar = GetVar(&B->getRightSubValue());
|
||||
|
||||
if (LeftSubVar == RightSubVar) {
|
||||
// `X <=> (A <=> A)` is equvalent to `X` which is already in
|
||||
// conjunctive normal form. Below we add each of the conjuncts of the
|
||||
// latter expression to the result.
|
||||
Formula.addClause(posLit(Var));
|
||||
|
||||
// No need to visit the sub-values of `Val`.
|
||||
} else {
|
||||
// `X <=> (A <=> B)` is equivalent to
|
||||
// `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which is
|
||||
// already in conjunctive normal form. Below we add each of the conjuncts
|
||||
// of the latter expression to the result.
|
||||
Formula.addClause(posLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
|
||||
Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
|
||||
Formula.addClause(negLit(Var), posLit(LeftSubVar), negLit(RightSubVar));
|
||||
Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
UnprocessedSubVals.push(&B->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&B->getRightSubValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,11 @@ bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
|
||||
bool alive = false;
|
||||
for (const BindingDecl *BD : DD->bindings())
|
||||
alive |= liveBindings.contains(BD);
|
||||
|
||||
// Note: the only known case this condition is necessary, is when a bindig
|
||||
// to a tuple-like structure is created. The HoldingVar initializers have a
|
||||
// DeclRefExpr to the DecompositionDecl.
|
||||
alive |= liveDecls.contains(DD);
|
||||
return alive;
|
||||
}
|
||||
return liveDecls.contains(D);
|
||||
@ -343,8 +348,12 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
|
||||
|
||||
if (const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
|
||||
Killed = !BD->getType()->isReferenceType();
|
||||
if (Killed)
|
||||
if (Killed) {
|
||||
if (const auto *HV = BD->getHoldingVar())
|
||||
val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
|
||||
|
||||
val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
|
||||
}
|
||||
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
Killed = writeShouldKill(VD);
|
||||
if (Killed)
|
||||
@ -371,8 +380,12 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
|
||||
const Decl* D = DR->getDecl();
|
||||
bool InAssignment = LV.inAssignment[DR];
|
||||
if (const auto *BD = dyn_cast<BindingDecl>(D)) {
|
||||
if (!InAssignment)
|
||||
if (!InAssignment) {
|
||||
if (const auto *HV = BD->getHoldingVar())
|
||||
val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
|
||||
|
||||
val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
|
||||
}
|
||||
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (!InAssignment && !isAlwaysAlive(VD))
|
||||
val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
|
||||
@ -382,8 +395,16 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
|
||||
void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
|
||||
for (const auto *DI : DS->decls()) {
|
||||
if (const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
|
||||
for (const auto *BD : DD->bindings())
|
||||
for (const auto *BD : DD->bindings()) {
|
||||
if (const auto *HV = BD->getHoldingVar())
|
||||
val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
|
||||
|
||||
val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
|
||||
}
|
||||
|
||||
// When a bindig to a tuple-like structure is created, the HoldingVar
|
||||
// initializers have a DeclRefExpr to the DecompositionDecl.
|
||||
val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
|
||||
} else if (const auto *VD = dyn_cast<VarDecl>(DI)) {
|
||||
if (!isAlwaysAlive(VD))
|
||||
val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
|
||||
|
@ -71,7 +71,7 @@ class LLVM_LIBRARY_VISIBILITY CSKYTargetInfo : public TargetInfo {
|
||||
|
||||
bool isValidCPUName(StringRef Name) const override;
|
||||
|
||||
virtual unsigned getMinGlobalAlign(uint64_t) const override;
|
||||
unsigned getMinGlobalAlign(uint64_t) const override;
|
||||
|
||||
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
|
||||
|
||||
|
@ -849,6 +849,9 @@ void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
|
||||
? &llvm::APFloat::IEEEquad()
|
||||
: &llvm::APFloat::PPCDoubleDouble();
|
||||
Opts.IEEE128 = 1;
|
||||
if (getTriple().isOSAIX() && Opts.EnableAIXQuadwordAtomicsABI &&
|
||||
HasQuadwordAtomics)
|
||||
MaxAtomicInlineWidth = 128;
|
||||
}
|
||||
|
||||
ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
|
||||
|
@ -229,14 +229,14 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
|
||||
bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
|
||||
StringRef Constraint, unsigned Size) const override;
|
||||
|
||||
virtual bool
|
||||
bool
|
||||
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
|
||||
if (CPU == llvm::X86::CK_None || CPU >= llvm::X86::CK_PentiumPro)
|
||||
return true;
|
||||
return TargetInfo::checkCFProtectionReturnSupported(Diags);
|
||||
};
|
||||
|
||||
virtual bool
|
||||
bool
|
||||
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override {
|
||||
if (CPU == llvm::X86::CK_None || CPU >= llvm::X86::CK_PentiumPro)
|
||||
return true;
|
||||
|
@ -127,7 +127,7 @@ namespace CodeGen {
|
||||
public:
|
||||
SwiftABIInfo(CodeGen::CodeGenTypes &cgt) : ABIInfo(cgt) {}
|
||||
|
||||
bool supportsSwift() const final override { return true; }
|
||||
bool supportsSwift() const final { return true; }
|
||||
|
||||
virtual bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> types,
|
||||
bool asReturnValue) const = 0;
|
||||
|
@ -41,6 +41,8 @@ struct CatchTypeInfo;
|
||||
|
||||
/// Implements C++ ABI-specific code generation functions.
|
||||
class CGCXXABI {
|
||||
friend class CodeGenModule;
|
||||
|
||||
protected:
|
||||
CodeGenModule &CGM;
|
||||
std::unique_ptr<MangleContext> MangleCtx;
|
||||
|
@ -4473,17 +4473,22 @@ llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee,
|
||||
// they are nested within.
|
||||
SmallVector<llvm::OperandBundleDef, 1>
|
||||
CodeGenFunction::getBundlesForFunclet(llvm::Value *Callee) {
|
||||
SmallVector<llvm::OperandBundleDef, 1> BundleList;
|
||||
// There is no need for a funclet operand bundle if we aren't inside a
|
||||
// funclet.
|
||||
if (!CurrentFuncletPad)
|
||||
return BundleList;
|
||||
return (SmallVector<llvm::OperandBundleDef, 1>());
|
||||
|
||||
// Skip intrinsics which cannot throw.
|
||||
auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts());
|
||||
if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow())
|
||||
return BundleList;
|
||||
// Skip intrinsics which cannot throw (as long as they don't lower into
|
||||
// regular function calls in the course of IR transformations).
|
||||
if (auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts())) {
|
||||
if (CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow()) {
|
||||
auto IID = CalleeFn->getIntrinsicID();
|
||||
if (!llvm::IntrinsicInst::mayLowerToFunctionCall(IID))
|
||||
return (SmallVector<llvm::OperandBundleDef, 1>());
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<llvm::OperandBundleDef, 1> BundleList;
|
||||
BundleList.emplace_back("funclet", CurrentFuncletPad);
|
||||
return BundleList;
|
||||
}
|
||||
|
@ -2698,15 +2698,21 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
|
||||
// Don't insert type test assumes if we are forcing public
|
||||
// visibility.
|
||||
!CGM.AlwaysHasLTOVisibilityPublic(RD)) {
|
||||
llvm::Metadata *MD =
|
||||
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
|
||||
QualType Ty = QualType(RD->getTypeForDecl(), 0);
|
||||
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(Ty);
|
||||
llvm::Value *TypeId =
|
||||
llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
|
||||
|
||||
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
|
||||
// If we already know that the call has hidden LTO visibility, emit
|
||||
// @llvm.type.test(). Otherwise emit @llvm.public.type.test(), which WPD
|
||||
// will convert to @llvm.type.test() if we assert at link time that we have
|
||||
// whole program visibility.
|
||||
llvm::Intrinsic::ID IID = CGM.HasHiddenLTOVisibility(RD)
|
||||
? llvm::Intrinsic::type_test
|
||||
: llvm::Intrinsic::public_type_test;
|
||||
llvm::Value *TypeTest =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
|
||||
{CastedVTable, TypeId});
|
||||
Builder.CreateCall(CGM.getIntrinsic(IID), {CastedVTable, TypeId});
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
|
||||
}
|
||||
}
|
||||
|
@ -491,9 +491,11 @@ StringRef CGDebugInfo::getCurrentDirname() {
|
||||
|
||||
if (!CWDName.empty())
|
||||
return CWDName;
|
||||
SmallString<256> CWD;
|
||||
llvm::sys::fs::current_path(CWD);
|
||||
return CWDName = internString(CWD);
|
||||
llvm::ErrorOr<std::string> CWD =
|
||||
CGM.getFileSystem()->getCurrentWorkingDirectory();
|
||||
if (!CWD)
|
||||
return StringRef();
|
||||
return CWDName = internString(*CWD);
|
||||
}
|
||||
|
||||
void CGDebugInfo::CreateCompileUnit() {
|
||||
|
@ -2837,11 +2837,13 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
|
||||
// Enter the continuation block and emit a phi if required.
|
||||
CGF.EmitBlock(continueBB);
|
||||
if (msgRet.isScalar()) {
|
||||
llvm::Value *v = msgRet.getScalarVal();
|
||||
llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
|
||||
phi->addIncoming(v, nonNilPathBB);
|
||||
phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB);
|
||||
msgRet = RValue::get(phi);
|
||||
// If the return type is void, do nothing
|
||||
if (llvm::Value *v = msgRet.getScalarVal()) {
|
||||
llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
|
||||
phi->addIncoming(v, nonNilPathBB);
|
||||
phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB);
|
||||
msgRet = RValue::get(phi);
|
||||
}
|
||||
} else if (msgRet.isAggregate()) {
|
||||
// Aggregate zeroing is handled in nilCleanupBB when it's required.
|
||||
} else /* isComplex() */ {
|
||||
|
@ -186,17 +186,16 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime {
|
||||
|
||||
/// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
|
||||
/// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
|
||||
virtual void emitProcBindClause(CodeGenFunction &CGF,
|
||||
llvm::omp::ProcBindKind ProcBind,
|
||||
SourceLocation Loc) override;
|
||||
void emitProcBindClause(CodeGenFunction &CGF,
|
||||
llvm::omp::ProcBindKind ProcBind,
|
||||
SourceLocation Loc) override;
|
||||
|
||||
/// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
|
||||
/// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
|
||||
/// clause.
|
||||
/// \param NumThreads An integer value of threads.
|
||||
virtual void emitNumThreadsClause(CodeGenFunction &CGF,
|
||||
llvm::Value *NumThreads,
|
||||
SourceLocation Loc) override;
|
||||
void emitNumThreadsClause(CodeGenFunction &CGF, llvm::Value *NumThreads,
|
||||
SourceLocation Loc) override;
|
||||
|
||||
/// This function ought to emit, in the general case, a call to
|
||||
// the openmp runtime kmpc_push_num_teams. In NVPTX backend it is not needed
|
||||
@ -300,12 +299,12 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime {
|
||||
/// SimpleReduction Emit reduction operation only. Used for omp simd
|
||||
/// directive on the host.
|
||||
/// ReductionKind The kind of reduction to perform.
|
||||
virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||
ArrayRef<const Expr *> Privates,
|
||||
ArrayRef<const Expr *> LHSExprs,
|
||||
ArrayRef<const Expr *> RHSExprs,
|
||||
ArrayRef<const Expr *> ReductionOps,
|
||||
ReductionOptionsTy Options) override;
|
||||
void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
|
||||
ArrayRef<const Expr *> Privates,
|
||||
ArrayRef<const Expr *> LHSExprs,
|
||||
ArrayRef<const Expr *> RHSExprs,
|
||||
ArrayRef<const Expr *> ReductionOps,
|
||||
ReductionOptionsTy Options) override;
|
||||
|
||||
/// Returns specified OpenMP runtime function for the current OpenMP
|
||||
/// implementation. Specialized for the NVPTX device.
|
||||
|
@ -146,6 +146,7 @@ namespace clang {
|
||||
|
||||
public:
|
||||
BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &HeaderSearchOpts,
|
||||
const PreprocessorOptions &PPOpts,
|
||||
const CodeGenOptions &CodeGenOpts,
|
||||
@ -159,8 +160,8 @@ namespace clang {
|
||||
AsmOutStream(std::move(OS)), Context(nullptr),
|
||||
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
|
||||
LLVMIRGenerationRefCount(0),
|
||||
Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
|
||||
CodeGenOpts, C, CoverageInfo)),
|
||||
Gen(CreateLLVMCodeGen(Diags, InFile, std::move(FS), HeaderSearchOpts,
|
||||
PPOpts, CodeGenOpts, C, CoverageInfo)),
|
||||
LinkModules(std::move(LinkModules)) {
|
||||
TimerIsEnabled = CodeGenOpts.TimePasses;
|
||||
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
|
||||
@ -171,6 +172,7 @@ namespace clang {
|
||||
// to use the clang diagnostic handler for IR input files. It avoids
|
||||
// initializing the OS field.
|
||||
BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &HeaderSearchOpts,
|
||||
const PreprocessorOptions &PPOpts,
|
||||
const CodeGenOptions &CodeGenOpts,
|
||||
@ -183,8 +185,8 @@ namespace clang {
|
||||
Context(nullptr),
|
||||
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
|
||||
LLVMIRGenerationRefCount(0),
|
||||
Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts,
|
||||
CodeGenOpts, C, CoverageInfo)),
|
||||
Gen(CreateLLVMCodeGen(Diags, "", std::move(FS), HeaderSearchOpts,
|
||||
PPOpts, CodeGenOpts, C, CoverageInfo)),
|
||||
LinkModules(std::move(LinkModules)), CurLinkModule(Module) {
|
||||
TimerIsEnabled = CodeGenOpts.TimePasses;
|
||||
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
|
||||
@ -1052,10 +1054,10 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
|
||||
CI.getPreprocessor());
|
||||
|
||||
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
|
||||
BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
|
||||
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
|
||||
CI.getLangOpts(), std::string(InFile), std::move(LinkModules),
|
||||
std::move(OS), *VMContext, CoverageInfo));
|
||||
BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
|
||||
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
|
||||
CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile),
|
||||
std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
|
||||
BEConsumer = Result.get();
|
||||
|
||||
// Enable generating macro debug info only when debug info is not disabled and
|
||||
@ -1185,9 +1187,10 @@ void CodeGenAction::ExecuteAction() {
|
||||
|
||||
// Set clang diagnostic handler. To do this we need to create a fake
|
||||
// BackendConsumer.
|
||||
BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
|
||||
CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
|
||||
CI.getTargetOpts(), CI.getLangOpts(), TheModule.get(),
|
||||
BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
|
||||
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
|
||||
CI.getCodeGenOpts(), CI.getTargetOpts(),
|
||||
CI.getLangOpts(), TheModule.get(),
|
||||
std::move(LinkModules), *VMContext, nullptr);
|
||||
// PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
|
||||
// true here because the valued names are needed for reading textual IR.
|
||||
|
@ -96,16 +96,18 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
|
||||
llvm_unreachable("invalid C++ ABI kind");
|
||||
}
|
||||
|
||||
CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
|
||||
CodeGenModule::CodeGenModule(ASTContext &C,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &HSO,
|
||||
const PreprocessorOptions &PPO,
|
||||
const CodeGenOptions &CGO, llvm::Module &M,
|
||||
DiagnosticsEngine &diags,
|
||||
CoverageSourceInfo *CoverageInfo)
|
||||
: Context(C), LangOpts(C.getLangOpts()), HeaderSearchOpts(HSO),
|
||||
PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
|
||||
Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
|
||||
VMContext(M.getContext()), Types(*this), VTables(*this),
|
||||
SanitizerMD(new SanitizerMetadata(*this)) {
|
||||
: Context(C), LangOpts(C.getLangOpts()), FS(std::move(FS)),
|
||||
HeaderSearchOpts(HSO), PreprocessorOpts(PPO), CodeGenOpts(CGO),
|
||||
TheModule(M), Diags(diags), Target(C.getTargetInfo()),
|
||||
ABI(createCXXABI(*this)), VMContext(M.getContext()), Types(*this),
|
||||
VTables(*this), SanitizerMD(new SanitizerMetadata(*this)) {
|
||||
|
||||
// Initialize the type cache.
|
||||
llvm::LLVMContext &LLVMContext = M.getContext();
|
||||
@ -795,18 +797,17 @@ void CodeGenModule::Release() {
|
||||
Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
|
||||
Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 ||
|
||||
Arch == llvm::Triple::aarch64_be) {
|
||||
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
|
||||
LangOpts.BranchTargetEnforcement);
|
||||
|
||||
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address",
|
||||
LangOpts.hasSignReturnAddress());
|
||||
|
||||
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
|
||||
LangOpts.isSignReturnAddressScopeAll());
|
||||
|
||||
getModule().addModuleFlag(llvm::Module::Min,
|
||||
"sign-return-address-with-bkey",
|
||||
!LangOpts.isSignReturnAddressWithAKey());
|
||||
if (LangOpts.BranchTargetEnforcement)
|
||||
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
|
||||
1);
|
||||
if (LangOpts.hasSignReturnAddress())
|
||||
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
|
||||
if (LangOpts.isSignReturnAddressScopeAll())
|
||||
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
|
||||
1);
|
||||
if (!LangOpts.isSignReturnAddressWithAKey())
|
||||
getModule().addModuleFlag(llvm::Module::Min,
|
||||
"sign-return-address-with-bkey", 1);
|
||||
}
|
||||
|
||||
if (!CodeGenOpts.MemoryProfileOutput.empty()) {
|
||||
@ -7000,4 +7001,6 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) {
|
||||
"Still have (unmerged) EmittedDeferredDecls deferred decls");
|
||||
|
||||
NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls);
|
||||
|
||||
NewBuilder->ABI->MangleCtx = std::move(ABI->MangleCtx);
|
||||
}
|
||||
|
@ -47,6 +47,10 @@ class DataLayout;
|
||||
class FunctionType;
|
||||
class LLVMContext;
|
||||
class IndexedInstrProfReader;
|
||||
|
||||
namespace vfs {
|
||||
class FileSystem;
|
||||
}
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -293,6 +297,7 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
private:
|
||||
ASTContext &Context;
|
||||
const LangOptions &LangOpts;
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
|
||||
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
|
||||
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
|
||||
const CodeGenOptions &CodeGenOpts;
|
||||
@ -584,7 +589,8 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
llvm::DenseMap<const llvm::Constant *, llvm::GlobalVariable *> RTTIProxyMap;
|
||||
|
||||
public:
|
||||
CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
|
||||
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &headersearchopts,
|
||||
const PreprocessorOptions &ppopts,
|
||||
const CodeGenOptions &CodeGenOpts, llvm::Module &M,
|
||||
DiagnosticsEngine &Diags,
|
||||
@ -712,6 +718,9 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
|
||||
ASTContext &getContext() const { return Context; }
|
||||
const LangOptions &getLangOpts() const { return LangOpts; }
|
||||
const IntrusiveRefCntPtr<llvm::vfs::FileSystem> &getFileSystem() const {
|
||||
return FS;
|
||||
}
|
||||
const HeaderSearchOptions &getHeaderSearchOpts()
|
||||
const { return HeaderSearchOpts; }
|
||||
const PreprocessorOptions &getPreprocessorOpts()
|
||||
|
@ -707,8 +707,12 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
|
||||
if (ShouldEmitCFICheck || ShouldEmitWPDInfo) {
|
||||
llvm::Value *VFPAddr =
|
||||
Builder.CreateGEP(CGF.Int8Ty, VTable, VTableOffset);
|
||||
llvm::Intrinsic::ID IID = CGM.HasHiddenLTOVisibility(RD)
|
||||
? llvm::Intrinsic::type_test
|
||||
: llvm::Intrinsic::public_type_test;
|
||||
|
||||
CheckResult = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::type_test),
|
||||
CGM.getIntrinsic(IID),
|
||||
{Builder.CreateBitCast(VFPAddr, CGF.Int8PtrTy), TypeId});
|
||||
}
|
||||
|
||||
|
@ -782,7 +782,7 @@ class MicrosoftCXXABI : public CGCXXABI {
|
||||
LoadVTablePtr(CodeGenFunction &CGF, Address This,
|
||||
const CXXRecordDecl *RD) override;
|
||||
|
||||
virtual bool
|
||||
bool
|
||||
isPermittedToBeHomogeneousAggregate(const CXXRecordDecl *RD) const override;
|
||||
|
||||
private:
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include <memory>
|
||||
|
||||
using namespace clang;
|
||||
@ -32,6 +33,7 @@ namespace {
|
||||
class CodeGeneratorImpl : public CodeGenerator {
|
||||
DiagnosticsEngine &Diags;
|
||||
ASTContext *Ctx;
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
|
||||
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
|
||||
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
|
||||
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
|
||||
@ -74,11 +76,12 @@ namespace {
|
||||
|
||||
public:
|
||||
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &HSO,
|
||||
const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
|
||||
llvm::LLVMContext &C,
|
||||
CoverageSourceInfo *CoverageInfo = nullptr)
|
||||
: Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
|
||||
: Diags(diags), Ctx(nullptr), FS(std::move(FS)), HeaderSearchOpts(HSO),
|
||||
PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
|
||||
CoverageInfo(CoverageInfo),
|
||||
M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
|
||||
@ -158,7 +161,7 @@ namespace {
|
||||
if (auto TVSDKVersion =
|
||||
Ctx->getTargetInfo().getDarwinTargetVariantSDKVersion())
|
||||
M->setDarwinTargetVariantSDKVersion(*TVSDKVersion);
|
||||
Builder.reset(new CodeGen::CodeGenModule(Context, HeaderSearchOpts,
|
||||
Builder.reset(new CodeGen::CodeGenModule(Context, FS, HeaderSearchOpts,
|
||||
PreprocessorOpts, CodeGenOpts,
|
||||
*M, Diags, CoverageInfo));
|
||||
|
||||
@ -356,11 +359,14 @@ llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
|
||||
return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
|
||||
}
|
||||
|
||||
CodeGenerator *clang::CreateLLVMCodeGen(
|
||||
DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
|
||||
const HeaderSearchOptions &HeaderSearchOpts,
|
||||
const PreprocessorOptions &PreprocessorOpts, const CodeGenOptions &CGO,
|
||||
llvm::LLVMContext &C, CoverageSourceInfo *CoverageInfo) {
|
||||
return new CodeGeneratorImpl(Diags, ModuleName, HeaderSearchOpts,
|
||||
PreprocessorOpts, CGO, C, CoverageInfo);
|
||||
CodeGenerator *
|
||||
clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
const HeaderSearchOptions &HeaderSearchOpts,
|
||||
const PreprocessorOptions &PreprocessorOpts,
|
||||
const CodeGenOptions &CGO, llvm::LLVMContext &C,
|
||||
CoverageSourceInfo *CoverageInfo) {
|
||||
return new CodeGeneratorImpl(Diags, ModuleName, std::move(FS),
|
||||
HeaderSearchOpts, PreprocessorOpts, CGO, C,
|
||||
CoverageInfo);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ class PCHContainerGenerator : public ASTConsumer {
|
||||
const std::string OutputFileName;
|
||||
ASTContext *Ctx;
|
||||
ModuleMap &MMap;
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
|
||||
const HeaderSearchOptions &HeaderSearchOpts;
|
||||
const PreprocessorOptions &PreprocessorOpts;
|
||||
CodeGenOptions CodeGenOpts;
|
||||
@ -144,6 +145,7 @@ class PCHContainerGenerator : public ASTConsumer {
|
||||
: Diags(CI.getDiagnostics()), MainFileName(MainFileName),
|
||||
OutputFileName(OutputFileName), Ctx(nullptr),
|
||||
MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()),
|
||||
FS(&CI.getVirtualFileSystem()),
|
||||
HeaderSearchOpts(CI.getHeaderSearchOpts()),
|
||||
PreprocessorOpts(CI.getPreprocessorOpts()),
|
||||
TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
|
||||
@ -173,7 +175,7 @@ class PCHContainerGenerator : public ASTConsumer {
|
||||
M.reset(new llvm::Module(MainFileName, *VMContext));
|
||||
M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
|
||||
Builder.reset(new CodeGen::CodeGenModule(
|
||||
*Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
|
||||
*Ctx, FS, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
|
||||
|
||||
// Prepare CGDebugInfo to emit debug info for a clang module.
|
||||
auto *DI = Builder->getModuleDebugInfo();
|
||||
|
@ -20,7 +20,6 @@
|
||||
namespace llvm {
|
||||
class GlobalVariable;
|
||||
class Instruction;
|
||||
class MDNode;
|
||||
} // namespace llvm
|
||||
|
||||
namespace clang {
|
||||
|
@ -548,6 +548,11 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
||||
if (CPUArg)
|
||||
checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures,
|
||||
Triple, CPUArgFPUID);
|
||||
|
||||
// TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
|
||||
// longstanding behavior.
|
||||
(void)Args.getLastArg(options::OPT_mtune_EQ);
|
||||
|
||||
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
|
||||
unsigned FPUID = llvm::ARM::FK_INVALID;
|
||||
const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
|
||||
|
@ -107,6 +107,10 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
|
||||
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
||||
const ArgList &Args,
|
||||
std::vector<StringRef> &Features) {
|
||||
// TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
|
||||
// longstanding behavior.
|
||||
(void)Args.getLastArg(options::OPT_mtune_EQ);
|
||||
|
||||
if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe)
|
||||
Features.push_back("+spe");
|
||||
|
||||
|
@ -5112,6 +5112,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back("-mabi=vec-default");
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_quadword_atomics)) {
|
||||
if (!Triple.isOSAIX() || Triple.isPPC32())
|
||||
D.Diag(diag::err_drv_unsupported_opt_for_target)
|
||||
<< A->getSpelling() << RawTriple.str();
|
||||
CmdArgs.push_back("-mabi=quadword-atomics");
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) {
|
||||
// Emit the unsupported option error until the Clang's library integration
|
||||
// support for 128-bit long double is available for AIX.
|
||||
|
@ -489,12 +489,14 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
|
||||
Res |= SanitizerKind::PointerCompare;
|
||||
Res |= SanitizerKind::PointerSubtract;
|
||||
Res |= SanitizerKind::Vptr;
|
||||
if (IsX86_64 || IsMIPS64) {
|
||||
if (IsAArch64 || IsX86_64 || IsMIPS64) {
|
||||
Res |= SanitizerKind::Leak;
|
||||
Res |= SanitizerKind::Thread;
|
||||
}
|
||||
if (IsX86 || IsX86_64) {
|
||||
Res |= SanitizerKind::Function;
|
||||
}
|
||||
if (IsAArch64 || IsX86 || IsX86_64) {
|
||||
Res |= SanitizerKind::SafeStack;
|
||||
Res |= SanitizerKind::Fuzzer;
|
||||
Res |= SanitizerKind::FuzzerNoLink;
|
||||
@ -502,8 +504,6 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
|
||||
if (IsAArch64 || IsX86_64) {
|
||||
Res |= SanitizerKind::KernelAddress;
|
||||
Res |= SanitizerKind::KernelMemory;
|
||||
}
|
||||
if (IsX86_64) {
|
||||
Res |= SanitizerKind::Memory;
|
||||
}
|
||||
return Res;
|
||||
|
@ -84,11 +84,11 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
|
||||
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
||||
auto I = ExpansionToArgMap.find(ExpLoc);
|
||||
if (I != ExpansionToArgMap.end() &&
|
||||
find_if(I->second, [&](const MacroArgUse &U) {
|
||||
llvm::any_of(I->second, [&](const MacroArgUse &U) {
|
||||
return ArgUse.Identifier == U.Identifier &&
|
||||
std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
|
||||
std::tie(U.ImmediateExpansionLoc, U.UseLoc);
|
||||
}) != I->second.end()) {
|
||||
})) {
|
||||
// Trying to write in a macro argument input that has already been
|
||||
// written by a previous commit for another expansion of the same macro
|
||||
// argument name. For example:
|
||||
|
@ -239,55 +239,6 @@ bool FormatTokenLexer::tryMergeCSharpStringLiteral() {
|
||||
if (Tokens.size() < 2)
|
||||
return false;
|
||||
|
||||
// Interpolated strings could contain { } with " characters inside.
|
||||
// $"{x ?? "null"}"
|
||||
// should not be split into $"{x ?? ", null, "}" but should treated as a
|
||||
// single string-literal.
|
||||
//
|
||||
// We opt not to try and format expressions inside {} within a C#
|
||||
// interpolated string. Formatting expressions within an interpolated string
|
||||
// would require similar work as that done for JavaScript template strings
|
||||
// in `handleTemplateStrings()`.
|
||||
auto &CSharpInterpolatedString = *(Tokens.end() - 2);
|
||||
if (CSharpInterpolatedString->getType() == TT_CSharpStringLiteral &&
|
||||
(CSharpInterpolatedString->TokenText.startswith(R"($")") ||
|
||||
CSharpInterpolatedString->TokenText.startswith(R"($@")"))) {
|
||||
int UnmatchedOpeningBraceCount = 0;
|
||||
|
||||
auto TokenTextSize = CSharpInterpolatedString->TokenText.size();
|
||||
for (size_t Index = 0; Index < TokenTextSize; ++Index) {
|
||||
char C = CSharpInterpolatedString->TokenText[Index];
|
||||
if (C == '{') {
|
||||
// "{{" inside an interpolated string is an escaped '{' so skip it.
|
||||
if (Index + 1 < TokenTextSize &&
|
||||
CSharpInterpolatedString->TokenText[Index + 1] == '{') {
|
||||
++Index;
|
||||
continue;
|
||||
}
|
||||
++UnmatchedOpeningBraceCount;
|
||||
} else if (C == '}') {
|
||||
// "}}" inside an interpolated string is an escaped '}' so skip it.
|
||||
if (Index + 1 < TokenTextSize &&
|
||||
CSharpInterpolatedString->TokenText[Index + 1] == '}') {
|
||||
++Index;
|
||||
continue;
|
||||
}
|
||||
--UnmatchedOpeningBraceCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (UnmatchedOpeningBraceCount > 0) {
|
||||
auto &NextToken = *(Tokens.end() - 1);
|
||||
CSharpInterpolatedString->TokenText =
|
||||
StringRef(CSharpInterpolatedString->TokenText.begin(),
|
||||
NextToken->TokenText.end() -
|
||||
CSharpInterpolatedString->TokenText.begin());
|
||||
CSharpInterpolatedString->ColumnWidth += NextToken->ColumnWidth;
|
||||
Tokens.erase(Tokens.end() - 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for @"aaaaaa" or $"aaaaaa".
|
||||
auto &String = *(Tokens.end() - 1);
|
||||
if (!String->is(tok::string_literal))
|
||||
@ -571,45 +522,105 @@ void FormatTokenLexer::tryParseJSRegexLiteral() {
|
||||
resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
|
||||
}
|
||||
|
||||
void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
|
||||
FormatToken *CSharpStringLiteral = Tokens.back();
|
||||
|
||||
if (CSharpStringLiteral->getType() != TT_CSharpStringLiteral)
|
||||
return;
|
||||
|
||||
// Deal with multiline strings.
|
||||
if (!(CSharpStringLiteral->TokenText.startswith(R"(@")") ||
|
||||
CSharpStringLiteral->TokenText.startswith(R"($@")"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *StrBegin =
|
||||
Lex->getBufferLocation() - CSharpStringLiteral->TokenText.size();
|
||||
const char *Offset = StrBegin;
|
||||
if (CSharpStringLiteral->TokenText.startswith(R"(@")"))
|
||||
Offset += 2;
|
||||
else // CSharpStringLiteral->TokenText.startswith(R"($@")")
|
||||
Offset += 3;
|
||||
static auto lexCSharpString(const char *Begin, const char *End, bool Verbatim,
|
||||
bool Interpolated) {
|
||||
auto Repeated = [&Begin, End]() {
|
||||
return Begin + 1 < End && Begin[1] == Begin[0];
|
||||
};
|
||||
|
||||
// Look for a terminating '"' in the current file buffer.
|
||||
// Make no effort to format code within an interpolated or verbatim string.
|
||||
for (; Offset != Lex->getBuffer().end(); ++Offset) {
|
||||
if (Offset[0] == '"') {
|
||||
// "" within a verbatim string is an escaped double quote: skip it.
|
||||
if (Offset + 1 < Lex->getBuffer().end() && Offset[1] == '"')
|
||||
++Offset;
|
||||
else
|
||||
//
|
||||
// Interpolated strings could contain { } with " characters inside.
|
||||
// $"{x ?? "null"}"
|
||||
// should not be split into $"{x ?? ", null, "}" but should be treated as a
|
||||
// single string-literal.
|
||||
//
|
||||
// We opt not to try and format expressions inside {} within a C#
|
||||
// interpolated string. Formatting expressions within an interpolated string
|
||||
// would require similar work as that done for JavaScript template strings
|
||||
// in `handleTemplateStrings()`.
|
||||
for (int UnmatchedOpeningBraceCount = 0; Begin < End; ++Begin) {
|
||||
switch (*Begin) {
|
||||
case '\\':
|
||||
if (!Verbatim)
|
||||
++Begin;
|
||||
break;
|
||||
case '{':
|
||||
if (Interpolated) {
|
||||
// {{ inside an interpolated string is escaped, so skip it.
|
||||
if (Repeated())
|
||||
++Begin;
|
||||
else
|
||||
++UnmatchedOpeningBraceCount;
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
if (Interpolated) {
|
||||
// }} inside an interpolated string is escaped, so skip it.
|
||||
if (Repeated())
|
||||
++Begin;
|
||||
else if (UnmatchedOpeningBraceCount > 0)
|
||||
--UnmatchedOpeningBraceCount;
|
||||
else
|
||||
return End;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (UnmatchedOpeningBraceCount > 0)
|
||||
break;
|
||||
// "" within a verbatim string is an escaped double quote: skip it.
|
||||
if (Verbatim && Repeated()) {
|
||||
++Begin;
|
||||
break;
|
||||
}
|
||||
return Begin;
|
||||
}
|
||||
}
|
||||
|
||||
return End;
|
||||
}
|
||||
|
||||
void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
|
||||
FormatToken *CSharpStringLiteral = Tokens.back();
|
||||
|
||||
if (CSharpStringLiteral->isNot(TT_CSharpStringLiteral))
|
||||
return;
|
||||
|
||||
auto &TokenText = CSharpStringLiteral->TokenText;
|
||||
|
||||
bool Verbatim = false;
|
||||
bool Interpolated = false;
|
||||
if (TokenText.startswith(R"($@")")) {
|
||||
Verbatim = true;
|
||||
Interpolated = true;
|
||||
} else if (TokenText.startswith(R"(@")")) {
|
||||
Verbatim = true;
|
||||
} else if (TokenText.startswith(R"($")")) {
|
||||
Interpolated = true;
|
||||
}
|
||||
|
||||
// Deal with multiline strings.
|
||||
if (!Verbatim && !Interpolated)
|
||||
return;
|
||||
|
||||
const char *StrBegin = Lex->getBufferLocation() - TokenText.size();
|
||||
const char *Offset = StrBegin;
|
||||
if (Verbatim && Interpolated)
|
||||
Offset += 3;
|
||||
else
|
||||
Offset += 2;
|
||||
|
||||
const auto End = Lex->getBuffer().end();
|
||||
Offset = lexCSharpString(Offset, End, Verbatim, Interpolated);
|
||||
|
||||
// Make no attempt to format code properly if a verbatim string is
|
||||
// unterminated.
|
||||
if (Offset == Lex->getBuffer().end())
|
||||
if (Offset >= End)
|
||||
return;
|
||||
|
||||
StringRef LiteralText(StrBegin, Offset - StrBegin + 1);
|
||||
CSharpStringLiteral->TokenText = LiteralText;
|
||||
TokenText = LiteralText;
|
||||
|
||||
// Adjust width for potentially multiline string literals.
|
||||
size_t FirstBreak = LiteralText.find('\n');
|
||||
@ -628,10 +639,8 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
|
||||
StartColumn, Style.TabWidth, Encoding);
|
||||
}
|
||||
|
||||
SourceLocation loc = Offset < Lex->getBuffer().end()
|
||||
? Lex->getSourceLocation(Offset + 1)
|
||||
: SourceMgr.getLocForEndOfFile(ID);
|
||||
resetLexer(SourceMgr.getFileOffset(loc));
|
||||
assert(Offset < End);
|
||||
resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset + 1)));
|
||||
}
|
||||
|
||||
void FormatTokenLexer::handleTemplateStrings() {
|
||||
|
@ -1926,6 +1926,12 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
|
||||
Opts.EnableAIXExtendedAltivecABI = O.matches(OPT_mabi_EQ_vec_extabi);
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(OPT_mabi_EQ_quadword_atomics)) {
|
||||
if (!T.isOSAIX() || T.isPPC32())
|
||||
Diags.Report(diag::err_drv_unsupported_opt_for_target)
|
||||
<< A->getSpelling() << T.str();
|
||||
}
|
||||
|
||||
bool NeedLocTracking = false;
|
||||
|
||||
if (!Opts.OptRecordFile.empty())
|
||||
|
@ -17,7 +17,8 @@
|
||||
* explicitly disallows `stdatomic.h` in the C mode via an `#error`. Fallback
|
||||
* to the clang resource header until that is fully supported.
|
||||
*/
|
||||
#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>) && !defined(_MSC_VER)
|
||||
#if __STDC_HOSTED__ && \
|
||||
__has_include_next(<stdatomic.h>) && !(defined(_MSC_VER) && !defined(__cplusplus))
|
||||
# include_next <stdatomic.h>
|
||||
#else
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
namespace llvm {
|
||||
class Error;
|
||||
class Module;
|
||||
namespace orc {
|
||||
class LLJIT;
|
||||
class ThreadSafeContext;
|
||||
|
@ -6344,23 +6344,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
||||
diag::err_expected_member_name_or_semi)
|
||||
<< (D.getDeclSpec().isEmpty() ? SourceRange()
|
||||
: D.getDeclSpec().getSourceRange());
|
||||
} else if (getLangOpts().CPlusPlus) {
|
||||
if (Tok.isOneOf(tok::period, tok::arrow))
|
||||
Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
|
||||
else {
|
||||
SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
|
||||
if (Tok.isAtStartOfLine() && Loc.isValid())
|
||||
Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
|
||||
<< getLangOpts().CPlusPlus;
|
||||
else
|
||||
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
|
||||
diag::err_expected_unqualified_id)
|
||||
<< getLangOpts().CPlusPlus;
|
||||
}
|
||||
} else {
|
||||
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
|
||||
diag::err_expected_either)
|
||||
<< tok::identifier << tok::l_paren;
|
||||
if (Tok.getKind() == tok::TokenKind::kw_while) {
|
||||
Diag(Tok, diag::err_while_loop_outside_of_a_function);
|
||||
} else if (getLangOpts().CPlusPlus) {
|
||||
if (Tok.isOneOf(tok::period, tok::arrow))
|
||||
Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
|
||||
else {
|
||||
SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
|
||||
if (Tok.isAtStartOfLine() && Loc.isValid())
|
||||
Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
|
||||
<< getLangOpts().CPlusPlus;
|
||||
else
|
||||
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
|
||||
diag::err_expected_unqualified_id)
|
||||
<< getLangOpts().CPlusPlus;
|
||||
}
|
||||
} else {
|
||||
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
|
||||
diag::err_expected_either)
|
||||
<< tok::identifier << tok::l_paren;
|
||||
}
|
||||
}
|
||||
D.SetIdentifier(nullptr, Tok.getLocation());
|
||||
D.setInvalidType(true);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -350,6 +350,16 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler {
|
||||
Token &FirstToken) override;
|
||||
};
|
||||
|
||||
struct PragmaRISCVHandler : public PragmaHandler {
|
||||
PragmaRISCVHandler(Sema &Actions)
|
||||
: PragmaHandler("riscv"), Actions(Actions) {}
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||
Token &FirstToken) override;
|
||||
|
||||
private:
|
||||
Sema &Actions;
|
||||
};
|
||||
|
||||
void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
|
||||
for (auto &T : Toks)
|
||||
T.setFlag(clang::Token::IsReinjected);
|
||||
@ -493,6 +503,11 @@ void Parser::initializePragmaHandlers() {
|
||||
|
||||
MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
|
||||
PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
|
||||
|
||||
if (getTargetInfo().getTriple().isRISCV()) {
|
||||
RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
|
||||
PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::resetPragmaHandlers() {
|
||||
@ -617,6 +632,11 @@ void Parser::resetPragmaHandlers() {
|
||||
|
||||
PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
|
||||
MaxTokensTotalPragmaHandler.reset();
|
||||
|
||||
if (getTargetInfo().getTriple().isRISCV()) {
|
||||
PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
|
||||
RISCVPragmaHandler.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the annotation token produced for #pragma unused(...)
|
||||
@ -3929,3 +3949,35 @@ void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP,
|
||||
|
||||
PP.overrideMaxTokens(MaxTokens, Loc);
|
||||
}
|
||||
|
||||
// Handle '#pragma clang riscv intrinsic vector'.
|
||||
void PragmaRISCVHandler::HandlePragma(Preprocessor &PP,
|
||||
PragmaIntroducer Introducer,
|
||||
Token &FirstToken) {
|
||||
Token Tok;
|
||||
PP.Lex(Tok);
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
|
||||
if (!II || !II->isStr("intrinsic")) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'intrinsic'";
|
||||
return;
|
||||
}
|
||||
|
||||
PP.Lex(Tok);
|
||||
II = Tok.getIdentifierInfo();
|
||||
if (!II || !II->isStr("vector")) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'vector'";
|
||||
return;
|
||||
}
|
||||
|
||||
PP.Lex(Tok);
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
<< "clang riscv intrinsic";
|
||||
return;
|
||||
}
|
||||
|
||||
Actions.DeclareRISCVVBuiltins = true;
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
|
||||
bool Parser::ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed) {
|
||||
if (TryConsumeToken(tok::semi))
|
||||
return false;
|
||||
|
||||
@ -172,7 +172,7 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ExpectAndConsume(tok::semi, DiagID);
|
||||
return ExpectAndConsume(tok::semi, DiagID , TokenUsed);
|
||||
}
|
||||
|
||||
void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
|
||||
|
@ -91,7 +91,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
|
||||
UsingDirectives.clear();
|
||||
Entity = nullptr;
|
||||
ErrorTrap.reset();
|
||||
NRVO.setPointerAndInt(nullptr, false);
|
||||
NRVO = None;
|
||||
}
|
||||
|
||||
bool Scope::containedInPrototypeScope() const {
|
||||
@ -118,19 +118,71 @@ void Scope::AddFlags(unsigned FlagsToSet) {
|
||||
Flags |= FlagsToSet;
|
||||
}
|
||||
|
||||
void Scope::mergeNRVOIntoParent() {
|
||||
if (VarDecl *Candidate = NRVO.getPointer()) {
|
||||
if (isDeclScope(Candidate))
|
||||
Candidate->setNRVOVariable(true);
|
||||
// The algorithm for updating NRVO candidate is as follows:
|
||||
// 1. All previous candidates become invalid because a new NRVO candidate is
|
||||
// obtained. Therefore, we need to clear return slots for other
|
||||
// variables defined before the current return statement in the current
|
||||
// scope and in outer scopes.
|
||||
// 2. Store the new candidate if its return slot is available. Otherwise,
|
||||
// there is no NRVO candidate so far.
|
||||
void Scope::updateNRVOCandidate(VarDecl *VD) {
|
||||
auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
|
||||
bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
|
||||
|
||||
// We found a candidate variable that can be put into a return slot.
|
||||
// Clear the set, because other variables cannot occupy a return
|
||||
// slot in the same scope.
|
||||
S->ReturnSlots.clear();
|
||||
|
||||
if (IsReturnSlotFound)
|
||||
S->ReturnSlots.insert(VD);
|
||||
|
||||
return IsReturnSlotFound;
|
||||
};
|
||||
|
||||
bool CanBePutInReturnSlot = false;
|
||||
|
||||
for (auto *S = this; S; S = S->getParent()) {
|
||||
CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
|
||||
|
||||
if (S->getEntity())
|
||||
break;
|
||||
}
|
||||
|
||||
if (getEntity())
|
||||
// Consider the variable as NRVO candidate if the return slot is available
|
||||
// for it in the current scope, or if it can be available in outer scopes.
|
||||
NRVO = CanBePutInReturnSlot ? VD : nullptr;
|
||||
}
|
||||
|
||||
void Scope::applyNRVO() {
|
||||
// There is no NRVO candidate in the current scope.
|
||||
if (!NRVO.hasValue())
|
||||
return;
|
||||
|
||||
if (NRVO.getInt())
|
||||
getParent()->setNoNRVO();
|
||||
else if (NRVO.getPointer())
|
||||
getParent()->addNRVOCandidate(NRVO.getPointer());
|
||||
if (*NRVO && isDeclScope(*NRVO))
|
||||
NRVO.getValue()->setNRVOVariable(true);
|
||||
|
||||
// It's necessary to propagate NRVO candidate to the parent scope for cases
|
||||
// when the parent scope doesn't contain a return statement.
|
||||
// For example:
|
||||
// X foo(bool b) {
|
||||
// X x;
|
||||
// if (b)
|
||||
// return x;
|
||||
// exit(0);
|
||||
// }
|
||||
// Also, we need to propagate nullptr value that means NRVO is not
|
||||
// allowed in this scope.
|
||||
// For example:
|
||||
// X foo(bool b) {
|
||||
// X x;
|
||||
// if (b)
|
||||
// return x;
|
||||
// else
|
||||
// return X(); // NRVO is not allowed
|
||||
// }
|
||||
if (!getEntity())
|
||||
getParent()->NRVO = *NRVO;
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
|
||||
@ -193,8 +245,10 @@ void Scope::dumpImpl(raw_ostream &OS) const {
|
||||
if (const DeclContext *DC = getEntity())
|
||||
OS << "Entity : (clang::DeclContext*)" << DC << '\n';
|
||||
|
||||
if (NRVO.getInt())
|
||||
OS << "NRVO not allowed\n";
|
||||
else if (NRVO.getPointer())
|
||||
OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
|
||||
if (!NRVO)
|
||||
OS << "there is no NRVO candidate\n";
|
||||
else if (*NRVO)
|
||||
OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
|
||||
else
|
||||
OS << "NRVO is not allowed\n";
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "clang/Sema/Initialization.h"
|
||||
#include "clang/Sema/MultiplexExternalSemaSource.h"
|
||||
#include "clang/Sema/ObjCMethodList.h"
|
||||
#include "clang/Sema/RISCVIntrinsicManager.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/SemaConsumer.h"
|
||||
@ -137,9 +138,9 @@ class SemaPPCallbacks : public PPCallbacks {
|
||||
|
||||
void reset() { S = nullptr; }
|
||||
|
||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType,
|
||||
FileID PrevFID) override {
|
||||
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType,
|
||||
FileID PrevFID) override {
|
||||
if (!S)
|
||||
return;
|
||||
switch (Reason) {
|
||||
|
@ -2092,7 +2092,7 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
|
||||
}
|
||||
|
||||
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
|
||||
S->mergeNRVOIntoParent();
|
||||
S->applyNRVO();
|
||||
|
||||
if (S->decl_empty()) return;
|
||||
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
|
||||
@ -18899,14 +18899,24 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
|
||||
const llvm::APSInt &InitVal = ECD->getInitVal();
|
||||
|
||||
// Keep track of the size of positive and negative values.
|
||||
if (InitVal.isUnsigned() || InitVal.isNonNegative())
|
||||
NumPositiveBits = std::max(NumPositiveBits,
|
||||
(unsigned)InitVal.getActiveBits());
|
||||
else
|
||||
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
|
||||
// If the enumerator is zero that should still be counted as a positive
|
||||
// bit since we need a bit to store the value zero.
|
||||
unsigned ActiveBits = InitVal.getActiveBits();
|
||||
NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
|
||||
} else {
|
||||
NumNegativeBits = std::max(NumNegativeBits,
|
||||
(unsigned)InitVal.getMinSignedBits());
|
||||
}
|
||||
}
|
||||
|
||||
// If we have have an empty set of enumerators we still need one bit.
|
||||
// From [dcl.enum]p8
|
||||
// If the enumerator-list is empty, the values of the enumeration are as if
|
||||
// the enumeration had a single enumerator with value 0
|
||||
if (!NumPositiveBits && !NumNegativeBits)
|
||||
NumPositiveBits = 1;
|
||||
|
||||
// Figure out the type that should be used for this enum.
|
||||
QualType BestType;
|
||||
unsigned BestWidth;
|
||||
|
@ -13824,7 +13824,8 @@ static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr,
|
||||
// C99 6.5.16.1
|
||||
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
|
||||
SourceLocation Loc,
|
||||
QualType CompoundType) {
|
||||
QualType CompoundType,
|
||||
BinaryOperatorKind Opc) {
|
||||
assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
|
||||
|
||||
// Verify that LHS is a modifiable lvalue, and emit error if not.
|
||||
@ -13937,10 +13938,18 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
|
||||
// expression or an unevaluated operand
|
||||
ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
|
||||
} else {
|
||||
// C++2a [expr.ass]p6:
|
||||
// C++20 [expr.ass]p6:
|
||||
// [Compound-assignment] expressions are deprecated if E1 has
|
||||
// volatile-qualified type
|
||||
Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
|
||||
// volatile-qualified type and op is not one of the bitwise
|
||||
// operators |, &, ˆ.
|
||||
switch (Opc) {
|
||||
case BO_OrAssign:
|
||||
case BO_AndAssign:
|
||||
case BO_XorAssign:
|
||||
break;
|
||||
default:
|
||||
Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14879,7 +14888,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||
|
||||
switch (Opc) {
|
||||
case BO_Assign:
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType(), Opc);
|
||||
if (getLangOpts().CPlusPlus &&
|
||||
LHS.get()->getObjectKind() != OK_ObjCProperty) {
|
||||
VK = LHS.get()->getValueKind();
|
||||
@ -14976,32 +14985,37 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||
Opc == BO_DivAssign);
|
||||
CompLHSTy = CompResultTy;
|
||||
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
|
||||
ResultTy =
|
||||
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
|
||||
break;
|
||||
case BO_RemAssign:
|
||||
CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true);
|
||||
CompLHSTy = CompResultTy;
|
||||
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
|
||||
ResultTy =
|
||||
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
|
||||
break;
|
||||
case BO_AddAssign:
|
||||
ConvertHalfVec = true;
|
||||
CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
|
||||
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
|
||||
ResultTy =
|
||||
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
|
||||
break;
|
||||
case BO_SubAssign:
|
||||
ConvertHalfVec = true;
|
||||
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
|
||||
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
|
||||
ResultTy =
|
||||
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
|
||||
break;
|
||||
case BO_ShlAssign:
|
||||
case BO_ShrAssign:
|
||||
CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true);
|
||||
CompLHSTy = CompResultTy;
|
||||
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
|
||||
ResultTy =
|
||||
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
|
||||
break;
|
||||
case BO_AndAssign:
|
||||
case BO_OrAssign: // fallthrough
|
||||
@ -15011,7 +15025,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
|
||||
CompLHSTy = CompResultTy;
|
||||
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
|
||||
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
|
||||
ResultTy =
|
||||
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
|
||||
break;
|
||||
case BO_Comma:
|
||||
ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Overload.h"
|
||||
#include "clang/Sema/RISCVIntrinsicManager.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
@ -928,6 +929,14 @@ bool Sema::LookupBuiltin(LookupResult &R) {
|
||||
}
|
||||
}
|
||||
|
||||
if (DeclareRISCVVBuiltins) {
|
||||
if (!RVIntrinsicManager)
|
||||
RVIntrinsicManager = CreateRISCVIntrinsicManager(*this);
|
||||
|
||||
if (RVIntrinsicManager->CreateIntrinsicIfFound(R, II, PP))
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this is a builtin on this (or all) targets, create the decl.
|
||||
if (unsigned BuiltinID = II->getBuiltinID()) {
|
||||
// In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
|
||||
@ -3838,6 +3847,12 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
|
||||
// associated classes are visible within their respective
|
||||
// namespaces even if they are not visible during an ordinary
|
||||
// lookup (11.4).
|
||||
//
|
||||
// C++20 [basic.lookup.argdep] p4.3
|
||||
// -- are exported, are attached to a named module M, do not appear
|
||||
// in the translation unit containing the point of the lookup, and
|
||||
// have the same innermost enclosing non-inline namespace scope as
|
||||
// a declaration of an associated entity attached to M.
|
||||
DeclContext::lookup_result R = NS->lookup(Name);
|
||||
for (auto *D : R) {
|
||||
auto *Underlying = D;
|
||||
@ -3858,6 +3873,36 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
|
||||
if (isVisible(D)) {
|
||||
Visible = true;
|
||||
break;
|
||||
} else if (getLangOpts().CPlusPlusModules &&
|
||||
D->isInExportDeclContext()) {
|
||||
// C++20 [basic.lookup.argdep] p4.3 .. are exported ...
|
||||
Module *FM = D->getOwningModule();
|
||||
// exports are only valid in module purview and outside of any
|
||||
// PMF (although a PMF should not even be present in a module
|
||||
// with an import).
|
||||
assert(FM && FM->isModulePurview() && !FM->isPrivateModule() &&
|
||||
"bad export context");
|
||||
// .. are attached to a named module M, do not appear in the
|
||||
// translation unit containing the point of the lookup..
|
||||
if (!isModuleUnitOfCurrentTU(FM) &&
|
||||
llvm::any_of(AssociatedClasses, [&](auto *E) {
|
||||
// ... and have the same innermost enclosing non-inline
|
||||
// namespace scope as a declaration of an associated entity
|
||||
// attached to M
|
||||
if (!E->hasOwningModule() ||
|
||||
E->getOwningModule()->getTopLevelModuleName() !=
|
||||
FM->getTopLevelModuleName())
|
||||
return false;
|
||||
// TODO: maybe this could be cached when generating the
|
||||
// associated namespaces / entities.
|
||||
DeclContext *Ctx = E->getDeclContext();
|
||||
while (!Ctx->isFileContext() || Ctx->isInlineNamespace())
|
||||
Ctx = Ctx->getParent();
|
||||
return Ctx == NS;
|
||||
})) {
|
||||
Visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (D->getFriendObjectKind()) {
|
||||
auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext());
|
||||
|
@ -63,8 +63,9 @@ static ExprResult CreateFunctionRefExpr(
|
||||
// being used.
|
||||
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
|
||||
return ExprError();
|
||||
DeclRefExpr *DRE = new (S.Context)
|
||||
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
|
||||
DeclRefExpr *DRE =
|
||||
DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(),
|
||||
Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl);
|
||||
if (HadMultipleCandidates)
|
||||
DRE->setHadMultipleCandidates(true);
|
||||
|
||||
@ -6400,6 +6401,27 @@ void Sema::AddOverloadCandidate(
|
||||
return;
|
||||
}
|
||||
|
||||
// Functions with internal linkage are only viable in the same module unit.
|
||||
if (auto *MF = Function->getOwningModule()) {
|
||||
if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() &&
|
||||
!isModuleUnitOfCurrentTU(MF)) {
|
||||
/// FIXME: Currently, the semantics of linkage in clang is slightly
|
||||
/// different from the semantics in C++ spec. In C++ spec, only names
|
||||
/// have linkage. So that all entities of the same should share one
|
||||
/// linkage. But in clang, different entities of the same could have
|
||||
/// different linkage.
|
||||
NamedDecl *ND = Function;
|
||||
if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
|
||||
ND = SpecInfo->getTemplate();
|
||||
|
||||
if (ND->getFormalLinkage() == Linkage::InternalLinkage) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_module_mismatched;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
|
||||
!Function->getAttr<TargetAttr>()->isDefaultVersion()) {
|
||||
Candidate.Viable = false;
|
||||
|
395
contrib/llvm-project/clang/lib/Sema/SemaRISCVVectorLookup.cpp
Normal file
395
contrib/llvm-project/clang/lib/Sema/SemaRISCVVectorLookup.cpp
Normal file
@ -0,0 +1,395 @@
|
||||
//==- SemaRISCVVectorLookup.cpp - Name Lookup for RISC-V Vector Intrinsic -==//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements name lookup for RISC-V vector intrinsic.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/RISCVIntrinsicManager.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "clang/Support/RISCVVIntrinsicUtils.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace clang;
|
||||
using namespace clang::RISCV;
|
||||
|
||||
namespace {
|
||||
|
||||
// Function definition of a RVV intrinsic.
|
||||
struct RVVIntrinsicDef {
|
||||
/// Full function name with suffix, e.g. vadd_vv_i32m1.
|
||||
std::string Name;
|
||||
|
||||
/// Overloaded function name, e.g. vadd.
|
||||
std::string OverloadName;
|
||||
|
||||
/// Mapping to which clang built-in function, e.g. __builtin_rvv_vadd.
|
||||
std::string BuiltinName;
|
||||
|
||||
/// Function signature, first element is return type.
|
||||
RVVTypes Signature;
|
||||
};
|
||||
|
||||
struct RVVOverloadIntrinsicDef {
|
||||
// Indexes of RISCVIntrinsicManagerImpl::IntrinsicList.
|
||||
SmallVector<size_t, 8> Indexes;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static const PrototypeDescriptor RVVSignatureTable[] = {
|
||||
#define DECL_SIGNATURE_TABLE
|
||||
#include "clang/Basic/riscv_vector_builtin_sema.inc"
|
||||
#undef DECL_SIGNATURE_TABLE
|
||||
};
|
||||
|
||||
static const RVVIntrinsicRecord RVVIntrinsicRecords[] = {
|
||||
#define DECL_INTRINSIC_RECORDS
|
||||
#include "clang/Basic/riscv_vector_builtin_sema.inc"
|
||||
#undef DECL_INTRINSIC_RECORDS
|
||||
};
|
||||
|
||||
// Get subsequence of signature table.
|
||||
static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index,
|
||||
uint8_t Length) {
|
||||
return makeArrayRef(&RVVSignatureTable[Index], Length);
|
||||
}
|
||||
|
||||
static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
|
||||
QualType QT;
|
||||
switch (Type->getScalarType()) {
|
||||
case ScalarTypeKind::Void:
|
||||
QT = Context.VoidTy;
|
||||
break;
|
||||
case ScalarTypeKind::Size_t:
|
||||
QT = Context.getSizeType();
|
||||
break;
|
||||
case ScalarTypeKind::Ptrdiff_t:
|
||||
QT = Context.getPointerDiffType();
|
||||
break;
|
||||
case ScalarTypeKind::UnsignedLong:
|
||||
QT = Context.UnsignedLongTy;
|
||||
break;
|
||||
case ScalarTypeKind::SignedLong:
|
||||
QT = Context.LongTy;
|
||||
break;
|
||||
case ScalarTypeKind::Boolean:
|
||||
QT = Context.BoolTy;
|
||||
break;
|
||||
case ScalarTypeKind::SignedInteger:
|
||||
QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true);
|
||||
break;
|
||||
case ScalarTypeKind::UnsignedInteger:
|
||||
QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false);
|
||||
break;
|
||||
case ScalarTypeKind::Float:
|
||||
switch (Type->getElementBitwidth()) {
|
||||
case 64:
|
||||
QT = Context.DoubleTy;
|
||||
break;
|
||||
case 32:
|
||||
QT = Context.FloatTy;
|
||||
break;
|
||||
case 16:
|
||||
QT = Context.Float16Ty;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported floating point width.");
|
||||
}
|
||||
break;
|
||||
case Invalid:
|
||||
llvm_unreachable("Unhandled type.");
|
||||
}
|
||||
if (Type->isVector())
|
||||
QT = Context.getScalableVectorType(QT, Type->getScale().getValue());
|
||||
|
||||
if (Type->isConstant())
|
||||
QT = Context.getConstType(QT);
|
||||
|
||||
// Transform the type to a pointer as the last step, if necessary.
|
||||
if (Type->isPointer())
|
||||
QT = Context.getPointerType(QT);
|
||||
|
||||
return QT;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
|
||||
private:
|
||||
Sema &S;
|
||||
ASTContext &Context;
|
||||
|
||||
// List of all RVV intrinsic.
|
||||
std::vector<RVVIntrinsicDef> IntrinsicList;
|
||||
// Mapping function name to index of IntrinsicList.
|
||||
StringMap<size_t> Intrinsics;
|
||||
// Mapping function name to RVVOverloadIntrinsicDef.
|
||||
StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics;
|
||||
|
||||
// Create IntrinsicList
|
||||
void InitIntrinsicList();
|
||||
|
||||
// Create RVVIntrinsicDef.
|
||||
void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr,
|
||||
StringRef OverloadedSuffixStr, bool IsMask,
|
||||
RVVTypes &Types);
|
||||
|
||||
// Create FunctionDecl for a vector intrinsic.
|
||||
void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
|
||||
Preprocessor &PP, unsigned Index,
|
||||
bool IsOverload);
|
||||
|
||||
public:
|
||||
RISCVIntrinsicManagerImpl(clang::Sema &S) : S(S), Context(S.Context) {
|
||||
InitIntrinsicList();
|
||||
}
|
||||
|
||||
// Create RISC-V vector intrinsic and insert into symbol table if found, and
|
||||
// return true, otherwise return false.
|
||||
bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
|
||||
Preprocessor &PP) override;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
|
||||
const TargetInfo &TI = Context.getTargetInfo();
|
||||
bool HasVectorFloat32 = TI.hasFeature("zve32f");
|
||||
bool HasVectorFloat64 = TI.hasFeature("zve64d");
|
||||
bool HasZvfh = TI.hasFeature("experimental-zvfh");
|
||||
bool HasRV64 = TI.hasFeature("64bit");
|
||||
bool HasFullMultiply = TI.hasFeature("v");
|
||||
|
||||
// Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics
|
||||
// in RISCVVEmitter.cpp.
|
||||
for (auto &Record : RVVIntrinsicRecords) {
|
||||
// Create Intrinsics for each type and LMUL.
|
||||
BasicType BaseType = BasicType::Unknown;
|
||||
ArrayRef<PrototypeDescriptor> BasicProtoSeq =
|
||||
ProtoSeq2ArrayRef(Record.PrototypeIndex, Record.PrototypeLength);
|
||||
ArrayRef<PrototypeDescriptor> SuffixProto =
|
||||
ProtoSeq2ArrayRef(Record.SuffixIndex, Record.SuffixLength);
|
||||
ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef(
|
||||
Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize);
|
||||
|
||||
llvm::SmallVector<PrototypeDescriptor> ProtoSeq =
|
||||
RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false,
|
||||
/*HasMaskedOffOperand=*/false,
|
||||
Record.HasVL, Record.NF);
|
||||
|
||||
llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq =
|
||||
RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/true,
|
||||
Record.HasMaskedOffOperand,
|
||||
Record.HasVL, Record.NF);
|
||||
|
||||
for (unsigned int TypeRangeMaskShift = 0;
|
||||
TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset);
|
||||
++TypeRangeMaskShift) {
|
||||
unsigned int BaseTypeI = 1 << TypeRangeMaskShift;
|
||||
BaseType = static_cast<BasicType>(BaseTypeI);
|
||||
|
||||
if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI)
|
||||
continue;
|
||||
|
||||
// Check requirement.
|
||||
if (BaseType == BasicType::Float16 && !HasZvfh)
|
||||
continue;
|
||||
|
||||
if (BaseType == BasicType::Float32 && !HasVectorFloat32)
|
||||
continue;
|
||||
|
||||
if (BaseType == BasicType::Float64 && !HasVectorFloat64)
|
||||
continue;
|
||||
|
||||
if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) &&
|
||||
!HasRV64)
|
||||
continue;
|
||||
|
||||
if ((BaseType == BasicType::Int64) &&
|
||||
((Record.RequiredExtensions & RVV_REQ_FullMultiply) ==
|
||||
RVV_REQ_FullMultiply) &&
|
||||
!HasFullMultiply)
|
||||
continue;
|
||||
|
||||
// Expanded with different LMUL.
|
||||
for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) {
|
||||
if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
|
||||
continue;
|
||||
|
||||
Optional<RVVTypes> Types =
|
||||
RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
|
||||
|
||||
// Ignored to create new intrinsic if there are any illegal types.
|
||||
if (!Types.hasValue())
|
||||
continue;
|
||||
|
||||
std::string SuffixStr =
|
||||
RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto);
|
||||
std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
|
||||
BaseType, Log2LMUL, OverloadedSuffixProto);
|
||||
|
||||
// Create non-masked intrinsic.
|
||||
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types);
|
||||
|
||||
if (Record.HasMasked) {
|
||||
// Create masked intrinsic.
|
||||
Optional<RVVTypes> MaskTypes = RVVType::computeTypes(
|
||||
BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
|
||||
|
||||
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
|
||||
*MaskTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute name and signatures for intrinsic with practical types.
|
||||
void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
|
||||
const RVVIntrinsicRecord &Record, StringRef SuffixStr,
|
||||
StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) {
|
||||
// Function name, e.g. vadd_vv_i32m1.
|
||||
std::string Name = Record.Name;
|
||||
if (!SuffixStr.empty())
|
||||
Name += "_" + SuffixStr.str();
|
||||
|
||||
if (IsMask)
|
||||
Name += "_m";
|
||||
|
||||
// Overloaded function name, e.g. vadd.
|
||||
std::string OverloadedName;
|
||||
if (!Record.OverloadedName)
|
||||
OverloadedName = StringRef(Record.Name).split("_").first.str();
|
||||
else
|
||||
OverloadedName = Record.OverloadedName;
|
||||
if (!OverloadedSuffixStr.empty())
|
||||
OverloadedName += "_" + OverloadedSuffixStr.str();
|
||||
|
||||
// clang built-in function name, e.g. __builtin_rvv_vadd.
|
||||
std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name);
|
||||
if (IsMask)
|
||||
BuiltinName += "_m";
|
||||
|
||||
// Put into IntrinsicList.
|
||||
size_t Index = IntrinsicList.size();
|
||||
IntrinsicList.push_back({Name, OverloadedName, BuiltinName, Signature});
|
||||
|
||||
// Creating mapping to Intrinsics.
|
||||
Intrinsics.insert({Name, Index});
|
||||
|
||||
// Get the RVVOverloadIntrinsicDef.
|
||||
RVVOverloadIntrinsicDef &OverloadIntrinsicDef =
|
||||
OverloadIntrinsics[OverloadedName];
|
||||
|
||||
// And added the index.
|
||||
OverloadIntrinsicDef.Indexes.push_back(Index);
|
||||
}
|
||||
|
||||
void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR,
|
||||
IdentifierInfo *II,
|
||||
Preprocessor &PP,
|
||||
unsigned Index,
|
||||
bool IsOverload) {
|
||||
ASTContext &Context = S.Context;
|
||||
RVVIntrinsicDef &IDef = IntrinsicList[Index];
|
||||
RVVTypes Sigs = IDef.Signature;
|
||||
size_t SigLength = Sigs.size();
|
||||
RVVType *ReturnType = Sigs[0];
|
||||
QualType RetType = RVVType2Qual(Context, ReturnType);
|
||||
SmallVector<QualType, 8> ArgTypes;
|
||||
QualType BuiltinFuncType;
|
||||
|
||||
// Skip return type, and convert RVVType to QualType for arguments.
|
||||
for (size_t i = 1; i < SigLength; ++i)
|
||||
ArgTypes.push_back(RVVType2Qual(Context, Sigs[i]));
|
||||
|
||||
FunctionProtoType::ExtProtoInfo PI(
|
||||
Context.getDefaultCallingConvention(false, false, true));
|
||||
|
||||
PI.Variadic = false;
|
||||
|
||||
SourceLocation Loc = LR.getNameLoc();
|
||||
BuiltinFuncType = Context.getFunctionType(RetType, ArgTypes, PI);
|
||||
DeclContext *Parent = Context.getTranslationUnitDecl();
|
||||
|
||||
FunctionDecl *RVVIntrinsicDecl = FunctionDecl::Create(
|
||||
Context, Parent, Loc, Loc, II, BuiltinFuncType, /*TInfo=*/nullptr,
|
||||
SC_Extern, S.getCurFPFeatures().isFPConstrained(),
|
||||
/*isInlineSpecified*/ false,
|
||||
/*hasWrittenPrototype*/ true);
|
||||
|
||||
// Create Decl objects for each parameter, adding them to the
|
||||
// FunctionDecl.
|
||||
const auto *FP = cast<FunctionProtoType>(BuiltinFuncType);
|
||||
SmallVector<ParmVarDecl *, 8> ParmList;
|
||||
for (unsigned IParm = 0, E = FP->getNumParams(); IParm != E; ++IParm) {
|
||||
ParmVarDecl *Parm =
|
||||
ParmVarDecl::Create(Context, RVVIntrinsicDecl, Loc, Loc, nullptr,
|
||||
FP->getParamType(IParm), nullptr, SC_None, nullptr);
|
||||
Parm->setScopeInfo(0, IParm);
|
||||
ParmList.push_back(Parm);
|
||||
}
|
||||
RVVIntrinsicDecl->setParams(ParmList);
|
||||
|
||||
// Add function attributes.
|
||||
if (IsOverload)
|
||||
RVVIntrinsicDecl->addAttr(OverloadableAttr::CreateImplicit(Context));
|
||||
|
||||
// Setup alias to __builtin_rvv_*
|
||||
IdentifierInfo &IntrinsicII = PP.getIdentifierTable().get(IDef.BuiltinName);
|
||||
RVVIntrinsicDecl->addAttr(
|
||||
BuiltinAliasAttr::CreateImplicit(S.Context, &IntrinsicII));
|
||||
|
||||
// Add to symbol table.
|
||||
LR.addDecl(RVVIntrinsicDecl);
|
||||
}
|
||||
|
||||
bool RISCVIntrinsicManagerImpl::CreateIntrinsicIfFound(LookupResult &LR,
|
||||
IdentifierInfo *II,
|
||||
Preprocessor &PP) {
|
||||
StringRef Name = II->getName();
|
||||
|
||||
// Lookup the function name from the overload intrinsics first.
|
||||
auto OvIItr = OverloadIntrinsics.find(Name);
|
||||
if (OvIItr != OverloadIntrinsics.end()) {
|
||||
const RVVOverloadIntrinsicDef &OvIntrinsicDef = OvIItr->second;
|
||||
for (auto Index : OvIntrinsicDef.Indexes)
|
||||
CreateRVVIntrinsicDecl(LR, II, PP, Index,
|
||||
/*IsOverload*/ true);
|
||||
|
||||
// If we added overloads, need to resolve the lookup result.
|
||||
LR.resolveKind();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Lookup the function name from the intrinsics.
|
||||
auto Itr = Intrinsics.find(Name);
|
||||
if (Itr != Intrinsics.end()) {
|
||||
CreateRVVIntrinsicDecl(LR, II, PP, Itr->second,
|
||||
/*IsOverload*/ false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// It's not an RVV intrinsics.
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
std::unique_ptr<clang::sema::RISCVIntrinsicManager>
|
||||
CreateRISCVIntrinsicManager(Sema &S) {
|
||||
return std::make_unique<RISCVIntrinsicManagerImpl>(S);
|
||||
}
|
||||
} // namespace clang
|
@ -3898,12 +3898,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
|
||||
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
|
||||
return R;
|
||||
|
||||
if (VarDecl *VD =
|
||||
const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
|
||||
CurScope->addNRVOCandidate(VD);
|
||||
} else {
|
||||
CurScope->setNoNRVO();
|
||||
}
|
||||
VarDecl *VD =
|
||||
const_cast<VarDecl *>(cast<ReturnStmt>(R.get())->getNRVOCandidate());
|
||||
|
||||
CurScope->updateNRVOCandidate(VD);
|
||||
|
||||
CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/TypeVisitor.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/DiagnosticSema.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/Stack.h"
|
||||
@ -8707,23 +8708,59 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
|
||||
// Check for conflicting previous declaration.
|
||||
DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc);
|
||||
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
|
||||
ForVisibleRedeclaration);
|
||||
forRedeclarationInCurContext());
|
||||
LookupName(Previous, S);
|
||||
|
||||
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false,
|
||||
/*AllowInlineNamespace*/false);
|
||||
if (!Previous.empty()) {
|
||||
auto *Old = Previous.getRepresentativeDecl();
|
||||
Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition :
|
||||
diag::err_redefinition_different_kind) << NewDecl->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
}
|
||||
bool AddToScope = true;
|
||||
CheckConceptRedefinition(NewDecl, Previous, AddToScope);
|
||||
|
||||
ActOnDocumentableDecl(NewDecl);
|
||||
PushOnScopeChains(NewDecl, S);
|
||||
if (AddToScope)
|
||||
PushOnScopeChains(NewDecl, S);
|
||||
return NewDecl;
|
||||
}
|
||||
|
||||
void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
|
||||
LookupResult &Previous, bool &AddToScope) {
|
||||
AddToScope = true;
|
||||
|
||||
if (Previous.empty())
|
||||
return;
|
||||
|
||||
auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
|
||||
if (!OldConcept) {
|
||||
auto *Old = Previous.getRepresentativeDecl();
|
||||
Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
|
||||
<< NewDecl->getDeclName();
|
||||
notePreviousDefinition(Old, NewDecl->getLocation());
|
||||
AddToScope = false;
|
||||
return;
|
||||
}
|
||||
// Check if we can merge with a concept declaration.
|
||||
bool IsSame = Context.isSameEntity(NewDecl, OldConcept);
|
||||
if (!IsSame) {
|
||||
Diag(NewDecl->getLocation(), diag::err_redefinition_different_concept)
|
||||
<< NewDecl->getDeclName();
|
||||
notePreviousDefinition(OldConcept, NewDecl->getLocation());
|
||||
AddToScope = false;
|
||||
return;
|
||||
}
|
||||
if (hasReachableDefinition(OldConcept)) {
|
||||
Diag(NewDecl->getLocation(), diag::err_redefinition)
|
||||
<< NewDecl->getDeclName();
|
||||
notePreviousDefinition(OldConcept, NewDecl->getLocation());
|
||||
AddToScope = false;
|
||||
return;
|
||||
}
|
||||
if (!Previous.isSingleResult()) {
|
||||
// FIXME: we should produce an error in case of ambig and failed lookups.
|
||||
// Other decls (e.g. namespaces) also have this shortcoming.
|
||||
return;
|
||||
}
|
||||
Context.setPrimaryMergedDecl(NewDecl, OldConcept);
|
||||
}
|
||||
|
||||
/// \brief Strips various properties off an implicit instantiation
|
||||
/// that has just been explicitly specialized.
|
||||
static void StripImplicitInstantiation(NamedDecl *D) {
|
||||
|
@ -2926,7 +2926,8 @@ Attr *ASTRecordReader::readAttr() {
|
||||
/// Reads attributes from the current stream position.
|
||||
void ASTRecordReader::readAttributes(AttrVec &Attrs) {
|
||||
for (unsigned I = 0, E = readInt(); I != E; ++I)
|
||||
Attrs.push_back(readAttr());
|
||||
if (auto *A = readAttr())
|
||||
Attrs.push_back(A);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -4347,8 +4347,12 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
|
||||
|
||||
void ASTRecordWriter::AddAttr(const Attr *A) {
|
||||
auto &Record = *this;
|
||||
if (!A)
|
||||
// FIXME: Clang can't handle the serialization/deserialization of
|
||||
// preferred_name properly now. See
|
||||
// https://github.com/llvm/llvm-project/issues/56490 for example.
|
||||
if (!A || (isa<PreferredNameAttr>(A) && Writer->isWritingNamedModules()))
|
||||
return Record.push_back(0);
|
||||
|
||||
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
|
||||
|
||||
Record.AddIdentifierRef(A->getAttrName());
|
||||
|
@ -26,9 +26,11 @@
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <functional>
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
using namespace std::placeholders;
|
||||
|
||||
namespace {
|
||||
struct AnyArgExpr {
|
||||
@ -118,10 +120,14 @@ class CStringChecker : public Checker< eval::Call,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call) const;
|
||||
|
||||
typedef void (CStringChecker::*FnCheck)(CheckerContext &,
|
||||
const CallExpr *) const;
|
||||
using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
|
||||
const CallExpr *)>;
|
||||
|
||||
CallDescriptionMap<FnCheck> Callbacks = {
|
||||
{{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy},
|
||||
{{CDF_MaybeBuiltin, "memcpy", 3},
|
||||
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)},
|
||||
{{CDF_MaybeBuiltin, "wmemcpy", 3},
|
||||
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)},
|
||||
{{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy},
|
||||
{{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp},
|
||||
{{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove},
|
||||
@ -135,7 +141,9 @@ class CStringChecker : public Checker< eval::Call,
|
||||
{{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
|
||||
{{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
|
||||
{{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
|
||||
{{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
|
||||
{{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
|
||||
{{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
|
||||
{{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
|
||||
{{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
|
||||
{{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp},
|
||||
@ -152,14 +160,14 @@ class CStringChecker : public Checker< eval::Call,
|
||||
StdCopyBackward{{"std", "copy_backward"}, 3};
|
||||
|
||||
FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
|
||||
void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const;
|
||||
void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
|
||||
ProgramStateRef state, SizeArgExpr Size,
|
||||
DestinationArgExpr Dest, SourceArgExpr Source,
|
||||
bool Restricted, bool IsMempcpy) const;
|
||||
bool Restricted, bool IsMempcpy, bool IsWide) const;
|
||||
|
||||
void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
|
||||
|
||||
@ -240,13 +248,14 @@ class CStringChecker : public Checker< eval::Call,
|
||||
AnyArgExpr Arg, SVal l) const;
|
||||
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
|
||||
AnyArgExpr Buffer, SVal Element,
|
||||
AccessKind Access) const;
|
||||
AccessKind Access, bool IsWide = false) const;
|
||||
ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
|
||||
AnyArgExpr Buffer, SizeArgExpr Size,
|
||||
AccessKind Access) const;
|
||||
AccessKind Access,
|
||||
bool IsWide = false) const;
|
||||
ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
|
||||
SizeArgExpr Size, AnyArgExpr First,
|
||||
AnyArgExpr Second) const;
|
||||
AnyArgExpr Second, bool IsWide = false) const;
|
||||
void emitOverlapBug(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
const Stmt *First,
|
||||
@ -329,7 +338,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
|
||||
ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
AnyArgExpr Buffer, SVal Element,
|
||||
AccessKind Access) const {
|
||||
AccessKind Access,
|
||||
bool IsWide) const {
|
||||
|
||||
// If a previous check has failed, propagate the failure.
|
||||
if (!state)
|
||||
@ -344,17 +354,36 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
|
||||
if (!ER)
|
||||
return state;
|
||||
|
||||
if (ER->getValueType() != C.getASTContext().CharTy)
|
||||
return state;
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
ASTContext &Ctx = svalBuilder.getContext();
|
||||
|
||||
// Get the index of the accessed element.
|
||||
NonLoc Idx = ER->getIndex();
|
||||
|
||||
if (!IsWide) {
|
||||
if (ER->getValueType() != Ctx.CharTy)
|
||||
return state;
|
||||
} else {
|
||||
if (ER->getValueType() != Ctx.WideCharTy)
|
||||
return state;
|
||||
|
||||
QualType SizeTy = Ctx.getSizeType();
|
||||
NonLoc WideSize =
|
||||
svalBuilder
|
||||
.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
|
||||
SizeTy)
|
||||
.castAs<NonLoc>();
|
||||
SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
|
||||
if (Offset.isUnknown())
|
||||
return state;
|
||||
Idx = Offset.castAs<NonLoc>();
|
||||
}
|
||||
|
||||
// Get the size of the array.
|
||||
const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
|
||||
DefinedOrUnknownSVal Size =
|
||||
getDynamicExtent(state, superReg, C.getSValBuilder());
|
||||
|
||||
// Get the index of the accessed element.
|
||||
DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
|
||||
|
||||
ProgramStateRef StInBound, StOutBound;
|
||||
std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
|
||||
if (StOutBound && !StInBound) {
|
||||
@ -385,11 +414,10 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
|
||||
return StInBound;
|
||||
}
|
||||
|
||||
ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
|
||||
ProgramStateRef State,
|
||||
AnyArgExpr Buffer,
|
||||
SizeArgExpr Size,
|
||||
AccessKind Access) const {
|
||||
ProgramStateRef
|
||||
CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
|
||||
AnyArgExpr Buffer, SizeArgExpr Size,
|
||||
AccessKind Access, bool IsWide) const {
|
||||
// If a previous check has failed, propagate the failure.
|
||||
if (!State)
|
||||
return nullptr;
|
||||
@ -398,7 +426,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
|
||||
ASTContext &Ctx = svalBuilder.getContext();
|
||||
|
||||
QualType SizeTy = Size.Expression->getType();
|
||||
QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
|
||||
QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
|
||||
|
||||
// Check that the first buffer is non-null.
|
||||
SVal BufVal = C.getSVal(Buffer.Expression);
|
||||
@ -432,7 +460,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
|
||||
|
||||
SVal BufEnd =
|
||||
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
|
||||
State = CheckLocation(C, State, Buffer, BufEnd, Access);
|
||||
State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide);
|
||||
|
||||
// If the buffer isn't large enough, abort.
|
||||
if (!State)
|
||||
@ -446,7 +474,8 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
|
||||
ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
SizeArgExpr Size, AnyArgExpr First,
|
||||
AnyArgExpr Second) const {
|
||||
AnyArgExpr Second,
|
||||
bool IsWide) const {
|
||||
if (!Filter.CheckCStringBufferOverlap)
|
||||
return state;
|
||||
|
||||
@ -525,7 +554,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
|
||||
// Convert the first buffer's start address to char*.
|
||||
// Bail out if the cast fails.
|
||||
ASTContext &Ctx = svalBuilder.getContext();
|
||||
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
|
||||
QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
|
||||
SVal FirstStart =
|
||||
svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
|
||||
Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
|
||||
@ -1161,7 +1190,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
|
||||
ProgramStateRef state, SizeArgExpr Size,
|
||||
DestinationArgExpr Dest,
|
||||
SourceArgExpr Source, bool Restricted,
|
||||
bool IsMempcpy) const {
|
||||
bool IsMempcpy, bool IsWide) const {
|
||||
CurrentFunctionDescription = "memory copy function";
|
||||
|
||||
// See if the size argument is zero.
|
||||
@ -1204,11 +1233,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
|
||||
return;
|
||||
|
||||
// Ensure the accesses are valid and that the buffers do not overlap.
|
||||
state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write);
|
||||
state = CheckBufferAccess(C, state, Source, Size, AccessKind::read);
|
||||
state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide);
|
||||
state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide);
|
||||
|
||||
if (Restricted)
|
||||
state = CheckOverlap(C, state, Size, Dest, Source);
|
||||
state = CheckOverlap(C, state, Size, Dest, Source, IsWide);
|
||||
|
||||
if (!state)
|
||||
return;
|
||||
@ -1258,7 +1287,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
|
||||
}
|
||||
}
|
||||
|
||||
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
|
||||
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
|
||||
bool IsWide) const {
|
||||
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
|
||||
// The return value is the address of the destination buffer.
|
||||
DestinationArgExpr Dest = {CE->getArg(0), 0};
|
||||
@ -1269,7 +1299,8 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
|
||||
|
||||
constexpr bool IsRestricted = true;
|
||||
constexpr bool IsMempcpy = false;
|
||||
evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy);
|
||||
evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy,
|
||||
IsWide);
|
||||
}
|
||||
|
||||
void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
|
||||
@ -1281,7 +1312,8 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
|
||||
|
||||
constexpr bool IsRestricted = true;
|
||||
constexpr bool IsMempcpy = true;
|
||||
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
|
||||
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
|
||||
false);
|
||||
}
|
||||
|
||||
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
|
||||
@ -1293,7 +1325,8 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
|
||||
|
||||
constexpr bool IsRestricted = false;
|
||||
constexpr bool IsMempcpy = false;
|
||||
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
|
||||
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
|
||||
false);
|
||||
}
|
||||
|
||||
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
|
||||
@ -1304,7 +1337,8 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
|
||||
|
||||
constexpr bool IsRestricted = false;
|
||||
constexpr bool IsMempcpy = false;
|
||||
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
|
||||
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
|
||||
false);
|
||||
}
|
||||
|
||||
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
|
||||
@ -2336,7 +2370,7 @@ bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
|
||||
|
||||
// Check and evaluate the call.
|
||||
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
|
||||
(this->*Callback)(C, CE);
|
||||
Callback(this, C, CE);
|
||||
|
||||
// If the evaluate call resulted in no change, chain to the next eval call
|
||||
// handler.
|
||||
|
@ -55,9 +55,9 @@ class InnerPointerChecker
|
||||
ID.AddPointer(getTag());
|
||||
}
|
||||
|
||||
virtual PathDiagnosticPieceRef
|
||||
VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR) override;
|
||||
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
|
||||
BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR) override;
|
||||
|
||||
// FIXME: Scan the map once in the visitor's constructor and do a direct
|
||||
// lookup by region.
|
||||
|
@ -852,9 +852,8 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
wasModifiedInFunction(const ExplodedNode *CallEnterN,
|
||||
const ExplodedNode *CallExitEndN) override {
|
||||
bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
|
||||
const ExplodedNode *CallExitEndN) override {
|
||||
if (!doesFnIntendToHandleOwnership(
|
||||
CallExitEndN->getFirstPred()->getLocationContext()->getDecl(),
|
||||
CallExitEndN->getState()->getAnalysisManager().getASTContext()))
|
||||
@ -885,7 +884,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
|
||||
"later deallocation");
|
||||
}
|
||||
|
||||
virtual PathDiagnosticPieceRef
|
||||
PathDiagnosticPieceRef
|
||||
maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
|
||||
const ObjCMethodCall &Call,
|
||||
const ExplodedNode *N) override {
|
||||
@ -893,7 +892,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual PathDiagnosticPieceRef
|
||||
PathDiagnosticPieceRef
|
||||
maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
|
||||
const CXXConstructorCall &Call,
|
||||
const ExplodedNode *N) override {
|
||||
@ -901,7 +900,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual PathDiagnosticPieceRef
|
||||
PathDiagnosticPieceRef
|
||||
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
|
||||
const ExplodedNode *N) override {
|
||||
// TODO: Factor the logic of "what constitutes as an entity being passed
|
||||
|
@ -182,7 +182,7 @@ class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
|
||||
return false;
|
||||
};
|
||||
|
||||
if (std::any_of(RD->field_begin(), RD->field_end(), IsTrickyField))
|
||||
if (llvm::any_of(RD->fields(), IsTrickyField))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ class StdLibraryFunctionsChecker
|
||||
ArgNo OtherArgN;
|
||||
|
||||
public:
|
||||
virtual StringRef getName() const override { return "Comparison"; };
|
||||
StringRef getName() const override { return "Comparison"; };
|
||||
ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
|
||||
ArgNo OtherArgN)
|
||||
: ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
|
||||
|
@ -57,19 +57,17 @@ class RegularField final : public FieldNode {
|
||||
public:
|
||||
RegularField(const FieldRegion *FR) : FieldNode(FR) {}
|
||||
|
||||
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
Out << "uninitialized field ";
|
||||
}
|
||||
|
||||
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
|
||||
virtual void printNode(llvm::raw_ostream &Out) const override {
|
||||
void printNode(llvm::raw_ostream &Out) const override {
|
||||
Out << getVariableName(getDecl());
|
||||
}
|
||||
|
||||
virtual void printSeparator(llvm::raw_ostream &Out) const override {
|
||||
Out << '.';
|
||||
}
|
||||
void printSeparator(llvm::raw_ostream &Out) const override { Out << '.'; }
|
||||
};
|
||||
|
||||
/// Represents that the FieldNode that comes after this is declared in a base
|
||||
@ -85,20 +83,20 @@ class BaseClass final : public FieldNode {
|
||||
assert(T->getAsCXXRecordDecl());
|
||||
}
|
||||
|
||||
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
llvm_unreachable("This node can never be the final node in the "
|
||||
"fieldchain!");
|
||||
}
|
||||
|
||||
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
|
||||
virtual void printNode(llvm::raw_ostream &Out) const override {
|
||||
void printNode(llvm::raw_ostream &Out) const override {
|
||||
Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";
|
||||
}
|
||||
|
||||
virtual void printSeparator(llvm::raw_ostream &Out) const override {}
|
||||
void printSeparator(llvm::raw_ostream &Out) const override {}
|
||||
|
||||
virtual bool isBase() const override { return true; }
|
||||
bool isBase() const override { return true; }
|
||||
};
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@ -34,20 +34,20 @@ class LocField final : public FieldNode {
|
||||
LocField(const FieldRegion *FR, const bool IsDereferenced = true)
|
||||
: FieldNode(FR), IsDereferenced(IsDereferenced) {}
|
||||
|
||||
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
if (IsDereferenced)
|
||||
Out << "uninitialized pointee ";
|
||||
else
|
||||
Out << "uninitialized pointer ";
|
||||
}
|
||||
|
||||
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
|
||||
virtual void printNode(llvm::raw_ostream &Out) const override {
|
||||
void printNode(llvm::raw_ostream &Out) const override {
|
||||
Out << getVariableName(getDecl());
|
||||
}
|
||||
|
||||
virtual void printSeparator(llvm::raw_ostream &Out) const override {
|
||||
void printSeparator(llvm::raw_ostream &Out) const override {
|
||||
if (getDecl()->getType()->isPointerType())
|
||||
Out << "->";
|
||||
else
|
||||
@ -64,11 +64,11 @@ class NeedsCastLocField final : public FieldNode {
|
||||
NeedsCastLocField(const FieldRegion *FR, const QualType &T)
|
||||
: FieldNode(FR), CastBackType(T) {}
|
||||
|
||||
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
Out << "uninitialized pointee ";
|
||||
}
|
||||
|
||||
virtual void printPrefix(llvm::raw_ostream &Out) const override {
|
||||
void printPrefix(llvm::raw_ostream &Out) const override {
|
||||
// If this object is a nonloc::LocAsInteger.
|
||||
if (getDecl()->getType()->isIntegerType())
|
||||
Out << "reinterpret_cast";
|
||||
@ -78,13 +78,11 @@ class NeedsCastLocField final : public FieldNode {
|
||||
Out << '<' << CastBackType.getAsString() << ">(";
|
||||
}
|
||||
|
||||
virtual void printNode(llvm::raw_ostream &Out) const override {
|
||||
void printNode(llvm::raw_ostream &Out) const override {
|
||||
Out << getVariableName(getDecl()) << ')';
|
||||
}
|
||||
|
||||
virtual void printSeparator(llvm::raw_ostream &Out) const override {
|
||||
Out << "->";
|
||||
}
|
||||
void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }
|
||||
};
|
||||
|
||||
/// Represents a Loc field that points to itself.
|
||||
@ -93,17 +91,17 @@ class CyclicLocField final : public FieldNode {
|
||||
public:
|
||||
CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
|
||||
|
||||
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
void printNoteMsg(llvm::raw_ostream &Out) const override {
|
||||
Out << "object references itself ";
|
||||
}
|
||||
|
||||
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
void printPrefix(llvm::raw_ostream &Out) const override {}
|
||||
|
||||
virtual void printNode(llvm::raw_ostream &Out) const override {
|
||||
void printNode(llvm::raw_ostream &Out) const override {
|
||||
Out << getVariableName(getDecl());
|
||||
}
|
||||
|
||||
virtual void printSeparator(llvm::raw_ostream &Out) const override {
|
||||
void printSeparator(llvm::raw_ostream &Out) const override {
|
||||
llvm_unreachable("CyclicLocField objects must be the last node of the "
|
||||
"fieldchain!");
|
||||
}
|
||||
|
@ -530,9 +530,8 @@ class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
|
||||
private:
|
||||
/// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
|
||||
/// the value it holds in \p CallExitBeginN.
|
||||
virtual bool
|
||||
wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
|
||||
const ExplodedNode *CallExitBeginN) override;
|
||||
bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
|
||||
const ExplodedNode *CallExitBeginN) override;
|
||||
|
||||
/// Attempts to find the region of interest in a given record decl,
|
||||
/// by either following the base classes or fields.
|
||||
@ -547,19 +546,17 @@ class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
|
||||
|
||||
// Region of interest corresponds to an IVar, exiting a method
|
||||
// which could have written into that IVar, but did not.
|
||||
virtual PathDiagnosticPieceRef
|
||||
maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
|
||||
const ObjCMethodCall &Call,
|
||||
const ExplodedNode *N) override final;
|
||||
PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
|
||||
const ObjCMethodCall &Call,
|
||||
const ExplodedNode *N) final;
|
||||
|
||||
virtual PathDiagnosticPieceRef
|
||||
maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
|
||||
const CXXConstructorCall &Call,
|
||||
const ExplodedNode *N) override final;
|
||||
PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
|
||||
const CXXConstructorCall &Call,
|
||||
const ExplodedNode *N) final;
|
||||
|
||||
virtual PathDiagnosticPieceRef
|
||||
PathDiagnosticPieceRef
|
||||
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
|
||||
const ExplodedNode *N) override final;
|
||||
const ExplodedNode *N) final;
|
||||
|
||||
/// Consume the information on the no-store stack frame in order to
|
||||
/// either emit a note or suppress the report enirely.
|
||||
|
@ -196,6 +196,14 @@ typedef llvm::ImmutableMap<
|
||||
IndexOfElementToConstructMap;
|
||||
REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct,
|
||||
IndexOfElementToConstructMap)
|
||||
|
||||
// This trait is responsible for holding our pending ArrayInitLoopExprs.
|
||||
// It pairs the LocationContext and the initializer CXXConstructExpr with
|
||||
// the size of the array that's being copy initialized.
|
||||
typedef llvm::ImmutableMap<
|
||||
std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
|
||||
PendingInitLoopMap;
|
||||
REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Engine construction and deletion.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -462,6 +470,34 @@ ProgramStateRef ExprEngine::setIndexOfElementToConstruct(
|
||||
return State->set<IndexOfElementToConstruct>(Key, Idx);
|
||||
}
|
||||
|
||||
Optional<unsigned> ExprEngine::getPendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx) {
|
||||
|
||||
return Optional<unsigned>::create(
|
||||
State->get<PendingInitLoop>({E, LCtx->getStackFrame()}));
|
||||
}
|
||||
|
||||
ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx) {
|
||||
auto Key = std::make_pair(E, LCtx->getStackFrame());
|
||||
|
||||
assert(E && State->contains<PendingInitLoop>(Key));
|
||||
return State->remove<PendingInitLoop>(Key);
|
||||
}
|
||||
|
||||
ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx,
|
||||
unsigned Size) {
|
||||
auto Key = std::make_pair(E, LCtx->getStackFrame());
|
||||
|
||||
assert(!State->contains<PendingInitLoop>(Key) && Size > 0);
|
||||
|
||||
return State->set<PendingInitLoop>(Key, Size);
|
||||
}
|
||||
|
||||
Optional<unsigned>
|
||||
ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
@ -487,17 +523,23 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
|
||||
const LocationContext *LC, SVal V) {
|
||||
ConstructedObjectKey Key(Item, LC->getStackFrame());
|
||||
|
||||
const CXXConstructExpr *E = nullptr;
|
||||
const Expr *Init = nullptr;
|
||||
|
||||
if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) {
|
||||
if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl()))
|
||||
E = dyn_cast<CXXConstructExpr>(VD->getInit());
|
||||
Init = VD->getInit();
|
||||
}
|
||||
|
||||
if (!E && !Item.getStmtOrNull()) {
|
||||
auto CtorInit = Item.getCXXCtorInitializer();
|
||||
E = dyn_cast<CXXConstructExpr>(CtorInit->getInit());
|
||||
}
|
||||
if (auto LE = dyn_cast_or_null<LambdaExpr>(Item.getStmtOrNull()))
|
||||
Init = *(LE->capture_init_begin() + Item.getIndex());
|
||||
|
||||
if (!Init && !Item.getStmtOrNull())
|
||||
Init = Item.getCXXCtorInitializer()->getInit();
|
||||
|
||||
// In an ArrayInitLoopExpr the real initializer is returned by
|
||||
// getSubExpr().
|
||||
if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init))
|
||||
Init = AILE->getSubExpr();
|
||||
|
||||
// FIXME: Currently the state might already contain the marker due to
|
||||
// incorrect handling of temporaries bound to default parameters.
|
||||
@ -508,7 +550,8 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
|
||||
assert((!State->get<ObjectsUnderConstruction>(Key) ||
|
||||
Key.getItem().getKind() ==
|
||||
ConstructionContextItem::TemporaryDestructorKind ||
|
||||
State->contains<IndexOfElementToConstruct>({E, LC})) &&
|
||||
State->contains<IndexOfElementToConstruct>(
|
||||
{dyn_cast_or_null<CXXConstructExpr>(Init), LC})) &&
|
||||
"The object is already marked as `UnderConstruction`, when it's not "
|
||||
"supposed to!");
|
||||
return State->set<ObjectsUnderConstruction>(Key, V);
|
||||
@ -2744,7 +2787,10 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
|
||||
|
||||
SVal Base = state->getLValue(DD, LCtx);
|
||||
if (DD->getType()->isReferenceType()) {
|
||||
Base = state->getSVal(Base.getAsRegion());
|
||||
if (const MemRegion *R = Base.getAsRegion())
|
||||
Base = state->getSVal(R);
|
||||
else
|
||||
Base = UnknownVal();
|
||||
}
|
||||
|
||||
SVal V = UnknownVal();
|
||||
@ -2765,15 +2811,27 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
|
||||
|
||||
V = state->getLValue(BD->getType(), Idx, Base);
|
||||
}
|
||||
// Handle binding to tuple-like strcutures
|
||||
else if (BD->getHoldingVar()) {
|
||||
// FIXME: handle tuples
|
||||
return;
|
||||
// Handle binding to tuple-like structures
|
||||
else if (const auto *HV = BD->getHoldingVar()) {
|
||||
V = state->getLValue(HV, LCtx);
|
||||
|
||||
if (HV->getType()->isReferenceType()) {
|
||||
if (const MemRegion *R = V.getAsRegion())
|
||||
V = state->getSVal(R);
|
||||
else
|
||||
V = UnknownVal();
|
||||
}
|
||||
} else
|
||||
llvm_unreachable("An unknown case of structured binding encountered!");
|
||||
|
||||
if (BD->getType()->isReferenceType())
|
||||
V = state->getSVal(V.getAsRegion());
|
||||
// In case of tuple-like types the references are already handled, so we
|
||||
// don't want to handle them again.
|
||||
if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
|
||||
if (const MemRegion *R = V.getAsRegion())
|
||||
V = state->getSVal(R);
|
||||
else
|
||||
V = UnknownVal();
|
||||
}
|
||||
|
||||
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
|
||||
ProgramPoint::PostLValueKind);
|
||||
@ -2797,6 +2855,11 @@ void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
|
||||
const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
|
||||
|
||||
for (auto *Node : CheckerPreStmt) {
|
||||
|
||||
// The constructor visitior has already taken care of everything.
|
||||
if (auto *CE = dyn_cast<CXXConstructExpr>(Ex->getSubExpr()))
|
||||
break;
|
||||
|
||||
const LocationContext *LCtx = Node->getLocationContext();
|
||||
ProgramStateRef state = Node->getState();
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user