Author: Andy Kaylor Date: 2025-05-15T14:41:43-07:00 New Revision: fc7857ca95bba93807959ad09f983221db8811e1
URL: https://github.com/llvm/llvm-project/commit/fc7857ca95bba93807959ad09f983221db8811e1 DIFF: https://github.com/llvm/llvm-project/commit/fc7857ca95bba93807959ad09f983221db8811e1.diff LOG: [CIR] Add PointerLikeType interface support for cir::PointerType (#139768) This adds code to attach the OpenACC PointerLikeType interface to cir::PointerType, along with a unit test for the interface. Added: clang/include/clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h clang/include/clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h clang/lib/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.cpp clang/lib/CIR/Dialect/OpenACC/CMakeLists.txt clang/lib/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.cpp clang/unittests/CIR/CMakeLists.txt clang/unittests/CIR/PointerLikeTest.cpp Modified: clang/lib/CIR/CodeGen/CIRGenerator.cpp clang/lib/CIR/CodeGen/CMakeLists.txt clang/lib/CIR/Dialect/CMakeLists.txt clang/unittests/CMakeLists.txt Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h b/clang/include/clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h new file mode 100644 index 0000000000000..3011245cd8a03 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains external dialect interfaces for CIR. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CIR_DIALECT_OPENACC_CIROPENACCTYPEINTERFACES_H +#define CLANG_CIR_DIALECT_OPENACC_CIROPENACCTYPEINTERFACES_H + +#include "mlir/Dialect/OpenACC/OpenACC.h" + +namespace cir::acc { + +template <typename T> +struct OpenACCPointerLikeModel + : public mlir::acc::PointerLikeType::ExternalModel< + OpenACCPointerLikeModel<T>, T> { + mlir::Type getElementType(mlir::Type pointer) const { + return mlir::cast<T>(pointer).getPointee(); + } + mlir::acc::VariableTypeCategory + getPointeeTypeCategory(mlir::Type pointer, + mlir::TypedValue<mlir::acc::PointerLikeType> varPtr, + mlir::Type varType) const; +}; + +} // namespace cir::acc + +#endif // CLANG_CIR_DIALECT_OPENACC_CIROPENACCTYPEINTERFACES_H diff --git a/clang/include/clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h b/clang/include/clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h new file mode 100644 index 0000000000000..13780a01ea1bb --- /dev/null +++ b/clang/include/clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CIR_DIALECT_OPENACC_REGISTEROPENACCEXTENSIONS_H +#define CLANG_CIR_DIALECT_OPENACC_REGISTEROPENACCEXTENSIONS_H + +namespace mlir { +class DialectRegistry; +} // namespace mlir + +namespace cir::acc { + +void registerOpenACCExtensions(mlir::DialectRegistry ®istry); + +} // namespace cir::acc + +#endif // CLANG_CIR_DIALECT_OPENACC_REGISTEROPENACCEXTENSIONS_H diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index aa3864deb733c..40252ffecfba1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclGroup.h" #include "clang/CIR/CIRGenerator.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h" using namespace cir; using namespace clang; @@ -38,6 +39,12 @@ void CIRGenerator::Initialize(ASTContext &astContext) { mlirContext = std::make_unique<mlir::MLIRContext>(); mlirContext->loadDialect<cir::CIRDialect>(); mlirContext->getOrLoadDialect<mlir::acc::OpenACCDialect>(); + + // Register extensions to integrate CIR types with OpenACC. + mlir::DialectRegistry registry; + cir::acc::registerOpenACCExtensions(registry); + mlirContext->appendDialectRegistry(registry); + cgm = std::make_unique<clang::CIRGen::CIRGenModule>( *mlirContext.get(), astContext, codeGenOpts, diags); } diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 7a701c3c0b82b..8f5796e59d3bb 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -35,6 +35,7 @@ add_clang_library(clangCIR clangBasic clangLex ${dialect_libs} + CIROpenACCSupport MLIRCIR MLIRCIRInterfaces ) diff --git a/clang/lib/CIR/Dialect/CMakeLists.txt b/clang/lib/CIR/Dialect/CMakeLists.txt index 9f57627c321fb..c825a61b2779b 100644 --- a/clang/lib/CIR/Dialect/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(IR) +add_subdirectory(OpenACC) add_subdirectory(Transforms) diff --git a/clang/lib/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.cpp b/clang/lib/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.cpp new file mode 100644 index 0000000000000..de8dd9c55ee32 --- /dev/null +++ b/clang/lib/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of external dialect interfaces for CIR. +// +//===----------------------------------------------------------------------===// + +#include "clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" + +namespace cir::acc { + +mlir::Type getBaseType(mlir::Value varPtr) { + mlir::Operation *op = varPtr.getDefiningOp(); + assert(op && "Expected a defining operation"); + + // This is the variable definition we're looking for. + if (auto allocaOp = mlir::dyn_cast<cir::AllocaOp>(*op)) + return allocaOp.getAllocaType(); + + // Look through casts to the source pointer. + if (auto castOp = mlir::dyn_cast<cir::CastOp>(*op)) + return getBaseType(castOp.getSrc()); + + // Follow the source of ptr strides. + if (auto ptrStrideOp = mlir::dyn_cast<cir::PtrStrideOp>(*op)) + return getBaseType(ptrStrideOp.getBase()); + + if (auto getMemberOp = mlir::dyn_cast<cir::GetMemberOp>(*op)) + return getBaseType(getMemberOp.getAddr()); + + return mlir::cast<cir::PointerType>(varPtr.getType()).getPointee(); +} + +template <> +mlir::acc::VariableTypeCategory +OpenACCPointerLikeModel<cir::PointerType>::getPointeeTypeCategory( + mlir::Type pointer, mlir::TypedValue<mlir::acc::PointerLikeType> varPtr, + mlir::Type varType) const { + mlir::Type eleTy = getBaseType(varPtr); + + if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(eleTy)) + return mappableTy.getTypeCategory(varPtr); + + if (isAnyIntegerOrFloatingPointType(eleTy) || + mlir::isa<cir::BoolType>(eleTy) || mlir::isa<cir::PointerType>(eleTy)) + return mlir::acc::VariableTypeCategory::scalar; + if (mlir::isa<cir::ArrayType>(eleTy)) + return mlir::acc::VariableTypeCategory::array; + if (mlir::isa<cir::RecordType>(eleTy)) + return mlir::acc::VariableTypeCategory::composite; + if (mlir::isa<cir::FuncType>(eleTy) || mlir::isa<cir::VectorType>(eleTy)) + return mlir::acc::VariableTypeCategory::nonscalar; + + // Without further checking, this type cannot be categorized. + return mlir::acc::VariableTypeCategory::uncategorized; +} + +} // namespace cir::acc diff --git a/clang/lib/CIR/Dialect/OpenACC/CMakeLists.txt b/clang/lib/CIR/Dialect/OpenACC/CMakeLists.txt new file mode 100644 index 0000000000000..de27f4cb27c59 --- /dev/null +++ b/clang/lib/CIR/Dialect/OpenACC/CMakeLists.txt @@ -0,0 +1,12 @@ +add_clang_library(CIROpenACCSupport + CIROpenACCTypeInterfaces.cpp + RegisterOpenACCExtensions.cpp + + DEPENDS + MLIRCIRTypeConstraintsIncGen + + LINK_LIBS PUBLIC + MLIRIR + MLIRCIR + MLIROpenACCDialect + ) diff --git a/clang/lib/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.cpp b/clang/lib/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.cpp new file mode 100644 index 0000000000000..3dfe7aeb6b1d6 --- /dev/null +++ b/clang/lib/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Registration for OpenACC extensions as applied to CIR dialect. +// +//===----------------------------------------------------------------------===// + +#include "clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h" + +namespace cir::acc { + +void registerOpenACCExtensions(mlir::DialectRegistry ®istry) { + registry.addExtension(+[](mlir::MLIRContext *ctx, cir::CIRDialect *dialect) { + cir::PointerType::attachInterface< + OpenACCPointerLikeModel<cir::PointerType>>(*ctx); + }); +} + +} // namespace cir::acc diff --git a/clang/unittests/CIR/CMakeLists.txt b/clang/unittests/CIR/CMakeLists.txt new file mode 100644 index 0000000000000..650fde38c48a9 --- /dev/null +++ b/clang/unittests/CIR/CMakeLists.txt @@ -0,0 +1,16 @@ +set(MLIR_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../mlir/include ) +set(MLIR_TABLEGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tools/mlir/include) +include_directories(SYSTEM ${MLIR_INCLUDE_DIR}) +include_directories(${MLIR_TABLEGEN_OUTPUT_DIR}) + +add_distinct_clang_unittest(CIRUnitTests + PointerLikeTest.cpp + LLVM_COMPONENTS + Core + + LINK_LIBS + MLIRCIR + CIROpenACCSupport + MLIRIR + MLIROpenACCDialect + ) diff --git a/clang/unittests/CIR/PointerLikeTest.cpp b/clang/unittests/CIR/PointerLikeTest.cpp new file mode 100644 index 0000000000000..c0da271d56d4c --- /dev/null +++ b/clang/unittests/CIR/PointerLikeTest.cpp @@ -0,0 +1,364 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Unit tests for CIR implementation of OpenACC's PointertLikeType interface +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/OpenACC/OpenACC.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/Diagnostics.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/IR/Value.h" +#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h" +#include "clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h" +#include "gtest/gtest.h" + +using namespace mlir; +using namespace cir; + +//===----------------------------------------------------------------------===// +// Test Fixture +//===----------------------------------------------------------------------===// + +class CIROpenACCPointerLikeTest : public ::testing::Test { +protected: + CIROpenACCPointerLikeTest() : b(&context), loc(UnknownLoc::get(&context)) { + context.loadDialect<cir::CIRDialect>(); + context.loadDialect<mlir::acc::OpenACCDialect>(); + + // Register extension to integrate CIR types with OpenACC. + mlir::DialectRegistry registry; + cir::acc::registerOpenACCExtensions(registry); + context.appendDialectRegistry(registry); + } + + MLIRContext context; + OpBuilder b; + Location loc; + llvm::StringMap<unsigned> recordNames; + + mlir::IntegerAttr getAlignOne(mlir::MLIRContext *ctx) { + // Note that mlir::IntegerType is used instead of cir::IntType here + // because we don't need sign information for this to be useful, so keep + // it simple. + clang::CharUnits align = clang::CharUnits::One(); + return mlir::IntegerAttr::get(mlir::IntegerType::get(ctx, 64), + align.getQuantity()); + } + + mlir::StringAttr getUniqueRecordName(const std::string &baseName) { + auto it = recordNames.find(baseName); + if (it == recordNames.end()) { + recordNames[baseName] = 0; + return b.getStringAttr(baseName); + } + + return b.getStringAttr(baseName + "." + + std::to_string(recordNames[baseName]++)); + } + + // General handler for types without a specific test + void testSingleType(mlir::Type ty, + mlir::acc::VariableTypeCategory expectedTypeCategory) { + mlir::Type ptrTy = cir::PointerType::get(ty); + + // cir::PointerType should be castable to acc::PointerLikeType + auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy); + ASSERT_NE(pltTy, nullptr); + + EXPECT_EQ(pltTy.getElementType(), ty); + + OwningOpRef<cir::AllocaOp> varPtrOp = + b.create<cir::AllocaOp>(loc, ptrTy, ty, "", getAlignOne(&context)); + + mlir::Value val = varPtrOp.get(); + mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(val), + mlir::acc::getVarType(varPtrOp.get())); + + EXPECT_EQ(typeCategory, expectedTypeCategory); + } + + void testScalarType(mlir::Type ty) { + testSingleType(ty, mlir::acc::VariableTypeCategory::scalar); + } + + void testNonScalarType(mlir::Type ty) { + testSingleType(ty, mlir::acc::VariableTypeCategory::nonscalar); + } + + void testUncategorizedType(mlir::Type ty) { + testSingleType(ty, mlir::acc::VariableTypeCategory::uncategorized); + } + + void testArrayType(mlir::Type ty) { + // Build the array pointer type. + mlir::Type arrTy = cir::ArrayType::get(ty, 10); + mlir::Type ptrTy = cir::PointerType::get(arrTy); + + // Verify that the pointer points to the array type.. + auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy); + ASSERT_NE(pltTy, nullptr); + EXPECT_EQ(pltTy.getElementType(), arrTy); + + // Create an alloca for the array + OwningOpRef<cir::AllocaOp> varPtrOp = + b.create<cir::AllocaOp>(loc, ptrTy, arrTy, "", getAlignOne(&context)); + + // Verify that the type category is array. + mlir::Value val = varPtrOp.get(); + mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(val), + mlir::acc::getVarType(varPtrOp.get())); + EXPECT_EQ(typeCategory, mlir::acc::VariableTypeCategory::array); + + // Create an array-to-pointer decay cast. + mlir::Type ptrToElemTy = cir::PointerType::get(ty); + OwningOpRef<cir::CastOp> decayPtr = b.create<cir::CastOp>( + loc, ptrToElemTy, cir::CastKind::array_to_ptrdecay, val); + mlir::Value decayVal = decayPtr.get(); + + // Verify that we still get the expected element type. + auto decayPltTy = + dyn_cast_if_present<mlir::acc::PointerLikeType>(decayVal.getType()); + ASSERT_NE(decayPltTy, nullptr); + EXPECT_EQ(decayPltTy.getElementType(), ty); + + // Verify that we still identify the type category as an array. + mlir::acc::VariableTypeCategory decayTypeCategory = + decayPltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(decayVal), + mlir::acc::getVarType(decayPtr.get())); + EXPECT_EQ(decayTypeCategory, mlir::acc::VariableTypeCategory::array); + + // Create an element access. + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + mlir::Value index = + b.create<cir::ConstantOp>(loc, cir::IntAttr::get(i32Ty, 2)); + OwningOpRef<cir::PtrStrideOp> accessPtr = + b.create<cir::PtrStrideOp>(loc, ptrToElemTy, decayVal, index); + mlir::Value accessVal = accessPtr.get(); + + // Verify that we still get the expected element type. + auto accessPltTy = + dyn_cast_if_present<mlir::acc::PointerLikeType>(accessVal.getType()); + ASSERT_NE(accessPltTy, nullptr); + EXPECT_EQ(accessPltTy.getElementType(), ty); + + // Verify that we still identify the type category as an array. + mlir::acc::VariableTypeCategory accessTypeCategory = + accessPltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(accessVal), + mlir::acc::getVarType(accessPtr.get())); + EXPECT_EQ(accessTypeCategory, mlir::acc::VariableTypeCategory::array); + } + + // Structures and unions are accessed in the same way, so use a common test. + void testRecordType(mlir::Type ty1, mlir::Type ty2, + cir::RecordType::RecordKind kind) { + // Build the structure pointer type. + cir::RecordType structTy = + cir::RecordType::get(&context, getUniqueRecordName("S"), kind); + structTy.complete({ty1, ty2}, false, false); + mlir::Type ptrTy = cir::PointerType::get(structTy); + + // Verify that the pointer points to the structure type. + auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy); + ASSERT_NE(pltTy, nullptr); + EXPECT_EQ(pltTy.getElementType(), structTy); + + // Create an alloca for the array + OwningOpRef<cir::AllocaOp> varPtrOp = b.create<cir::AllocaOp>( + loc, ptrTy, structTy, "", getAlignOne(&context)); + + // Verify that the type category is composite. + mlir::Value val = varPtrOp.get(); + mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(val), + mlir::acc::getVarType(varPtrOp.get())); + EXPECT_EQ(typeCategory, mlir::acc::VariableTypeCategory::composite); + + // Access the first element of the structure. + OwningOpRef<cir::GetMemberOp> access1 = b.create<cir::GetMemberOp>( + loc, cir::PointerType::get(ty1), val, b.getStringAttr("f1"), 0); + mlir::Value accessVal1 = access1.get(); + + // Verify that we get the expected element type. + auto access1PltTy = + dyn_cast_if_present<mlir::acc::PointerLikeType>(accessVal1.getType()); + ASSERT_NE(access1PltTy, nullptr); + EXPECT_EQ(access1PltTy.getElementType(), ty1); + + // Verify that the type category is still composite. + mlir::acc::VariableTypeCategory access1TypeCategory = + access1PltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(accessVal1), + mlir::acc::getVarType(access1.get())); + EXPECT_EQ(access1TypeCategory, mlir::acc::VariableTypeCategory::composite); + + // Access the second element of the structure. + OwningOpRef<cir::GetMemberOp> access2 = b.create<cir::GetMemberOp>( + loc, cir::PointerType::get(ty2), val, b.getStringAttr("f2"), 1); + mlir::Value accessVal2 = access2.get(); + + // Verify that we get the expected element type. + auto access2PltTy = + dyn_cast_if_present<mlir::acc::PointerLikeType>(accessVal2.getType()); + ASSERT_NE(access2PltTy, nullptr); + EXPECT_EQ(access2PltTy.getElementType(), ty2); + + // Verify that the type category is still composite. + mlir::acc::VariableTypeCategory access2TypeCategory = + access2PltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(accessVal2), + mlir::acc::getVarType(access2.get())); + EXPECT_EQ(access2TypeCategory, mlir::acc::VariableTypeCategory::composite); + } + + void testStructType(mlir::Type ty1, mlir::Type ty2) { + testRecordType(ty1, ty2, cir::RecordType::RecordKind::Struct); + } + + void testUnionType(mlir::Type ty1, mlir::Type ty2) { + testRecordType(ty1, ty2, cir::RecordType::RecordKind::Union); + } + + // This is testing a case like this: + // + // struct S { + // int *f1; + // int *f2; + // } *p; + // int *pMember = p->f2; + // + // That is, we are not testing a pointer to a member, we're testing a pointer + // that is loaded as a member value. + void testPointerToMemberType( + mlir::Type ty, mlir::acc::VariableTypeCategory expectedTypeCategory) { + // Construct a struct type with two members that are pointers to the input + // type. + mlir::Type ptrTy = cir::PointerType::get(ty); + cir::RecordType structTy = + cir::RecordType::get(&context, getUniqueRecordName("S"), + cir::RecordType::RecordKind::Struct); + structTy.complete({ptrTy, ptrTy}, false, false); + mlir::Type structPptrTy = cir::PointerType::get(structTy); + + // Create an alloca for the struct. + OwningOpRef<cir::AllocaOp> varPtrOp = b.create<cir::AllocaOp>( + loc, structPptrTy, structTy, "S", getAlignOne(&context)); + mlir::Value val = varPtrOp.get(); + + // Get a pointer to the second member. + OwningOpRef<cir::GetMemberOp> access = b.create<cir::GetMemberOp>( + loc, cir::PointerType::get(ptrTy), val, b.getStringAttr("f2"), 1); + mlir::Value accessVal = access.get(); + + // Load the value of the second member. This is the pointer we want to test. + OwningOpRef<cir::LoadOp> loadOp = b.create<cir::LoadOp>(loc, accessVal); + mlir::Value loadVal = loadOp.get(); + + // Verify that the type category is the expected type category. + auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy); + mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory( + cast<TypedValue<mlir::acc::PointerLikeType>>(loadVal), + mlir::acc::getVarType(loadOp.get())); + + EXPECT_EQ(typeCategory, expectedTypeCategory); + } +}; + +TEST_F(CIROpenACCPointerLikeTest, testPointerToInt) { + // Test various scalar types. + testScalarType(cir::IntType::get(&context, 8, true)); + testScalarType(cir::IntType::get(&context, 8, false)); + testScalarType(cir::IntType::get(&context, 16, true)); + testScalarType(cir::IntType::get(&context, 16, false)); + testScalarType(cir::IntType::get(&context, 32, true)); + testScalarType(cir::IntType::get(&context, 32, false)); + testScalarType(cir::IntType::get(&context, 64, true)); + testScalarType(cir::IntType::get(&context, 64, false)); + testScalarType(cir::IntType::get(&context, 128, true)); + testScalarType(cir::IntType::get(&context, 128, false)); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToBool) { + testScalarType(cir::BoolType::get(&context)); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToFloat) { + testScalarType(cir::SingleType::get(&context)); + testScalarType(cir::DoubleType::get(&context)); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToPointer) { + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + mlir::Type ptrTy = cir::PointerType::get(i32Ty); + testScalarType(ptrTy); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToArray) { + // Test an array type. + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + testArrayType(i32Ty); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToStruct) { + // Test a struct type. + mlir::Type i16Ty = cir::IntType::get(&context, 16, true); + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + testStructType(i16Ty, i32Ty); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToUnion) { + // Test a union type. + mlir::Type i16Ty = cir::IntType::get(&context, 16, true); + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + testUnionType(i16Ty, i32Ty); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToFunction) { + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + mlir::Type funcTy = + cir::FuncType::get(SmallVector<mlir::Type, 2>{i32Ty, i32Ty}, i32Ty); + testNonScalarType(funcTy); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToVector) { + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + mlir::Type vecTy = cir::VectorType::get(i32Ty, 4); + testNonScalarType(vecTy); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToVoid) { + mlir::Type voidTy = cir::VoidType::get(&context); + testUncategorizedType(voidTy); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToIntMember) { + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + testPointerToMemberType(i32Ty, mlir::acc::VariableTypeCategory::scalar); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToArrayMember) { + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + mlir::Type arrTy = cir::ArrayType::get(i32Ty, 10); + testPointerToMemberType(arrTy, mlir::acc::VariableTypeCategory::array); +} + +TEST_F(CIROpenACCPointerLikeTest, testPointerToStructMember) { + mlir::Type i32Ty = cir::IntType::get(&context, 32, true); + cir::RecordType structTy = cir::RecordType::get( + &context, getUniqueRecordName("S"), cir::RecordType::RecordKind::Struct); + structTy.complete({i32Ty, i32Ty}, false, false); + testPointerToMemberType(structTy, mlir::acc::VariableTypeCategory::composite); +} diff --git a/clang/unittests/CMakeLists.txt b/clang/unittests/CMakeLists.txt index b4114d419b75c..aef28f914b640 100644 --- a/clang/unittests/CMakeLists.txt +++ b/clang/unittests/CMakeLists.txt @@ -105,7 +105,9 @@ add_subdirectory(Index) add_subdirectory(InstallAPI) add_subdirectory(Serialization) add_subdirectory(Support) - +if (CLANG_ENABLE_CIR) + add_subdirectory(CIR) +endif() # If we're doing a single merged clang unit test binary, add that target after # all the previous subdirectories have been processed. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits