javed.absar created this revision.

This patch enables the msvc pragma section to choose whether zero initialized 
variables are to be placed in data_seg or bss_seg. The current 
implementation  ignores bss_seg directive for variables that are initialized 
(i.e. it does not check if the initialization is, in fact, to all zeros). 
This patch now allows that. The variables are now placed in named bss_seg but 
only so If (a) the initialization is all zeros; AND (b) ''-falways-use-bss flag 
is set'. In other words, current functionality is not impacted and a useful 
feature is provided to users.


https://reviews.llvm.org/D30326

Files:
  include/clang/AST/APValue.h
  include/clang/AST/Expr.h
  include/clang/Basic/LangOptions.def
  include/clang/Driver/Options.td
  include/clang/Sema/Sema.h
  lib/AST/APValue.cpp
  lib/AST/Expr.cpp
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Sema/SemaDecl.cpp
  test/CodeGenCXX/zi-sections.cpp

Index: test/CodeGenCXX/zi-sections.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/zi-sections.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -fms-extensions -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ZI-DATA
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -fms-extensions -falways-use-bss -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ZI-BSS
+// Test that when '-falways-use-bss' is specified, variables initialized with zero are assigned to bss_seg.
+#pragma bss_seg(".bss.1")
+#pragma data_seg(".data.1")
+extern "C" {
+short ShortZero = 0;
+short ShortTwo = 2;
+short ShortMinusTwo = -2;
+short ShortUnInit;
+
+int IntZero = 0;
+int IntTwo = 2;
+int IntMinusTwo = -2;
+int IntUnInit;
+
+float FloatZero = 0.0;
+float FloatMinusZero = -0.0;
+float FloatTwo = 2.0;
+float FloatUnInit;
+
+double DoubleZero = 0.0;
+double DoubleMinusZero = -0.0;
+double DoubleTwo = 2.0;
+double DoubleUnInit;
+
+struct S {
+  int x, y;
+  int z;
+};
+struct S StructZero = { 0, 0, 0 };
+struct S StructTwo = { 0, 0, 2};
+struct S StructMinusTwo = {0, -2, 0};
+struct S StructUnInit;
+
+int ArrayZero[] = {0, 0, 0};
+int ArrayTwo[] = {0, 2, 0};
+int ArrayMinusTwo[] = {0, -2, 0};
+int ArrayUnInit;
+// CHECK-ZI-DATA: @ShortZero = global i16 0, section ".data.1", align 2
+// CHECK-ZI-BSS: @ShortZero = global i16 0, section ".bss.1", align 2
+// CHECK: @ShortTwo = global i16 2, section ".data.1", align 2
+// CHECK: @ShortMinusTwo = global i16 -2, section ".data.1", align 2
+// CHECK: @ShortUnInit = global i16 0, section ".bss.1", align 2
+//
+// CHECK-ZI-DATA: @IntZero = global i32 0, section ".data.1", align 4
+// CHECK-ZI-BSS: @IntZero = global i32 0, section ".bss.1", align 4
+// CHECK: @IntTwo = global i32 2, section ".data.1", align 4
+// CHECK: @IntMinusTwo = global i32 -2, section ".data.1", align 4
+// CHECK: @IntUnInit = global i32 0, section ".bss.1", align 4
+//
+// CHECK-ZI-DATA: @FloatZero = global float 0.000000e+00, section ".data.1", align 4
+// CHECK-ZI-BSS: @FloatZero = global float 0.000000e+00, section ".bss.1", align 4
+// CHECK: @FloatMinusZero = global float -0.000000e+00, section ".data.1", align 4
+// CHECK: @FloatTwo = global float 2.000000e+00, section ".data.1", align 4
+// CHECK: @FloatUnInit = global float 0.000000e+00, section ".bss.1", align 4
+//
+// CHECK-ZI-DATA: @DoubleZero = global double 0.000000e+00, section ".data.1", align 8
+// CHECK-ZI-BSS: @DoubleZero = global double 0.000000e+00, section ".bss.1", align 8
+// CHECK: @DoubleMinusZero = global double -0.000000e+00, section ".data.1", align 8
+// CHECK: @DoubleTwo = global double 2.000000e+00, section ".data.1", align 8
+// CHECK: @DoubleUnInit = global double 0.000000e+00, section ".bss.1", align 8
+//
+// CHECK-ZI-DATA: @StructZero = global %struct.S zeroinitializer, section ".data.1", align 4
+// CHECK-ZI-BSS: @StructZero = global %struct.S zeroinitializer, section ".bss.1", align 4
+// CHECK: @StructTwo = global %struct.S { i32 0, i32 0, i32 2 }, section ".data.1", align 4
+// CHECK: @StructMinusTwo = global %struct.S { i32 0, i32 -2, i32 0 }, section ".data.1", align 4
+// CHECK: @StructUnInit = global %struct.S zeroinitializer, section ".data.1", align 4
+//
+// CHECK-ZI-DATA: @ArrayZero = global [3 x i32] zeroinitializer, section ".data.1", align 4
+// CHECK-ZI-BSS: @ArrayZero = global [3 x i32] zeroinitializer, section ".bss.1", align 4
+// CHECK: @ArrayTwo = global [3 x i32] [i32 0, i32 2, i32 0], section ".data.1", align 4
+// CHECK: @ArrayMinusTwo = global [3 x i32] [i32 0, i32 -2, i32 0], section ".data.1", align 4
+// CHECK: @ArrayUnInit = global i32 0, section ".bss.1", align 4
+}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10736,6 +10736,18 @@
                        AttrEnd.isValid() ? AttrEnd : IdentLoc);
 }
 
