javed.absar updated this revision to Diff 89897.
javed.absar added a comment.

Hi Roger:
Thanks for the review. I have extended the test and fixed driver flag passing 
that you pointed out.

Regarding the check in Sema::DeclarationIsZeroInitialized, the check if to keep 
the function return value consistent, in case function is called with a 
declaration that is without an initializer.
Best Regards, 
Javed


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
  test/Driver/always-use-bss.c

Index: test/Driver/always-use-bss.c
===================================================================
--- /dev/null
+++ test/Driver/always-use-bss.c
@@ -0,0 +1,3 @@
+// RUN: %clang -### -target i686-pc-windows -fms-extensions -falways-use-bss %s 2>&1 | FileCheck %s
+// CHECK: "-falways-use-bss"
+void f() {}
Index: test/CodeGenCXX/zi-sections.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/zi-sections.cpp
@@ -0,0 +1,86 @@
+// 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;
+
+int ArrayWithFillerZero[10] = { 0 };
+int ArrayWithFillerTwo[10] = { 0, 2 };
+int ArrayWithAllFiller[10] = { };
+
+// 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
+//
+// CHECK-ZI-DATA: @ArrayWithFillerZero = global [10 x i32] zeroinitializer, section ".data.1", align 4
+// CHECK-ZI-BSS:  @ArrayWithFillerZero = global [10 x i32] zeroinitializer, section ".bss.1", align 4
+// CHECK: @ArrayWithFillerTwo = global [10 x i32] [i32 0, i32 2, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0], section ".data.1", align 4
+// CHECK-ZI-DATA: @ArrayWithAllFiller = global [10 x i32] zeroinitializer, section ".data.1", align 4
+// CHECK-ZI-BSS:  @ArrayWithAllFiller = global [10 x i32] zeroinitializer, 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("-falways-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