Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -587,6 +587,7 @@ ATTR_KIND_SPECULATABLE = 53, ATTR_KIND_STRICT_FP = 54, ATTR_KIND_SANITIZE_HWADDRESS = 55, + ATTR_KIND_NO_CFG_SELECT_FORMATION = 56, }; enum ComdatSelectionKindCodes { Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -82,6 +82,9 @@ /// Function creates no aliases of pointer. def NoCapture : EnumAttr<"nocapture">; +/// CFG simplification shouldn't convert control flow to selects. +def NoCFGSelectFormation : EnumAttr<"no_cfg_select_formation">; + /// Call cannot be duplicated. def NoDuplicate : EnumAttr<"noduplicate">; Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -640,6 +640,7 @@ KEYWORD(noalias); KEYWORD(nobuiltin); KEYWORD(nocapture); + KEYWORD(no_cfg_select_formation); KEYWORD(noduplicate); KEYWORD(noimplicitfloat); KEYWORD(noinline); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1124,6 +1124,8 @@ case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break; case lltok::kw_naked: B.addAttribute(Attribute::Naked); break; case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin); break; + case lltok::kw_no_cfg_select_formation: + B.addAttribute(Attribute::NoCFGSelectFormation); break; case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break; case lltok::kw_noimplicitfloat: B.addAttribute(Attribute::NoImplicitFloat); break; @@ -1462,6 +1464,7 @@ case lltok::kw_minsize: case lltok::kw_naked: case lltok::kw_nobuiltin: + case lltok::kw_no_cfg_select_formation: case lltok::kw_noduplicate: case lltok::kw_noimplicitfloat: case lltok::kw_noinline: @@ -1555,6 +1558,7 @@ case lltok::kw_minsize: case lltok::kw_naked: case lltok::kw_nobuiltin: + case lltok::kw_no_cfg_select_formation: case lltok::kw_noduplicate: case lltok::kw_noimplicitfloat: case lltok::kw_noinline: Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -191,6 +191,7 @@ kw_noalias, kw_nobuiltin, kw_nocapture, + kw_no_cfg_select_formation, kw_noduplicate, kw_noimplicitfloat, kw_noinline, Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1160,6 +1160,7 @@ case Attribute::Speculatable: return 1ULL << 54; case Attribute::StrictFP: return 1ULL << 55; case Attribute::SanitizeHWAddress: return 1ULL << 56; + case Attribute::NoCFGSelectFormation: return 1ULL << 57; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; @@ -1316,6 +1317,8 @@ return Attribute::NoBuiltin; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; + case bitc::ATTR_KIND_NO_CFG_SELECT_FORMATION: + return Attribute::NoCFGSelectFormation; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -618,6 +618,8 @@ return bitc::ATTR_KIND_NO_BUILTIN; case Attribute::NoCapture: return bitc::ATTR_KIND_NO_CAPTURE; + case Attribute::NoCFGSelectFormation: + return bitc::ATTR_KIND_NO_CFG_SELECT_FORMATION; case Attribute::NoDuplicate: return bitc::ATTR_KIND_NO_DUPLICATE; case Attribute::NoImplicitFloat: Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -285,6 +285,8 @@ return "nobuiltin"; if (hasAttribute(Attribute::NoCapture)) return "nocapture"; + if (hasAttribute(Attribute::NoCFGSelectFormation)) + return "no_cfg_select_formation"; if (hasAttribute(Attribute::NoDuplicate)) return "noduplicate"; if (hasAttribute(Attribute::NoImplicitFloat)) Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -1405,6 +1405,7 @@ case Attribute::StackProtectStrong: case Attribute::SafeStack: case Attribute::NoRedZone: + case Attribute::NoCFGSelectFormation: case Attribute::NoImplicitFloat: case Attribute::Naked: case Attribute::InlineHint: Index: llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -36,6 +36,7 @@ .Case("minsize", Attribute::MinSize) .Case("naked", Attribute::Naked) .Case("nobuiltin", Attribute::NoBuiltin) + .Case("no_cfg_select_formation", Attribute::NoCFGSelectFormation) .Case("noduplicate", Attribute::NoDuplicate) .Case("noimplicitfloat", Attribute::NoImplicitFloat) .Case("noinline", Attribute::NoInline) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -678,6 +678,7 @@ case Attribute::NoRecurse: case Attribute::InlineHint: case Attribute::MinSize: + case Attribute::NoCFGSelectFormation: case Attribute::NoDuplicate: case Attribute::NoImplicitFloat: case Attribute::NoInline: Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -2260,6 +2260,10 @@ // dependence information for this check, but simplifycfg can't keep it up // to date, and this catches most of the cases we care about anyway. BasicBlock *BB = PN->getParent(); + const Function *Fn = BB->getParent(); + if (Fn && Fn->hasFnAttribute(Attribute::NoCFGSelectFormation)) + return false; + BasicBlock *IfTrue, *IfFalse; Value *IfCond = GetIfCondition(BB, IfTrue, IfFalse); if (!IfCond || @@ -5786,6 +5790,9 @@ bool SimplifyCFGOpt::SimplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { BasicBlock *BB = BI->getParent(); + const Function *Fn = BB->getParent(); + if (Fn && Fn->hasFnAttribute(Attribute::NoCFGSelectFormation)) + return false; // Conditional branch if (isValueEqualityComparison(BI)) { Index: llvm/test/Transforms/SimplifyCFG/no-select-formation.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/SimplifyCFG/no-select-formation.ll @@ -0,0 +1,49 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +define i32 @foo(i32 %x) no_cfg_select_formation { +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) +; 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 +}