+/// Check if initialization is to zero
+bool Sema::DeclarationIsZeroInitialized(VarDecl *var) {
+  Expr* InitExpr = var->getInit();
+  if (!InitExpr)
+    return var->hasGlobalStorage();
+
+  const Expr *Culprit;
+  if (!InitExpr->isConstantInitializer(Context, false, &Culprit))
+    return false;
+  return InitExpr->isZeroInitializer(Context, false, &Culprit);
+}
+
 void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
   if (var->isInvalidDecl()) return;
 
@@ -10827,7 +10839,9 @@
     int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
     if (var->getType().isConstQualified())
       Stack = &ConstSegStack;
-    else if (!var->getInit()) {
+    else if (!var->getInit() ||
+             (getLangOpts().AlwaysUseBSS &&
+              DeclarationIsZeroInitialized(var))) {
       Stack = &BSSSegStack;
       SectionFlags |= ASTContext::PSF_Write;
     } else {
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1917,6 +1917,8 @@
                                   VT.getSubminor().getValueOr(0);
   }
 
+  Opts.AlwaysUseBSS = Args.hasArg(OPT_falways_use_bss);
+
   // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
   // is specified, or -std is set to a conforming mode.
   // Trigraphs are disabled by default in c++1z onwards.
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -5935,6 +5935,10 @@
                    IsWindowsMSVC))
     CmdArgs.push_back("-fms-extensions");
 
+  if (Args.hasFlag(options::OPT_falways_use_bss,
+                   options::OPT_fno_always_use_bss, false))
+    CmdArgs.push_back("-always-use-bss");
+
   // -fno-use-line-directives is default.
   if (Args.hasFlag(options::OPT_fuse_line_directives,
                    options::OPT_fno_use_line_directives, false))
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2837,6 +2837,136 @@
   return false;
 }
 
