Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -210,6 +210,8 @@ HelpText<"Emit an error if a C++ static local initializer would need a guard variable">; def no_implicit_float : Flag<["-"], "no-implicit-float">, HelpText<"Don't generate implicit floating point instructions">; +def fno_simplify_cfg : Flag<["-"], "fno-simplify-cfg">, + HelpText<"Disable CFG simplification">; def fdump_vtable_layouts : Flag<["-"], "fdump-vtable-layouts">, HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">; def fmerge_functions : Flag<["-"], "fmerge-functions">, Index: clang/include/clang/Frontend/CodeGenOptions.def =================================================================== --- clang/include/clang/Frontend/CodeGenOptions.def +++ clang/include/clang/Frontend/CodeGenOptions.def @@ -120,6 +120,7 @@ ///< enabled. CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled. CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled. +CODEGENOPT(NoSimplifyCFG , 1, 0) ///< Disable CFG simplification. CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf. CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero CODEGENOPT(Reassociate , 1, 0) ///< Allow reassociation of FP math ops Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -862,6 +862,11 @@ if (SanOpts.has(SanitizerKind::SafeStack)) Fn->addFnAttr(llvm::Attribute::SafeStack); + // Apply no-simplify-cfg attribute to the function + if (CGM.getCodeGenOpts().NoSimplifyCFG) + Fn->setMetadata("no_simplify_cfg", + llvm::MDNode::get(CGM.getLLVMContext(), None)); + // Ignore TSan memory acesses from within ObjC/ObjC++ dealloc, initialize, // .cxx_destruct, __destroy_helper_block_ and all of their calees at run time. if (SanOpts.has(SanitizerKind::Thread)) { Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -571,6 +571,7 @@ Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); + Opts.NoSimplifyCFG = Args.hasArg(OPT_fno_simplify_cfg); Opts.OptimizeSize = getOptimizationLevelSize(Args); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); Index: clang/test/CodeGen/no-simplify-cfg.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/no-simplify-cfg.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s --check-prefix=SIMPLIFY +// RUN: %clang_cc1 -fno-simplify-cfg -emit-llvm -o - %s | FileCheck %s + +// CHECK: define i32 @_Z3foov() {{.*}} !no_simplify_cfg +int foo() { + return 42; +} + +// CHECK: define i32 @_Z3barv() {{.*}} !no_simplify_cfg +int bar() { + return foo() * foo() + foo(); +} + +// CHECK: define i32 @_Z3bazii(i32 %x, i32 %y) {{.*}} !no_simplify_cfg +int baz(int x, int y) { + int z = x / y; + return z + foo() - bar(); +} + +// SIMPLIFY-NOT: no_simplify_cfg Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -6053,6 +6053,9 @@ bool llvm::simplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI, const SimplifyCFGOptions &Options, SmallPtrSetImpl *LoopHeaders) { + const Function *Fn = BB->getParent(); + if (Fn && Fn->getMetadata("no_simplify_cfg")) + return false; return SimplifyCFGOpt(TTI, BB->getModule()->getDataLayout(), LoopHeaders, Options) .run(BB); Index: llvm/test/Transforms/SimplifyCFG/no-simplify-cfg.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/SimplifyCFG/no-simplify-cfg.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +define i32 @foo(i32 %x) !no_simplify_cfg !{} { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + %0 = load i32, i32* %x.addr, align 4 + %cmp = icmp sgt i32 %0, 16 + br i1 %cmp, label %land.rhs, label %land.end + +land.rhs: + %1 = load i32, i32* %x.addr, align 4 + %cmp1 = icmp slt i32 %1, 32 + br label %land.end + +land.end: + %2 = phi i1 [ false, %entry ], [ %cmp1, %land.rhs ] + %conv = zext i1 %2 to i32 + ret i32 %conv + +; CHECK-LABEL: define i32 @foo(i32 %x) !no_simplify_cfg +; CHECK-LABEL: entry: +; CHECK: br i1 %cmp, label %land.rhs, label %land.end +; CHECK-LABEL: land.rhs: +; CHECK: br label %land.end +; CHECK-LABEL: land.end: +; CHECK: phi {{.*}} %entry {{.*}} %land.rhs +} + +define i32 @bar(i32 %x) { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + %0 = load i32, i32* %x.addr, align 4 + %cmp = icmp sgt i32 %0, 16 + br i1 %cmp, label %land.rhs, label %land.end + +land.rhs: + %1 = load i32, i32* %x.addr, align 4 + %cmp1 = icmp slt i32 %1, 32 + br label %land.end + +land.end: + %2 = phi i1 [ false, %entry ], [ %cmp1, %land.rhs ] + %conv = zext i1 %2 to i32 + ret i32 %conv + +; CHECK-LABEL: define i32 @bar(i32 %x) +; CHECK-NOT: br +}