diff --git a/llvm/include/llvm/IR/Assumptions.h b/llvm/include/llvm/IR/Assumptions.h --- a/llvm/include/llvm/IR/Assumptions.h +++ b/llvm/include/llvm/IR/Assumptions.h @@ -34,6 +34,10 @@ /// Helper that allows to insert a new assumption string in the known assumption /// set by creating a (static) object. struct KnownAssumptionString { + KnownAssumptionString(const char *AssumptionStr) + : AssumptionStr(AssumptionStr) { + KnownAssumptionStrings.insert(AssumptionStr); + } KnownAssumptionString(StringRef AssumptionStr) : AssumptionStr(AssumptionStr) { KnownAssumptionStrings.insert(AssumptionStr); diff --git a/llvm/lib/IR/Assumptions.cpp b/llvm/lib/IR/Assumptions.cpp --- a/llvm/lib/IR/Assumptions.cpp +++ b/llvm/lib/IR/Assumptions.cpp @@ -107,4 +107,5 @@ "omp_no_openmp_routines", // OpenMP 5.1 "omp_no_parallelism", // OpenMP 5.1 "ompx_spmd_amenable", // OpenMPOpt extension + "ompx_no_call_asm", // OpenMPOpt extension }); diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -32,6 +32,7 @@ #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/Argument.h" #include "llvm/IR/Assumptions.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" @@ -9540,7 +9541,9 @@ CallBase *CB = cast(getCtxI()); if (CB->isInlineAsm()) { - setHasUnknownCallee(false, Change); + if (!hasAssumption(*CB->getCaller(), "ompx_no_call_asm") && + !hasAssumption(*CB, "ompx_no_call_asm")) + setHasUnknownCallee(false, Change); return Change; } diff --git a/llvm/test/Transforms/Attributor/reachability.ll b/llvm/test/Transforms/Attributor/reachability.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Attributor/reachability.ll @@ -0,0 +1,49 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals +; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM +; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM +; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM + +define void @non_recursive_asm_fn() #0 { +; CHECK: Function Attrs: norecurse +; CHECK-LABEL: define {{[^@]+}}@non_recursive_asm_fn +; CHECK-SAME: () #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: call void asm sideeffect "barrier.sync $0 +; CHECK-NEXT: ret void +; +entry: + call void asm sideeffect "barrier.sync $0;", "r,~{memory},~{dirflag},~{fpsr},~{flags}"(i32 1) + ret void +} + +define void @non_recursive_asm_cs() { +; CHECK: Function Attrs: norecurse +; CHECK-LABEL: define {{[^@]+}}@non_recursive_asm_cs +; CHECK-SAME: () #[[ATTR1:[0-9]+]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: call void asm sideeffect "barrier.sync $0 +; CHECK-NEXT: ret void +; +entry: + call void asm sideeffect "barrier.sync $0;", "r,~{memory},~{dirflag},~{fpsr},~{flags}"(i32 1) #0 + ret void +} + +define void @recursive_asm() { +; CHECK-LABEL: define {{[^@]+}}@recursive_asm() { +; CHECK-NEXT: entry: +; CHECK-NEXT: call void asm sideeffect "barrier.sync $0 +; CHECK-NEXT: ret void +; +entry: + call void asm sideeffect "barrier.sync $0;", "r,~{memory},~{dirflag},~{fpsr},~{flags}"(i32 1) + ret void +} + +attributes #0 = { "llvm.assume"="ompx_no_call_asm" } +;. +; CHECK: attributes #[[ATTR0]] = { norecurse "llvm.assume"="ompx_no_call_asm" } +; CHECK: attributes #[[ATTR1]] = { norecurse } +; CHECK: attributes #[[ATTR2:[0-9]+]] = { "llvm.assume"="ompx_no_call_asm" } +;. diff --git a/openmp/libomptarget/DeviceRTL/include/Types.h b/openmp/libomptarget/DeviceRTL/include/Types.h --- a/openmp/libomptarget/DeviceRTL/include/Types.h +++ b/openmp/libomptarget/DeviceRTL/include/Types.h @@ -12,6 +12,15 @@ #ifndef OMPTARGET_TYPES_H #define OMPTARGET_TYPES_H +// Tell the compiler that we do not have any "call-like" inline assembly in the +// device rutime. That means we cannot have inline assembly which will call +// another function but only inline assembly that performs some operation or +// side-effect and then continues execution with something on the existing call +// stack. +// +// TODO: Find a good place for this +#pragma omp assumes ext_no_call_asm + /// Base type declarations for freestanding mode /// ///{