melver updated this revision to Diff 351229.
melver added a comment.

As promised, some cleanups, docs, and updated test for the current version (no
other major changes yet).

While the identical-writes test is quite contrived, the currently failing
switch test is a more realistic example. The example uses AArch64, where the
optimizer does not emit a branch but instead uses cinc, which would break the
requirement of emitting a real branch.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103958/new/

https://reviews.llvm.org/D103958

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Sema/SemaStmtAttr.cpp
  clang/test/CodeGenCXX/attr-mustcontrol.cpp
  llvm/include/llvm/IR/FixedMetadataKinds.def
  llvm/include/llvm/IR/IRBuilder.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/include/llvm/IR/MDBuilder.h
  llvm/lib/CodeGen/BranchFolding.cpp
  llvm/lib/IR/IRBuilder.cpp
  llvm/lib/IR/MDBuilder.cpp

Index: llvm/lib/IR/MDBuilder.cpp
===================================================================
--- llvm/lib/IR/MDBuilder.cpp
+++ llvm/lib/IR/MDBuilder.cpp
@@ -56,6 +56,8 @@
   return MDNode::get(Context, None);
 }
 
+MDNode *MDBuilder::createMustControl() { return MDNode::get(Context, None); }
+
 MDNode *MDBuilder::createFunctionEntryCount(
     uint64_t Count, bool Synthetic,
     const DenseSet<GlobalValue::GUID> *Imports) {
Index: llvm/lib/IR/IRBuilder.cpp
===================================================================
--- llvm/lib/IR/IRBuilder.cpp
+++ llvm/lib/IR/IRBuilder.cpp
@@ -960,7 +960,7 @@
   if (MDFrom) {
     MDNode *Prof = MDFrom->getMetadata(LLVMContext::MD_prof);
     MDNode *Unpred = MDFrom->getMetadata(LLVMContext::MD_unpredictable);
-    Sel = addBranchMetadata(Sel, Prof, Unpred);
+    Sel = addBranchMetadata(Sel, Prof, Unpred, nullptr /*TODO*/);
   }
   if (isa<FPMathOperator>(Sel))
     setFPAttrs(Sel, nullptr /* MDNode* */, FMF);
Index: llvm/lib/CodeGen/BranchFolding.cpp
===================================================================
--- llvm/lib/CodeGen/BranchFolding.cpp
+++ llvm/lib/CodeGen/BranchFolding.cpp
@@ -1217,7 +1217,20 @@
 // Blocks should be considered empty if they contain only debug info;
 // else the debug info would affect codegen.
 static bool IsEmptyBlock(MachineBasicBlock *MBB) {
-  return MBB->getFirstNonDebugInstr(true) == MBB->end();
+  if (MBB->getFirstNonDebugInstr(true) != MBB->end())
+    return false;
+
+  // Even though this block is empty, check if we should preserve it.
+  // XXX: Implementation subject to change.
+  if (const auto *BB = MBB->getBasicBlock()) {
+    for (const BasicBlock *PredBB : predecessors(BB)) {
+      const auto *PredBr = dyn_cast<BranchInst>(PredBB->getTerminator());
+      if (PredBr && PredBr->getMetadata(LLVMContext::MD_mustcontrol))
+        return false;
+    }
+  }
+
+  return true;
 }
 
 // Blocks with only debug info and branches should be considered the same
Index: llvm/include/llvm/IR/MDBuilder.h
===================================================================
--- llvm/include/llvm/IR/MDBuilder.h
+++ llvm/include/llvm/IR/MDBuilder.h
@@ -66,6 +66,9 @@
   /// Return metadata specifying that a branch or switch is unpredictable.
   MDNode *createUnpredictable();
 
+  /// Return metadata specifying that a branch or switch must not be removed.
+  MDNode *createMustControl();
+
   /// Return metadata containing the entry \p Count for a function, a boolean
   /// \Synthetic indicating whether the counts were synthetized, and the
   /// GUIDs stored in \p Imports that need to be imported for sample PGO, to
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -1326,7 +1326,8 @@
 // has having opaque side effects. This may be inserted into loops to ensure
 // that they are not removed even if they turn out to be empty, for languages
 // which specify that infinite loops must be preserved.
-def int_sideeffect : DefaultAttrsIntrinsic<[], [], [IntrInaccessibleMemOnly, IntrWillReturn]>;
+def int_sideeffect : DefaultAttrsIntrinsic<[], [llvm_vararg_ty],
+                                           [IntrInaccessibleMemOnly, IntrWillReturn]>;
 
 // The pseudoprobe intrinsic works as a place holder to the block it probes.
 // Like the sideeffect intrinsic defined above, this intrinsic is treated by the 
Index: llvm/include/llvm/IR/IRBuilder.h
===================================================================
--- llvm/include/llvm/IR/IRBuilder.h
+++ llvm/include/llvm/IR/IRBuilder.h
@@ -934,15 +934,18 @@
   //===--------------------------------------------------------------------===//
 
 private:
-  /// Helper to add branch weight and unpredictable metadata onto an
-  /// instruction.
+  /// Helper to add branch weight, unpredictable, and mustcontrol metadata onto
+  /// an instruction.
   /// \returns The annotated instruction.
   template <typename InstTy>
-  InstTy *addBranchMetadata(InstTy *I, MDNode *Weights, MDNode *Unpredictable) {
+  InstTy *addBranchMetadata(InstTy *I, MDNode *Weights, MDNode *Unpredictable,
+                            MDNode *MustControl) {
     if (Weights)
       I->setMetadata(LLVMContext::MD_prof, Weights);
     if (Unpredictable)
       I->setMetadata(LLVMContext::MD_unpredictable, Unpredictable);
+    if (MustControl)
+      I->setMetadata(LLVMContext::MD_mustcontrol, MustControl);
     return I;
   }
 
@@ -980,9 +983,10 @@
   /// instruction.
   BranchInst *CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False,
                            MDNode *BranchWeights = nullptr,
-                           MDNode *Unpredictable = nullptr) {
+                           MDNode *Unpredictable = nullptr,
+                           MDNode *MustControl = nullptr) {
     return Insert(addBranchMetadata(BranchInst::Create(True, False, Cond),
-                                    BranchWeights, Unpredictable));
+                                    BranchWeights, Unpredictable, MustControl));
   }
 
   /// Create a conditional 'br Cond, TrueDest, FalseDest'