+/// Returns true if the initializer is all zeros.
+bool Expr::isZeroInitializer(ASTContext &Ctx, bool IsForRef,
+                             const Expr **Culprit) const {
+  if (IsForRef)
+    return false;
+
+  switch (getStmtClass()) {
+  default: break;
+  case CompoundLiteralExprClass: {
+    const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
+    return Exp->isZeroInitializer(Ctx, false, Culprit);
+  }
+  case DesignatedInitUpdateExprClass: {
+    const DesignatedInitUpdateExpr *DIUE = cast<DesignatedInitUpdateExpr>(this);
+    return DIUE->getBase()->isZeroInitializer(Ctx, false, Culprit) &&
+           DIUE->getUpdater()->isZeroInitializer(Ctx, false, Culprit);
+  }
+  case  InitListExprClass: {
+    const InitListExpr *ILE = cast<InitListExpr>(this);
+    // array initializer
+    if (ILE->getType()->isArrayType()) {
+      unsigned numInits = ILE->getNumInits();
+      for (unsigned i = 0; i < numInits; i++) {
+        if (!ILE->getInit(i)->isZeroInitializer(Ctx, false, Culprit))
+          return false;
+      }
+      return true;
+    }
+
+    // record initializer
+    if (ILE->getType()->isRecordType()) {
+      unsigned ElementNo = 0;
+      RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+      for (const auto *Field : RD->fields()) {
+        // If this is a union, skip all the fields that aren't being initialized.
+        if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
+          continue;
+
+        // Don't emit anonymous bitfields, they just affect layout.
+        if (Field->isUnnamedBitfield())
+          continue;
+
+        if (ElementNo < ILE->getNumInits()) {
+          const Expr *Elt = ILE->getInit(ElementNo++);
+          if (Field->isBitField()) {
+            // Bitfields have to evaluate to an integer.
+            llvm::APSInt ResultTmp;
+            if (!Elt->EvaluateAsInt(ResultTmp, Ctx)) {
+              if (Culprit)
+                *Culprit = Elt;
+              return false;
+            }
+            if (ResultTmp != 0)
+              return false;
+          } else {
+            //bool RefType = Field->getType()->isReferenceType();
+            if (!Elt->isZeroInitializer(Ctx, false, Culprit))
+              return false;
+          }
+        }
+      }
+      return true;
+    }
+    break;
+  }
+  case ImplicitValueInitExprClass:
+  case NoInitExprClass:
+    return true;
+  case ParenExprClass:
+    return cast<ParenExpr>(this)->getSubExpr()
+      ->isZeroInitializer(Ctx, false, Culprit);
+  case GenericSelectionExprClass:
+    return cast<GenericSelectionExpr>(this)->getResultExpr()
+      ->isZeroInitializer(Ctx, false, Culprit);
+  case ChooseExprClass:
+    if (cast<ChooseExpr>(this)->isConditionDependent()) {
+      if (Culprit)
+        *Culprit = this;
+      return false;
+    }
+    return cast<ChooseExpr>(this)->getChosenSubExpr()
+      ->isZeroInitializer(Ctx, false, Culprit);
+  case UnaryOperatorClass: {
+    const UnaryOperator* Exp = cast<UnaryOperator>(this);
+    if (Exp->getOpcode() == UO_Extension)
+      return Exp->getSubExpr()->isZeroInitializer(Ctx, false, Culprit);
+    break;
+  }
+  case CXXFunctionalCastExprClass:
+  case CXXStaticCastExprClass:
+  case ImplicitCastExprClass:
+  case CStyleCastExprClass:
+  case ObjCBridgedCastExprClass:
+  case CXXDynamicCastExprClass:
+  case CXXReinterpretCastExprClass:
+  case CXXConstCastExprClass: {
+    const CastExpr *CE = cast<CastExpr>(this);
+
+    if (CE->getCastKind() == CK_NoOp ||
+        CE->getCastKind() == CK_LValueToRValue ||
+        CE->getCastKind() == CK_ToUnion ||
+        CE->getCastKind() == CK_ConstructorConversion ||
+        CE->getCastKind() == CK_NonAtomicToAtomic ||
+        CE->getCastKind() == CK_AtomicToNonAtomic ||
+        CE->getCastKind() == CK_IntToOCLSampler)
+      return CE->getSubExpr()->isZeroInitializer(Ctx, false, Culprit);
+
+    break;
+  }
+  case MaterializeTemporaryExprClass:
+    return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
+      ->isZeroInitializer(Ctx, false, Culprit);
+
+  case SubstNonTypeTemplateParmExprClass:
+    return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
+      ->isZeroInitializer(Ctx, false, Culprit);
+  case CXXDefaultArgExprClass:
+    return cast<CXXDefaultArgExpr>(this)->getExpr()
+      ->isZeroInitializer(Ctx, false, Culprit);
+  case CXXDefaultInitExprClass:
+    return cast<CXXDefaultInitExpr>(this)->getExpr()
+      ->isZeroInitializer(Ctx, false, Culprit);
+  }
+
+  EvalResult Result;
+  if (EvaluateAsRValue(Result, Ctx))
+    return Result.Val.isAllZeros();
+  return false;
+}
+
 namespace {
   /// \brief Look for any side effects within a Stmt.
   class SideEffectFinder : public ConstEvaluatedExprVisitor<SideEffectFinder> {
Index: lib/AST/APValue.cpp
===================================================================
--- lib/AST/APValue.cpp
+++ lib/AST/APValue.cpp
@@ -656,3 +656,21 @@
   MPD->resizePath(Path.size());
   memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*));
 }
