363 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Unit tests for CIR implementation of OpenACC's PointertLikeType interface10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Dialect/OpenACC/OpenACC.h"14#include "mlir/IR/BuiltinTypes.h"15#include "mlir/IR/Diagnostics.h"16#include "mlir/IR/MLIRContext.h"17#include "mlir/IR/Value.h"18#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"19#include "clang/CIR/Dialect/IR/CIRDialect.h"20#include "clang/CIR/Dialect/IR/CIRTypes.h"21#include "clang/CIR/Dialect/OpenACC/CIROpenACCTypeInterfaces.h"22#include "clang/CIR/Dialect/OpenACC/RegisterOpenACCExtensions.h"23#include "gtest/gtest.h"24 25using namespace mlir;26using namespace cir;27 28//===----------------------------------------------------------------------===//29// Test Fixture30//===----------------------------------------------------------------------===//31 32class CIROpenACCPointerLikeTest : public ::testing::Test {33protected:34 CIROpenACCPointerLikeTest() : b(&context), loc(UnknownLoc::get(&context)) {35 context.loadDialect<cir::CIRDialect>();36 context.loadDialect<mlir::acc::OpenACCDialect>();37 38 // Register extension to integrate CIR types with OpenACC.39 mlir::DialectRegistry registry;40 cir::acc::registerOpenACCExtensions(registry);41 context.appendDialectRegistry(registry);42 }43 44 MLIRContext context;45 OpBuilder b;46 Location loc;47 llvm::StringMap<unsigned> recordNames;48 49 mlir::IntegerAttr getAlignOne(mlir::MLIRContext *ctx) {50 // Note that mlir::IntegerType is used instead of cir::IntType here because51 // we don't need sign information for this to be useful, so keep it simple.52 clang::CharUnits align = clang::CharUnits::One();53 return b.getI64IntegerAttr(align.getQuantity());54 }55 56 mlir::StringAttr getUniqueRecordName(const std::string &baseName) {57 auto it = recordNames.find(baseName);58 if (it == recordNames.end()) {59 recordNames[baseName] = 0;60 return b.getStringAttr(baseName);61 }62 63 return b.getStringAttr(baseName + "." +64 std::to_string(recordNames[baseName]++));65 }66 67 // General handler for types without a specific test68 void testSingleType(mlir::Type ty,69 mlir::acc::VariableTypeCategory expectedTypeCategory) {70 mlir::Type ptrTy = cir::PointerType::get(ty);71 72 // cir::PointerType should be castable to acc::PointerLikeType73 auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy);74 ASSERT_NE(pltTy, nullptr);75 76 EXPECT_EQ(pltTy.getElementType(), ty);77 78 OwningOpRef<cir::AllocaOp> varPtrOp =79 cir::AllocaOp::create(b, loc, ptrTy, ty, "", getAlignOne(&context));80 81 mlir::Value val = varPtrOp.get();82 mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory(83 cast<TypedValue<mlir::acc::PointerLikeType>>(val),84 mlir::acc::getVarType(varPtrOp.get()));85 86 EXPECT_EQ(typeCategory, expectedTypeCategory);87 }88 89 void testScalarType(mlir::Type ty) {90 testSingleType(ty, mlir::acc::VariableTypeCategory::scalar);91 }92 93 void testNonScalarType(mlir::Type ty) {94 testSingleType(ty, mlir::acc::VariableTypeCategory::nonscalar);95 }96 97 void testUncategorizedType(mlir::Type ty) {98 testSingleType(ty, mlir::acc::VariableTypeCategory::uncategorized);99 }100 101 void testArrayType(mlir::Type ty) {102 // Build the array pointer type.103 mlir::Type arrTy = cir::ArrayType::get(ty, 10);104 mlir::Type ptrTy = cir::PointerType::get(arrTy);105 106 // Verify that the pointer points to the array type..107 auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy);108 ASSERT_NE(pltTy, nullptr);109 EXPECT_EQ(pltTy.getElementType(), arrTy);110 111 // Create an alloca for the array112 OwningOpRef<cir::AllocaOp> varPtrOp =113 cir::AllocaOp::create(b, loc, ptrTy, arrTy, "", getAlignOne(&context));114 115 // Verify that the type category is array.116 mlir::Value val = varPtrOp.get();117 mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory(118 cast<TypedValue<mlir::acc::PointerLikeType>>(val),119 mlir::acc::getVarType(varPtrOp.get()));120 EXPECT_EQ(typeCategory, mlir::acc::VariableTypeCategory::array);121 122 // Create an array-to-pointer decay cast.123 mlir::Type ptrToElemTy = cir::PointerType::get(ty);124 OwningOpRef<cir::CastOp> decayPtr = cir::CastOp::create(125 b, loc, ptrToElemTy, cir::CastKind::array_to_ptrdecay, val);126 mlir::Value decayVal = decayPtr.get();127 128 // Verify that we still get the expected element type.129 auto decayPltTy =130 dyn_cast_if_present<mlir::acc::PointerLikeType>(decayVal.getType());131 ASSERT_NE(decayPltTy, nullptr);132 EXPECT_EQ(decayPltTy.getElementType(), ty);133 134 // Verify that we still identify the type category as an array.135 mlir::acc::VariableTypeCategory decayTypeCategory =136 decayPltTy.getPointeeTypeCategory(137 cast<TypedValue<mlir::acc::PointerLikeType>>(decayVal),138 mlir::acc::getVarType(decayPtr.get()));139 EXPECT_EQ(decayTypeCategory, mlir::acc::VariableTypeCategory::array);140 141 // Create an element access.142 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);143 mlir::Value index =144 cir::ConstantOp::create(b, loc, cir::IntAttr::get(i32Ty, 2));145 OwningOpRef<cir::PtrStrideOp> accessPtr =146 cir::PtrStrideOp::create(b, loc, ptrToElemTy, decayVal, index);147 mlir::Value accessVal = accessPtr.get();148 149 // Verify that we still get the expected element type.150 auto accessPltTy =151 dyn_cast_if_present<mlir::acc::PointerLikeType>(accessVal.getType());152 ASSERT_NE(accessPltTy, nullptr);153 EXPECT_EQ(accessPltTy.getElementType(), ty);154 155 // Verify that we still identify the type category as an array.156 mlir::acc::VariableTypeCategory accessTypeCategory =157 accessPltTy.getPointeeTypeCategory(158 cast<TypedValue<mlir::acc::PointerLikeType>>(accessVal),159 mlir::acc::getVarType(accessPtr.get()));160 EXPECT_EQ(accessTypeCategory, mlir::acc::VariableTypeCategory::array);161 }162 163 // Structures and unions are accessed in the same way, so use a common test.164 void testRecordType(mlir::Type ty1, mlir::Type ty2,165 cir::RecordType::RecordKind kind) {166 // Build the structure pointer type.167 cir::RecordType structTy =168 cir::RecordType::get(&context, getUniqueRecordName("S"), kind);169 structTy.complete({ty1, ty2}, false, false);170 mlir::Type ptrTy = cir::PointerType::get(structTy);171 172 // Verify that the pointer points to the structure type.173 auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy);174 ASSERT_NE(pltTy, nullptr);175 EXPECT_EQ(pltTy.getElementType(), structTy);176 177 // Create an alloca for the array178 OwningOpRef<cir::AllocaOp> varPtrOp = cir::AllocaOp::create(179 b, loc, ptrTy, structTy, "", getAlignOne(&context));180 181 // Verify that the type category is composite.182 mlir::Value val = varPtrOp.get();183 mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory(184 cast<TypedValue<mlir::acc::PointerLikeType>>(val),185 mlir::acc::getVarType(varPtrOp.get()));186 EXPECT_EQ(typeCategory, mlir::acc::VariableTypeCategory::composite);187 188 // Access the first element of the structure.189 OwningOpRef<cir::GetMemberOp> access1 = cir::GetMemberOp::create(190 b, loc, cir::PointerType::get(ty1), val, "f1", 0u);191 mlir::Value accessVal1 = access1.get();192 193 // Verify that we get the expected element type.194 auto access1PltTy =195 dyn_cast_if_present<mlir::acc::PointerLikeType>(accessVal1.getType());196 ASSERT_NE(access1PltTy, nullptr);197 EXPECT_EQ(access1PltTy.getElementType(), ty1);198 199 // Verify that the type category is still composite.200 mlir::acc::VariableTypeCategory access1TypeCategory =201 access1PltTy.getPointeeTypeCategory(202 cast<TypedValue<mlir::acc::PointerLikeType>>(accessVal1),203 mlir::acc::getVarType(access1.get()));204 EXPECT_EQ(access1TypeCategory, mlir::acc::VariableTypeCategory::composite);205 206 // Access the second element of the structure.207 OwningOpRef<cir::GetMemberOp> access2 = cir::GetMemberOp::create(208 b, loc, cir::PointerType::get(ty2), val, "f2", 1u);209 mlir::Value accessVal2 = access2.get();210 211 // Verify that we get the expected element type.212 auto access2PltTy =213 dyn_cast_if_present<mlir::acc::PointerLikeType>(accessVal2.getType());214 ASSERT_NE(access2PltTy, nullptr);215 EXPECT_EQ(access2PltTy.getElementType(), ty2);216 217 // Verify that the type category is still composite.218 mlir::acc::VariableTypeCategory access2TypeCategory =219 access2PltTy.getPointeeTypeCategory(220 cast<TypedValue<mlir::acc::PointerLikeType>>(accessVal2),221 mlir::acc::getVarType(access2.get()));222 EXPECT_EQ(access2TypeCategory, mlir::acc::VariableTypeCategory::composite);223 }224 225 void testStructType(mlir::Type ty1, mlir::Type ty2) {226 testRecordType(ty1, ty2, cir::RecordType::RecordKind::Struct);227 }228 229 void testUnionType(mlir::Type ty1, mlir::Type ty2) {230 testRecordType(ty1, ty2, cir::RecordType::RecordKind::Union);231 }232 233 // This is testing a case like this:234 //235 // struct S {236 // int *f1;237 // int *f2;238 // } *p;239 // int *pMember = p->f2;240 //241 // That is, we are not testing a pointer to a member, we're testing a pointer242 // that is loaded as a member value.243 void testPointerToMemberType(244 mlir::Type ty, mlir::acc::VariableTypeCategory expectedTypeCategory) {245 // Construct a struct type with two members that are pointers to the input246 // type.247 mlir::Type ptrTy = cir::PointerType::get(ty);248 cir::RecordType structTy =249 cir::RecordType::get(&context, getUniqueRecordName("S"),250 cir::RecordType::RecordKind::Struct);251 structTy.complete({ptrTy, ptrTy}, false, false);252 mlir::Type structPptrTy = cir::PointerType::get(structTy);253 254 // Create an alloca for the struct.255 OwningOpRef<cir::AllocaOp> varPtrOp = cir::AllocaOp::create(256 b, loc, structPptrTy, structTy, "S", getAlignOne(&context));257 mlir::Value val = varPtrOp.get();258 259 // Get a pointer to the second member.260 OwningOpRef<cir::GetMemberOp> access = cir::GetMemberOp::create(261 b, loc, cir::PointerType::get(ptrTy), val, b.getStringAttr("f2"), 1);262 mlir::Value accessVal = access.get();263 264 // Load the value of the second member. This is the pointer we want to test.265 OwningOpRef<cir::LoadOp> loadOp = cir::LoadOp::create(b, loc, accessVal);266 mlir::Value loadVal = loadOp.get();267 268 // Verify that the type category is the expected type category.269 auto pltTy = dyn_cast_if_present<mlir::acc::PointerLikeType>(ptrTy);270 mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory(271 cast<TypedValue<mlir::acc::PointerLikeType>>(loadVal),272 mlir::acc::getVarType(loadOp.get()));273 274 EXPECT_EQ(typeCategory, expectedTypeCategory);275 }276};277 278TEST_F(CIROpenACCPointerLikeTest, testPointerToInt) {279 // Test various scalar types.280 testScalarType(cir::IntType::get(&context, 8, true));281 testScalarType(cir::IntType::get(&context, 8, false));282 testScalarType(cir::IntType::get(&context, 16, true));283 testScalarType(cir::IntType::get(&context, 16, false));284 testScalarType(cir::IntType::get(&context, 32, true));285 testScalarType(cir::IntType::get(&context, 32, false));286 testScalarType(cir::IntType::get(&context, 64, true));287 testScalarType(cir::IntType::get(&context, 64, false));288 testScalarType(cir::IntType::get(&context, 128, true));289 testScalarType(cir::IntType::get(&context, 128, false));290}291 292TEST_F(CIROpenACCPointerLikeTest, testPointerToBool) {293 testScalarType(cir::BoolType::get(&context));294}295 296TEST_F(CIROpenACCPointerLikeTest, testPointerToFloat) {297 testScalarType(cir::SingleType::get(&context));298 testScalarType(cir::DoubleType::get(&context));299}300 301TEST_F(CIROpenACCPointerLikeTest, testPointerToPointer) {302 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);303 mlir::Type ptrTy = cir::PointerType::get(i32Ty);304 testScalarType(ptrTy);305}306 307TEST_F(CIROpenACCPointerLikeTest, testPointerToArray) {308 // Test an array type.309 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);310 testArrayType(i32Ty);311}312 313TEST_F(CIROpenACCPointerLikeTest, testPointerToStruct) {314 // Test a struct type.315 mlir::Type i16Ty = cir::IntType::get(&context, 16, true);316 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);317 testStructType(i16Ty, i32Ty);318}319 320TEST_F(CIROpenACCPointerLikeTest, testPointerToUnion) {321 // Test a union type.322 mlir::Type i16Ty = cir::IntType::get(&context, 16, true);323 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);324 testUnionType(i16Ty, i32Ty);325}326 327TEST_F(CIROpenACCPointerLikeTest, testPointerToFunction) {328 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);329 mlir::Type funcTy =330 cir::FuncType::get(SmallVector<mlir::Type, 2>{i32Ty, i32Ty}, i32Ty);331 testNonScalarType(funcTy);332}333 334TEST_F(CIROpenACCPointerLikeTest, testPointerToVector) {335 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);336 mlir::Type vecTy = cir::VectorType::get(i32Ty, 4);337 testNonScalarType(vecTy);338}339 340TEST_F(CIROpenACCPointerLikeTest, testPointerToVoid) {341 mlir::Type voidTy = cir::VoidType::get(&context);342 testUncategorizedType(voidTy);343}344 345TEST_F(CIROpenACCPointerLikeTest, testPointerToIntMember) {346 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);347 testPointerToMemberType(i32Ty, mlir::acc::VariableTypeCategory::scalar);348}349 350TEST_F(CIROpenACCPointerLikeTest, testPointerToArrayMember) {351 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);352 mlir::Type arrTy = cir::ArrayType::get(i32Ty, 10);353 testPointerToMemberType(arrTy, mlir::acc::VariableTypeCategory::array);354}355 356TEST_F(CIROpenACCPointerLikeTest, testPointerToStructMember) {357 mlir::Type i32Ty = cir::IntType::get(&context, 32, true);358 cir::RecordType structTy = cir::RecordType::get(359 &context, getUniqueRecordName("S"), cir::RecordType::RecordKind::Struct);360 structTy.complete({i32Ty, i32Ty}, false, false);361 testPointerToMemberType(structTy, mlir::acc::VariableTypeCategory::composite);362}363