Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d249e67
[libc][math] Disable `FEnvSafeTest.cpp` if AArch64 target has no FP s…
vhscampos Nov 5, 2025
fedd3b0
[clang][bytecode] Remove dummy variables once they are proper globals…
tbaederr Nov 5, 2025
e856483
[clang-tidy][doc] add more information in twine-local's document (#16…
HerrCai0907 Nov 5, 2025
c1dc064
[CIR] Add support for storing into _Atomic variables (#165872)
Lancern Nov 5, 2025
a38e094
[mlir] Dialect Conversion: Add support for post-order legalization or…
matthias-springer Nov 5, 2025
6c640b8
[mlir][LLVM] Fix unsupported FP lowering in `VectorConvertToLLVMPatte…
matthias-springer Nov 5, 2025
c782ed3
[utils][UpdateLLCTestChecks] Add MIR support to update_llc_test_check…
vpykhtin Nov 5, 2025
a410570
[llvm][LoongArch] Introduce LASX and LSX conversion intrinsics (#157818)
heiher Nov 5, 2025
04c01f0
[gn] port 0c7300923638403
nico Nov 5, 2025
0d77cba
[libc][math] Refactor exp2m1f16 implementation to header-only in src/…
bassiounix Nov 5, 2025
98ca2e8
[clang-tidy][NFC] Fix broken link in `bugprone-default-operator-new-o…
zeyi2 Nov 5, 2025
a389472
[Clang][NFC] Refactor SemaCXX/dllexport.cpp to use -verify= instead o…
philnik777 Nov 5, 2025
b675c0c
[RISCV] Add a test for multiple save locations of a callee-saved regi…
mgudim Nov 5, 2025
1de55c9
[VPlan] Avoid sinking allocas in sinkScalarOperands (#166135)
artagnon Nov 5, 2025
305cf62
[Polly] Check for ISL errors after schedule optimization (#166551)
Meinersbur Nov 5, 2025
ba1dbdd
Revert "[utils][UpdateLLCTestChecks] Add MIR support to update_llc_te…
vpykhtin Nov 5, 2025
438a18c
[X86] Add test coverage for #166534 (#166552)
RKSimon Nov 5, 2025
5fedb7c
[Clang][ARM] Fix tests using thumb instead arm arch on cc1 (#166416)
tomershafir Nov 5, 2025
dd14eb8
[RISCV] Introduce pass to promote double constants to a global array …
asb Nov 5, 2025
8ccff62
merge main into amd-staging
z1-cciauto Nov 5, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cert-mem57-cpp
==============

The `cert-mem57-cpp` is an aliaes, please see
`bugprone-default-operator-new-on-overaligned-type <../bugprone/default-operator-new-on-overaligned-type>`_
`bugprone-default-operator-new-on-overaligned-type <../bugprone/default-operator-new-on-overaligned-type.html>`_
for more information.

This check corresponds to the CERT C++ Coding Standard rule
Expand Down
18 changes: 18 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/llvm/twine-local.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,21 @@ should be generally avoided.
// becomes

static std::string Moo = (Twine("bark") + "bah").str();

The ``Twine`` does not own the memory of its contents, so it is not
recommended to use ``Twine`` created from temporary strings or string literals.

.. code-block:: c++

static Twine getModuleIdentifier(StringRef moduleName) {
return moduleName + "_module";
}
void foo() {
Twine result = getModuleIdentifier(std::string{"abc"} + "def");
// temporary std::string is destroyed here, result is dangling
}

After applying this fix-it hints, the code will use ``std::string`` instead of
``Twine`` for local variables. However, ``Twine`` has lots of methods that
are incompatible with ``std::string``, so the user may need to adjust the code
manually after applying the fix-it hints.
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ struct MissingFeatures {
static bool atomicSyncScopeID() { return false; }
static bool atomicTypes() { return false; }
static bool atomicUseLibCall() { return false; }
static bool atomicMicrosoftVolatile() { return false; }
static bool atomicOpenMP() { return false; }

// Global ctor handling
static bool globalCtorLexOrder() { return false; }
Expand Down
29 changes: 25 additions & 4 deletions clang/lib/AST/ByteCode/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,21 +218,42 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) {
return std::nullopt;

Global *NewGlobal = Globals[*Idx];
// Note that this loop has one iteration where Redecl == VD.
for (const Decl *Redecl : VD->redecls()) {
unsigned &PIdx = GlobalIndices[Redecl];

// If this redecl was registered as a dummy variable, it is now a proper
// global variable and points to the block we just created.
if (auto DummyIt = DummyVariables.find(Redecl);
DummyIt != DummyVariables.end()) {
assert(!Globals[DummyIt->second]->block()->hasPointers());
Globals[DummyIt->second] = NewGlobal;
DummyVariables.erase(DummyIt);
}
// If the redeclaration hasn't been registered yet at all, we just set its
// global index to Idx. If it has been registered yet, it might have
// pointers pointing to it and we need to transfer those pointers to the new
// block.
auto [Iter, Inserted] = GlobalIndices.try_emplace(Redecl);
if (Inserted) {
GlobalIndices[Redecl] = *Idx;
continue;
}

if (Redecl != VD) {
if (Block *RedeclBlock = Globals[PIdx]->block();
if (Block *RedeclBlock = Globals[Iter->second]->block();
RedeclBlock->isExtern()) {
Globals[PIdx] = NewGlobal;

// All pointers pointing to the previous extern decl now point to the
// new decl.
// A previous iteration might've already fixed up the pointers for this
// global.
if (RedeclBlock != NewGlobal->block())
RedeclBlock->movePointersTo(NewGlobal->block());

Globals[Iter->second] = NewGlobal;
}
}
PIdx = *Idx;
Iter->second = *Idx;
}

return *Idx;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/ByteCode/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ class Program final {
const Block *block() const { return &B; }

private:
/// Required metadata - does not actually track pointers.
Block B;
};

Expand Down
121 changes: 118 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class AtomicInfo {
CharUnits atomicAlign;
CharUnits valueAlign;
TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
bool useLibCall = true;
LValue lvalue;
mlir::Location loc;

Expand Down Expand Up @@ -62,8 +63,8 @@ class AtomicInfo {
assert(!cir::MissingFeatures::atomicInfo());
cgf.cgm.errorNYI(loc, "AtomicInfo: non-simple lvalue");
}

assert(!cir::MissingFeatures::atomicUseLibCall());
useLibCall = !ctx.getTargetInfo().hasBuiltinAtomic(
atomicSizeInBits, ctx.toBits(lvalue.getAlignment()));
}

QualType getValueType() const { return valueTy; }
Expand All @@ -75,6 +76,8 @@ class AtomicInfo {
assert(!cir::MissingFeatures::atomicInfoGetAtomicPointer());
return nullptr;
}
bool shouldUseLibCall() const { return useLibCall; }
const LValue &getAtomicLValue() const { return lvalue; }
Address getAtomicAddress() const {
mlir::Type elemTy;
if (lvalue.isSimple()) {
Expand All @@ -96,6 +99,8 @@ class AtomicInfo {

bool emitMemSetZeroIfNecessary() const;

mlir::Value getScalarRValValueOrNull(RValue rvalue) const;

/// Cast the given pointer to an integer pointer suitable for atomic
/// operations on the source.
Address castToAtomicIntPointer(Address addr) const;
Expand All @@ -105,6 +110,9 @@ class AtomicInfo {
/// copy the value across.
Address convertToAtomicIntPointer(Address addr) const;

/// Converts a rvalue to integer value.
mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;

/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue) const;

Expand Down Expand Up @@ -195,6 +203,12 @@ Address AtomicInfo::createTempAlloca() const {
return tempAlloca;
}

mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue) const {
if (rvalue.isScalar() && (!hasPadding() || !lvalue.isSimple()))
return rvalue.getValue();
return nullptr;
}

Address AtomicInfo::castToAtomicIntPointer(Address addr) const {
auto intTy = mlir::dyn_cast<cir::IntType>(addr.getElementType());
// Don't bother with int casts if the integer size is the same.
Expand All @@ -211,10 +225,38 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
return false;

cgf.cgm.errorNYI(loc,
"AtomicInfo::emitMemSetZeroIfNecessary: emit memset zero");
"AtomicInfo::emitMemSetZeroIfNecaessary: emit memset zero");
return false;
}

/// Return true if \param valueTy is a type that should be casted to integer
/// around the atomic memory operation. If \param cmpxchg is true, then the
/// cast of a floating point type is made as that instruction can not have
/// floating point operands. TODO: Allow compare-and-exchange and FP - see
/// comment in CIRGenAtomicExpandPass.cpp.
static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
if (cir::isAnyFloatingPointType(valueTy))
return isa<cir::FP80Type>(valueTy) || cmpxchg;
return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
}

mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
// If we've got a scalar value of the right size, try to avoid going
// through memory. Floats get casted if needed by AtomicExpandPass.
if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
if (!shouldCastToInt(value.getType(), cmpxchg))
return cgf.emitToMemory(value, valueTy);

cgf.cgm.errorNYI(
loc, "AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
return nullptr;
}

cgf.cgm.errorNYI(
loc, "AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
return nullptr;
}

/// Copy an r-value into memory as part of storing to an atomic type.
/// This needs to create a bit-pattern suitable for atomic operations.
void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
Expand Down Expand Up @@ -815,6 +857,79 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
e->getExprLoc());
}

void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
bool isVolatile = dest.isVolatileQualified();
auto order = cir::MemOrder::SequentiallyConsistent;
if (!dest.getType()->isAtomicType()) {
assert(!cir::MissingFeatures::atomicMicrosoftVolatile());
}
return emitAtomicStore(rvalue, dest, order, isVolatile, isInit);
}

/// Emit a store to an l-value of atomic type.
///
/// Note that the r-value is expected to be an r-value of the atomic type; this
/// means that for aggregate r-values, it should include storage for any padding
/// that was necessary.
void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest,
cir::MemOrder order, bool isVolatile,
bool isInit) {
// If this is an aggregate r-value, it should agree in type except
// maybe for address-space qualification.
mlir::Location loc = dest.getPointer().getLoc();
assert(!rvalue.isAggregate() ||
rvalue.getAggregateAddress().getElementType() ==
dest.getAddress().getElementType());

AtomicInfo atomics(*this, dest, loc);
LValue lvalue = atomics.getAtomicLValue();

if (lvalue.isSimple()) {
// If this is an initialization, just put the value there normally.
if (isInit) {
atomics.emitCopyIntoMemory(rvalue);
return;
}

// Check whether we should use a library call.
if (atomics.shouldUseLibCall()) {
assert(!cir::MissingFeatures::atomicUseLibCall());
cgm.errorNYI(loc, "emitAtomicStore: atomic store with library call");
return;
}

// Okay, we're doing this natively.
mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);

// Do the atomic store.
Address addr = atomics.getAtomicAddress();
if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
if (shouldCastToInt(value.getType(), /*CmpXchg=*/false)) {
addr = atomics.castToAtomicIntPointer(addr);
valueToStore =
builder.createIntCast(valueToStore, addr.getElementType());
}
}
cir::StoreOp store = builder.createStore(loc, valueToStore, addr);

// Initializations don't need to be atomic.
if (!isInit) {
assert(!cir::MissingFeatures::atomicOpenMP());
store.setMemOrder(order);
}

// Other decoration.
if (isVolatile)
store.setIsVolatile(true);

assert(!cir::MissingFeatures::opLoadStoreTbaa());
return;
}

cgm.errorNYI(loc, "emitAtomicStore: non-simple atomic lvalue");
assert(!cir::MissingFeatures::opLoadStoreAtomic());
}

