Skip to content

Commit 3f911a4

Browse files
committed
[CIR] Integral types; simple global variables
Add integral types to ClangIR. These are the first ClangIR types, so the change includes some infrastructure for managing ClangIR types. So that the integral types can be used somewhere, generate ClangIR for global variables using the new cir.global op. As with the current support for functions, global variables are just a stub at the moment. The only properties that global variables have are a name and a type. Add a new ClangIR code gen test global-var-simple.cpp, which defines global variables with most of the integral types. (Part of upstreaming the ClangIR incubator project into LLVM.)
1 parent 50f8580 commit 3f911a4

File tree

12 files changed

+567
-34
lines changed

12 files changed

+567
-34
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_CLANG_CIR_DIALECT_IR_CIROPS
1616

1717
include "clang/CIR/Dialect/IR/CIRDialect.td"
18+
include "clang/CIR/Dialect/IR/CIRTypes.td"
1819

1920
include "mlir/IR/BuiltinAttributeInterfaces.td"
2021
include "mlir/IR/EnumAttr.td"
@@ -74,6 +75,32 @@ class LLVMLoweringInfo {
7475
class CIR_Op<string mnemonic, list<Trait> traits = []> :
7576
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
7677

78+
//===----------------------------------------------------------------------===//
79+
// GlobalOp
80+
//===----------------------------------------------------------------------===//
81+
82+
// TODO(CIR): For starters, cir.global has only name and type. The other
83+
// properties of a global variable will be added over time as more of ClangIR
84+
// is upstreamed.
85+
86+
def GlobalOp : CIR_Op<"global"> {
87+
let summary = "Declare or define a global variable";
88+
let description = [{
89+
... lots of text to be added later ...
90+
}];
91+
92+
let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type);
93+
94+
let assemblyFormat = [{ $sym_name `:` $sym_type attr-dict }];
95+
96+
let skipDefaultBuilders = 1;
97+
98+
let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name,
99+
"mlir::Type":$sym_type)>];
100+
101+
let hasVerifier = 1;
102+
}
103+
77104
//===----------------------------------------------------------------------===//
78105
// FuncOp
79106
//===----------------------------------------------------------------------===//
@@ -92,7 +119,7 @@ def FuncOp : CIR_Op<"func"> {
92119

93120
let skipDefaultBuilders = 1;
94121

95-
let builders = [OpBuilder<(ins "llvm::StringRef":$name)>];
122+
let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name)>];
96123

