Skip to content

Commit 4b22631

Browse files
authored
[MLIR] Add target_specific_attrs attribute to mlir.global (#154706)
Adds a `target_specific_attrs` optional array attribute to `mlir.global`, as well as conversions to and from LLVM attributes on `llvm::GlobalVariable` objects. This is necessary to preserve unknown attributes on global variables when converting to and from the LLVM Dialect. Previously, any attributes on an `llvm::GlobalVariable` not explicitly modeled by `mlir.global` were dropped during conversion.
1 parent 2320529 commit 4b22631

File tree

10 files changed

+264
-145
lines changed

10 files changed

+264
-145
lines changed

llvm/include/llvm/IR/Attributes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ class AttributeSet {
399399
[[nodiscard]] LLVM_ABI AttributeSet addAttributes(LLVMContext &C,
400400
AttributeSet AS) const;
401401

402+
/// Add attributes to the attribute set. Returns a new set because attribute
403+
/// sets are immutable.
404+
AttributeSet addAttributes(LLVMContext &C, const AttrBuilder &B) const;
405+
402406
/// Remove the specified attribute from this set. Returns a new set because
403407
/// attribute sets are immutable.
404408
[[nodiscard]] LLVM_ABI AttributeSet

llvm/include/llvm/IR/GlobalVariable.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> {
219219
Attrs = Attrs.addAttribute(getContext(), Kind, Val);
220220
}
221221

222+
/// Add attributes to this global.
223+
void addAttributes(const AttrBuilder &AttrBuilder) {
224+
Attrs = Attrs.addAttributes(getContext(), AttrBuilder);
225+
}
226+
222227
/// Return true if the attribute exists.
223228
bool hasAttribute(Attribute::AttrKind Kind) const {
224229
return Attrs.hasAttribute(Kind);

llvm/lib/IR/Attributes.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,19 @@ AttributeSet AttributeSet::addAttributes(LLVMContext &C,
954954
return get(C, B);
955955
}
956956

957+
AttributeSet AttributeSet::addAttributes(LLVMContext &C,
958+
const AttrBuilder &B) const {
959+
if (!hasAttributes())
960+
return get(C, B);
961+
962+
if (!B.hasAttributes())
963+
return *this;
964+
965+
AttrBuilder Merged(C, *this);
966+
Merged.merge(B);
967+
return get(C, Merged);
968+
}
969+
957970
AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
958971
Attribute::AttrKind Kind) const {
959972
if (!hasAttribute(Kind)) return *this;

mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,8 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
13131313
OptionalAttr<StrAttr>:$section,
13141314
OptionalAttr<SymbolRefAttr>:$comdat,
13151315
OptionalAttr<DIGlobalVariableExpressionArrayAttr>:$dbg_exprs,
1316-
DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_
1316+
DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_,
1317+
OptionalAttr<ArrayAttr>:$target_specific_attrs
13171318
);
13181319
let summary = "LLVM dialect global.";
13191320
let description = [{
@@ -1411,6 +1412,21 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
14111412
llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) { alignment = 32 : i64 } : !llvm.array<8 x f32>
14121413
```
14131414

1415+
The `target_specific_attrs` attribute provides a mechanism to preserve
1416+
target-specific LLVM IR attributes that are not explicitly modeled in the
1417+
LLVM dialect.
1418+
1419+
The attribute is an array containing either string attributes or
1420+
two-element array attributes of strings. The value of a standalone string
1421+
attribute is interpreted as the name of an LLVM IR attribute on the global.
1422+
A two-element array is interpreted as a key-value pair.
1423+
1424+
Example:
1425+
1426+
```mlir
1427+
llvm.mlir.global external @example() {
1428+
target_specific_attrs = ["value-less-attr", ["int-attr", "4"], ["string-attr", "string"]]} : f64
1429+
```
14141430
}];
14151431
let regions = (region AnyRegion:$initializer);
14161432

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,67 @@ LogicalResult ModuleImport::convertIFunc(llvm::GlobalIFunc *ifunc) {
14091409
return success();
14101410
}
14111411

1412+
/// Converts LLVM string, integer, and enum attributes into MLIR attributes,
1413+
/// skipping those in `attributesToSkip` and emitting a warning at `loc` for
1414+
/// any other unsupported attributes.
1415+
static ArrayAttr
1416+
convertLLVMAttributesToMLIR(Location loc, MLIRContext *context,
1417+
llvm::AttributeSet attributes,
1418+
ArrayRef<StringLiteral> attributesToSkip = {}) {
1419+
SmallVector<Attribute> mlirAttributes;
1420+
for (llvm::Attribute attr : attributes) {
1421+
StringRef attrName;
1422+
if (attr.isStringAttribute())
1423+
attrName = attr.getKindAsString();
1424+
else
1425+
attrName = llvm::Attribute::getNameFromAttrKind(attr.getKindAsEnum());
1426+
if (llvm::is_contained(attributesToSkip, attrName))
1427+
continue;
1428+
1429+
auto keyAttr = StringAttr::get(context, attrName);
1430+
if (attr.isStringAttribute()) {
1431+
StringRef val = attr.getValueAsString();
1432+
if (val.empty()) {
1433+
// For string attributes without values, add only the attribute name.
1434+
mlirAttributes.push_back(keyAttr);
1435+
continue;
1436+
}
1437+
// For string attributes with a value, create a [name, value] pair.
1438+
mlirAttributes.push_back(
1439+
ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)}));
1440+
continue;
1441+
}
1442+
if (attr.isIntAttribute()) {
1443+
// For integer attributes, convert the value to a string and create a
1444+
// [name, value] pair.
1445+
auto val = std::to_string(attr.getValueAsInt());
1446+
mlirAttributes.push_back(
1447+
ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)}));
1448+
continue;
1449+
}
1450+
if (attr.isEnumAttribute()) {
1451+
// For enum attributes, add only the attribute name.
1452+
mlirAttributes.push_back(keyAttr);
1453+
continue;
1454+
}
1455+
1456+
emitWarning(loc)
1457+
<< "'" << attrName
1458+
<< "' attribute is invalid on current operation, skipping it";
1459+
}
1460+
return ArrayAttr::get(context, mlirAttributes);
1461+
}
1462+
1463+
/// Converts LLVM attributes from `globalVar` into MLIR attributes and adds them
1464+
/// to `globalOp` as target-specific attributes.
1465+
static void processTargetSpecificAttrs(llvm::GlobalVariable *globalVar,
1466+
GlobalOp globalOp) {
1467+
ArrayAttr targetSpecificAttrs = convertLLVMAttributesToMLIR(
1468+
globalOp.getLoc(), globalOp.getContext(), globalVar->getAttributes());
1469+
if (!targetSpecificAttrs.empty())
1470+
globalOp.setTargetSpecificAttrsAttr(targetSpecificAttrs);
1471+
}
1472+
14121473
LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
14131474
// Insert the global after the last one or at the start of the module.
14141475
OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();
@@ -1474,6 +1535,8 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {
14741535
if (globalVar->hasComdat())
14751536
globalOp.setComdatAttr(comdatMapping.lookup(globalVar->getComdat()));
14761537

1538+
processTargetSpecificAttrs(globalVar, globalOp);
1539+
14771540
return success();
14781541
}
14791542

@@ -2526,7 +2589,7 @@ static void processMemoryEffects(llvm::Function *func, LLVMFuncOp funcOp) {
25262589

25272590
// List of LLVM IR attributes that map to an explicit attribute on the MLIR
25282591
// LLVMFuncOp.
2529-
static constexpr std::array kExplicitAttributes{
2592+
static constexpr std::array kExplicitLLVMFuncOpAttributes{
25302593
StringLiteral("aarch64_in_za"),
25312594
StringLiteral("aarch64_inout_za"),
25322595
StringLiteral("aarch64_new_za"),
@@ -2543,6 +2606,7 @@ static constexpr std::array kExplicitAttributes{
25432606
StringLiteral("frame-pointer"),
25442607
StringLiteral("instrument-function-entry"),
25452608
StringLiteral("instrument-function-exit"),
2609+
StringLiteral("memory"),
25462610
StringLiteral("no-infs-fp-math"),
25472611
StringLiteral("no-nans-fp-math"),
25482612
StringLiteral("no-signed-zeros-fp-math"),
@@ -2557,61 +2621,17 @@ static constexpr std::array kExplicitAttributes{
25572621
StringLiteral("willreturn"),
25582622
};
25592623

2624+
/// Converts LLVM attributes from `func` into MLIR attributes and adds them
2625+
/// to `funcOp` as passthrough attributes, skipping those listed in
2626+
/// `kExplicitLLVMFuncAttributes`.
25602627
static void processPassthroughAttrs(llvm::Function *func, LLVMFuncOp funcOp) {
2561-
MLIRContext *context = funcOp.getContext();
2562-
SmallVector<Attribute> passthroughs;
25632628
llvm::AttributeSet funcAttrs = func->getAttributes().getAttributes(
25642629
llvm::AttributeList::AttrIndex::FunctionIndex);
2565-
for (llvm::Attribute attr : funcAttrs) {
2566-
// Skip the memory attribute since the LLVMFuncOp has an explicit memory
2567-
// attribute.
2568-
if (attr.hasAttribute(llvm::Attribute::Memory))
2569-
continue;
2570-
2571-
// Skip invalid type attributes.
2572-
if (attr.isTypeAttribute()) {
2573-
emitWarning(funcOp.getLoc(),
2574-
"type attributes on a function are invalid, skipping it");
2575-
continue;
2576-
}
2577-
2578-
StringRef attrName;
2579-
if (attr.isStringAttribute())
2580-
attrName = attr.getKindAsString();
2581-
else
2582-
attrName = llvm::Attribute::getNameFromAttrKind(attr.getKindAsEnum());
2583-
auto keyAttr = StringAttr::get(context, attrName);
2584-
2585-
// Skip attributes that map to an explicit attribute on the LLVMFuncOp.
2586-
if (llvm::is_contained(kExplicitAttributes, attrName))
2587-
continue;
2588-
2589-
if (attr.isStringAttribute()) {
2590-
StringRef val = attr.getValueAsString();
2591-
if (val.empty()) {
2592-
passthroughs.push_back(keyAttr);
2593-
continue;
2594-
}
2595-
passthroughs.push_back(
2596-
ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)}));
2597-
continue;
2598-
}
2599-
if (attr.isIntAttribute()) {
2600-
auto val = std::to_string(attr.getValueAsInt());
2601-
passthroughs.push_back(
2602-
ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)}));
2603-
continue;
2604-
}
2605-
if (attr.isEnumAttribute()) {
2606-
passthroughs.push_back(keyAttr);
2607-
continue;
2608-
}
2609-
2610-
llvm_unreachable("unexpected attribute kind");
2611-
}
2612-
2613-
if (!passthroughs.empty())
2614-
funcOp.setPassthroughAttr(ArrayAttr::get(context, passthroughs));
2630+
ArrayAttr passthroughAttr =
2631+
convertLLVMAttributesToMLIR(funcOp.getLoc(), funcOp.getContext(),
2632+
funcAttrs, kExplicitLLVMFuncOpAttributes);
2633+
if (!passthroughAttr.empty())
2634+
funcOp.setPassthroughAttr(passthroughAttr);
26152635
}
26162636

26172637
void ModuleImport::processFunctionAttributes(llvm::Function *func,

0 commit comments

Comments
 (0)