Skip to content

[CIR] Upstream basic support for ArrayType #130502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 13, 2025

Conversation

AmrDeveloper
Copy link
Member

This change adds the basic support for ArrayType

Issue #130197

@AmrDeveloper
Copy link
Member Author

There will be two upcoming patches.

1 - Initializing const array and zero initializing support (Depends on upstreaming ConstantEmitter and ZeroAttr)
2 - Dynamic-size arrays, and accessing arrays using the cir.ptr_stride operation (Depends on upstreaming CastOp)

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Mar 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 9, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes

This change adds the basic support for ArrayType

Issue #130197


Full diff: https://github.com/llvm/llvm-project/pull/130502.diff

7 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.h (+4)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+20-1)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+8)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+12)
  • (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+3)
  • (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+16)
  • (added) clang/test/CIR/CodeGen/array.cpp (+12)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
index 438fb7d09608d..1451ea47c50c8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
@@ -30,6 +30,10 @@ class VarDecl;
 class RecordDecl;
 } // namespace clang
 
+namespace cir {
+class ArrayType;
+} // namespace cir
+
 #define GET_ATTRDEF_CLASSES
 #include "clang/CIR/Dialect/IR/CIROpsAttributes.h.inc"
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index a78e5eae08e33..b2bac643b62da 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -280,6 +280,25 @@ def CIR_BoolType :
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// ArrayType
+//===----------------------------------------------------------------------===//
+
+def CIR_ArrayType : CIR_Type<"Array", "array",
+    [DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
+
+  let summary = "CIR array type";
+  let description = [{
+    `CIR.array` represents C/C++ constant arrays.
+  }];
+
+  let parameters = (ins "mlir::Type":$eltType, "uint64_t":$size);
+
+  let assemblyFormat = [{
+    `<` $eltType `x` $size `>`
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // FuncType
 //===----------------------------------------------------------------------===//
@@ -386,7 +405,7 @@ def VoidPtr : Type<
 //===----------------------------------------------------------------------===//
 
 def CIR_AnyType : AnyTypeOf<[
-  CIR_VoidType, CIR_BoolType, CIR_IntType, CIR_AnyFloat, CIR_PointerType,
+  CIR_VoidType, CIR_BoolType, CIR_ArrayType, CIR_IntType, CIR_AnyFloat, CIR_PointerType,
   CIR_FuncType
 ]>;
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 01d56963883cc..250192ec254d1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -33,6 +33,14 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
       llvm_unreachable("NYI: PPC double-double format for long double");
     llvm_unreachable("Unsupported format for long double");
   }
+
+  bool isSized(mlir::Type ty) {
+    if (mlir::isa<cir::PointerType, cir::ArrayType, cir::BoolType,
+                  cir::IntType>(ty))
+      return true;
+    assert(0 && "Unimplemented size for type");
+    return false;
+  }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index dcfaaedc2ef57..78e894dee0071 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -202,6 +202,18 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
     break;
   }
 
+  case Type::ConstantArray: {
+    const ConstantArrayType *arrTy = cast<ConstantArrayType>(ty);
+    mlir::Type elemTy = convertTypeForMem(arrTy->getElementType());
+
+    // FIXME: In LLVM, "lower arrays of undefined struct type to arrays of
+    // i8 just to have a concrete type". Not sure this makes sense in CIR yet.
+    assert(builder.isSized(elemTy) && "not implemented");
+    resultType = cir::ArrayType::get(builder.getContext(), elemTy,
+                                     arrTy->getSize().getZExtValue());
+    break;
+  }
+
   case Type::FunctionNoProto:
   case Type::FunctionProto:
     resultType = convertFunctionTypeInternal(type);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 5ad369b40cda1..1e078e2797270 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -166,6 +166,9 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
     return success();
   }
 
+  if (mlir::isa<cir::ArrayType>(opType))
+    return success();
+
   assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");
   return op->emitOpError("global with type ")
          << cast<TypedAttr>(attrType).getType() << " not yet supported";
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 8bdde54ad41f6..6291297492227 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -369,6 +369,22 @@ BoolType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
   return 1;
 }
 
+//===----------------------------------------------------------------------===//
+//  Definitions
+//===----------------------------------------------------------------------===//
+
+llvm::TypeSize
+ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
+                             ::mlir::DataLayoutEntryListRef params) const {
+  return getSize() * dataLayout.getTypeSizeInBits(getEltType());
+}
+
+uint64_t
+ArrayType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
+                           ::mlir::DataLayoutEntryListRef params) const {
+  return dataLayout.getTypeABIAlignment(getEltType());
+}
+
 //===----------------------------------------------------------------------===//
 // PointerType Definitions
 //===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
new file mode 100644
index 0000000000000..3a5950ffe3d87
--- /dev/null
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s
+
+int a[10];
+// CHECK: cir.global external @a : !cir.array<!cir.int<s, 32> x 10>
+
+extern int b[10];
+// CHECK: cir.global external @b : !cir.array<!cir.int<s, 32> x 10>
+
+void f() {
+  int c[10];
+  // CHECK: %[[ARR:.*]] = cir.alloca !cir.array<!cir.int<s, 32> x 10>, !cir.ptr<!cir.array<!cir.int<s, 32> x 10>>, ["c"]
+}


