diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4462eb6fc00ba..0d6c65ecf4102 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -15,6 +15,7 @@ #define LLVM_CLANG_CIR_DIALECT_IR_CIROPS include "clang/CIR/Dialect/IR/CIRDialect.td" +include "clang/CIR/Dialect/IR/CIRTypes.td" include "mlir/IR/BuiltinAttributeInterfaces.td" include "mlir/IR/EnumAttr.td" @@ -74,6 +75,35 @@ class LLVMLoweringInfo { class CIR_Op traits = []> : Op, LLVMLoweringInfo; +//===----------------------------------------------------------------------===// +// GlobalOp +//===----------------------------------------------------------------------===// + +// TODO(CIR): For starters, cir.global has only name and type. The other +// properties of a global variable will be added over time as more of ClangIR +// is upstreamed. + +def GlobalOp : CIR_Op<"global"> { + let summary = "Declare or define a global variable"; + let description = [{ + The `cir.global` operation declares or defines a named global variable. + + The backing memory for the variable is allocated statically and is + described by the type of the variable. + }]; + + let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type); + + let assemblyFormat = [{ $sym_name `:` $sym_type attr-dict }]; + + let skipDefaultBuilders = 1; + + let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name, + "mlir::Type":$sym_type)>]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // FuncOp //===----------------------------------------------------------------------===// @@ -85,14 +115,15 @@ class CIR_Op traits = []> : def FuncOp : CIR_Op<"func"> { let summary = "Declare or define a function"; let description = [{ - ... lots of text to be added later ... + The `cir.func` operation defines a function, similar to the `mlir::FuncOp` + built-in. }]; let arguments = (ins SymbolNameAttr:$sym_name); let skipDefaultBuilders = 1; - let builders = [OpBuilder<(ins "llvm::StringRef":$name)>]; + let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name)>]; let hasCustomAssemblyFormat = 1; let hasVerifier = 1; diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h new file mode 100644 index 0000000000000..2bc7d77b2bc8a --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the types in the CIR dialect. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_DIALECT_CIR_IR_CIRTYPES_H_ +#define MLIR_DIALECT_CIR_IR_CIRTYPES_H_ + +#include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/Types.h" +#include "mlir/Interfaces/DataLayoutInterfaces.h" + +//===----------------------------------------------------------------------===// +// CIR Dialect Tablegen'd Types +//===----------------------------------------------------------------------===// + +#define GET_TYPEDEF_CLASSES +#include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc" + +#endif // MLIR_DIALECT_CIR_IR_CIRTYPES_H_ diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td new file mode 100644 index 0000000000000..ce0b6ba1d68c5 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -0,0 +1,132 @@ +//===- CIRTypes.td - CIR dialect types ---------------------*- tablegen -*-===// +// +// 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 declares the CIR dialect types. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_CIR_DIALECT_CIR_TYPES +#define MLIR_CIR_DIALECT_CIR_TYPES + +include "clang/CIR/Dialect/IR/CIRDialect.td" +include "mlir/Interfaces/DataLayoutInterfaces.td" +include "mlir/IR/AttrTypeBase.td" + +//===----------------------------------------------------------------------===// +// CIR Types +//===----------------------------------------------------------------------===// + +class CIR_Type traits = [], + string baseCppClass = "::mlir::Type"> + : TypeDef { + let mnemonic = typeMnemonic; +} + +//===----------------------------------------------------------------------===// +// IntType +//===----------------------------------------------------------------------===// + +def CIR_IntType : CIR_Type<"Int", "int", + [DeclareTypeInterfaceMethods]> { + let summary = "Integer type with arbitrary precision up to a fixed limit"; + let description = [{ + CIR type that represents integer types with arbitrary precision, including + standard integral types such as `int` and `long`, extended integral types + such as `__int128`, and arbitrary width types such as `_BitInt(n)`. + + Those integer types that are directly available in C/C++ standard are called + primitive integer types. Said types are: `signed char`, `short`, `int`, + `long`, `long long`, and their unsigned variations. + }]; + let parameters = (ins "unsigned":$width, "bool":$isSigned); + let hasCustomAssemblyFormat = 1; + let extraClassDeclaration = [{ + /// Return true if this is a signed integer type. + bool isSigned() const { return getIsSigned(); } + /// Return true if this is an unsigned integer type. + bool isUnsigned() const { return !getIsSigned(); } + /// Return type alias. + std::string getAlias() const { + return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i'; + } + /// Return true if this is a primitive integer type (i.e. signed or unsigned + /// integer types whose bit width is 8, 16, 32, or 64). + bool isPrimitive() const { + return isValidPrimitiveIntBitwidth(getWidth()); + } + bool isSignedPrimitive() const { + return isPrimitive() && isSigned(); + } + + /// Returns a minimum bitwidth of cir::IntType + static unsigned minBitwidth() { return 1; } + /// Returns a maximum bitwidth of cir::IntType + static unsigned maxBitwidth() { return 128; } + + /// Returns true if cir::IntType that represents a primitive integer type + /// can be constructed from the provided bitwidth. + static bool isValidPrimitiveIntBitwidth(unsigned width) { + return width == 8 || width == 16 || width == 32 || width == 64; + } + }]; + let genVerifyDecl = 1; +} + +// Constraints + +// Unsigned integer type of a specific width. +class UInt + : Type($_self)">, + CPred<"::mlir::cast<::cir::IntType>($_self).isUnsigned()">, + CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width> + ]>, width # "-bit unsigned integer", "::cir::IntType">, + BuildableType< + "cir::IntType::get($_builder.getContext(), " + # width # ", /*isSigned=*/false)"> { + int bitwidth = width; +} + +def UInt1 : UInt<1>; +def UInt8 : UInt<8>; +def UInt16 : UInt<16>; +def UInt32 : UInt<32>; +def UInt64 : UInt<64>; + +// Signed integer type of a specific width. +class SInt + : Type($_self)">, + CPred<"::mlir::cast<::cir::IntType>($_self).isSigned()">, + CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width> + ]>, width # "-bit signed integer", "::cir::IntType">, + BuildableType< + "cir::IntType::get($_builder.getContext(), " + # width # ", /*isSigned=*/true)"> { + int bitwidth = width; +} + +def SInt1 : SInt<1>; +def SInt8 : SInt<8>; +def SInt16 : SInt<16>; +def SInt32 : SInt<32>; +def SInt64 : SInt<64>; + +def PrimitiveUInt + : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64], "primitive unsigned int", + "::cir::IntType">; + +def PrimitiveSInt + : AnyTypeOf<[SInt8, SInt16, SInt32, SInt64], "primitive signed int", + "::cir::IntType">; + +def PrimitiveInt + : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64], + "primitive int", "::cir::IntType">; + +#endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 5963d43bb9672..b44f66493254f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -31,7 +31,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context, DiagnosticsEngine &diags) : builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()), theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))}, - diags(diags), target(astCtx.getTargetInfo()) {} + diags(diags), target(astCtx.getTargetInfo()), genTypes(*this) {} mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) { assert(cLoc.isValid() && "expected valid source location"); @@ -67,7 +67,8 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) { return; } } else { - errorNYI(global->getSourceRange(), "global variable declaration"); + assert(cast(global)->isFileVarDecl() && + "Cannot emit local var decl as global"); } // TODO(CIR): Defer emitting some global definitions until later @@ -77,9 +78,27 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) { void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op) { auto const *funcDecl = cast(gd.getDecl()); - auto funcOp = builder.create( - getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName()); - theModule.push_back(funcOp); + if (clang::IdentifierInfo *identifier = funcDecl->getIdentifier()) { + auto funcOp = builder.create( + getLoc(funcDecl->getSourceRange()), identifier->getName()); + theModule.push_back(funcOp); + } else { + errorNYI(funcDecl->getSourceRange().getBegin(), + "function definition with a non-identifier for a name"); + } +} + +void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, + bool isTentative) { + mlir::Type type = getTypes().convertType(vd->getType()); + if (clang::IdentifierInfo *identifier = vd->getIdentifier()) { + auto varOp = builder.create(getLoc(vd->getSourceRange()), + identifier->getName(), type); + theModule.push_back(varOp); + } else { + errorNYI(vd->getSourceRange().getBegin(), + "variable definition with a non-identifier for a name"); + } } void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd, @@ -103,6 +122,9 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd, return; } + if (const auto *vd = dyn_cast(decl)) + return emitGlobalVarDefinition(vd, !vd->hasDefinition()); + llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition"); } @@ -126,13 +148,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { emitGlobal(fd); break; } - } -} -DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) { - unsigned diagID = diags.getCustomDiagID( - DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0"); - return diags.Report(diagID) << feature; + case Decl::Var: { + auto *vd = cast(decl); + emitGlobal(vd); + break; + } + } } DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, @@ -142,21 +164,7 @@ DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, return diags.Report(loc, diagID) << feature; } -DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc, - llvm::StringRef feature, - llvm::StringRef name) { - unsigned diagID = diags.getCustomDiagID( - DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1"); - return diags.Report(loc, diagID) << feature << name; -} - DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, llvm::StringRef feature) { return errorNYI(loc.getBegin(), feature) << loc; } - -DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, - llvm::StringRef feature, - llvm::StringRef name) { - return errorNYI(loc.getBegin(), feature, name) << loc; -} diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index aaded92e6a633..7a84c942af491 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -14,23 +14,22 @@ #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H #include "CIRGenTypeCache.h" +#include "CIRGenTypes.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/MLIRContext.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" namespace clang { class ASTContext; class CodeGenOptions; class Decl; -class DiagnosticBuilder; -class DiagnosticsEngine; class GlobalDecl; class LangOptions; -class SourceLocation; -class SourceRange; class TargetInfo; +class VarDecl; namespace CIRGen { @@ -64,8 +63,13 @@ class CIRGenModule : public CIRGenTypeCache { const clang::TargetInfo ⌖ + CIRGenTypes genTypes; + public: mlir::ModuleOp getModule() const { return theModule; } + mlir::OpBuilder &getBuilder() { return builder; } + clang::ASTContext &getASTContext() const { return astCtx; } + CIRGenTypes &getTypes() { return genTypes; } /// Helpers to convert the presumed location of Clang's SourceLocation to an /// MLIR Location. @@ -81,13 +85,28 @@ class CIRGenModule : public CIRGenTypeCache { void emitGlobalDefinition(clang::GlobalDecl gd, mlir::Operation *op = nullptr); void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op); + void emitGlobalVarDefinition(const clang::VarDecl *vd, + bool isTentative = false); /// Helpers to emit "not yet implemented" error diagnostics - DiagnosticBuilder errorNYI(llvm::StringRef); DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef); - DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef); + + template + DiagnosticBuilder errorNYI(SourceLocation loc, llvm::StringRef feature, + const T &name) { + unsigned diagID = + diags.getCustomDiagID(DiagnosticsEngine::Error, + "ClangIR code gen Not Yet Implemented: %0: %1"); + return diags.Report(loc, diagID) << feature << name; + } + DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef); - DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef); + + template + DiagnosticBuilder errorNYI(SourceRange loc, llvm::StringRef feature, + const T &name) { + return errorNYI(loc.getBegin(), feature, name) << loc; + } }; } // namespace CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp new file mode 100644 index 0000000000000..e3fcbacf5f810 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -0,0 +1,87 @@ +#include "CIRGenTypes.h" + +#include "CIRGenModule.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" + +using namespace clang; +using namespace clang::CIRGen; + +CIRGenTypes::CIRGenTypes(CIRGenModule &genModule) + : cgm(genModule), context(genModule.getASTContext()) {} + +CIRGenTypes::~CIRGenTypes() {} + +mlir::Type CIRGenTypes::convertType(QualType type) { + type = context.getCanonicalType(type); + const Type *ty = type.getTypePtr(); + + // For types that haven't been implemented yet or are otherwise unsupported, + // report an error and return 'int'. + + mlir::Type resultType = nullptr; + switch (ty->getTypeClass()) { + case Type::Builtin: { + switch (cast(ty)->getKind()) { + // Signed types. + case BuiltinType::Char_S: + case BuiltinType::Int: + case BuiltinType::Int128: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::WChar_S: + resultType = cir::IntType::get(cgm.getBuilder().getContext(), + context.getTypeSize(ty), + /*isSigned=*/true); + break; + // Unsigned types. + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::UInt: + case BuiltinType::UInt128: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UShort: + case BuiltinType::WChar_U: + resultType = cir::IntType::get(cgm.getBuilder().getContext(), + context.getTypeSize(ty), + /*isSigned=*/false); + break; + default: + cgm.errorNYI(SourceLocation(), "processing of built-in type", type); + resultType = cir::IntType::get(cgm.getBuilder().getContext(), 32, + /*isSigned=*/true); + break; + } + break; + } + case Type::BitInt: { + const auto *bitIntTy = cast(type); + if (bitIntTy->getNumBits() > cir::IntType::maxBitwidth()) { + cgm.errorNYI(SourceLocation(), "large _BitInt type", type); + resultType = cir::IntType::get(cgm.getBuilder().getContext(), 32, + /*isSigned=*/true); + } else { + resultType = + cir::IntType::get(cgm.getBuilder().getContext(), + bitIntTy->getNumBits(), bitIntTy->isSigned()); + } + break; + } + default: + cgm.errorNYI(SourceLocation(), "processing of type", type); + resultType = + cir::IntType::get(cgm.getBuilder().getContext(), 32, /*isSigned=*/true); + break; + } + + assert(resultType && "Type conversion not yet implemented"); + + return resultType; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h new file mode 100644 index 0000000000000..b37738c770de1 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -0,0 +1,47 @@ +//===--- CIRGenTypes.h - Type translation for CIR CodeGen -------*- C++ -*-===// +// +// 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 is the code that handles AST -> CIR type lowering. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H +#define LLVM_CLANG_LIB_CODEGEN_CODEGENTYPES_H + +#include "clang/CIR/Dialect/IR/CIRTypes.h" + +namespace clang { +class ASTContext; +class QualType; +} // namespace clang + +namespace mlir { +class Type; +} + +namespace clang::CIRGen { + +class CIRGenModule; + +/// This class organizes the cross-module state that is used while lowering +/// AST types to CIR types. +class CIRGenTypes { + CIRGenModule &cgm; + clang::ASTContext &context; + +public: + CIRGenTypes(CIRGenModule &cgm); + ~CIRGenTypes(); + + /// Convert a Clang type into a mlir::Type. + mlir::Type convertType(clang::QualType type); +}; + +} // namespace clang::CIRGen + +#endif diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 17a3aabfbd7f0..9ada31c11de95 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -9,6 +9,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) add_clang_library(clangCIR CIRGenerator.cpp CIRGenModule.cpp + CIRGenTypes.cpp DEPENDS MLIRCIR diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index f666e5ab4b999..dbdca1f840166 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -32,6 +32,22 @@ void cir::CIRDialect::initialize() { >(); } +//===----------------------------------------------------------------------===// +// GlobalOp +//===----------------------------------------------------------------------===// + +// TODO(CIR): The properties of global variables that require verification +// haven't been implemented yet. +mlir::LogicalResult cir::GlobalOp::verify() { return success(); } + +void cir::GlobalOp::build(OpBuilder &odsBuilder, OperationState &odsState, + llvm::StringRef sym_name, mlir::Type sym_type) { + odsState.addAttribute(getSymNameAttrName(odsState.name), + odsBuilder.getStringAttr(sym_name)); + odsState.addAttribute(getSymTypeAttrName(odsState.name), + mlir::TypeAttr::get(sym_type)); +} + //===----------------------------------------------------------------------===// // FuncOp //===----------------------------------------------------------------------===// @@ -56,6 +72,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p.printSymbolName(getSymName()); } +// TODO(CIR): The properties of functions that require verification haven't +// been implemented yet. mlir::LogicalResult cir::FuncOp::verify() { return success(); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 4eeb70f06f5f7..de38337057d3d 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -10,7 +10,18 @@ // //===----------------------------------------------------------------------===// +#include "clang/CIR/Dialect/IR/CIRTypes.h" + +#include "mlir/IR/DialectImplementation.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "llvm/ADT/TypeSwitch.h" + +//===----------------------------------------------------------------------===// +// Get autogenerated stuff +//===----------------------------------------------------------------------===// + +#define GET_TYPEDEF_CLASSES +#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" using namespace mlir; using namespace cir; @@ -20,12 +31,106 @@ using namespace cir; //===----------------------------------------------------------------------===// Type CIRDialect::parseType(DialectAsmParser &parser) const { - // No types yet to parse - return Type{}; + llvm::SMLoc typeLoc = parser.getCurrentLocation(); + llvm::StringRef mnemonic; + Type genType; + + // Try to parse as a tablegen'd type. + OptionalParseResult parseResult = + generatedTypeParser(parser, &mnemonic, genType); + if (parseResult.has_value()) + return genType; + + // TODO(CIR) Attempt to parse as a raw C++ type. + parser.emitError(typeLoc) << "unknown CIR type: " << mnemonic; + return Type(); } void CIRDialect::printType(Type type, DialectAsmPrinter &os) const { - // No types yet to print + // Try to print as a tablegen'd type. + if (generatedTypePrinter(type, os).succeeded()) + return; + + // TODO(CIR) Attempt to print as a raw C++ type. + llvm::report_fatal_error("printer is missing a handler for this type"); +} + +//===----------------------------------------------------------------------===// +// IntType Definitions +//===----------------------------------------------------------------------===// + +Type IntType::parse(mlir::AsmParser &parser) { + mlir::MLIRContext *context = parser.getBuilder().getContext(); + llvm::SMLoc loc = parser.getCurrentLocation(); + bool isSigned; + unsigned width; + + if (parser.parseLess()) + return {}; + + // Fetch integer sign. + llvm::StringRef sign; + if (parser.parseKeyword(&sign)) + return {}; + if (sign == "s") + isSigned = true; + else if (sign == "u") + isSigned = false; + else { + parser.emitError(loc, "expected 's' or 'u'"); + return {}; + } + + if (parser.parseComma()) + return {}; + + // Fetch integer size. + if (parser.parseInteger(width)) + return {}; + if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) { + parser.emitError(loc, "expected integer width to be from ") + << IntType::minBitwidth() << " up to " << IntType::maxBitwidth(); + return {}; + } + + if (parser.parseGreater()) + return {}; + + return IntType::get(context, width, isSigned); +} + +void IntType::print(mlir::AsmPrinter &printer) const { + char sign = isSigned() ? 's' : 'u'; + printer << '<' << sign << ", " << getWidth() << '>'; +} + +llvm::TypeSize +IntType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return llvm::TypeSize::getFixed(getWidth()); +} + +uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout, + mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +uint64_t +IntType::getPreferredAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + return (uint64_t)(getWidth() / 8); +} + +mlir::LogicalResult +IntType::verify(llvm::function_ref emitError, + unsigned width, bool isSigned) { + if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) { + emitError() << "IntType only supports widths from " + << IntType::minBitwidth() << " up to " + << IntType::maxBitwidth(); + return mlir::failure(); + } + return mlir::success(); } //===----------------------------------------------------------------------===// @@ -33,5 +138,12 @@ void CIRDialect::printType(Type type, DialectAsmPrinter &os) const { //===----------------------------------------------------------------------===// void CIRDialect::registerTypes() { - // No types yet to register + // Register tablegen'd types. + addTypes< +#define GET_TYPEDEF_LIST +#include "clang/CIR/Dialect/IR/CIROpsTypes.cpp.inc" + >(); + + // Register raw C++ types. + // TODO(CIR) addTypes(); } diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt index 75cee3f871130..7ddc4ce501907 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -8,4 +8,8 @@ add_clang_library(MLIRCIR LINK_LIBS PUBLIC MLIRIR + MLIRDLTIDialect + MLIRDataLayoutInterfaces + MLIRFuncDialect + clangAST ) diff --git a/clang/test/CIR/global-var-simple.cpp b/clang/test/CIR/global-var-simple.cpp new file mode 100644 index 0000000000000..5230ff53f87d7 --- /dev/null +++ b/clang/test/CIR/global-var-simple.cpp @@ -0,0 +1,59 @@ +// Global variables of intergal types +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s + +char c; +// CHECK: cir.global @c : !cir.int + +signed char sc; +// CHECK: cir.global @sc : !cir.int + +unsigned char uc; +// CHECK: cir.global @uc : !cir.int + +short ss; +// CHECK: cir.global @ss : !cir.int + +unsigned short us; +// CHECK: cir.global @us : !cir.int + +int si; +// CHECK: cir.global @si : !cir.int + +unsigned ui; +// CHECK: cir.global @ui : !cir.int + +long sl; +// CHECK: cir.global @sl : !cir.int + +unsigned long ul; +// CHECK: cir.global @ul : !cir.int + +long long sll; +// CHECK: cir.global @sll : !cir.int + +unsigned long long ull; +// CHECK: cir.global @ull : !cir.int + +__int128 s128; +// CHECK: cir.global @s128 : !cir.int + +unsigned __int128 u128; +// CHECK: cir.global @u128 : !cir.int + +wchar_t wc; +// CHECK: cir.global @wc : !cir.int + +char8_t c8; +// CHECK: cir.global @c8 : !cir.int + +char16_t c16; +// CHECK: cir.global @c16 : !cir.int + +char32_t c32; +// CHECK: cir.global @c32 : !cir.int + +_BitInt(20) sb20; +// CHECK: cir.global @sb20 : !cir.int + +unsigned _BitInt(48) ub48; +// CHECK: cir.global @ub48 : !cir.int