@@ -3540,8 +3540,48 @@ bool fir::hasHostAssociationArgument(mlir::func::FuncOp func) {
3540
3540
return false ;
3541
3541
}
3542
3542
3543
- bool fir::valueHasFirAttribute (mlir::Value value,
3544
- llvm::StringRef attributeName) {
3543
+ // Test if value's definition has the specified set of
3544
+ // attributeNames. The value's definition is one of the operations
3545
+ // that are able to carry the Fortran variable attributes, e.g.
3546
+ // fir.alloca or fir.allocmem. Function arguments may also represent
3547
+ // value definitions and carry relevant attributes.
3548
+ //
3549
+ // If it is not possible to reach the limited set of definition
3550
+ // entities from the given value, then the function will return
3551
+ // std::nullopt. Otherwise, the definition is known and the return
3552
+ // value is computed as:
3553
+ // * if checkAny is true, then the function will return true
3554
+ // iff any of the attributeNames attributes is set on the definition.
3555
+ // * if checkAny is false, then the function will return true
3556
+ // iff all of the attributeNames attributes are set on the definition.
3557
+ static std::optional<bool >
3558
+ valueCheckFirAttributes (mlir::Value value,
3559
+ llvm::ArrayRef<llvm::StringRef> attributeNames,
3560
+ bool checkAny) {
3561
+ auto testAttributeSets = [&](llvm::ArrayRef<mlir::NamedAttribute> setAttrs,
3562
+ llvm::ArrayRef<llvm::StringRef> checkAttrs) {
3563
+ if (checkAny) {
3564
+ // Return true iff any of checkAttrs attributes is present
3565
+ // in setAttrs set.
3566
+ for (llvm::StringRef checkAttrName : checkAttrs)
3567
+ if (llvm::any_of (setAttrs, [&](mlir::NamedAttribute setAttr) {
3568
+ return setAttr.getName () == checkAttrName;
3569
+ }))
3570
+ return true ;
3571
+
3572
+ return false ;
3573
+ }
3574
+
3575
+ // Return true iff all attributes from checkAttrs are present
3576
+ // in setAttrs set.
3577
+ for (mlir::StringRef checkAttrName : checkAttrs)
3578
+ if (llvm::none_of (setAttrs, [&](mlir::NamedAttribute setAttr) {
3579
+ return setAttr.getName () == checkAttrName;
3580
+ }))
3581
+ return false ;
3582
+
3583
+ return true ;
3584
+ };
3545
3585
// If this is a fir.box that was loaded, the fir attributes will be on the
3546
3586
// related fir.ref<fir.box> creation.
3547
3587
if (value.getType ().isa <fir::BoxType>())
@@ -3553,32 +3593,50 @@ bool fir::valueHasFirAttribute(mlir::Value value,
3553
3593
if (blockArg.getOwner () && blockArg.getOwner ()->isEntryBlock ())
3554
3594
if (auto funcOp = mlir::dyn_cast<mlir::func::FuncOp>(
3555
3595
blockArg.getOwner ()->getParentOp ()))
3556
- if (funcOp.getArgAttr (blockArg.getArgNumber (), attributeName))
3557
- return true ;
3558
- return false ;
3596
+ return testAttributeSets (
3597
+ mlir::cast<mlir::FunctionOpInterface>(*funcOp).getArgAttrs (
3598
+ blockArg.getArgNumber ()),
3599
+ attributeNames);
3600
+
3601
+ // If it is not a function argument, the attributes are unknown.
3602
+ return std::nullopt;
3559
3603
}
3560
3604
3561
3605
if (auto definingOp = value.getDefiningOp ()) {
3562
3606
// If this is an allocated value, look at the allocation attributes.
3563
3607
if (mlir::isa<fir::AllocMemOp>(definingOp) ||
3564
- mlir::isa<AllocaOp>(definingOp))
3565
- return definingOp->hasAttr (attributeName );
3608
+ mlir::isa<fir:: AllocaOp>(definingOp))
3609
+ return testAttributeSets ( definingOp->getAttrs (), attributeNames );
3566
3610
// If this is an imported global, look at AddrOfOp and GlobalOp attributes.
3567
3611
// Both operations are looked at because use/host associated variable (the
3568
3612
// AddrOfOp) can have ASYNCHRONOUS/VOLATILE attributes even if the ultimate
3569
3613
// entity (the globalOp) does not have them.
3570
3614
if (auto addressOfOp = mlir::dyn_cast<fir::AddrOfOp>(definingOp)) {
3571
- if (addressOfOp->hasAttr (attributeName ))
3615
+ if (testAttributeSets ( addressOfOp->getAttrs (), attributeNames ))
3572
3616
return true ;
3573
3617
if (auto module = definingOp->getParentOfType <mlir::ModuleOp>())
3574
3618
if (auto globalOp =
3575
3619
module .lookupSymbol <fir::GlobalOp>(addressOfOp.getSymbol ()))
3576
- return globalOp->hasAttr (attributeName );
3620
+ return testAttributeSets ( globalOp->getAttrs (), attributeNames );
3577
3621
}
3578
3622
}
3579
3623
// TODO: Construct associated entities attributes. Decide where the fir
3580
3624
// attributes must be placed/looked for in this case.
3581
- return false ;
3625
+ return std::nullopt;
3626
+ }
3627
+
3628
+ bool fir::valueMayHaveFirAttributes (
3629
+ mlir::Value value, llvm::ArrayRef<llvm::StringRef> attributeNames) {
3630
+ std::optional<bool > mayHaveAttr =
3631
+ valueCheckFirAttributes (value, attributeNames, /* checkAny=*/ true );
3632
+ return mayHaveAttr.value_or (true );
3633
+ }
3634
+
3635
+ bool fir::valueHasFirAttribute (mlir::Value value,
3636
+ llvm::StringRef attributeName) {
3637
+ std::optional<bool > mayHaveAttr =
3638
+ valueCheckFirAttributes (value, {attributeName}, /* checkAny=*/ false );
3639
+ return mayHaveAttr.value_or (false );
3582
3640
}
3583
3641
3584
3642
bool fir::anyFuncArgsHaveAttr (mlir::func::FuncOp func, llvm::StringRef attr) {
0 commit comments