void CIRGenFunction::emitAtomicInit(Expr *init, LValue dest) {
AtomicInfo atomics(*this, dest, getLoc(init->getSourceRange()));

Expand Down
14 changes: 11 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,8 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e,

void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
bool isVolatile, QualType ty,
bool isInit, bool isNontemporal) {
LValueBaseInfo baseInfo, bool isInit,
bool isNontemporal) {
assert(!cir::MissingFeatures::opLoadStoreThreadLocal());

if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) {
Expand All @@ -333,7 +334,13 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,

value = emitToMemory(value, ty);

assert(!cir::MissingFeatures::opLoadStoreAtomic());
assert(!cir::MissingFeatures::opLoadStoreTbaa());
LValue atomicLValue = LValue::makeAddr(addr, ty, baseInfo);
if (ty->isAtomicType() ||
(!isInit && isLValueSuitableForInlineAtomic(atomicLValue))) {
emitAtomicStore(RValue::get(value), atomicLValue, isInit);
return;
}

// Update the alloca with more info on initialization.
assert(addr.getPointer() && "expected pointer to exist");
Expand Down Expand Up @@ -550,7 +557,8 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, LValue lvalue,
}

emitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getType(), isInit, /*isNontemporal=*/false);
lvalue.getType(), lvalue.getBaseInfo(), isInit,
/*isNontemporal=*/false);
}

mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile,
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,9 @@ class CIRGenFunction : public CIRGenTypeCache {

RValue emitAtomicExpr(AtomicExpr *e);
void emitAtomicInit(Expr *init, LValue dest);
void emitAtomicStore(RValue rvalue, LValue dest, bool isInit);
void emitAtomicStore(RValue rvalue, LValue dest, cir::MemOrder order,
bool isVolatile, bool isInit);

AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
mlir::OpBuilder::InsertPoint ip = {});
Expand Down Expand Up @@ -1680,8 +1683,8 @@ class CIRGenFunction : public CIRGenTypeCache {
bool isInit);

void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile,
clang::QualType ty, bool isInit = false,
bool isNontemporal = false);
clang::QualType ty, LValueBaseInfo baseInfo,
bool isInit = false, bool isNontemporal = false);
void emitStoreOfScalar(mlir::Value value, LValue lvalue, bool isInit);

/// Store the specified rvalue into the specified
Expand Down
11 changes: 11 additions & 0 deletions clang/test/AST/ByteCode/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1882,3 +1882,14 @@ namespace MethodWillHaveBody {
}
int n = f(0); // both-note {{instantiation of}}
}

namespace StaticRedecl {
struct T {
static T tt;
constexpr T() : p(&tt) {}
T *p;
};
T T::tt;
constexpr T t;
static_assert(t.p == &T::tt, "");
}
6 changes: 3 additions & 3 deletions clang/test/AST/ast-dump-arm-attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// RUN: %clang_cc1 -triple arm-apple-darwin -ast-dump -ast-dump-filter Test %s \
// RUN: | FileCheck --strict-whitespace %s
//
// RUN: %clang_cc1 -triple armv8m.base-none-eabi -mcmse -ast-dump -ast-dump-filter Test %s \
// RUN: %clang_cc1 -triple thumbv8m.base-none-eabi -mcmse -ast-dump -ast-dump-filter Test %s \
// RUN: | FileCheck --strict-whitespace %s --check-prefix=CHECK-CMSE
//
// Tests with serialization:
Expand All @@ -11,8 +11,8 @@
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --strict-whitespace %s
//
// RUN: %clang_cc1 -triple armv8m.base-none-eabi -mcmse -emit-pch -o %t %s
// RUN: %clang_cc1 -x c -triple armv8m.base-none-eabi -mcmse -include-pch %t -ast-dump-all -ast-dump-filter Test /dev/null \
// RUN: %clang_cc1 -triple thumbv8m.base-none-eabi -mcmse -emit-pch -o %t %s
// RUN: %clang_cc1 -x c -triple thumbv8m.base-none-eabi -mcmse -include-pch %t -ast-dump-all -ast-dump-filter Test /dev/null \
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --strict-whitespace %s

Expand Down
26 changes: 26 additions & 0 deletions clang/test/CIR/CodeGen/atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,32 @@ void f2(void) {
// OGCG-NEXT: store i32 42, ptr %[[SLOT]], align 4
// OGCG: }

void f3(_Atomic(int) *p) {
*p = 42;
}

// CIR-LABEL: @f3
// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i>

// LLVM-LABEL: @f3
// LLVM: store atomic i32 42, ptr %{{.+}} seq_cst, align 4

// OGCG-LABEL: @f3
// OGCG: store atomic i32 42, ptr %{{.+}} seq_cst, align 4

void f4(_Atomic(float) *p) {
*p = 3.14;
}

// CIR-LABEL: @f4
// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !cir.float, !cir.ptr<!cir.float>

// LLVM-LABEL: @f4
// LLVM: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4

// OGCG-LABEL: @f4
// OGCG: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4

void load(int *ptr) {
int x;
__atomic_load(ptr, &x, __ATOMIC_RELAXED);
Expand Down
Loading