Skip to content

[RFC] Add clang atomic control options and pragmas #102569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ class alignas(void *) Stmt {
LLVM_PREFERRED_TYPE(bool)
unsigned HasFPFeatures : 1;

/// True if the compound statement has one or more pragmas that set some
/// atomic options.
LLVM_PREFERRED_TYPE(bool)
unsigned HasAtomicOptions : 1;

unsigned NumStmts;
};

Expand Down Expand Up @@ -1603,7 +1608,8 @@ class NullStmt : public Stmt {
/// CompoundStmt - This represents a group of statements like { stmt stmt }.
class CompoundStmt final
: public Stmt,
private llvm::TrailingObjects<CompoundStmt, Stmt *, FPOptionsOverride> {
private llvm::TrailingObjects<CompoundStmt, Stmt *, FPOptionsOverride,
AtomicOptionsOverride> {
friend class ASTStmtReader;
friend TrailingObjects;

Expand All @@ -1614,7 +1620,8 @@ class CompoundStmt final
SourceLocation RBraceLoc;

CompoundStmt(ArrayRef<Stmt *> Stmts, FPOptionsOverride FPFeatures,
SourceLocation LB, SourceLocation RB);
AtomicOptionsOverride AtomicOptions, SourceLocation LB,
SourceLocation RB);
explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty) {}

void setStmts(ArrayRef<Stmt *> Stmts);
Expand All @@ -1625,13 +1632,24 @@ class CompoundStmt final
*getTrailingObjects<FPOptionsOverride>() = F;
}

/// Set AtomicOptionsOverride in trailing storage. Used only by Serialization.
void setStoredAtomicOptions(AtomicOptionsOverride A) {
assert(hasStoredAtomicOptions());
*getTrailingObjects<AtomicOptionsOverride>() = A;
}

size_t numTrailingObjects(OverloadToken<Stmt *>) const {
return CompoundStmtBits.NumStmts;
}

size_t numTrailingObjects(OverloadToken<FPOptionsOverride>) const {
return CompoundStmtBits.HasFPFeatures;
}

public:
static CompoundStmt *Create(const ASTContext &C, ArrayRef<Stmt *> Stmts,
FPOptionsOverride FPFeatures, SourceLocation LB,
FPOptionsOverride FPFeatures,
AtomicOptionsOverride, SourceLocation LB,
SourceLocation RB);

// Build an empty compound statement with a location.
Expand All @@ -1641,16 +1659,20 @@ class CompoundStmt final
: Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(EndLoc) {
CompoundStmtBits.NumStmts = 0;
CompoundStmtBits.HasFPFeatures = 0;
CompoundStmtBits.HasAtomicOptions = 0;
}

// Build an empty compound statement.
static CompoundStmt *CreateEmpty(const ASTContext &C, unsigned NumStmts,
bool HasFPFeatures);
bool HasFPFeatures, bool HasAtomicOptions);

bool body_empty() const { return CompoundStmtBits.NumStmts == 0; }
unsigned size() const { return CompoundStmtBits.NumStmts; }

bool hasStoredFPFeatures() const { return CompoundStmtBits.HasFPFeatures; }
bool hasStoredAtomicOptions() const {
return CompoundStmtBits.HasAtomicOptions;
}

/// Get FPOptionsOverride from trailing storage.
FPOptionsOverride getStoredFPFeatures() const {
Expand All @@ -1663,6 +1685,18 @@ class CompoundStmt final
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}

/// Get AtomicOptionsOverride from trailing storage.
AtomicOptionsOverride getStoredAtomicOptions() const {
assert(hasStoredAtomicOptions());
return *getTrailingObjects<AtomicOptionsOverride>();
}

/// Get the stored AtomicOptionsOverride or default if not stored.
AtomicOptionsOverride getStoredAtomicOptionsOrDefault() const {
return hasStoredAtomicOptions() ? getStoredAtomicOptions()
: AtomicOptionsOverride();
}

using body_iterator = Stmt **;
using body_range = llvm::iterator_range<body_iterator>;

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class TextNodeDumper

const char *getCommandName(unsigned CommandID);
void printFPOptions(FPOptionsOverride FPO);
void printAtomicOptions(AtomicOptionsOverride AO);

void dumpAPValueChildren(const APValue &Value, QualType Ty,
const APValue &(*IdxToChildFun)(const APValue &,
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Basic/AtomicOptions.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===--- AtomicOptions.def - Atomic Options database -------------*- 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 Atomic language options. Users of this file
// must define the OPTION macro to make use of this information.
#ifndef OPTION
# error Define the OPTION macro to handle atomic language options
#endif

// OPTION(name, type, width, previousName)
OPTION(NoRemoteMemory, bool, 1, First)
OPTION(NoFineGrainedMemory, bool, 1, NoRemoteMemory)
OPTION(IgnoreDenormalMode, bool, 1, NoFineGrainedMemory)

#undef OPTION
Copy link
Contributor

Choose a reason for hiding this comment

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

End of file missing line error

7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">;
def err_drv_invalid_value_with_suggestion : Error<
"invalid value '%1' in '%0', expected one of: %2">;
def err_drv_alignment_not_power_of_two : Error<"alignment is not a power of 2 in '%0'">;

def err_drv_invalid_atomic_option : Error<
"invalid argument '%0' to -fatomic=; must be a "
"comma-separated list of key:value pairs, where allowed keys are "
"'no_fine_grained_memory', 'no_remote_memory', 'ignore_denormal_mode', "
"and values are 'on' or 'off', and each key must be unique">;

def err_drv_invalid_remap_file : Error<
"invalid option '%0' not of the form <from-file>;<to-file>">;
def err_drv_invalid_gcc_install_dir : Error<"'%0' does not contain a GCC installation">;
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,9 @@ def warn_pragma_init_seg_unsupported_target : Warning<
def err_pragma_file_or_compound_scope : Error<
"'#pragma %0' can only appear at file scope or at the start of a "
"compound statement">;
// - #pragma restricted to start of compound statement
def err_pragma_compound_scope : Error<
"'#pragma %0' can only appear at the start of a compound statement">;
// - #pragma stdc unknown
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
InGroup<UnknownPragmas>;
Expand Down Expand Up @@ -1655,6 +1658,12 @@ def err_pragma_fp_invalid_argument : Error<
"'ignore', 'maytrap' or 'strict'|"
"'source', 'double' or 'extended'}2">;

def err_pragma_atomic_invalid_option : Error<
"%select{invalid|missing}0 option%select{ %1|}0; expected 'no_remote_memory', 'no_fine_grained_memory', or 'ignore_denormal_mode'">;

def err_pragma_atomic_invalid_argument : Error<
"unexpected argument '%0' to '#pragma clang atomic %1'; expected 'on' or 'off'">;

def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
def err_pragma_pipeline_invalid_keyword : Error<
Expand Down
167 changes: 167 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,10 @@ class LangOptions : public LangOptionsBase {
// WebAssembly target.
bool NoWasmOpt = false;

/// The default atomic codegen options specified by command line in the
/// format of key:{on|off}.
std::vector<std::string> AtomicOptionsAsWritten;

LangOptions();

/// Set language defaults for the given input language and
Expand Down Expand Up @@ -1034,6 +1038,169 @@ inline void FPOptions::applyChanges(FPOptionsOverride FPO) {
*this = FPO.applyOverrides(*this);
}

/// Atomic control options
class AtomicOptionsOverride;
class AtomicOptions {
public:
using storage_type = uint16_t;

static constexpr unsigned StorageBitSize = 8 * sizeof(storage_type);

static constexpr storage_type FirstShift = 0, FirstWidth = 0;
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
static constexpr storage_type NAME##Shift = \
PREVIOUS##Shift + PREVIOUS##Width; \
static constexpr storage_type NAME##Width = WIDTH; \
static constexpr storage_type NAME##Mask = ((1 << NAME##Width) - 1) \
<< NAME##Shift;
#include "clang/Basic/AtomicOptions.def"

static constexpr storage_type TotalWidth = 0
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) +WIDTH
#include "clang/Basic/AtomicOptions.def"
;
static_assert(TotalWidth <= StorageBitSize,
"Too short type for AtomicOptions");

private:
storage_type Value;

AtomicOptionsOverride getChangesSlow(const AtomicOptions &Base) const;

public:
AtomicOptions() : Value(0) {
setNoRemoteMemory(false);
setNoFineGrainedMemory(false);
setIgnoreDenormalMode(false);
}
explicit AtomicOptions(const LangOptions &LO) {
Value = 0;
#if 0
Copy link
Contributor

Choose a reason for hiding this comment

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

Disabled code

setNoRemoteMemory(LO.NoRemoteMemoryAccess);
setNoFineGrainedMemory(LO.NoFineGrainedMemoryAccess);
setIgnoreDenormalMode(LO.IgnoreDenormals);
#endif
}

bool operator==(AtomicOptions other) const { return Value == other.Value; }

/// Return the default value of AtomicOptions that's used when trailing
/// storage isn't required.
static AtomicOptions defaultWithoutTrailingStorage(const LangOptions &LO);

storage_type getAsOpaqueInt() const { return Value; }
static AtomicOptions getFromOpaqueInt(storage_type Value) {
AtomicOptions Opts;
Opts.Value = Value;
return Opts;
}

/// Return difference with the given option set.
AtomicOptionsOverride getChangesFrom(const AtomicOptions &Base) const;

void applyChanges(AtomicOptionsOverride AO);

#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
TYPE get##NAME() const { \
return static_cast<TYPE>((Value & NAME##Mask) >> NAME##Shift); \
} \
void set##NAME(TYPE value) { \
Value = (Value & ~NAME##Mask) | (storage_type(value) << NAME##Shift); \
}
#include "clang/Basic/AtomicOptions.def"
LLVM_DUMP_METHOD void dump();
};

/// Represents difference between two AtomicOptions values.
class AtomicOptionsOverride {
AtomicOptions Options = AtomicOptions::getFromOpaqueInt(0);
AtomicOptions::storage_type OverrideMask = 0;

public:
/// The type suitable for storing values of AtomicOptionsOverride. Must be
/// twice as wide as bit size of AtomicOption.
using storage_type = uint32_t;
static_assert(sizeof(storage_type) >= 2 * sizeof(AtomicOptions::storage_type),
"Too short type for AtomicOptionsOverride");

/// Bit mask selecting bits of OverrideMask in serialized representation of
/// AtomicOptionsOverride.
static constexpr storage_type OverrideMaskBits =
(static_cast<storage_type>(1) << AtomicOptions::StorageBitSize) - 1;

AtomicOptionsOverride() {}
AtomicOptionsOverride(const LangOptions &LO);
AtomicOptionsOverride(AtomicOptions AO)
: Options(AO), OverrideMask(OverrideMaskBits) {}
AtomicOptionsOverride(AtomicOptions AO, AtomicOptions::storage_type Mask)
: Options(AO), OverrideMask(Mask) {}

bool requiresTrailingStorage() const { return OverrideMask != 0; }

storage_type getAsOpaqueInt() const {
return (static_cast<storage_type>(Options.getAsOpaqueInt())
<< AtomicOptions::StorageBitSize) |
OverrideMask;
}

static AtomicOptionsOverride getFromOpaqueInt(storage_type I) {
AtomicOptionsOverride Opts;
Opts.OverrideMask = I & OverrideMaskBits;
Opts.Options =
AtomicOptions::getFromOpaqueInt(I >> AtomicOptions::StorageBitSize);
return Opts;
}

AtomicOptions applyOverrides(AtomicOptions Base) {
AtomicOptions Result = AtomicOptions::getFromOpaqueInt(
(Base.getAsOpaqueInt() & ~OverrideMask) |
(Options.getAsOpaqueInt() & OverrideMask));
return Result;
}

AtomicOptions applyOverrides(const LangOptions &LO) {
return applyOverrides(AtomicOptions(LO));
}

bool operator==(AtomicOptionsOverride other) const {
return Options == other.Options && OverrideMask == other.OverrideMask;
}
bool operator!=(AtomicOptionsOverride other) const {
return !(*this == other);
}

#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
bool has##NAME##Override() const { \
return OverrideMask & AtomicOptions::NAME##Mask; \
} \
TYPE get##NAME##Override() const { \
assert(has##NAME##Override()); \
return Options.get##NAME(); \
} \
void clear##NAME##Override() { \
Options.set##NAME(TYPE(0)); \
OverrideMask &= ~AtomicOptions::NAME##Mask; \
} \
void set##NAME##Override(TYPE value) { \
Options.set##NAME(value); \
OverrideMask |= AtomicOptions::NAME##Mask; \
}
#include "clang/Basic/AtomicOptions.def"

LLVM_DUMP_METHOD void dump();
};

