domada created this revision.
domada added a reviewer: kiranchandramohan.
Herald added subscribers: bzcheeseman, awarzynski, sdasgup3, wenzhicui, wrengr, 
cota, teijeong, rdzhabarov, tatianashp, msifontes, jurahul, Kayjukh, grosul1, 
Joonsoo, liufengdb, aartbik, mgester, arpith-jacob, antiagainst, shauheen, 
rriddle, mehdi_amini, guansong, hiraditya, yaxunl.
Herald added a reviewer: ftynse.
Herald added a project: All.
domada requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: llvm-commits, cfe-commits, pcwang-thead, sstefan1, 
stephenneuendorffer, nicolasvasilache.
Herald added a reviewer: dcaballe.
Herald added projects: clang, MLIR, LLVM.

Currently generation of align assumptions for OpenMP simd construct is done 
outside OMPIRBuilder for C code and it is not supported for Fortran.

According to OpenMP 5.0 standard (2.9.3) only pointers and arrays can be 
aligned for C code.

If given aligned variable is pointer, then Clang generates the following set of 
the LLVM IR instructions to support simd align clause:

  ; memory allocation for pointer address:
  %A.addr = alloca ptr, align 8
  ; some LLVM IR code
  ; Alignment instructions (alignment is equal to 32):
  %0 = load ptr, ptr %A.addr, align 8
  call void @llvm.assume(i1 true) [ "align"(ptr %0, i64 32) ]

If given aligned variable is array, then Clang generates the following set of 
the LLVM IR instructions to support simd align clause:

  ; memory allocation for array: 
  %B = alloca [10 x i32], align 16
  ; some LLVM IR code
  ; Alignment instructions (alignment is equal to 32):
  %arraydecay = getelementptr inbounds [10 x i32], ptr %B, i64 0, i64 0
  call void @llvm.assume(i1 true) [ "align"(ptr %arraydecay, i64 32) ]

OMPIRBuilder was modified to support this codegen scheme. Attached unit tests 
check if generation of align assumptions is successful.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133578

Files:
  clang/lib/CodeGen/CGStmtOpenMP.cpp
  llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
  llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
  llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
  mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp

Index: mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
===================================================================
--- mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -996,7 +996,7 @@
     safelen = builder.getInt64(safelenVar.value());
 
   ompBuilder->applySimd(
-      loopInfo,
+      loopInfo, {}, nullptr,
       loop.if_expr() ? moduleTranslation.lookupValue(loop.if_expr()) : nullptr,
       simdlen, safelen);
 
Index: llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
===================================================================
--- llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -1771,7 +1771,8 @@
   CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
 
   // Simd-ize the loop.
-  OMPBuilder.applySimd(CLI, /* IfCond */ nullptr, /* Simdlen */ nullptr,
+  OMPBuilder.applySimd(CLI, /* AlignedVars */ {}, /* Alignment */ nullptr,
+                       /* IfCond */ nullptr, /* Simdlen */ nullptr,
                        /* Safelen */ nullptr);
 
   OMPBuilder.finalize();
@@ -1797,13 +1798,137 @@
   }));
 }
 