+
+bool APValue::isAllZeros() const {
+  switch (getKind()) {
+  case Uninitialized:
+    return false;
+  case Int:
+    return !getInt().getBoolValue();
+  case  Float:
+    return getFloat().isPosZero();
+  case ComplexInt:
+    return !getComplexIntReal().getBoolValue() && !getComplexIntImag().getBoolValue();
+  case ComplexFloat:
+    return getComplexFloatReal().isPosZero() && getComplexFloatImag().isPosZero();
+  default:
+    return false;
+  }
+  return false;
+}
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1763,6 +1763,7 @@
   bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
                                      Expr *Init);
   void CheckCompleteVariableDeclaration(VarDecl *VD);
+  bool DeclarationIsZeroInitialized(VarDecl *VD);
   void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
   void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
 
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1440,6 +1440,12 @@
 def fno_data_sections : Flag <["-"], "fno-data-sections">, Group<f_Group>,
   Flags<[CC1Option]>;
 
+def falways_use_bss : Flag<["-"], "falways-use-bss">,Group<f_Group>,
+  Flags<[CC1Option]>,
+  HelpText<"Place variables initialized to 0 in pragma bss_seg">;
+def fno_always_use_bss : Flag<["-"], "fno-always-use-bss">,Group<f_Group>,
+  Flags<[CC1Option]>;
+
 def funique_section_names : Flag <["-"], "funique-section-names">,
   Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Use unique names for text and data sections (ELF Only)">;
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -179,6 +179,7 @@
 ENUM_LANGOPT(DefaultCallingConv, DefaultCallingConvention, 3, DCC_None, "default calling convention")
 
 LANGOPT(ShortEnums        , 1, 0, "short enum types")
+LANGOPT(AlwaysUseBSS, 1, 0, "place variables initialized to 0 in pragma bss_seg")
 
 LANGOPT(OpenCL            , 1, 0, "OpenCL")
 LANGOPT(OpenCLVersion     , 32, 0, "OpenCL version")
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -533,6 +533,10 @@
   bool isConstantInitializer(ASTContext &Ctx, bool ForRef,
                              const Expr **Culprit = nullptr) const;
 
+   /// isZeroInitializer - Returns true if this initializer is all zeros.
+   bool isZeroInitializer(ASTContext &Ctx, bool IsForRef,
+                          const Expr **Culprit = nullptr) const;
+
   /// EvalStatus is a struct with detailed info about an evaluation in progress.
   struct EvalStatus {
     /// \brief Whether the evaluated expression has side effects.
Index: include/clang/AST/APValue.h
===================================================================
--- include/clang/AST/APValue.h
+++ include/clang/AST/APValue.h
@@ -191,6 +191,7 @@
   bool isUnion() const { return Kind == Union; }
   bool isMemberPointer() const { return Kind == MemberPointer; }
   bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; }
+  bool isAllZeros() const;
 
   void dump() const;
   void dump(raw_ostream &OS) const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to