Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -604,6 +604,11 @@ bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + /// EvaluateAsIntInConstantContext - The same as EvaluteAsInt except we assume + /// that we're in a constant context. + bool EvaluateAsIntInConstantContext(EvalResult &Result, + const ASTContext &Ctx) const; + /// EvaluateAsFloat - Return true if this is a constant which we can fold and /// convert to a floating point value, using any crazy technique that we /// want to. Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -10830,6 +10830,13 @@ return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info); } +bool Expr::EvaluateAsIntInConstantContext(EvalResult &Result, + const ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); + Info.InConstantContext = true; + return ::EvaluateAsInt(this, Result, Ctx, SE_NoSideEffects, Info); +} + bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects) const { if (!getType()->isRealFloatingType()) Index: lib/CodeGen/CGStmt.cpp =================================================================== --- lib/CodeGen/CGStmt.cpp +++ lib/CodeGen/CGStmt.cpp @@ -1821,7 +1821,12 @@ // (immediate or symbolic), try to emit it as such. if (!Info.allowsRegister() && !Info.allowsMemory()) { Expr::EvalResult Result; - if (InputExpr->EvaluateAsInt(Result, getContext())) + bool Success = false; + if (CGM.getCodeGenOpts().OptimizationLevel > 0) + Success = InputExpr->EvaluateAsInt(Result, getContext()); + else + Success = InputExpr->EvaluateAsIntInConstantContext(Result, getContext()); + if (Success) return llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()); assert(!Info.requiresImmediateConstant() && "Required-immediate inlineasm arg isn't constant?"); Index: test/CodeGen/builtin-constant-p.c =================================================================== --- test/CodeGen/builtin-constant-p.c +++ test/CodeGen/builtin-constant-p.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O2 | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O2 | FileCheck --check-prefix=O2 %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O0 | FileCheck --check-prefix=O0 %s int a = 42; @@ -14,8 +15,8 @@ struct foo f = (struct foo){ __builtin_constant_p(y), 42 }; struct foo test0(int expr) { - // CHECK: define i64 @test0(i32 %expr) - // CHECK: call i1 @llvm.is.constant.i32(i32 %expr) + // O2: define i64 @test0(i32 %expr) + // O2: call i1 @llvm.is.constant.i32(i32 %expr) struct foo f = (struct foo){ __builtin_constant_p(expr), 42 }; return f; } @@ -27,15 +28,15 @@ } int test1() { - // CHECK: define i32 @test1 - // CHECK: add nsw i32 %0, -13 - // CHECK-NEXT: call i1 @llvm.is.constant.i32(i32 %sub) + // O2: define i32 @test1 + // O2: add nsw i32 %0, -13 + // O2-NEXT: call i1 @llvm.is.constant.i32(i32 %sub) return bcp(test1_i(&a) - 13); } int test2() { - // CHECK: define i32 @test2 - // CHECK: ret i32 0 + // O2: define i32 @test2 + // O2: ret i32 0 return __builtin_constant_p(&a - 13); } @@ -44,8 +45,8 @@ } int test3() { - // CHECK: define i32 @test3 - // CHECK: ret i32 1 + // O2: define i32 @test3 + // O2: ret i32 1 return bcp(test3_i(&a) - 13); } @@ -54,16 +55,16 @@ int b[] = {1, 2, 3}; int test4() { - // CHECK: define i32 @test4 - // CHECK: ret i32 0 + // O2: define i32 @test4 + // O2: ret i32 0 return __builtin_constant_p(b); } const char test5_c[] = {1, 2, 3, 0}; int test5() { - // CHECK: define i32 @test5 - // CHECK: ret i32 0 + // O2: define i32 @test5 + // O2: ret i32 0 return __builtin_constant_p(test5_c); } @@ -72,16 +73,16 @@ } int test6() { - // CHECK: define i32 @test6 - // CHECK: ret i32 0 + // O2: define i32 @test6 + // O2: ret i32 0 return __builtin_constant_p(test6_i(test5_c)); } /* --- Non-constant global variables */ int test7() { - // CHECK: define i32 @test7 - // CHECK: call i1 @llvm.is.constant.i32(i32 %0) + // O2: define i32 @test7 + // O2: call i1 @llvm.is.constant.i32(i32 %0) return bcp(a); } @@ -90,8 +91,8 @@ const int c = 42; int test8() { - // CHECK: define i32 @test8 - // CHECK: ret i32 1 + // O2: define i32 @test8 + // O2: ret i32 1 return bcp(c); } @@ -101,34 +102,34 @@ const int c_arr[] = { 1, 2, 3 }; int test9() { - // CHECK: define i32 @test9 - // CHECK: call i1 @llvm.is.constant.i32(i32 %0) + // O2: define i32 @test9 + // O2: call i1 @llvm.is.constant.i32(i32 %0) return __builtin_constant_p(arr[2]); } int test10() { - // CHECK: define i32 @test10 - // CHECK: ret i32 1 + // O2: define i32 @test10 + // O2: ret i32 1 return __builtin_constant_p(c_arr[2]); } int test11() { - // CHECK: define i32 @test11 - // CHECK: ret i32 0 + // O2: define i32 @test11 + // O2: ret i32 0 return __builtin_constant_p(c_arr); } /* --- Function pointers */ int test12() { - // CHECK: define i32 @test12 - // CHECK: ret i32 0 + // O2: define i32 @test12 + // O2: ret i32 0 return __builtin_constant_p(&test10); } int test13() { - // CHECK: define i32 @test13 - // CHECK: ret i32 1 + // O2: define i32 @test13 + // O2: ret i32 1 return __builtin_constant_p(&test10 != 0); } @@ -166,3 +167,13 @@ extern char test16_v; struct { int a; } test16 = { __builtin_constant_p(test16_v) }; + +extern unsigned long long test17_v; + +void test17() { + // O0: define void @test17 + // O0: call void asm sideeffect "", {{.*}}(i32 -1) + // O0: call void asm sideeffect "", {{.*}}(i32 -1) + __asm__ __volatile__("" :: "n"( (__builtin_constant_p(test17_v) || 0) ? 1 : -1)); + __asm__ __volatile__("" :: "i"( (__builtin_constant_p(test17_v) || 0) ? 1 : -1)); +}