@@ -991,9 +995,10 @@
                            Instruction *MDSrc) {
     BranchInst *Br = BranchInst::Create(True, False, Cond);
     if (MDSrc) {
-      unsigned WL[4] = {LLVMContext::MD_prof, LLVMContext::MD_unpredictable,
-                        LLVMContext::MD_make_implicit, LLVMContext::MD_dbg};
-      Br->copyMetadata(*MDSrc, makeArrayRef(&WL[0], 4));
+      unsigned WL[5] = {LLVMContext::MD_prof, LLVMContext::MD_unpredictable,
+                        LLVMContext::MD_make_implicit, LLVMContext::MD_dbg,
+                        LLVMContext::MD_mustcontrol};
+      Br->copyMetadata(*MDSrc, makeArrayRef(&WL[0], 5));
     }
     return Insert(Br);
   }
@@ -1003,9 +1008,10 @@
   /// allocation).
   SwitchInst *CreateSwitch(Value *V, BasicBlock *Dest, unsigned NumCases = 10,
                            MDNode *BranchWeights = nullptr,
-                           MDNode *Unpredictable = nullptr) {
+                           MDNode *Unpredictable = nullptr,
+                           MDNode *MustControl = nullptr) {
     return Insert(addBranchMetadata(SwitchInst::Create(V, Dest, NumCases),
-                                    BranchWeights, Unpredictable));
+                                    BranchWeights, Unpredictable, MustControl));
   }
 
   /// Create an indirect branch instruction with the specified address
Index: llvm/include/llvm/IR/FixedMetadataKinds.def
===================================================================
--- llvm/include/llvm/IR/FixedMetadataKinds.def
+++ llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -42,3 +42,4 @@
 LLVM_FIXED_MD_KIND(MD_vcall_visibility, "vcall_visibility", 28)
 LLVM_FIXED_MD_KIND(MD_noundef, "noundef", 29)
 LLVM_FIXED_MD_KIND(MD_annotation, "annotation", 30)
