Skip to content

[CIR] Upstream initial attribute support #121069

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
#ifndef LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H

#include "clang/CIR/Dialect/IR/CIRAttrs.h"

#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Types.h"

namespace cir {

Expand All @@ -26,6 +30,13 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
cir::PointerType getVoidPtrTy() {
return getPointerTo(cir::VoidType::get(getContext()));
}

mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
auto valueAttr = mlir::IntegerAttr::get(
mlir::IntegerType::get(type.getContext(), 64), value);
return cir::ConstPtrAttr::get(
getContext(), mlir::cast<cir::PointerType>(type), valueAttr);
}
};

} // namespace cir
Expand Down
36 changes: 36 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// 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 attributes in the CIR dialect.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_H
#define LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_H

#include "clang/CIR/Dialect/IR/CIRTypes.h"

#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributeInterfaces.h"

#include "llvm/ADT/SmallVector.h"

//===----------------------------------------------------------------------===//
// CIR Dialect Attrs
//===----------------------------------------------------------------------===//

namespace clang {
class FunctionDecl;
class VarDecl;
class RecordDecl;
} // namespace clang

#define GET_ATTRDEF_CLASSES
#include "clang/CIR/Dialect/IR/CIROpsAttributes.h.inc"

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_H
142 changes: 142 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//===----------------------------------------------------------------------===//
//
// 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 attributes.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD
#define LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD

include "mlir/IR/BuiltinAttributeInterfaces.td"
include "mlir/IR/EnumAttr.td"

include "clang/CIR/Dialect/IR/CIRDialect.td"

//===----------------------------------------------------------------------===//
// CIR Attrs
//===----------------------------------------------------------------------===//

class CIR_Attr<string name, string attrMnemonic, list<Trait> traits = []>
: AttrDef<CIR_Dialect, name, traits> {
let mnemonic = attrMnemonic;
}

class CIRUnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
: CIR_Attr<name, attrMnemonic, traits> {
let returnType = "bool";
let defaultValue = "false";
let valueType = NoneType;
let isOptional = 1;
}

//===----------------------------------------------------------------------===//
// IntegerAttr
//===----------------------------------------------------------------------===//

def IntAttr : CIR_Attr<"Int", "int", [TypedAttrInterface]> {
let summary = "An attribute containing an integer value";
let description = [{
An integer attribute is a literal attribute that represents an integral
value of the specified integer type.
}];
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
"llvm::APInt":$value);
let builders = [
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
"const llvm::APInt &":$value), [{
return $_get(type.getContext(), type, value);
}]>,
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
"int64_t":$value), [{
IntType intType = mlir::cast<IntType>(type);
mlir::APInt apValue(intType.getWidth(), value, intType.isSigned());
return $_get(intType.getContext(), intType, apValue);
}]>,
];
let extraClassDeclaration = [{
int64_t getSInt() const { return getValue().getSExtValue(); }
uint64_t getUInt() const { return getValue().getZExtValue(); }
bool isNullValue() const { return getValue() == 0; }
uint64_t getBitWidth() const {
return mlir::cast<IntType>(getType()).getWidth();
}
}];
let genVerifyDecl = 1;
let hasCustomAssemblyFormat = 1;
}

//===----------------------------------------------------------------------===//
// FPAttr
//===----------------------------------------------------------------------===//

def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> {
let summary = "An attribute containing a floating-point value";
let description = [{
An fp attribute is a literal attribute that represents a floating-point
value of the specified floating-point type. Supporting only CIR FP types.
}];
let parameters = (ins
AttributeSelfTypeParameter<"", "::cir::CIRFPTypeInterface">:$type,
APFloatParameter<"">:$value
);
let builders = [
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
"const llvm::APFloat &":$value), [{
return $_get(type.getContext(), mlir::cast<CIRFPTypeInterface>(type),
value);
}]>,
AttrBuilder<(ins "mlir::Type":$type,
"const llvm::APFloat &":$value), [{
return $_get($_ctxt, mlir::cast<CIRFPTypeInterface>(type), value);
}]>,
];
let extraClassDeclaration = [{
static FPAttr getZero(mlir::Type type);
}];
let genVerifyDecl = 1;

let assemblyFormat = [{
`<` custom<FloatLiteral>($value, ref($type)) `>`
}];
}

//===----------------------------------------------------------------------===//
// ConstPtrAttr
//===----------------------------------------------------------------------===//

def ConstPtrAttr : CIR_Attr<"ConstPtr", "ptr", [TypedAttrInterface]> {
let summary = "Holds a constant pointer value";
let parameters = (ins
AttributeSelfTypeParameter<"", "::cir::PointerType">:$type,
"mlir::IntegerAttr":$value);
let description = [{
A pointer attribute is a literal attribute that represents an integral
value of a pointer type.
}];
let builders = [
AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
"mlir::IntegerAttr":$value), [{
return $_get(type.getContext(), mlir::cast<cir::PointerType>(type),
value);
}]>,
AttrBuilder<(ins "mlir::Type":$type,
"mlir::IntegerAttr":$value), [{
return $_get($_ctxt, mlir::cast<cir::PointerType>(type), value);
}]>,
];
let extraClassDeclaration = [{
bool isNullValue() const { return getValue().getInt() == 0; }
}];

