/// Get the attribute of a given kind for the function.
Attribute getFnAttr(StringRef Kind) const {
- return getAttributes().getFnAttr(Kind);
+ Attribute Attr = getAttributes().getFnAttr(Kind);
+ if (Attr.isValid())
+ return Attr;
+ return getFnAttrOnCalledFunction(Kind);
}
/// Get the attribute of a given kind for the function.
Attribute getFnAttr(Attribute::AttrKind Kind) const {
- return getAttributes().getFnAttr(Kind);
+ Attribute A = getAttributes().getFnAttr(Kind);
+ if (A.isValid())
+ return A;
+ return getFnAttrOnCalledFunction(Kind);
}
/// Get the attribute of a given kind from a given arg
return hasFnAttrOnCalledFunction(Kind);
}
+ template <typename AK> Attribute getFnAttrOnCalledFunction(AK Kind) const;
/// A specialized version of hasFnAttrImpl for when the caller wants to
/// know if an attribute's semantics are implied, not whether the attribute
"disable-gep-const-evaluation", cl::Hidden, cl::init(false),
cl::desc("Disables evaluation of GetElementPtr with constant operands"));
-namespace {
-/// This function behaves more like CallBase::hasFnAttr: when it looks for the
-/// requested attribute, it check both the call instruction and the called
-/// function (if it's available and operand bundles don't prohibit that).
-Attribute getFnAttr(CallBase &CB, StringRef AttrKind) {
- Attribute CallAttr = CB.getFnAttr(AttrKind);
- if (CallAttr.isValid())
- return CallAttr;
-
- // Operand bundles override attributes on the called function, but don't
- // override attributes directly present on the call instruction.
- if (!CB.isFnAttrDisallowedByOpBundle(AttrKind))
- if (const Function *F = CB.getCalledFunction())
- return F->getFnAttribute(AttrKind);
-
- return {};
-}
-} // namespace
-
namespace llvm {
Optional<int> getStringFnAttrAsInt(CallBase &CB, StringRef AttrKind) {
- Attribute Attr = getFnAttr(CB, AttrKind);
+ Attribute Attr = CB.getFnAttr(AttrKind);
int AttrValue;
if (Attr.getValueAsString().getAsInteger(10, AttrValue))
return None;
return false;
}
+template <typename AK>
+Attribute CallBase::getFnAttrOnCalledFunction(AK Kind) const {
+ // Operand bundles override attributes on the called function, but don't
+ // override attributes directly present on the call instruction.
+ if (isFnAttrDisallowedByOpBundle(Kind))
+ return Attribute();
+ Value *V = getCalledOperand();
+ if (auto *CE = dyn_cast<ConstantExpr>(V))
+ if (CE->getOpcode() == BitCast)
+ V = CE->getOperand(0);
+
+ if (auto *F = dyn_cast<Function>(V))
+ return F->getAttributes().getFnAttr(Kind);
+
+ return Attribute();
+}
+
+template Attribute
+CallBase::getFnAttrOnCalledFunction(Attribute::AttrKind Kind) const;
+template Attribute CallBase::getFnAttrOnCalledFunction(StringRef Kind) const;
+
void CallBase::getOperandBundlesAsDefs(
SmallVectorImpl<OperandBundleDef> &Defs) const {
for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i)
; CHECK-LABEL: define {{[^@]+}}@entry
; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @foo(i1 [[COND]]) #[[ATTR1:[0-9]+]]
-; CHECK-NEXT: call void @bar() #[[ATTR2:[0-9]+]]
-; CHECK-NEXT: call void @qux() #[[ATTR1]]
+; CHECK-NEXT: call void @foo(i1 [[COND]])
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: call void @qux() #[[ATTR1:[0-9]+]]
; CHECK-NEXT: ret void
;
entry:
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i1 [[COND:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @baz(i1 [[COND]]) #[[ATTR1]]
+; CHECK-NEXT: call void @baz(i1 [[COND]])
; CHECK-NEXT: ret void
;
entry:
define internal void @bar() #2 {
; CHECK-LABEL: define {{[^@]+}}@bar
-; CHECK-SAME: () #[[ATTR2]] {
+; CHECK-SAME: () #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @baz(i1 noundef false) #[[ATTR2]]
; CHECK-NEXT: ret void
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i1 [[COND]], false
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: call void @baz(i1 noundef false) #[[ATTR1]]
+; CHECK-NEXT: call void @baz(i1 noundef false)
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
-; CHECK-NEXT: call void @qux() #[[ATTR1]]
+; CHECK-NEXT: call void @qux()
; CHECK-NEXT: ret void
;
entry:
; CHECK-LABEL: define {{[^@]+}}@qux
; CHECK-SAME: () #[[ATTR1]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @call() #[[ATTR2]]
+; CHECK-NEXT: call void @call()
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* nonnull null, i8 1, i1 false, i1 true)
; CHECK-NEXT: call void @foo() #[[ATTR0:[0-9]+]]
; CHECK-NEXT: call void @bar() #[[ATTR0]]
-; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR5:[0-9]+]]
+; CHECK-NEXT: call void @unknown_no_openmp()
; CHECK-NEXT: call void @__kmpc_target_deinit(%struct.ident_t* nonnull null, i8 1, i1 true)
; CHECK-NEXT: ret void
;
; CHECK-DISABLED-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* nonnull null, i8 1, i1 false, i1 true)
; CHECK-DISABLED-NEXT: call void @foo() #[[ATTR0:[0-9]+]]
; CHECK-DISABLED-NEXT: call void @bar() #[[ATTR0]]
-; CHECK-DISABLED-NEXT: call void @unknown_no_openmp() #[[ATTR5:[0-9]+]]
+; CHECK-DISABLED-NEXT: call void @unknown_no_openmp()
; CHECK-DISABLED-NEXT: call void @__kmpc_target_deinit(%struct.ident_t* nonnull null, i8 1, i1 true)
; CHECK-DISABLED-NEXT: ret void
;
; CHECK: attributes #[[ATTR2]] = { nounwind readnone }
; CHECK: attributes #[[ATTR3]] = { nofree nosync nounwind writeonly }
; CHECK: attributes #[[ATTR4:[0-9]+]] = { nosync nounwind allocsize(0) }
-; CHECK: attributes #[[ATTR5]] = { "llvm.assume"="omp_no_openmp" }
+; CHECK: attributes #[[ATTR5:[0-9]+]] = { "llvm.assume"="omp_no_openmp" }
; CHECK: attributes #[[ATTR6]] = { nosync nounwind writeonly }
;.
; CHECK-DISABLED: attributes #[[ATTR0]] = { nounwind }
; CHECK-DISABLED: attributes #[[ATTR2]] = { nounwind readnone }
; CHECK-DISABLED: attributes #[[ATTR3]] = { nofree nosync nounwind writeonly }
; CHECK-DISABLED: attributes #[[ATTR4:[0-9]+]] = { nosync nounwind allocsize(0) }
-; CHECK-DISABLED: attributes #[[ATTR5]] = { "llvm.assume"="omp_no_openmp" }
+; CHECK-DISABLED: attributes #[[ATTR5:[0-9]+]] = { "llvm.assume"="omp_no_openmp" }
; CHECK-DISABLED: attributes #[[ATTR6]] = { nosync nounwind writeonly }
;.
; CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* @[[GLOB1]], i8 1, i1 false, i1 true)
; CHECK-NEXT: [[X:%.*]] = call align 4 i8* @__kmpc_alloc_shared(i64 4) #[[ATTR7:[0-9]+]]
-; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6:[0-9]+]]
+; CHECK-NEXT: call void @unknown_no_openmp()
; CHECK-NEXT: [[X_ON_STACK:%.*]] = bitcast i8* [[X]] to i32*
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[X_ON_STACK]] to i8*
; CHECK-NEXT: call void @use.internalized(i8* nofree [[TMP0]]) #[[ATTR8:[0-9]+]]
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT: [[C:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* @[[GLOB1]], i8 1, i1 false, i1 true)
-; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6]]
+; CHECK-NEXT: call void @unknown_no_openmp()
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], -1
; CHECK-NEXT: br i1 [[CMP]], label [[MASTER1:%.*]], label [[EXIT:%.*]]
; CHECK: master1:
; CHECK-NEXT: call void @use.internalized(i8* nofree [[A0]]) #[[ATTR8]]
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
-; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6]]
+; CHECK-NEXT: call void @unknown_no_openmp()
; CHECK-NEXT: br label [[MASTER2:%.*]]
; CHECK: master2:
; CHECK-NEXT: [[Y_ON_STACK:%.*]] = bitcast i8* addrspacecast (i8 addrspace(3)* getelementptr inbounds ([4 x i8], [4 x i8] addrspace(3)* @y_shared, i32 0, i32 0) to i8*) to [4 x i32]*
; CHECK-LABEL: define {{[^@]+}}@baz_spmd
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT: [[C:%.*]] = call i32 @__kmpc_target_init(%struct.ident_t* @[[GLOB1]], i8 2, i1 true, i1 true)
-; CHECK-NEXT: call void @unknown_no_openmp() #[[ATTR6]]
+; CHECK-NEXT: call void @unknown_no_openmp()
; CHECK-NEXT: [[C0:%.*]] = icmp eq i32 [[C]], -1
; CHECK-NEXT: br i1 [[C0]], label [[MASTER3:%.*]], label [[EXIT:%.*]]
; CHECK: master3:
; CHECK: attributes #[[ATTR3:[0-9]+]] = { nosync nounwind }
; CHECK: attributes #[[ATTR4:[0-9]+]] = { nounwind readnone speculatable }
; CHECK: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nosync nounwind readnone speculatable willreturn }
-; CHECK: attributes #[[ATTR6]] = { "llvm.assume"="omp_no_openmp" }
+; CHECK: attributes #[[ATTR6:[0-9]+]] = { "llvm.assume"="omp_no_openmp" }
; CHECK: attributes #[[ATTR7]] = { nounwind readonly }
; CHECK: attributes #[[ATTR8]] = { nounwind writeonly }
; CHECK: attributes #[[ATTR9]] = { nounwind }