+LLVM_FIXED_MD_KIND(MD_mustcontrol, "mustcontrol", 31)
Index: clang/test/CodeGenCXX/attr-mustcontrol.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/attr-mustcontrol.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -O2 -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -O2 -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | opt -verify
+//
+// TODO: move to .ll test
+// RUN: %clang_cc1 -O2 -S %s -triple aarch64-unknown-linux-gnu -o - | FileCheck %s -check-prefix=ARM
+
+#if __has_attribute(mustcontrol)
+#define mustcontrol [[clang::mustcontrol]]
+#else
+#error "mustcontrol not supported!"
+#endif
+
+volatile int x, y;
+int z;
+
+// CHECK-LABEL: define{{.*}}IfThenIdenticalWrites
+void IfThenIdenticalWrites() {
+  z = 42;
+
+  // CHECK: br{{.*}}mustcontrol
+  // ARM: cbz
+  mustcontrol if (x) {
+    y = z;
+  } else {
+    y = z;
+  }
+}
+
+// CHECK-LABEL: define{{.*}}SupportWhile
+void SupportWhile() {
+  mustcontrol while (x) { y = 1; }
+}
+
+// CHECK-LABEL: define{{.*}}SupportFor
+void SupportFor() {
+  mustcontrol for (; x; y++) { }
+}
+
+// FIXME: This test currently fails because the optimizer turns the switch into
+// a cinc!!!
+//
+// CHECK-LABEL: define{{.*}}SupportSwitch
+// ARM-LABEL: _Z13SupportSwitchv:
+void SupportSwitch() {
+  // ARM-NOT: cinc
+  mustcontrol switch (x) {
+    case 0:
+      y = 1;
+      break;
+    default:
+      y = 2;
+      break;
+  }
+}
Index: clang/lib/Sema/SemaStmtAttr.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAttr.cpp
+++ clang/lib/Sema/SemaStmtAttr.cpp
@@ -233,6 +233,11 @@
   return ::new (S.Context) UnlikelyAttr(S.Context, A);
 }
 
+static Attr *handleMustControl(Sema &S, Stmt *St, const ParsedAttr &A,
+                               SourceRange Range) {
+  return ::new (S.Context) MustControlAttr(S.Context, A);
+}
+
 #define WANT_STMT_MERGE_LOGIC
 #include "clang/Sema/AttrParsedAttrImpl.inc"
 #undef WANT_STMT_MERGE_LOGIC
@@ -424,6 +429,8 @@
     return handleLikely(S, St, A, Range);
   case ParsedAttr::AT_Unlikely:
     return handleUnlikely(S, St, A, Range);
+  case ParsedAttr::AT_MustControl:
+    return handleMustControl(S, St, A, Range);
   default:
     // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
     // declaration attribute is not written on a statement, but this code is
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -524,6 +524,10 @@
   // applies to.  nullptr if there is no 'musttail' on the current statement.
   const CallExpr *MustTailCall = nullptr;
 
+  // The Stmt within the current statement that the mustcontrol attribute
+  // applies to. nullptr if there is no 'mustcontrol' on the current statement.
+  const Stmt *MustControlStmt = nullptr;
+
   /// Returns true if a function must make progress, which means the
   /// mustprogress attribute can be added.
   bool checkIfFunctionMustProgress() {
@@ -4488,7 +4492,8 @@
   /// evaluate to true based on PGO data.
   void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
                             llvm::BasicBlock *FalseBlock, uint64_t TrueCount,
-                            Stmt::Likelihood LH = Stmt::LH_None);
+                            Stmt::Likelihood LH = Stmt::LH_None,
+                            bool MustControl = false);
 
   /// Given an assignment `*LHS = RHS`, emit a test that checks if \p RHS is
   /// nonnull, if \p LHS is marked _Nonnull.
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1606,11 +1606,9 @@
 /// statement) to the specified blocks.  Based on the condition, this might try
 /// to simplify the codegen of the conditional based on the branch.
 /// \param LH The value of the likelihood attribute on the True branch.
-void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
-                                           llvm::BasicBlock *TrueBlock,
-                                           llvm::BasicBlock *FalseBlock,
-                                           uint64_t TrueCount,
-                                           Stmt::Likelihood LH) {
+void CodeGenFunction::EmitBranchOnBoolExpr(
+    const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock,
+    uint64_t TrueCount, Stmt::Likelihood LH, bool MustControl) {
   Cond = Cond->IgnoreParens();
 
   if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
@@ -1795,8 +1793,10 @@
     CondV = EvaluateExprAsBool(Cond);
   }
 
+  llvm::MDBuilder MDHelper(getLLVMContext());
   llvm::MDNode *Weights = nullptr;
   llvm::MDNode *Unpredictable = nullptr;
+  llvm::MDNode *MustControlMD = nullptr;
 
   // If the branch has a condition wrapped by __builtin_unpredictable,
   // create metadata that specifies that the branch is unpredictable.
@@ -1804,10 +1804,8 @@
   auto *Call = dyn_cast<CallExpr>(Cond->IgnoreImpCasts());
   if (Call && CGM.getCodeGenOpts().OptimizationLevel != 0) {
     auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
-    if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
-      llvm::MDBuilder MDHelper(getLLVMContext());
+    if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable)
       Unpredictable = MDHelper.createUnpredictable();
-    }
   }
 
   // If there is a Likelihood knowledge for the cond, lower it.
