================
@@ -1476,6 +1476,127 @@ static bool shouldExtendLifetime(const ASTContext 
&Context,
   return true;
 }
 
+/// Adds metadata for restrict-qualified pointers at any nesting level.
+///
+/// This function processes pointer types recursively to generate metadata
+/// for restrict-qualified pointers. The metadata encodes which pointer levels
+/// are restrict qualified and assigns unique identifiers to each restrict
+/// qualification level.
+///
+/// For example, consider the type `int * restrict * restrict` in foo():
+///   - First level: pointer to restrict pointer (gets unique code 1)
+///   - Second level: restrict pointer to int (gets another unique code 1)
+///
+/// The metadata structure is attached to the alloca instruction and consists
+/// of:
+///   1. Full variable name (function name + scope encoding)
+///   2. List of restrict codes for each pointer level:
+///      - Non-zero: unique identifier for restrict-qualified pointer
+///      - Zero: non-restrict qualified pointer at that level
+///
+/// For example, consider function `foo` with variable declarations:
+///   void foo() {
+///     int * restrict p1;       // Single-level restrict pointer
+///     int * restrict *p2;      // restrict at first level, non-restrict at
+///     second int * restrict * restrict p3;  // restrict at both levels
+///   }
+///
+/// Generated metadata would be:
+///   p1: !{!"foo_1", !{1}}          // One restrict level, code 1
+///   p2: !{!"foo_1", !{2, 0}}       // First level restrict (1), second
+///   non-restrict (0) p3: !{!"foo_1", !{3, 1}}       // First level restrict
+///   (1), second restrict (2)
+///
+/// The unique codes allow distinguishing different restrict pointers at the
+/// same nesting level within the same function and scope.
+///
+void CodeGenFunction::AddPointerMetodataForRestrict(RawAddress AllocaAddr,
+                                                    QualType Ty,
+                                                    llvm::StringRef FullName) {
+  auto *AllocaInst = cast<llvm::AllocaInst>(AllocaAddr.getPointer());
+
+  unsigned RestictNesting = 0;
+
+  llvm::SmallVector<llvm::Metadata *, 8> RestrictMDs;
+  llvm::LLVMContext &Ctx = AllocaInst->getContext();
+
+  while (const PointerType *PT = Ty->getAs<PointerType>()) {
+    if (Ty.isRestrictQualified()) {
+      if (RestictNesting >= RestrictCodes.size())
+        RestrictCodes.push_back(1);
+      unsigned Code = RestrictCodes[RestictNesting];
+      llvm::Constant *C =
+          llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), Code);
+      RestrictMDs.push_back(llvm::ConstantAsMetadata::get(C));
+      RestrictCodes[RestictNesting]++;
+    } else {
+      if (PT->getPointeeType()->getAs<RecordType>())
+        AddMetodataForRestrict(AllocaAddr, PT->getPointeeType(), FullName);
+      llvm::Constant *C =
+          llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), 0);
+      RestrictMDs.push_back(llvm::ConstantAsMetadata::get(C));
+    }
+    RestictNesting++;
+    Ty = PT->getPointeeType();
+  }
+  llvm::MDNode *RestrictList = llvm::MDNode::get(Ctx, RestrictMDs);
+  llvm::MDString *NameMD = llvm::MDString::get(Ctx, FullName.str());
+  llvm::MDNode *Node = llvm::MDNode::get(Ctx, {NameMD, RestrictList});
+  AllocaInst->setMetadata(llvm::LLVMContext::MD_scope, Node);
+}
+
+bool CodeGenFunction::IsRestrictExperimentalSupportEnabled() const {
+  return (getLangOpts().IsCLanguageOnly() &&
+          (CGM.getCodeGenOpts().RestrictExperimental));
+}
+
+/// Constructs metadata for variables in the current lexical scope.
+///
+/// This function builds a unique name for each variable by combining the
----------------
AnastasiyaChernikova wrote:

In this case, a separate method is used for a class of variables (all variables 
in one scope have the same prefix, and then only the variables designated as 
restriction differ)

Example:
```
void test() {
  for (int i = 0; i < 3; i++) {
    int * restrict p;
    int *m;
    int *n;

    if (i % 2 == 0) {
      int *q;
    } else {
      int * restrict r;
      int *l;
    }
  }
}
```

After After the frontend work phase:
```
define dso_local void @test() #0 {
entry:
  %i = alloca i32, align 4
  %p = alloca ptr, align 8, !scope !9
  %m = alloca ptr, align 8, !scope !11
  %n = alloca ptr, align 8, !scope !11
  %q = alloca ptr, align 8, !scope !13
  %r = alloca ptr, align 8, !scope !14
  %l = alloca ptr, align 8, !scope !16
  call void @llvm.lifetime.start.p0(ptr %i) #2
  store i32 0, ptr %i, align 4, !tbaa !5
  br label %for.cond
  ...
}
!9 = !{!"test_10", !10}
!10 = !{i64 1}
!11 = !{!"test_10", !12}
!12 = !{i64 0}
!13 = !{!"test_100", !12}
!14 = !{!"test_1001", !15}
!15 = !{i64 2}
!16 = !{!"test_1001", !12}
```

https://github.com/llvm/llvm-project/pull/173394
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to