97124
let hasCustomAssemblyFormat = 1;
98125
let hasVerifier = 1;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===- CIRTypes.h - MLIR CIR Types ------------------------------*- C++ -*-===//
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 declares the types in the CIR dialect.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef MLIR_DIALECT_CIR_IR_CIRTYPES_H_
14+
#define MLIR_DIALECT_CIR_IR_CIRTYPES_H_
15+
16+
#include "mlir/IR/BuiltinAttributes.h"
17+
#include "mlir/IR/Types.h"
18+
#include "mlir/Interfaces/DataLayoutInterfaces.h"
19+
20+
//===----------------------------------------------------------------------===//
21+
// CIR Dialect Tablegen'd Types
22+
//===----------------------------------------------------------------------===//
23+
24+
#define GET_TYPEDEF_CLASSES
25+
#include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc"
26+
27+
#endif // MLIR_DIALECT_CIR_IR_CIRTYPES_H_
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//===- CIRTypes.td - CIR dialect types ---------------------*- tablegen -*-===//
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 declares the CIR dialect types.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef MLIR_CIR_DIALECT_CIR_TYPES
14+
#define MLIR_CIR_DIALECT_CIR_TYPES
15+
16+
include "clang/CIR/Dialect/IR/CIRDialect.td"
17+
include "mlir/Interfaces/DataLayoutInterfaces.td"
18+
include "mlir/IR/AttrTypeBase.td"
19+
20+
//===----------------------------------------------------------------------===//
21+
// CIR Types
22+
//===----------------------------------------------------------------------===//
23+
24+
class CIR_Type<string name, string typeMnemonic, list<Trait> traits = [],
25+
string baseCppClass = "::mlir::Type">
26+
: TypeDef<CIR_Dialect, name, traits, baseCppClass> {
27+
let mnemonic = typeMnemonic;
28+
}
29+
30+
//===----------------------------------------------------------------------===//
31+
// IntType
32+
//===----------------------------------------------------------------------===//
33+
34+
def CIR_IntType : CIR_Type<"Int", "int",
35+
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
36+
let summary = "Integer type with arbitrary precision up to a fixed limit";
37+
let description = [{
38+
CIR type that represents integer types with arbitrary precision.
39+
40+
Those integer types that are directly available in C/C++ standard are called
41+
primitive integer types. Said types are: `signed char`, `short`, `int`,
42+
`long`, `long long`, and their unsigned variations.
43+
}];
44+
let parameters = (ins "unsigned":$width, "bool":$isSigned);
45+
let hasCustomAssemblyFormat = 1;
46+
let extraClassDeclaration = [{
47+
/// Return true if this is a signed integer type.
48+
bool isSigned() const { return getIsSigned(); }
49+
/// Return true if this is an unsigned integer type.
50+
bool isUnsigned() const { return !getIsSigned(); }
51+
/// Return type alias.
52+
std::string getAlias() const {
53+
return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
54+
}
55+
/// Return true if this is a primitive integer type (i.e. signed or unsigned
56+
/// integer types whose bit width is 8, 16, 32, or 64).
57+
bool isPrimitive() const {
58+
return isValidPrimitiveIntBitwidth(getWidth());
59+
}
60+
bool isSignedPrimitive() const {
61+
return isPrimitive() && isSigned();
62+
}
63+
64+
/// Returns a minimum bitwidth of cir::IntType
65+
static unsigned minBitwidth() { return 1; }
66+
/// Returns a maximum bitwidth of cir::IntType
67+
static unsigned maxBitwidth() { return 128; }
68+
69+
/// Returns true if cir::IntType that represents a primitive integer type
70+
/// can be constructed from the provided bitwidth.
71+
static bool isValidPrimitiveIntBitwidth(unsigned width) {
72+
return width == 8 || width == 16 || width == 32 || width == 64;
73+
}
74+
}];
75+
let genVerifyDecl = 1;
76+
}
77+
78+
// Constraints
79+
80+
// Unsigned integer type of a specific width.
81+
class UInt<int width>
82+
: Type<And<[
83+
CPred<"::mlir::isa<::cir::IntType>($_self)">,
84+
CPred<"::mlir::cast<::cir::IntType>($_self).isUnsigned()">,
85+
CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
86+
]>, width # "-bit unsigned integer", "::cir::IntType">,
87+
BuildableType<
88+
"cir::IntType::get($_builder.getContext(), "
89+
# width # ", /*isSigned=*/false)"> {
90+
int bitwidth = width;
91+
}
92+
93+
def UInt1 : UInt<1>;
94+
def UInt8 : UInt<8>;
95+
def UInt16 : UInt<16>;
96+
def UInt32 : UInt<32>;
97+
def UInt64 : UInt<64>;
98+
99+
// Signed integer type of a specific width.
100+
class SInt<int width>
101+
: Type<And<[
102+
CPred<"::mlir::isa<::cir::IntType>($_self)">,
103+
CPred<"::mlir::cast<::cir::IntType>($_self).isSigned()">,
104+
CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
105+
]>, width # "-bit signed integer", "::cir::IntType">,
106+
BuildableType<
107+
"cir::IntType::get($_builder.getContext(), "
108+
# width # ", /*isSigned=*/true)"> {
109+
int bitwidth = width;
110+
}
111+
112+
def SInt1 : SInt<1>;
113+
def SInt8 : SInt<8>;
114+
def SInt16 : SInt<16>;
115+
def SInt32 : SInt<32>;
116+
def SInt64 : SInt<64>;
117+
118+
def PrimitiveUInt
119+
: AnyTypeOf<[UInt8, UInt16, UInt32, UInt64], "primitive unsigned int",
120+
"::cir::IntType">;
121+
122+
def PrimitiveSInt
123+
: AnyTypeOf<[SInt8, SInt16, SInt32, SInt64], "primitive signed int",
124+
"::cir::IntType">;
125+
126+
def PrimitiveInt
127+
: AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64],
128+
"primitive int", "::cir::IntType">;
129+
130+
#endif // MLIR_CIR_DIALECT_CIR_TYPES

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
3131
DiagnosticsEngine &diags)
3232
: builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()),
3333
theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))},
34-
diags(diags), target(astCtx.getTargetInfo()) {}
34+
diags(diags), target(astCtx.getTargetInfo()), genTypes(*this) {}
3535

3636
mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
3737
assert(cLoc.isValid() && "expected valid source location");
@@ -67,7 +67,8 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
6767
return;
6868
}
6969
} else {
70-
errorNYI(global->getSourceRange(), "global variable declaration");
70+
const auto *vd = cast<VarDecl>(global);
71+
assert(vd->isFileVarDecl() && "Cannot emit local var decl as global");
7172
}
7273

7374
// TODO(CIR): Defer emitting some global definitions until later
@@ -82,6 +83,14 @@ void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
8283
theModule.push_back(funcOp);
8384
}
8485

