1 //===- CIRTypes.cpp - MLIR CIR Types --------------------------------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the types in the CIR dialect. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/CIR/Dialect/IR/CIRTypes.h" 14 15 #include "mlir/IR/DialectImplementation.h" 16 #include "clang/CIR/Dialect/IR/CIRDialect.h" 17 #include "llvm/ADT/TypeSwitch.h" 18 19 //===----------------------------------------------------------------------===// 20 // CIR Custom Parser/Printer Signatures 21 //===----------------------------------------------------------------------===// 22 23 static mlir::ParseResult 24 parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> ¶ms, 25 bool &isVarArg); 26 static void printFuncTypeArgs(mlir::AsmPrinter &p, 27 mlir::ArrayRef<mlir::Type> params, bool isVarArg); 28 29 //===----------------------------------------------------------------------===// 30 // Get autogenerated stuff 31 //===----------------------------------------------------------------------===// 32 33 #define GET_TYPEDEF_CLASSES 34 #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" 35 36 using namespace mlir; 37 using namespace cir; 38 39 //===----------------------------------------------------------------------===// 40 // General CIR parsing / printing 41 //===----------------------------------------------------------------------===// 42 43 Type CIRDialect::parseType(DialectAsmParser &parser) const { 44 llvm::SMLoc typeLoc = parser.getCurrentLocation(); 45 llvm::StringRef mnemonic; 46 Type genType; 47 48 // Try to parse as a tablegen'd type. 49 OptionalParseResult parseResult = 50 generatedTypeParser(parser, &mnemonic, genType); 51 if (parseResult.has_value()) 52 return genType; 53 54 // TODO(CIR) Attempt to parse as a raw C++ type. 55 parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic; 56 return Type(); 57 } 58 59 void CIRDialect::printType(Type type, DialectAsmPrinter &os) const { 60 // Try to print as a tablegen'd type. 61 if (generatedTypePrinter(type, os).succeeded()) 62 return; 63 64 // TODO(CIR) Attempt to print as a raw C++ type. 65 llvm::report_fatal_error("printer is missing a handler for this type"); 66 } 67 68 //===----------------------------------------------------------------------===// 69 // IntType Definitions 70 //===----------------------------------------------------------------------===// 71 72 Type IntType::parse(mlir::AsmParser &parser) { 73 mlir::MLIRContext *context = parser.getBuilder().getContext(); 74 llvm::SMLoc loc = parser.getCurrentLocation(); 75 bool isSigned; 76 unsigned width; 77 78 if (parser.parseLess()) 79 return {}; 80 81 // Fetch integer sign. 82 llvm::StringRef sign; 83 if (parser.parseKeyword(&sign)) 84 return {}; 85 if (sign == "s") 86 isSigned = true; 87 else if (sign == "u") 88 isSigned = false; 89 else { 90 parser.emitError(loc, "expected 's' or 'u'"); 91 return {}; 92 } 93 94 if (parser.parseComma()) 95 return {}; 96 97 // Fetch integer size. 98 if (parser.parseInteger(width)) 99 return {}; 100 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) { 101 parser.emitError(loc, "expected integer width to be from ") 102 << IntType::minBitwidth() << " up to " << IntType::maxBitwidth(); 103 return {}; 104 } 105 106 if (parser.parseGreater()) 107 return {}; 108 109 return IntType::get(context, width, isSigned); 110 } 111 112 void IntType::print(mlir::AsmPrinter &printer) const { 113 char sign = isSigned() ? 's' : 'u'; 114 printer << '<' << sign << ", " << getWidth() << '>'; 115 } 116 117 llvm::TypeSize 118 IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 119 mlir::DataLayoutEntryListRef params) const { 120 return llvm::TypeSize::getFixed(getWidth()); 121 } 122 123 uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout, 124 mlir::DataLayoutEntryListRef params) const { 125 return (uint64_t)(getWidth() / 8); 126 } 127 128 uint64_t 129 IntType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 130 ::mlir::DataLayoutEntryListRef params) const { 131 return (uint64_t)(getWidth() / 8); 132 } 133 134 mlir::LogicalResult 135 IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, 136 unsigned width, bool isSigned) { 137 if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) { 138 emitError() << "IntType only supports widths from " 139 << IntType::minBitwidth() << " up to " 140 << IntType::maxBitwidth(); 141 return mlir::failure(); 142 } 143 return mlir::success(); 144 } 145 146 //===----------------------------------------------------------------------===// 147 // Floating-point type definitions 148 //===----------------------------------------------------------------------===// 149 150 const llvm::fltSemantics &SingleType::getFloatSemantics() const { 151 return llvm::APFloat::IEEEsingle(); 152 } 153 154 llvm::TypeSize 155 SingleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 156 mlir::DataLayoutEntryListRef params) const { 157 return llvm::TypeSize::getFixed(getWidth()); 158 } 159 160 uint64_t 161 SingleType::getABIAlignment(const mlir::DataLayout &dataLayout, 162 mlir::DataLayoutEntryListRef params) const { 163 return (uint64_t)(getWidth() / 8); 164 } 165 166 uint64_t 167 SingleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 168 ::mlir::DataLayoutEntryListRef params) const { 169 return (uint64_t)(getWidth() / 8); 170 } 171 172 const llvm::fltSemantics &DoubleType::getFloatSemantics() const { 173 return llvm::APFloat::IEEEdouble(); 174 } 175 176 llvm::TypeSize 177 DoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 178 mlir::DataLayoutEntryListRef params) const { 179 return llvm::TypeSize::getFixed(getWidth()); 180 } 181 182 uint64_t 183 DoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, 184 mlir::DataLayoutEntryListRef params) const { 185 return (uint64_t)(getWidth() / 8); 186 } 187 188 uint64_t 189 DoubleType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 190 ::mlir::DataLayoutEntryListRef params) const { 191 return (uint64_t)(getWidth() / 8); 192 } 193 194 const llvm::fltSemantics &FP16Type::getFloatSemantics() const { 195 return llvm::APFloat::IEEEhalf(); 196 } 197 198 llvm::TypeSize 199 FP16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 200 mlir::DataLayoutEntryListRef params) const { 201 return llvm::TypeSize::getFixed(getWidth()); 202 } 203 204 uint64_t FP16Type::getABIAlignment(const mlir::DataLayout &dataLayout, 205 mlir::DataLayoutEntryListRef params) const { 206 return (uint64_t)(getWidth() / 8); 207 } 208 209 uint64_t 210 FP16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 211 ::mlir::DataLayoutEntryListRef params) const { 212 return (uint64_t)(getWidth() / 8); 213 } 214 215 const llvm::fltSemantics &BF16Type::getFloatSemantics() const { 216 return llvm::APFloat::BFloat(); 217 } 218 219 llvm::TypeSize 220 BF16Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 221 mlir::DataLayoutEntryListRef params) const { 222 return llvm::TypeSize::getFixed(getWidth()); 223 } 224 225 uint64_t BF16Type::getABIAlignment(const mlir::DataLayout &dataLayout, 226 mlir::DataLayoutEntryListRef params) const { 227 return (uint64_t)(getWidth() / 8); 228 } 229 230 uint64_t 231 BF16Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 232 ::mlir::DataLayoutEntryListRef params) const { 233 return (uint64_t)(getWidth() / 8); 234 } 235 236 const llvm::fltSemantics &FP80Type::getFloatSemantics() const { 237 return llvm::APFloat::x87DoubleExtended(); 238 } 239 240 llvm::TypeSize 241 FP80Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 242 mlir::DataLayoutEntryListRef params) const { 243 // Though only 80 bits are used for the value, the type is 128 bits in size. 244 return llvm::TypeSize::getFixed(128); 245 } 246 247 uint64_t FP80Type::getABIAlignment(const mlir::DataLayout &dataLayout, 248 mlir::DataLayoutEntryListRef params) const { 249 return 16; 250 } 251 252 uint64_t 253 FP80Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 254 ::mlir::DataLayoutEntryListRef params) const { 255 return 16; 256 } 257 258 const llvm::fltSemantics &FP128Type::getFloatSemantics() const { 259 return llvm::APFloat::IEEEquad(); 260 } 261 262 llvm::TypeSize 263 FP128Type::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 264 mlir::DataLayoutEntryListRef params) const { 265 return llvm::TypeSize::getFixed(getWidth()); 266 } 267 268 uint64_t FP128Type::getABIAlignment(const mlir::DataLayout &dataLayout, 269 mlir::DataLayoutEntryListRef params) const { 270 return 16; 271 } 272 273 uint64_t 274 FP128Type::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, 275 ::mlir::DataLayoutEntryListRef params) const { 276 return 16; 277 } 278 279 const llvm::fltSemantics &LongDoubleType::getFloatSemantics() const { 280 return mlir::cast<cir::CIRFPTypeInterface>(getUnderlying()) 281 .getFloatSemantics(); 282 } 283 284 llvm::TypeSize 285 LongDoubleType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, 286 mlir::DataLayoutEntryListRef params) const { 287 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying()) 288 .getTypeSizeInBits(dataLayout, params); 289 } 290 291 uint64_t 292 LongDoubleType::getABIAlignment(const mlir::DataLayout &dataLayout, 293 mlir::DataLayoutEntryListRef params) const { 294 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying()) 295 .getABIAlignment(dataLayout, params); 296 } 297 298 uint64_t LongDoubleType::getPreferredAlignment( 299 const ::mlir::DataLayout &dataLayout, 300 mlir::DataLayoutEntryListRef params) const { 301 return mlir::cast<mlir::DataLayoutTypeInterface>(getUnderlying()) 302 .getPreferredAlignment(dataLayout, params); 303 } 304 305 LogicalResult 306 LongDoubleType::verify(function_ref<InFlightDiagnostic()> emitError, 307 mlir::Type underlying) { 308 if (!mlir::isa<DoubleType, FP80Type, FP128Type>(underlying)) { 309 emitError() << "invalid underlying type for long double"; 310 return failure(); 311 } 312 313 return success(); 314 } 315 316 //===----------------------------------------------------------------------===// 317 // Floating-point type helpers 318 //===----------------------------------------------------------------------===// 319 320 bool cir::isAnyFloatingPointType(mlir::Type t) { 321 return isa<cir::SingleType, cir::DoubleType, cir::LongDoubleType, 322 cir::FP80Type, cir::BF16Type, cir::FP16Type, cir::FP128Type>(t); 323 } 324 325 //===----------------------------------------------------------------------===// 326 // FuncType Definitions 327 //===----------------------------------------------------------------------===// 328 329 FuncType FuncType::clone(TypeRange inputs, TypeRange results) const { 330 assert(results.size() == 1 && "expected exactly one result type"); 331 return get(llvm::to_vector(inputs), results[0], isVarArg()); 332 } 333 334 mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p, 335 llvm::SmallVector<mlir::Type> ¶ms, 336 bool &isVarArg) { 337 isVarArg = false; 338 // `(` `)` 339 if (succeeded(p.parseOptionalRParen())) 340 return mlir::success(); 341 342 // `(` `...` `)` 343 if (succeeded(p.parseOptionalEllipsis())) { 344 isVarArg = true; 345 return p.parseRParen(); 346 } 347 348 // type (`,` type)* (`,` `...`)? 349 mlir::Type type; 350 if (p.parseType(type)) 351 return mlir::failure(); 352 params.push_back(type); 353 while (succeeded(p.parseOptionalComma())) { 354 if (succeeded(p.parseOptionalEllipsis())) { 355 isVarArg = true; 356 return p.parseRParen(); 357 } 358 if (p.parseType(type)) 359 return mlir::failure(); 360 params.push_back(type); 361 } 362 363 return p.parseRParen(); 364 } 365 366 void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef<mlir::Type> params, 367 bool isVarArg) { 368 llvm::interleaveComma(params, p, 369 [&p](mlir::Type type) { p.printType(type); }); 370 if (isVarArg) { 371 if (!params.empty()) 372 p << ", "; 373 p << "..."; 374 } 375 p << ')'; 376 } 377 378 llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const { 379 return static_cast<detail::FuncTypeStorage *>(getImpl())->returnType; 380 } 381 382 bool FuncType::isVoid() const { return mlir::isa<VoidType>(getReturnType()); } 383 384 //===----------------------------------------------------------------------===// 385 // PointerType Definitions 386 //===----------------------------------------------------------------------===// 387 388 llvm::TypeSize 389 PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, 390 ::mlir::DataLayoutEntryListRef params) const { 391 // FIXME: improve this in face of address spaces 392 return llvm::TypeSize::getFixed(64); 393 } 394 395 uint64_t 396 PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout, 397 ::mlir::DataLayoutEntryListRef params) const { 398 // FIXME: improve this in face of address spaces 399 return 8; 400 } 401 402 uint64_t PointerType::getPreferredAlignment( 403 const ::mlir::DataLayout &dataLayout, 404 ::mlir::DataLayoutEntryListRef params) const { 405 // FIXME: improve this in face of address spaces 406 return 8; 407 } 408 409 mlir::LogicalResult 410 PointerType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, 411 mlir::Type pointee) { 412 // TODO(CIR): Verification of the address space goes here. 413 return mlir::success(); 414 } 415 416 //===----------------------------------------------------------------------===// 417 // CIR Dialect 418 //===----------------------------------------------------------------------===// 419 420 void CIRDialect::registerTypes() { 421 // Register tablegen'd types. 422 addTypes< 423 #define GET_TYPEDEF_LIST 424 #include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" 425 >(); 426 427 // Register raw C++ types. 428 // TODO(CIR) addTypes<StructType>(); 429 } 430