Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -3608,6 +3608,19 @@ 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, Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -4802,6 +4802,9 @@ // 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()) { Index: clang/lib/CodeGen/CGExprComplex.cpp =================================================================== --- clang/lib/CodeGen/CGExprComplex.cpp +++ clang/lib/CodeGen/CGExprComplex.cpp @@ -177,11 +177,15 @@ 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(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); Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -2225,7 +2225,9 @@ return Visit(const_cast(E)); case CK_NoOp: { - llvm::Value *V = Visit(const_cast(E)); + llvm::Value *V = CE->changesVolatileQualification() + ? EmitLoadOfLValue(CE) + : Visit(const_cast(E)); if (V) { // CK_NoOp can model a pointer qualification conversion, which can remove // an array bound and change the IR type. Index: clang/test/CodeGen/volatile.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/volatile.cpp @@ -0,0 +1,44 @@ +// 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 vol =10; +void f0() { + const_cast(cf) = const_cast(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(cf) = static_cast(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(a.a) = const_cast(t.a) ; +// CHECK: %0 = load volatile i32, ptr @t +// CHECK: store volatile i32 %0, ptr @a + static_cast(a.b) = static_cast(t.a) ; +// CHECK: %1 = load volatile i32, ptr @t +// CHECK: store volatile i32 %1, ptr getelementptr + const_cast(vt) = const_cast(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(vt) = static_cast(vt) + 1; +// CHECK: %3 = load volatile i32, ptr @vt +// CHECK: %add5 = add nsw i32 %3, 1 +// CHECK: store volatile i32 %add5, ptr @vt + static_cast(vol) = static_cast(vol) + 1; +// CHECK: %4 = load i32, ptr @vol +// CHECK: %add6 = add nsw i32 %4, 1 +// CHECK: store i32 %add6, ptr @vol +}