inline AtomicOptionsOverride
AtomicOptions::getChangesFrom(const AtomicOptions &Base) const {
if (Value == Base.Value)
return AtomicOptionsOverride();
return getChangesSlow(Base);
}

inline void AtomicOptions::applyChanges(AtomicOptionsOverride AO) {
*this = AO.applyOverrides(*this);
}

/// Describes the kind of translation unit being processed.
enum TranslationUnitKind {
/// The translation unit is a complete translation unit.
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/PragmaKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ enum PragmaFPKind {
PFK_Exceptions, // #pragma clang fp exceptions
PFK_EvalMethod // #pragma clang fp eval_method
};

enum PragmaAtomicKind {
PAK_NoRemoteMemory, // #prama clang atomic begin(no_remote_memory:on)
PAK_NoFineGrainedMemory, // #pragma clang atomic
// begin(no_fine_grained_memory:on)
PAK_IgnoreDenormalMode, // #pragma clang atomic begin(ignore_denormal_mode:on)
};
}

#endif
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ class TargetInfo : public TransferrableTargetInfo,
// in function attributes in IR.
llvm::StringSet<> ReadOnlyFeatures;

// Default atomic options
AtomicOptions AtomicOpts;

public:
/// Construct a target for the given options.
///
Expand Down Expand Up @@ -1680,6 +1683,9 @@ class TargetInfo : public TransferrableTargetInfo,
return CC_C;
}

/// Get the default atomic options.
AtomicOptions getAtomicOpts() const { return AtomicOpts; }

enum CallingConvCheckResult {
CCCR_OK,
CCCR_Warning,
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,8 @@ PRAGMA_ANNOTATION(pragma_loop_hint)

PRAGMA_ANNOTATION(pragma_fp)

PRAGMA_ANNOTATION(pragma_atomic)

// Annotation for the attribute pragma directives - #pragma clang attribute ...
PRAGMA_ANNOTATION(pragma_attribute)

Expand Down
Loading
Loading