let assemblyFormat = [{
`<` custom<ConstPtr>($value) `>`
}];
}

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD
1 change: 1 addition & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "mlir/Interfaces/MemorySlotInterfaces.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"

// TableGen'erated files for MLIR dialects require that a macro be defined when
Expand Down
54 changes: 52 additions & 2 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

include "clang/CIR/Dialect/IR/CIRDialect.td"
include "clang/CIR/Dialect/IR/CIRTypes.td"
include "clang/CIR/Dialect/IR/CIRAttrs.td"

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

//===----------------------------------------------------------------------===//
// ConstantOp
//===----------------------------------------------------------------------===//

def ConstantOp : CIR_Op<"const",
[ConstantLike, Pure, AllTypesMatch<["value", "res"]>]> {
let summary = "Defines a CIR constant";
let description = [{
The `cir.const` operation turns a literal into an SSA value. The data is
attached to the operation as an attribute.

```mlir
%0 = cir.const 42 : i32
%1 = cir.const 4.2 : f32
%2 = cir.const nullptr : !cir.ptr<i32>
```
}];

// The constant operation takes an attribute as the only input.
let arguments = (ins TypedAttrInterface:$value);

// The constant operation returns a single value of CIR_AnyType.
let results = (outs CIR_AnyType:$res);

let assemblyFormat = "attr-dict $value";

let hasVerifier = 1;

let extraClassDeclaration = [{
bool isNullPtr() {
if (const auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(getValue()))
return ptrAttr.isNullValue();
return false;
}
}];

let hasFolder = 1;
}

//===----------------------------------------------------------------------===//
// GlobalOp
//===----------------------------------------------------------------------===//
Expand All @@ -92,9 +132,19 @@ def GlobalOp : CIR_Op<"global"> {
described by the type of the variable.
}];

let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type);
let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type,
OptionalAttr<AnyAttr>:$initial_value);

let assemblyFormat = [{
$sym_name
custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value)
attr-dict
}];

let assemblyFormat = [{ $sym_name `:` $sym_type attr-dict }];
let extraClassDeclaration = [{
bool isDeclaration() { return !getInitialValue(); }
bool hasInitializer() { return !isDeclaration(); }
}];

let skipDefaultBuilders = 1;

Expand Down
12 changes: 10 additions & 2 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> {

// Constraints

def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128, CIR_LongDouble,
CIR_FP16, CIR_BFloat16]>;
def CIR_AnyFloat: AnyTypeOf<[CIR_Single, CIR_Double, CIR_FP80, CIR_FP128,
CIR_LongDouble, CIR_FP16, CIR_BFloat16]>;
def CIR_AnyIntOrFloat: AnyTypeOf<[CIR_AnyFloat, CIR_IntType]>;

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -350,4 +350,12 @@ def VoidPtr : Type<
"cir::VoidType::get($_builder.getContext()))"> {
}

//===----------------------------------------------------------------------===//
// Global type constraints
//===----------------------------------------------------------------------===//

def CIR_AnyType : AnyTypeOf<[
CIR_VoidType, CIR_IntType, CIR_AnyFloat, CIR_PointerType, CIR_FuncType
]>;

#endif // MLIR_CIR_DIALECT_CIR_TYPES
3 changes: 3 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ mlir_tablegen(CIROpsDialect.cpp.inc -gen-dialect-defs)
add_public_tablegen_target(MLIRCIROpsIncGen)
add_dependencies(mlir-headers MLIRCIROpsIncGen)

mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
add_public_tablegen_target(MLIRCIRAttrsEnumsGen)
42 changes: 42 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,48 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
identifier->getName(), type);
// TODO(CIR): This code for processing initial values is a placeholder
// until class ConstantEmitter is upstreamed and the code for processing
// constant expressions is filled out. Only the most basic handling of
// certain constant expressions is implemented for now.
const VarDecl *initDecl;
const Expr *initExpr = vd->getAnyInitializer(initDecl);
if (initExpr) {
mlir::Attribute initializer;
if (APValue *value = initDecl->evaluateValue()) {
switch (value->getKind()) {
case APValue::Int: {
initializer = builder.getAttr<cir::IntAttr>(type, value->getInt());
break;
}
case APValue::Float: {
initializer = builder.getAttr<cir::FPAttr>(type, value->getFloat());
break;
}
case APValue::LValue: {
if (value->getLValueBase()) {
errorNYI(initExpr->getSourceRange(),
"non-null pointer initialization");
} else {
if (auto ptrType = mlir::dyn_cast<cir::PointerType>(type)) {
initializer = builder.getConstPtrAttr(
ptrType, value->getLValueOffset().getQuantity());
} else {
llvm_unreachable(
"non-pointer variable initialized with a pointer");
}
}
break;
}
default:
errorNYI(initExpr->getSourceRange(), "unsupported initializer kind");
break;
}
} else {
errorNYI(initExpr->getSourceRange(), "non-constant initializer");
}
varOp.setInitialValueAttr(initializer);
}
theModule.push_back(varOp);
} else {
errorNYI(vd->getSourceRange().getBegin(),
Expand Down
Loading
Loading