@@ -1821,7 +1819,11 @@
     Weights = createProfileWeights(TrueCount, CurrentCount - TrueCount);
   }
 
-  Builder.CreateCondBr(CondV, TrueBlock, FalseBlock, Weights, Unpredictable);
+  if (MustControl)
+    MustControlMD = MDHelper.createMustControl();
+
+  Builder.CreateCondBr(CondV, TrueBlock, FalseBlock, Weights, Unpredictable,
+                       MustControlMD);
 }
 
 /// ErrorUnsupported - Print out an error that codegen doesn't support the
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -657,6 +657,7 @@
 void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   bool nomerge = false;
   const CallExpr *musttail = nullptr;
+  const Stmt *mustcontrol = nullptr;
 
   for (const auto *A : S.getAttrs()) {
     if (A->getKind() == attr::NoMerge) {
@@ -667,9 +668,12 @@
       const ReturnStmt *R = cast<ReturnStmt>(Sub);
       musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
     }
+    if (A->getKind() == attr::MustControl)
+      mustcontrol = S.getSubStmt();
   }
   SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
   SaveAndRestore<const CallExpr *> save_musttail(MustTailCall, musttail);
+  SaveAndRestore<const Stmt *> save_mustcontrol(MustControlStmt, mustcontrol);
   EmitStmt(S.getSubStmt(), S.getAttrs());
 }
 
@@ -755,10 +759,21 @@
   uint64_t Count = getProfileCount(S.getThen());
   if (!Count && CGM.getCodeGenOpts().OptimizationLevel)
     LH = Stmt::getLikelihood(S.getThen(), S.getElse());
-  EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, LH);
+  EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, LH,
+                       &S == MustControlStmt);
 
   // Emit the 'then' code.
   EmitBlock(ThenBlock);
+  if (&S == MustControlStmt) {
+    // XXX: Implementation subject to change.
+    // TODO: Make arg unique, so that optimizer doesn't get the bright idea to
+    // collapse nested mustcontrol statement blocks.
+    // TODO: Make LLVM emit this during optimization, so that mustcontrol
+    // doesn't just work for Clang.
+    Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::sideeffect),
+                       {llvm::ConstantInt::get(IntPtrTy, 42)});
+  }
+
   incrementProfileCounter(&S);
   {
     RunCleanupsScope ThenScope(*this);
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -469,6 +469,25 @@
   }];
 }
 
+def MustControlDocs : Documentation {
+  let Category = DocCatStmt;
+  let Content = [{
+Marking a conditional control statement as ``mustcontrol`` indicates that the
+compiler must generate a conditional branch in machine code, and such
+conditional branch is placed *before* conditionally executed instructions. The
+attribute may be ignored if the condition of the control statement is a
+constant expression.
+
+This typically affects optimizations that would cause removal of a conditional
+branch. However, it also ensures that a conditional branch and subsequent
+instructions are not replaced with non-branching conditional instructions.
+
+Requesting the generation of a branch may be required in execution environments
+where execution of a specific conditional branch inhibits speculation or has
+observable side-effects of interest otherwise.
+  }];
+}
+
 def AssertCapabilityDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "assert_capability, assert_shared_capability";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1385,6 +1385,13 @@
   let Subjects = SubjectList<[ReturnStmt], ErrorDiag, "return statements">;
 }
 
+def MustControl : StmtAttr {
+  let Spellings = [Clang<"mustcontrol">];
+  let Documentation = [MustControlDocs];
+  let Subjects = SubjectList<[IfStmt, SwitchStmt, ForStmt, WhileStmt, DoStmt],
+                              ErrorDiag, "conditional control statements">;
+}
+
 def FastCall : DeclOrTypeAttr {
   let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
                    Keyword<"_fastcall">];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to