86+
void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
87+
bool isTentative) {
88+
mlir::Type type = getTypes().convertType(vd->getType());
89+
auto varOp = builder.create<cir::GlobalOp>(
90+
getLoc(vd->getSourceRange()), vd->getIdentifier()->getName(), type);
91+
theModule.push_back(varOp);
92+
}
93+
8594
void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
8695
mlir::Operation *op) {
8796
const auto *decl = cast<ValueDecl>(gd.getDecl());
@@ -103,6 +112,9 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
103112
return;
104113
}
105114

115+
if (const auto *vd = dyn_cast<VarDecl>(decl))
116+
return emitGlobalVarDefinition(vd, !vd->hasDefinition());
117+
106118
llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");
107119
}
108120

@@ -126,13 +138,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
126138
emitGlobal(fd);
127139
break;
128140
}
129-
}
130-
}
131141

132-
DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
133-
unsigned diagID = diags.getCustomDiagID(
134-
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
135-
return diags.Report(diagID) << feature;
142+
case Decl::Var: {
143+
auto *vd = cast<VarDecl>(decl);
144+
emitGlobal(vd);
145+
break;
146+
}
147+
}
136148
}
137149

138150
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
@@ -142,21 +154,7 @@ DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
142154
return diags.Report(loc, diagID) << feature;
143155
}
144156

145-
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
146-
llvm::StringRef feature,
147-
llvm::StringRef name) {
148-
unsigned diagID = diags.getCustomDiagID(
149-
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1");
150-
return diags.Report(loc, diagID) << feature << name;
151-
}
152-
153157
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
154158
llvm::StringRef feature) {
155159
return errorNYI(loc.getBegin(), feature) << loc;
156160
}
157-
158-
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
159-
llvm::StringRef feature,
160-
llvm::StringRef name) {
161-
return errorNYI(loc.getBegin(), feature, name) << loc;
162-
}

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,22 @@
1414
#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
1515

1616
#include "CIRGenTypeCache.h"
17+
#include "CIRGenTypes.h"
1718

1819
#include "mlir/IR/Builders.h"
1920
#include "mlir/IR/BuiltinOps.h"
2021
#include "mlir/IR/MLIRContext.h"
22+
#include "clang/Basic/SourceManager.h"
2123
#include "llvm/ADT/StringRef.h"
2224

2325
namespace clang {
2426
class ASTContext;
2527
class CodeGenOptions;
2628
class Decl;
27-
class DiagnosticBuilder;
28-
class DiagnosticsEngine;
2929
class GlobalDecl;
3030
class LangOptions;
31-
class SourceLocation;
32-
class SourceRange;
3331
class TargetInfo;
32+
class VarDecl;
3433

3534
namespace CIRGen {
3635

@@ -64,8 +63,13 @@ class CIRGenModule : public CIRGenTypeCache {
6463

6564
const clang::TargetInfo &target;
6665

66+
CIRGenTypes genTypes;
67+
6768
public:
6869
mlir::ModuleOp getModule() const { return theModule; }
70+
mlir::OpBuilder &getBuilder() { return builder; }
71+
clang::ASTContext &getASTContext() const { return astCtx; }
72+
CIRGenTypes &getTypes() { return genTypes; }
6973

7074
/// Helpers to convert the presumed location of Clang's SourceLocation to an
7175
/// MLIR Location.
@@ -81,13 +85,28 @@ class CIRGenModule : public CIRGenTypeCache {
8185
void emitGlobalDefinition(clang::GlobalDecl gd,
8286
mlir::Operation *op = nullptr);
8387
void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
88+
void emitGlobalVarDefinition(const clang::VarDecl *vd,
89+
bool isTentative = false);
8490

8591
/// Helpers to emit "not yet implemented" error diagnostics
86-
DiagnosticBuilder errorNYI(llvm::StringRef);
8792
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
88-
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);
93+
94+
template <typename T>
95+
DiagnosticBuilder errorNYI(SourceLocation loc, llvm::StringRef feature,
96+
const T &name) {
97+
unsigned diagID =
98+
diags.getCustomDiagID(DiagnosticsEngine::Error,
99+
"ClangIR code gen Not Yet Implemented: %0: %1");
100+
return diags.Report(loc, diagID) << feature << name;
101+
}
102+
89103
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef);
90-
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef);
104+
105+
template <typename T>
106+
DiagnosticBuilder errorNYI(SourceRange loc, llvm::StringRef feature,
107+
const T &name) {
108+
return errorNYI(loc.getBegin(), feature, name) << loc;
109+
}
91110
};
92111
} // namespace CIRGen
93112

0 commit comments

Comments
 (0)