Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -802,6 +802,8 @@ def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group; def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group; def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group; +def fno_strict_shifts : Flag<["-"], "fno-strict-shifts">, Group, + Flags<[CC1Option]>; def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group; def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group, Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">; @@ -928,6 +930,9 @@ def fstrict_enums : Flag<["-"], "fstrict-enums">, Group, Flags<[CC1Option]>, HelpText<"Enable optimizations based on the strict definition of an enum's " "value range">; +def fstrict_shifts : Flag<["-"], "fstrict-shifts">, Group, + HelpText<"Enable optimizations based on the strict definition of the operands" + " that may be correctly passed to a shift operation">; def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group; def fsyntax_only : Flag<["-"], "fsyntax-only">, Flags<[DriverOption,CC1Option]>, Group; def ftabstop_EQ : Joined<["-"], "ftabstop=">, Group; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -116,6 +116,7 @@ CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. +CODEGENOPT(StrictShifts , 1, 0) ///< Optimize based on strict shift definition. CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled. CODEGENOPT(UnitAtATime , 1, 1) ///< Unused. For mirroring GCC optimization ///< selection. Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -2716,6 +2716,7 @@ bool SanitizeBase = CGF.SanOpts.has(SanitizerKind::ShiftBase) && Ops.Ty->hasSignedIntegerRepresentation(); bool SanitizeExponent = CGF.SanOpts.has(SanitizerKind::ShiftExponent); + bool HasNUW = false; // OpenCL 6.3j: shift values are effectively % word size of LHS. if (CGF.getLangOpts().OpenCL) RHS = @@ -2765,9 +2766,11 @@ assert(!Checks.empty()); EmitBinOpCheck(Checks, Ops); + } else { + HasNUW = Ops.Ty->isSignedIntegerOrEnumerationType() && + CGF.CGM.getCodeGenOpts().StrictShifts; } - - return Builder.CreateShl(Ops.LHS, RHS, "shl"); + return Builder.CreateShl(Ops.LHS, RHS, "shl", HasNUW); } Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -2949,6 +2949,8 @@ if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); + if (!Args.hasFlag(options::OPT_fstrict_shifts, options::OPT_fno_strict_shifts)) + CmdArgs.push_back("-fno-strict-shifts"); if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -464,6 +464,7 @@ Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.StrictEnums = Args.hasArg(OPT_fstrict_enums); + Opts.StrictShifts = !Args.hasArg(OPT_fno_strict_shifts); Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); Index: test/CodeGen/compound-type.c =================================================================== --- test/CodeGen/compound-type.c +++ test/CodeGen/compound-type.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 < %s -emit-llvm -triple i686-pc-linux-gnu > %t // RUN: grep "div i32" %t -// RUN: grep "shl i32" %t +// RUN: grep "shl nuw i32" %t unsigned char a,b; void c(void) {a <<= b;} Index: test/OpenMP/atomic_update_codegen.cpp =================================================================== --- test/OpenMP/atomic_update_codegen.cpp +++ test/OpenMP/atomic_update_codegen.cpp @@ -125,7 +125,7 @@ // CHECK: br label %[[CONT:.+]] // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i32 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] -// CHECK: [[DESIRED:%.+]] = shl i32 [[EXPECTED]], [[EXPR]] +// CHECK: [[DESIRED:%.+]] = shl nuw i32 [[EXPECTED]], [[EXPR]] // CHECK: [[RES:%.+]] = cmpxchg i32* [[X_ADDR]], i32 [[EXPECTED]], i32 [[DESIRED]] monotonic monotonic // CHECK: [[OLD_X]] = extractvalue { i32, i1 } [[RES]], 0 // CHECK: [[SUCCESS_FAIL:%.+]] = extractvalue { i32, i1 } [[RES]], 1 @@ -432,7 +432,7 @@ // CHECK: [[CONT]] // CHECK: [[EXPECTED:%.+]] = phi i64 [ [[X]], %{{.+}} ], [ [[OLD_X:%.+]], %[[CONT]] ] // CHECK: [[X_RVAL:%.+]] = trunc i64 [[EXPECTED]] to i32 -// CHECK: [[SHL:%.+]] = shl i32 [[EXPR]], [[X_RVAL]] +// CHECK: [[SHL:%.+]] = shl nuw i32 [[EXPR]], [[X_RVAL]] // CHECK: [[DESIRED:%.+]] = sext i32 [[SHL]] to i64 // CHECK: [[RES:%.+]] = cmpxchg i64* [[ULX_ADDR]], i64 [[EXPECTED]], i64 [[DESIRED]] monotonic monotonic // CHECK: [[OLD_X:%.+]] = extractvalue { i64, i1 } [[RES]], 0