Skip to content

Commit 8e32959

Browse files
authored
[CIR] Upstream initial attribute support (#121069)
Upstream several ClangIR-specific MLIR attributes, in particular attributes for integer, floating-point, and null pointer constants. These are the first ClangIR attributes to be upstreamed, so infrastructure changes are included, such as the table-gen file `CIRAttrs.td`. Attributes can be used as the initial values for global variables. The existing automated test global-var-simple.cpp includes initial values for some of the global variables in the test.
1 parent f1bc3af commit 8e32959

File tree

13 files changed

+583
-23
lines changed

13 files changed

+583
-23
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
#ifndef LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
1010
#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
1111

12+
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
13+
1214
#include "mlir/IR/Builders.h"
15+
#include "mlir/IR/BuiltinTypes.h"
16+
#include "mlir/IR/Types.h"
1317

1418
namespace cir {
1519

@@ -26,6 +30,13 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
2630
cir::PointerType getVoidPtrTy() {
2731
return getPointerTo(cir::VoidType::get(getContext()));
2832
}
33+
34+
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
35+
auto valueAttr = mlir::IntegerAttr::get(
36+
mlir::IntegerType::get(type.getContext(), 64), value);
37+
return cir::ConstPtrAttr::get(
38+
getContext(), mlir::cast<cir::PointerType>(type), valueAttr);
39+
}
2940
};
3041

3142
} // namespace cir
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares the attributes in the CIR dialect.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_H
14+
#define LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_H
15+
16+
#include "clang/CIR/Dialect/IR/CIRTypes.h"
17+
18+
#include "mlir/IR/Attributes.h"
19+
#include "mlir/IR/BuiltinAttributeInterfaces.h"
20+
21+
#include "llvm/ADT/SmallVector.h"
22+
23+
//===----------------------------------------------------------------------===//
24+
// CIR Dialect Attrs
25+
//===----------------------------------------------------------------------===//
26+
27+
namespace clang {
28+
class FunctionDecl;
29+
class VarDecl;
30+
class RecordDecl;
31+
} // namespace clang
32+
33+
#define GET_ATTRDEF_CLASSES
34+
#include "clang/CIR/Dialect/IR/CIROpsAttributes.h.inc"
35+
36+
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_H
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares the CIR dialect attributes.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD
14+
#define LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD
15+
16+
include "mlir/IR/BuiltinAttributeInterfaces.td"
17+
include "mlir/IR/EnumAttr.td"
18+
19+
include "clang/CIR/Dialect/IR/CIRDialect.td"
20+
21+
//===----------------------------------------------------------------------===//
22+
// CIR Attrs
23+
//===----------------------------------------------------------------------===//
24+
25+
class CIR_Attr<string name, string attrMnemonic, list<Trait> traits = []>
26+
: AttrDef<CIR_Dialect, name, traits> {
27+
let mnemonic = attrMnemonic;
28+
}
29+
30+
class CIRUnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
31+
: CIR_Attr<name, attrMnemonic, traits> {
32+
let returnType = "bool";
33+
let defaultValue = "false";
34+
let valueType = NoneType;
35+
let isOptional = 1;
36+
}
37+
38+
//===----------------------------------------------------------------------===//
39+
// IntegerAttr
40+
//===----------------------------------------------------------------------===//
41+
42+
def IntAttr : CIR_Attr<"Int", "int", [TypedAttrInterface]> {
43+
let summary = "An attribute containing an integer value";
44+
let description = [{
45+
An integer attribute is a literal attribute that represents an integral
46+
value of the specified integer type.
47+
}];
48+
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
49+
"llvm::APInt":$value);
50+
let builders = [
51+
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
52+
"const llvm::APInt &":$value), [{
53+
return $_get(type.getContext(), type, value);
54+
}]>,
55+
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
56+
"int64_t":$value), [{
57+
IntType intType = mlir::cast<IntType>(type);
58+
mlir::APInt apValue(intType.getWidth(), value, intType.isSigned());
59+
return $_get(intType.getContext(), intType, apValue);
60+
}]>,
61+
];
62+
let extraClassDeclaration = [{
63+
int64_t getSInt() const { return getValue().getSExtValue(); }
64+
uint64_t getUInt() const { return getValue().getZExtValue(); }
65+
bool isNullValue() const { return getValue() == 0; }
66+
uint64_t getBitWidth() const {
67+
return mlir::cast<IntType>(getType()).getWidth();
68+
}
69+
}];
70+
let genVerifyDecl = 1;
71+
let hasCustomAssemblyFormat = 1;
72+
}
73+
74+
//===----------------------------------------------------------------------===//
75+
// FPAttr
76+
//===----------------------------------------------------------------------===//
77+
78+
def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> {
79+
let summary = "An attribute containing a floating-point value";
80+
let description = [{
81+
An fp attribute is a literal attribute that represents a floating-point
82+
value of the specified floating-point type. Supporting only CIR FP types.
83+
}];
84+
let parameters = (ins
85+
AttributeSelfTypeParameter<"", "::cir::CIRFPTypeInterface">:$type,
86+
APFloatParameter<"">:$value
87+
);
88+
let builders = [
89+
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
90+
"const llvm::APFloat &":$value), [{
91+
return $_get(type.getContext(), mlir::cast<CIRFPTypeInterface>(type),
92+
value);
93+
}]>,
94+
AttrBuilder<(ins "mlir::Type":$type,
95+
"const llvm::APFloat &":$value), [{
96+
return $_get($_ctxt, mlir::cast<CIRFPTypeInterface>(type), value);
97+
}]>,
98+
];
99+
let extraClassDeclaration = [{
100+
static FPAttr getZero(mlir::Type type);
101+
}];
102+
let genVerifyDecl = 1;
103+
104+
let assemblyFormat = [{
105+
`<` custom<FloatLiteral>($value, ref($type)) `>`
106+
}];
107+
}
108+
109+
//===----------------------------------------------------------------------===//
110+
// ConstPtrAttr
111+
//===----------------------------------------------------------------------===//
112+
113+
def ConstPtrAttr : CIR_Attr<"ConstPtr", "ptr", [TypedAttrInterface]> {
114+
let summary = "Holds a constant pointer value";
115+
let parameters = (ins
116+
AttributeSelfTypeParameter<"", "::cir::PointerType">:$type,
117+
"mlir::IntegerAttr":$value);
118+
let description = [{
119+
A pointer attribute is a literal attribute that represents an integral
120+
value of a pointer type.
121+
}];
122+
let builders = [
123+
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
124+
"mlir::IntegerAttr":$value), [{
125+
return $_get(type.getContext(), mlir::cast<cir::PointerType>(type),
126+
value);
127+
}]>,
128+
AttrBuilder<(ins "mlir::Type":$type,
129+
"mlir::IntegerAttr":$value), [{
130+
return $_get($_ctxt, mlir::cast<cir::PointerType>(type), value);
131+
}]>,
132+
];
133+
let extraClassDeclaration = [{
134+
bool isNullValue() const { return getValue().getInt() == 0; }
135+
}];
136+
137+
let assemblyFormat = [{
138+
`<` custom<ConstPtr>($value) `>`
139+
}];
140+
}
141+
142+
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD

clang/include/clang/CIR/Dialect/IR/CIRDialect.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "mlir/Interfaces/MemorySlotInterfaces.h"
2727
#include "mlir/Interfaces/SideEffectInterfaces.h"
2828

29+
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
2930
#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"
3031

3132
// TableGen'erated files for MLIR dialects require that a macro be defined when

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
include "clang/CIR/Dialect/IR/CIRDialect.td"
1818
include "clang/CIR/Dialect/IR/CIRTypes.td"
19+
include "clang/CIR/Dialect/IR/CIRAttrs.td"
1920

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

79+
//===----------------------------------------------------------------------===//
80+
// ConstantOp
81+
//===----------------------------------------------------------------------===//
82+
83+
def ConstantOp : CIR_Op<"const",
84+
[ConstantLike, Pure, AllTypesMatch<["value", "res"]>]> {
85+
let summary = "Defines a CIR constant";
86+
let description = [{
87+
The `cir.const` operation turns a literal into an SSA value. The data is
88+
attached to the operation as an attribute.
89+
90+
```mlir
91+
%0 = cir.const 42 : i32
92+
%1 = cir.const 4.2 : f32
93+
%2 = cir.const nullptr : !cir.ptr<i32>
94+
```
95+
}];
96+
97+
// The constant operation takes an attribute as the only input.
98+
let arguments = (ins TypedAttrInterface:$value);
99+
100+
// The constant operation returns a single value of CIR_AnyType.
101+
let results = (outs CIR_AnyType:$res);
102+
103+
let assemblyFormat = "attr-dict $value";
104+
105+
let hasVerifier = 1;
106+
107+
let extraClassDeclaration = [{
108+
bool isNullPtr() {
109+
if (const auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(getValue()))
110+
return ptrAttr.isNullValue();
111+
return false;
112+
}
113+
}];
114+
115+
let hasFolder = 1;
116+
}
117+
78118
//===----------------------------------------------------------------------===//
79119
// GlobalOp
80120
//===----------------------------------------------------------------------===//
@@ -92,9 +132,19 @@ def GlobalOp : CIR_Op<"global"> {
92132
described by the type of the variable.
93133
}];
94134

