Skip to content

Commit

Permalink
Propagate the volatile qualifier of exp to store /load operations .
Browse files Browse the repository at this point in the history
This changes to address the PR : 55207

We update the volatility  on the LValue by looking at the LHS cast operation qualifier and propagate the RValue volatile-ness   from  the CGF data structure .

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D157890
  • Loading branch information
UmeshKalappa authored and Long5hot committed Sep 23, 2023
1 parent b5440e4 commit 2641d9b
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 1 deletion.
13 changes: 13 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3608,6 +3608,19 @@ class CastExpr : public Expr {
return FPOptionsOverride();
}

/// Return
// True : if this conversion changes the volatile-ness of a gl-value.
// Qualification conversions on gl-values currently use CK_NoOp, but
// it's important to recognize volatile-changing conversions in
// clients code generation that normally eagerly peephole loads. Note
// that the query is answering for this specific node; Sema may
// produce multiple cast nodes for any particular conversion sequence.
// False : Otherwise.
bool changesVolatileQualification() const {
return (isGLValue() && (getType().isVolatileQualified() !=
getSubExpr()->getType().isVolatileQualified()));
}

static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType,
QualType opType);
static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4802,6 +4802,9 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
// bound and change the IR type.
// FIXME: Once pointee types are removed from IR, remove this.
LValue LV = EmitLValue(E->getSubExpr());
// Propagate the volatile qualifer to LValue, if exist in E.
if (E->changesVolatileQualification())
LV.getQuals() = E->getType().getQualifiers();
if (LV.isSimple()) {
Address V = LV.getAddress(*this);
if (V.isValid()) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGExprComplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,15 @@ class ComplexExprEmitter
ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
// Unlike for scalars, we don't have to worry about function->ptr demotion
// here.
if (E->changesVolatileQualification())
return EmitLoadOfLValue(E);
return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType());
}
ComplexPairTy VisitCastExpr(CastExpr *E) {
if (const auto *ECE = dyn_cast<ExplicitCastExpr>(E))
CGF.CGM.EmitExplicitCastExprType(ECE, &CGF);
if (E->changesVolatileQualification())
return EmitLoadOfLValue(E);
return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType());
}
ComplexPairTy VisitCallExpr(const CallExpr *E);
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2225,7 +2225,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Visit(const_cast<Expr*>(E));

case CK_NoOp: {
llvm::Value *V = Visit(const_cast<Expr *>(E));
llvm::Value *V = CE->changesVolatileQualification()
? EmitLoadOfLValue(CE)
: Visit(const_cast<Expr *>(E));
if (V) {
// CK_NoOp can model a pointer qualification conversion, which can remove
// an array bound and change the IR type.
Expand Down
43 changes: 43 additions & 0 deletions clang/test/CodeGen/volatile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %clang_cc1 -O2 -triple=x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK
struct agg
{
int a ;
int b ;
} t;
struct agg a;
int vt=10;
_Complex float cf;
int volatile vol =10;
void f0() {
const_cast<volatile _Complex float &>(cf) = const_cast<volatile _Complex float&>(cf) + 1;
// CHECK: %cf.real = load volatile float, ptr @cf
// CHECK: %cf.imag = load volatile float, ptr getelementptr
// CHECK: %add.r = fadd float %cf.real, 1.000000e+00
// CHECK: %add.i = fadd float %cf.imag, 0.000000e+00
// CHECK: store volatile float %add.r
// CHECK: store volatile float %add.i, ptr getelementptr
static_cast<volatile _Complex float &>(cf) = static_cast<volatile _Complex float&>(cf) + 1;
// CHECK: %cf.real1 = load volatile float, ptr @cf
// CHECK: %cf.imag2 = load volatile float, ptr getelementptr
// CHECK: %add.r3 = fadd float %cf.real1, 1.000000e+00
// CHECK: %add.i4 = fadd float %cf.imag2, 0.000000e+00
// CHECK: store volatile float %add.r3, ptr @cf
// CHECK: store volatile float %add.i4, ptr getelementptr
const_cast<volatile int &>(a.a) = const_cast<volatile int &>(t.a) ;
// CHECK: %0 = load volatile i32, ptr @t
// CHECK: store volatile i32 %0, ptr @a
static_cast<volatile int &>(a.b) = static_cast<volatile int &>(t.a) ;
// CHECK: %1 = load volatile i32, ptr @t
// CHECK: store volatile i32 %1, ptr getelementptr
const_cast<volatile int&>(vt) = const_cast<volatile int&>(vt) + 1;
// CHECK: %2 = load volatile i32, ptr @vt
// CHECK: %add = add nsw i32 %2, 1
// CHECK: store volatile i32 %add, ptr @vt
static_cast<volatile int&>(vt) = static_cast<volatile int&>(vt) + 1;
// CHECK: %3 = load volatile i32, ptr @vt
// CHECK: %add5 = add nsw i32 %3, 1
// CHECK: store volatile i32 %add5, ptr @vt
vt = const_cast<int&>(vol);
// %4 = load i32, ptr @vol
// store i32 %4, ptr @vt
}

0 comments on commit 2641d9b

Please sign in to comment.