+TEST_F(OpenMPIRBuilderTest, ApplySimdiDefaultAligned) {
+  OpenMPIRBuilder OMPBuilder(*M);
+  IRBuilder<> Builder(BB);
+  AllocaInst *Alloc1 =
+      Builder.CreateAlloca(Builder.getInt8PtrTy(), Builder.getInt64(1));
+  AllocaInst *Alloc2 = Builder.CreateAlloca(
+      ArrayType::get(Builder.getInt32Ty(), 10), Builder.getInt64(1));
+  SmallVector<Value *> AlignedVars;
+  auto Int8Ty = Builder.getInt8Ty();
+  Instruction *MallocInstr = CallInst::CreateMalloc(
+      Alloc2, Builder.getInt64Ty(), Int8Ty, ConstantExpr::getSizeOf(Int8Ty),
+      Builder.getInt64(400), nullptr, "");
+  Builder.CreateStore(MallocInstr, Alloc1);
+
+  AlignedVars.push_back(Alloc1);
+  AlignedVars.push_back(Alloc2);
+
+  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
+
+  // Simd-ize the loop.
+  OMPBuilder.applySimd(CLI, AlignedVars, /* Alignment */ nullptr,
+                       /* IfCond */ nullptr, /* Simdlen */ nullptr,
+                       /* Safelen */ nullptr);
+
+  OMPBuilder.finalize();
+  EXPECT_FALSE(verifyModule(*M, &errs()));
+
+  PassBuilder PB;
+  FunctionAnalysisManager FAM;
+  PB.registerFunctionAnalyses(FAM);
+  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);
+
+  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();
+  EXPECT_EQ(TopLvl.size(), 1u);
+
+  Loop *L = TopLvl.front();
+  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));
+  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));
+
+  // Check for llvm.access.group metadata attached to the printf
+  // function in the loop body.
+  BasicBlock *LoopBody = CLI->getBody();
+  EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) {
+    return I.getMetadata("llvm.access.group") != nullptr;
+  }));
+
+  // Check if number of assumption instructions is equal to number of aligned
+  // variables
+  BasicBlock *LoopPreheader = CLI->getPreheader();
+  size_t NumAssummptionCallsInPreheader = count_if(
+      *LoopPreheader, [](Instruction &I) { return isa<AssumeInst>(I); });
+  EXPECT_EQ(NumAssummptionCallsInPreheader, AlignedVars.size());
+}
+
+TEST_F(OpenMPIRBuilderTest, ApplySimdiCustomAligned) {
+  OpenMPIRBuilder OMPBuilder(*M);
+  IRBuilder<> Builder(BB);
+  const int AlignmentValue = 32;
+  AllocaInst *Alloc1 =
+      Builder.CreateAlloca(Builder.getInt8PtrTy(), Builder.getInt64(1));
+  AllocaInst *Alloc2 = Builder.CreateAlloca(
+      ArrayType::get(Builder.getInt32Ty(), 10), Builder.getInt64(1));
+  SmallVector<Value *> AlignedVars;
+  auto Int8Ty = Builder.getInt8Ty();
+  Instruction *MallocInstr = CallInst::CreateMalloc(
+      Alloc2, Builder.getInt64Ty(), Int8Ty, ConstantExpr::getSizeOf(Int8Ty),
+      Builder.getInt64(400), nullptr, "");
+  Builder.CreateStore(MallocInstr, Alloc1);
+
+  AlignedVars.push_back(Alloc1);
+  AlignedVars.push_back(Alloc2);
+
+  CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
+
+  // Simd-ize the loop.
+  OMPBuilder.applySimd(CLI, AlignedVars, Builder.getInt64(AlignmentValue),
+                       /* IfCond */ nullptr, /* Simdlen */ nullptr,
+                       /* Safelen */ nullptr);
+
+  OMPBuilder.finalize();
+  EXPECT_FALSE(verifyModule(*M, &errs()));
+
+  PassBuilder PB;
+  FunctionAnalysisManager FAM;
+  PB.registerFunctionAnalyses(FAM);
+  LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F);
+
+  const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops();
+  EXPECT_EQ(TopLvl.size(), 1u);
+
+  Loop *L = TopLvl.front();
+  EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses"));
+  EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable"));
+
+  // Check for llvm.access.group metadata attached to the printf
+  // function in the loop body.
+  BasicBlock *LoopBody = CLI->getBody();
+  EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) {
+    return I.getMetadata("llvm.access.group") != nullptr;
+  }));
+
+  // Check if number of assumption instructions is equal to number of aligned
+  // variables
+  BasicBlock *LoopPreheader = CLI->getPreheader();
+  size_t NumAssummptionCallsInPreheader = count_if(
+      *LoopPreheader, [](Instruction &I) { return isa<AssumeInst>(I); });
+  EXPECT_EQ(NumAssummptionCallsInPreheader, AlignedVars.size());
+
+  // Check if variables are correctly aligned
+  for (auto &Instr : LoopPreheader->getInstList()) {
+    if (isa<AssumeInst>(Instr)) {
+      auto AssumeInstruction = dyn_cast<AssumeInst>(&Instr);
+      if (AssumeInstruction->getNumTotalBundleOperands()) {
+        auto Bundle = AssumeInstruction->getOperandBundleAt(0);
+        if (Bundle.getTagName() == "align") {
+          EXPECT_TRUE(isa<ConstantInt>(Bundle.Inputs[1]));
+          auto ConstIntVal = dyn_cast<ConstantInt>(Bundle.Inputs[1]);
+          EXPECT_EQ(ConstIntVal->getSExtValue(), AlignmentValue);
+        }
+      }
+    }
+  }
+}
 TEST_F(OpenMPIRBuilderTest, ApplySimdlen) {
   OpenMPIRBuilder OMPBuilder(*M);
 
   CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
 
   // Simd-ize the loop.
-  OMPBuilder.applySimd(CLI, /* IfCond */ nullptr,
+  OMPBuilder.applySimd(CLI, /* AlignedVars */ {}, /* Alignment */ nullptr,
+                       /* IfCond */ nullptr,
                        ConstantInt::get(Type::getInt32Ty(Ctx), 3),
                        /* Safelen */ nullptr);
 
@@ -1837,9 +1962,9 @@
   CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
 
   // Simd-ize the loop.
-  OMPBuilder.applySimd(CLI, /* IfCond */ nullptr,
-                       /* Simdlen */ nullptr,
-                       ConstantInt::get(Type::getInt32Ty(Ctx), 3));
+  OMPBuilder.applySimd(
+      CLI, /* AlignedVars */ {}, /* Alignment */ nullptr, /* IfCond */ nullptr,
+      /* Simdlen */ nullptr, ConstantInt::get(Type::getInt32Ty(Ctx), 3));
 
   OMPBuilder.finalize();
   EXPECT_FALSE(verifyModule(*M, &errs()));
@@ -1871,7 +1996,8 @@
   CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
 
   // Simd-ize the loop.
-  OMPBuilder.applySimd(CLI, /* IfCond */ nullptr,
+  OMPBuilder.applySimd(CLI, /* AlignedVars */ {}, /* Alignment */ nullptr,
+                       /* IfCond */ nullptr,
                        ConstantInt::get(Type::getInt32Ty(Ctx), 2),
                        ConstantInt::get(Type::getInt32Ty(Ctx), 3));
 
@@ -1916,7 +2042,8 @@
   CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder, 32);
 
   // Simd-ize the loop with if condition
-  OMPBuilder.applySimd(CLI, IfCmp, ConstantInt::get(Type::getInt32Ty(Ctx), 3),
+  OMPBuilder.applySimd(CLI, /* AlignedVars */ {}, /* Alignment */ nullptr,
+                       IfCmp, ConstantInt::get(Type::getInt32Ty(Ctx), 3),
                        /* Safelen */ nullptr);
 
   OMPBuilder.finalize();
Index: llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
===================================================================
--- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -2965,12 +2965,16 @@
   Builder.CreateBr(NewBlocks.front());
 }
 
-void OpenMPIRBuilder::applySimd(CanonicalLoopInfo *CanonicalLoop, Value *IfCond,
-                                ConstantInt *Simdlen, ConstantInt *Safelen) {
+void OpenMPIRBuilder::applySimd(CanonicalLoopInfo *CanonicalLoop,
+                                ArrayRef<Value *> AlignedVars, Value *Alignment,
+                                Value *IfCond, ConstantInt *Simdlen,
+                                ConstantInt *Safelen) {
   LLVMContext &Ctx = Builder.getContext();
 
   Function *F = CanonicalLoop->getFunction();
 
+  const int DefaultAlignment = 16;
+
   // TODO: We should not rely on pass manager. Currently we use pass manager
   // only for getting llvm::Loop which corresponds to given CanonicalLoopInfo
   // object. We should have a method  which returns all blocks between
@@ -2985,6 +2989,30 @@
 
   Loop *L = LI.getLoopFor(CanonicalLoop->getHeader());
 
+  for (auto *AlignedItem : AlignedVars) {
+    assert(isa<AllocaInst>(AlignedItem) &&
+           "Value which needs to be aligned must represented by alloca "
+           "instruction");
+    Value *AlignPtrInstruction = nullptr;
+    AllocaInst *AllocaInstruction = dyn_cast<AllocaInst>(AlignedItem);
+    Builder.SetInsertPoint(CanonicalLoop->getPreheader()->getTerminator());
+    Type *AllocatedVarType = AllocaInstruction->getAllocatedType();
+    if (isa<ArrayType>(AllocatedVarType))
+      AlignPtrInstruction = Builder.CreateInBoundsGEP(
+          AllocaInstruction->getAllocatedType(), AllocaInstruction,
+          SmallVector<Value *>{Builder.getInt64(0), Builder.getInt64(0)},
+          "arraydecay");
+    else if (isa<PointerType>(AllocatedVarType))
+      AlignPtrInstruction = Builder.CreateLoad(
+          AllocaInstruction->getAllocatedType(), AllocaInstruction);
+    assert(AlignPtrInstruction &&
+           "Aligned variables must be either pointer or array type");
+
+    Builder.CreateAlignmentAssumption(
+        F->getParent()->getDataLayout(), AlignPtrInstruction,
+        Alignment ? Alignment : Builder.getInt64(DefaultAlignment));
+  }
+
   if (IfCond) {
     ValueToValueMapTy VMap;
     createIfVersion(CanonicalLoop, IfCond, VMap, "simd");
Index: llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
===================================================================
--- llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
+++ llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
@@ -617,11 +617,16 @@
   /// to the cloned loop. The cloned loop is executed when ifCond is evaluated
   /// to false.
   ///
-  /// \param Loop    The loop to simd-ize.
-  /// \param IfCond  The value which corresponds to the if clause condition.
+  /// \param Loop        The loop to simd-ize.
+  /// \param AlignedVars The variables which need to aligned.
+  /// \param Alignment   The value of alignment.
+  /// \param IfCond      The value which corresponds to the if clause
+  ///                    condition.
   /// \param Simdlen The Simdlen length to apply to the simd loop.
   /// \param Safelen The Safelen length to apply to the simd loop.
-  void applySimd(CanonicalLoopInfo *Loop, Value *IfCond, ConstantInt *Simdlen,
+  void applySimd(CanonicalLoopInfo *Loop,
+                 llvm::ArrayRef<llvm::Value *> AlignedVars,
+                 llvm::Value *Alignment, Value *IfCond, ConstantInt *Simdlen,
                  ConstantInt *Safelen);
 
   /// Generator for '#omp flush'
Index: clang/lib/CodeGen/CGStmtOpenMP.cpp
===================================================================
--- clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -2662,7 +2662,8 @@
         }
         // Add simd metadata to the collapsed loop. Do not generate
         // another loop for if clause. Support for if clause is done earlier.
-        OMPBuilder.applySimd(CLI, /*IfCond*/ nullptr, Simdlen, Safelen);
+        OMPBuilder.applySimd(CLI, /*AlignedVars*/ {}, /*Alignment*/ nullptr,
+                             /*IfCond*/ nullptr, Simdlen, Safelen);
         return;
       }
     };
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to