95-
let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type);
135+
let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type,
136+
OptionalAttr<AnyAttr>:$initial_value);
137+
138+
let assemblyFormat = [{
139+
$sym_name
140+
custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value)
141+
attr-dict
142+
}];
96143

97-
let assemblyFormat = [{ $sym_name `:` $sym_type attr-dict }];
144+
let extraClassDeclaration = [{
145+
bool isDeclaration() { return !getInitialValue(); }
146+
bool hasInitializer() { return !isDeclaration(); }
147+
}];
98148

99149
let skipDefaultBuilders = 1;
100150

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,8 @@ def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> {
220220

221221
// Constraints
222222

223-
def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128, CIR_LongDouble,
224-
CIR_FP16, CIR_BFloat16]>;
223+
def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128,
224+
CIR_LongDouble, CIR_FP16, CIR_BFloat16]>;
225225
def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>;
226226

227227
//===----------------------------------------------------------------------===//
@@ -350,4 +350,12 @@ def VoidPtr : Type<
350350
"cir::VoidType::get($_builder.getContext()))"> {
351351
}
352352

353+
//===----------------------------------------------------------------------===//
354+
// Global type constraints
355+
//===----------------------------------------------------------------------===//
356+
357+
def CIR_AnyType : AnyTypeOf<[
358+
CIR_VoidType, CIR_IntType, CIR_AnyFloat, CIR_PointerType, CIR_FuncType
359+
]>;
360+
353361
#endif // MLIR_CIR_DIALECT_CIR_TYPES

clang/include/clang/CIR/Dialect/IR/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ mlir_tablegen(CIROpsDialect.cpp.inc -gen-dialect-defs)
1414
add_public_tablegen_target(MLIRCIROpsIncGen)
1515
add_dependencies(mlir-headers MLIRCIROpsIncGen)
1616

17+
mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
18+
mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
19+
add_public_tablegen_target(MLIRCIRAttrsEnumsGen)

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,48 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
115115
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
116116
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
117117
identifier->getName(), type);
118+
// TODO(CIR): This code for processing initial values is a placeholder
119+
// until class ConstantEmitter is upstreamed and the code for processing
120+
// constant expressions is filled out. Only the most basic handling of
121+
// certain constant expressions is implemented for now.
122+
const VarDecl *initDecl;
123+
const Expr *initExpr = vd->getAnyInitializer(initDecl);
124+
if (initExpr) {
125+
mlir::Attribute initializer;
126+
if (APValue *value = initDecl->evaluateValue()) {
127+
switch (value->getKind()) {
128+
case APValue::Int: {
129+
initializer = builder.getAttr<cir::IntAttr>(type, value->getInt());
130+
break;
131+
}
132+
case APValue::Float: {
133+
initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat());
134+
break;
135+
}
136+
case APValue::LValue: {
137+
if (value->getLValueBase()) {
138+
errorNYI(initExpr->getSourceRange(),
139+
"non-null pointer initialization");
140+
} else {
141+
if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) {
142+
initializer = builder.getConstPtrAttr(
143+
ptrType, value->getLValueOffset().getQuantity());
144+
} else {
145+
llvm_unreachable(
146+
"non-pointer variable initialized with a pointer");
147+
}
148+
}
149+
break;
150+
}
151+
default:
152+
errorNYI(initExpr->getSourceRange(), "unsupported initializer kind");
153+
break;
154+
}
155+
} else {
156+
errorNYI(initExpr->getSourceRange(), "non-constant initializer");
157+
}
158+
varOp.setInitialValueAttr(initializer);
159+
}
118160
theModule.push_back(varOp);
119161
} else {
120162
errorNYI(vd->getSourceRange().getBegin(),

0 commit comments

Comments
 (0)