Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -4805,6 +4805,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->getType().isVolatileQualified()) + LV.getQuals().addVolatile(); 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 @@ -182,6 +182,8 @@ ComplexPairTy VisitCastExpr(CastExpr *E) { if (const auto *ECE = dyn_cast(E)) CGF.CGM.EmitExplicitCastExprType(ECE, &CGF); + if (E->getCastKind() == CK_NoOp && E->getType().isVolatileQualified()) + 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,16 @@ return Visit(const_cast(E)); case CK_NoOp: { - llvm::Value *V = Visit(const_cast(E)); + // Emit the expression as an l-value(if volatile qual exist) and then load from it + // rather than aggressively recursing going through. + // |-ImplicitCastExpr 'int' + // | `-CXXStaticCastExpr 'volatile int' lvalue static_cast + // | `-ImplicitCastExpr 'volatile int' lvalue part_of_explicit_cast + // | `-DeclRefExpr 'int' lvalue Var 'x' 'int' + + llvm::Value *V = CE->getType().isVolatileQualified() + ? 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,41 @@ +// 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; +_Complex float cf; +volatile _Complex float cf1; + +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 +// CHECK1: 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 +}