// FIXME: In LLVM, "lower arrays of undefined struct type to arrays of
// i8 just to have a concrete type". Not sure this makes sense in CIR yet.
assert(builder.isSized(elemTy) && "not implemented");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably use the cgm.errorNYI, then just come up with a way to recover. That said, this is exactly why having isSized assert is awkward here.

Copy link
Member Author

@AmrDeveloper AmrDeveloper Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey, thats make sense and i will try to recover with SInt32Ty

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a test for lowering to LLVM IR?

@@ -386,7 +405,7 @@ def VoidPtr : Type<
//===----------------------------------------------------------------------===//

def CIR_AnyType : AnyTypeOf<[
CIR_VoidType, CIR_BoolType, CIR_IntType, CIR_AnyFloat, CIR_PointerType,
CIR_VoidType, CIR_BoolType, CIR_ArrayType, CIR_IntType, CIR_AnyFloat, CIR_PointerType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line is over 80 characters. It should wrap to avoid that.

@@ -0,0 +1,12 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will multidimensional arrays and array function arguments work at this point? If so, can you add tests for those?

@@ -166,6 +166,9 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,
return success();
}

if (mlir::isa<cir::ArrayType>(opType))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this in the incubator implementation of this function. Why is this here?

//===----------------------------------------------------------------------===//

llvm::TypeSize
ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these functions being called with any of the test cases? I don't see any checks that would be related to this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of sizeof operator but it's not implemented yet, is there is another way to test the size in lit test

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point was that if the code isn't being called, you should leave it out until it is needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it's part of the DataLayoutTypeInterface interface so we must implement it, I can test it after merging the sizeof PR #130847

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thanks for the clarification.

mlir::Type elemTy = convertTypeForMem(arrTy->getElementType());

if (!builder.isSized(elemTy)) {
cgm.errorNYI(SourceLocation(), "unimplemented size for type", type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the error being handled this way. If you're going to report an error about unimplemented types here, the check for the types should be here. If someone were to change the implementation of isSized(), they would have no way to know that this code needed to be updated.

@@ -33,6 +33,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
llvm_unreachable("NYI: PPC double-double format for long double");
llvm_unreachable("Unsupported format for long double");
}

bool isSized(mlir::Type ty) {
return mlir::isa<cir::PointerType, cir::ArrayType, cir::BoolType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was better with the assert for other types. This function should handle all types that can occur in the current form of CIR. As we add new types, this function should be updated to indicate if they are sized or not. So, this isn't quite like other errorNYI cases. An assert here is reasonable as a permanent part of the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes i will update it, and i think no need for NYI or other assert when calling it because in call cases we will not need to recover

//===----------------------------------------------------------------------===//

llvm::TypeSize
ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point was that if the code isn't being called, you should leave it out until it is needed.

@@ -572,6 +572,10 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,

return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);
});
converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
auto ty = convertTypeForMemory(converter, dataLayout, type.getEltType());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto ty = convertTypeForMemory(converter, dataLayout, type.getEltType());
mlir::Type ty = convertTypeForMemory(converter, dataLayout, type.getEltType());

// CHECK: cir.global external @a : !cir.array<!cir.int<s, 32> x 10>

int aa[10][10];
// CHECK: cir.global external @aa : !cir.array<!cir.array<!cir.int<s, 32> x 10> x 10>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use different sizes for the dimensions here so we can verify that the CIR generated has them in the right order.

}

void f2(int p[10]) {}
// CHECK: cir.func @f2(%arg0: !cir.ptr<!cir.int<s, 32>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also check the cir.alloca generated in this case?

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have just one minor comment on the update. Please wait for @erichkeane to review again, but this looks good to me.

void f() {
int l[10];
}
// CHECK: alloca [10 x i32], i64 1, align 16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good practice to have a check for the function name to establish that we're seeing the alloca in the correct context.

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is still not fixed, and Andy/Bruno still have comments here, so I don't believe this to be ready yet.

@AmrDeveloper
Copy link
Member Author

My concern is still not fixed, and Andy/Bruno still have comments here, so I don't believe this to be ready yet.

I already addressed all comments except the test for Size and it's need sizeof PR to merge, and the assert line which we need to agree on, other than that every thing is addressed :D

Co-authored-by: Andy Kaylor <[email protected]>
cir::IntType>(ty))
return true;

assert(0 && "Unexpected MLIR type");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the

Suggested change
assert(0 && "Unexpected MLIR type");
assert(!MissingFeatures::unsizedTypes());

was the suggestion here (see the other uses of MissingFeatures).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey, i will check MissingFeatures and update it

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 nit, else LGTM.

Copy link

github-actions bot commented Mar 12, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@AmrDeveloper AmrDeveloper merged commit bd0d28a into llvm:main Mar 13, 2025
11 checks passed
frederik-h pushed a commit to frederik-h/llvm-project that referenced this pull request Mar 18, 2025
This change adds the basic support for ArrayType

Issue llvm#130197
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants