33 changes: 33 additions & 0 deletions clang/test/CodeGen/fmaxfmin-invalid-arguments-type.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: not %clang_cc1 -triple x86_64 %s -fsyntax-only -verify 2>&1 | FileCheck %s --check-prefix=CHECK-ERR

float fminimum_numf (float, float);
double fminimum_num (double, double);
long double fminimum_numl (long double, long double);
float fmaximum_numf (float, float);
double fmaximum_num (double, double);
long double fmaximum_numl (long double, long double);

// CHECK-ERR: passing 'char *' to parameter of incompatible type 'float'
float fmin1(char *a, char *b) {
return fminimum_numf(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'double'
float fmin2(char *a, char *b) {
return fminimum_num(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'long double'
float fmin3(char *a, char *b) {
return fminimum_numl(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'float'
float fmax1(char *a, char *b) {
return fmaximum_numf(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'double'
float fmax2(char *a, char *b) {
return fmaximum_num(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'long double'
float fmax3(char *a, char *b) {
return fmaximum_numl(a, b);
}
22 changes: 17 additions & 5 deletions clang/test/CodeGen/math-libcalls.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm %s | FileCheck %s --check-prefix=NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 %s | FileCheck %s --check-prefix=NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -ffp-exception-behavior=maytrap %s | FileCheck %s --check-prefix=HAS_MAYTRAP
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm %s | FileCheck %s --check-prefixes=COMMON,NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefixes=COMMON,HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 %s | FileCheck %s --check-prefixes=COMMON,NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 -fmath-errno %s | FileCheck %s --check-prefixes=COMMON,HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -ffp-exception-behavior=maytrap %s | FileCheck %s --check-prefixes=COMMON,HAS_MAYTRAP
// RUN: %clang_cc1 -triple x86_64-unknown-unknown-gnu -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_GNU
// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_WIN

Expand Down Expand Up @@ -372,6 +372,18 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(

fmaximum_num(*d,*d); fmaximum_numf(f,f); fmaximum_numl(*l,*l);

// COMMON: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
// COMMON: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
// COMMON: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]

fminimum_num(*d,*d); fminimum_numf(f,f); fminimum_numl(*l,*l);

// COMMON: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
// COMMON: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
// COMMON: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]

hypot(f,f); hypotf(f,f); hypotl(f,f);

// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]
Expand Down
4 changes: 3 additions & 1 deletion clang/test/Preprocessor/feature_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@

// Check __has_constexpr_builtin
#if !__has_constexpr_builtin(__builtin_fmax) || \
!__has_constexpr_builtin(__builtin_fmin)
!__has_constexpr_builtin(__builtin_fmin) || \
!__has_constexpr_builtin(__builtin_fmaximum_num) || \
!__has_constexpr_builtin(__builtin_fminimum_num)
#error Clang should have these constexpr builtins
#endif

Expand Down
69 changes: 69 additions & 0 deletions clang/test/Sema/constant-builtins-fmaximum-num.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
// FIXME: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

constexpr double NaN = __builtin_nan("");
constexpr double SNaN = __builtin_nans("");
constexpr double Inf = __builtin_inf();
constexpr double NegInf = -__builtin_inf();

#define FMAXIMUMNUM_TEST_SIMPLE(T, FUNC) \
static_assert(T(6.7890) == FUNC(T(1.2345), T(6.7890))); \
static_assert(T(6.7890) == FUNC(T(6.7890), T(1.2345)));

#define FMAXIMUMNUM_TEST_SNAN(T, FUNC) \
static_assert(Inf == FUNC(SNaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, SNaN)); \
static_assert(0.0 == FUNC(SNaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, SNaN)); \
static_assert(T(-1.2345) == FUNC(SNaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), SNaN)); \
static_assert(__builtin_isnan(FUNC(SNaN, SNaN))); \
static_assert(__builtin_isnan(FUNC(NaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(SNaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(NaN, SNaN)));

#define FMAXIMUMNUM_TEST_NAN(T, FUNC) \
static_assert(Inf == FUNC(NaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, NaN)); \
static_assert(0.0 == FUNC(NaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, NaN)); \
static_assert(T(-1.2345) == FUNC(NaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), NaN)); \
static_assert(__builtin_isnan(FUNC(NaN, NaN)));

#define FMAXIMUMNUM_TEST_INF(T, FUNC) \
static_assert(Inf == FUNC(NegInf, Inf)); \
static_assert(Inf == FUNC(Inf, 0.0)); \
static_assert(Inf == FUNC(-0.0, Inf)); \
static_assert(Inf == FUNC(Inf, T(1.2345))); \
static_assert(Inf == FUNC(T(-1.2345), Inf));

#define FMAXIMUMNUM_TEST_NEG_INF(T, FUNC) \
static_assert(Inf == FUNC(Inf, NegInf)); \
static_assert(0.0 == FUNC(NegInf, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, NegInf)); \
static_assert(T(-1.2345) == FUNC(NegInf, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), NegInf));

#define FMAXIMUMNUM_TEST_BOTH_ZERO(T, FUNC) \
static_assert(__builtin_copysign(1.0, FUNC(0.0, 0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, 0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(0.0, -0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, -0.0)) == -1.0);

#define LIST_FMAXIMUMNUM_TESTS(T, FUNC) \
FMAXIMUMNUM_TEST_SIMPLE(T, FUNC) \
FMAXIMUMNUM_TEST_NAN(T, FUNC) \
FMAXIMUMNUM_TEST_SNAN(T, FUNC) \
FMAXIMUMNUM_TEST_INF(T, FUNC) \
FMAXIMUMNUM_TEST_NEG_INF(T, FUNC) \
FMAXIMUMNUM_TEST_BOTH_ZERO(T, FUNC)

LIST_FMAXIMUMNUM_TESTS(double, __builtin_fmaximum_num)
LIST_FMAXIMUMNUM_TESTS(float, __builtin_fmaximum_numf)
LIST_FMAXIMUMNUM_TESTS((long double), __builtin_fmaximum_numl)
LIST_FMAXIMUMNUM_TESTS(__fp16, __builtin_fmaximum_numf16)
#ifdef __FLOAT128__
LIST_FMAXIMUMNUM_TESTS(__float128, __builtin_fmaximum_numf128)
#endif
69 changes: 69 additions & 0 deletions clang/test/Sema/constant-builtins-fminimum-num.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
// FIXME: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

constexpr double NaN = __builtin_nan("");
constexpr double SNaN = __builtin_nans("");
constexpr double Inf = __builtin_inf();
constexpr double NegInf = -__builtin_inf();

#define FMINIMUMNUM_TEST_SIMPLE(T, FUNC) \
static_assert(T(1.2345) == FUNC(T(1.2345), T(6.7890))); \
static_assert(T(1.2345) == FUNC(T(6.7890), T(1.2345)));

#define FMINIMUMNUM_TEST_NAN(T, FUNC) \
static_assert(Inf == FUNC(NaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, NaN)); \
static_assert(0.0 == FUNC(NaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, NaN)); \
static_assert(T(-1.2345) == FUNC(NaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), NaN)); \
static_assert(__builtin_isnan(FUNC(NaN, NaN)));

#define FMINIMUMNUM_TEST_SNAN(T, FUNC) \
static_assert(Inf == FUNC(SNaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, SNaN)); \
static_assert(0.0 == FUNC(SNaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, SNaN)); \
static_assert(T(-1.2345) == FUNC(SNaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), SNaN)); \
static_assert(__builtin_isnan(FUNC(SNaN, SNaN))); \
static_assert(__builtin_isnan(FUNC(NaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(SNaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(NaN, SNaN)));

#define FMINIMUMNUM_TEST_INF(T, FUNC) \
static_assert(NegInf == FUNC(NegInf, Inf)); \
static_assert(0.0 == FUNC(Inf, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, Inf)); \
static_assert(T(1.2345) == FUNC(Inf, T(1.2345))); \
static_assert(T(-1.2345) == FUNC(T(-1.2345), Inf));

#define FMINIMUMNUM_TEST_NEG_INF(T, FUNC) \
static_assert(NegInf == FUNC(Inf, NegInf)); \
static_assert(NegInf == FUNC(NegInf, 0.0)); \
static_assert(NegInf == FUNC(-0.0, NegInf)); \
static_assert(NegInf == FUNC(NegInf, T(-1.2345))); \
static_assert(NegInf == FUNC(T(1.2345), NegInf));

#define FMINIMUMNUM_TEST_BOTH_ZERO(T, FUNC) \
static_assert(__builtin_copysign(1.0, FUNC(0.0, 0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, 0.0)) == -1.0); \
static_assert(__builtin_copysign(1.0, FUNC(0.0, -0.0)) == -1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, -0.0)) == -1.0);

#define LIST_FMINIMUMNUM_TESTS(T, FUNC) \
FMINIMUMNUM_TEST_SIMPLE(T, FUNC) \
FMINIMUMNUM_TEST_NAN(T, FUNC) \
FMINIMUMNUM_TEST_SNAN(T, FUNC) \
FMINIMUMNUM_TEST_INF(T, FUNC) \
FMINIMUMNUM_TEST_NEG_INF(T, FUNC) \
FMINIMUMNUM_TEST_BOTH_ZERO(T, FUNC)

LIST_FMINIMUMNUM_TESTS(double, __builtin_fminimum_num)
LIST_FMINIMUMNUM_TESTS(float, __builtin_fminimum_numf)
LIST_FMINIMUMNUM_TESTS((long double), __builtin_fminimum_numl)
LIST_FMINIMUMNUM_TESTS(__fp16, __builtin_fminimum_numf16)
#ifdef __FLOAT128__
LIST_FMINIMUMNUM_TESTS(__float128, __builtin_fminimum_numf128)
#endif
4 changes: 2 additions & 2 deletions compiler-rt/lib/builtins/cpu_model/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct {

struct {
unsigned mvendorid;
unsigned marchid;
unsigned mimpid;
unsigned long long marchid;
unsigned long long mimpid;
} __riscv_cpu_model __attribute__((visibility("hidden"), nocommon));

// NOTE: Should sync-up with RISCVFeatures.td
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/fuzzer/strncmp.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
UNSUPPORTED: target={{.*freebsd.*}}
RUN: %cpp_compiler %S/StrncmpTest.cpp -o %t-StrncmpTest
RUN: not %run %t-StrncmpTest -seed=2 -runs=10000000 2>&1 | FileCheck %s
RUN: not %run %t-StrncmpTest -seed=2 -runs=20000000 2>&1 | FileCheck %s
CHECK: BINGO
5 changes: 5 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ class CodeGenSpecifics {
structArgumentType(mlir::Location loc, fir::RecordType recTy,
const Marshalling &previousArguments) const = 0;

/// Type representation of a `fir.type<T>` type argument when returned by
/// value. Such value may need to be converted to a hidden reference argument.
virtual Marshalling structReturnType(mlir::Location loc,
fir::RecordType eleTy) const = 0;

/// Type representation of a `boxchar<n>` type argument when passed by value.
/// An argument value may need to be passed as a (safe) reference argument.
///
Expand Down
21 changes: 21 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,27 @@ inline mlir::NamedAttribute getAdaptToByRefAttr(Builder &builder) {
}

bool isDummyArgument(mlir::Value v);

template <fir::FortranProcedureFlagsEnum Flag>
inline bool hasProcedureAttr(fir::FortranProcedureFlagsEnumAttr flags) {
return flags && bitEnumContainsAny(flags.getValue(), Flag);
}

template <fir::FortranProcedureFlagsEnum Flag>
inline bool hasProcedureAttr(mlir::Operation *op) {
if (auto firCallOp = mlir::dyn_cast<fir::CallOp>(op))
return hasProcedureAttr<Flag>(firCallOp.getProcedureAttrsAttr());
if (auto firCallOp = mlir::dyn_cast<fir::DispatchOp>(op))
return hasProcedureAttr<Flag>(firCallOp.getProcedureAttrsAttr());
return hasProcedureAttr<Flag>(
op->getAttrOfType<fir::FortranProcedureFlagsEnumAttr>(
getFortranProcedureFlagsAttrName()));
}

inline bool hasBindcAttr(mlir::Operation *op) {
return hasProcedureAttr<fir::FortranProcedureFlagsEnum::bind_c>(op);
}

} // namespace fir

#endif // FORTRAN_OPTIMIZER_DIALECT_FIROPSSUPPORT_H
4 changes: 4 additions & 0 deletions flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
while (defOp && !breakFromLoop) {
ty = defOp->getResultTypes()[0];
llvm::TypeSwitch<Operation *>(defOp)
.Case<hlfir::AsExprOp>([&](auto op) {
v = op.getVar();
defOp = v.getDefiningOp();
})
.Case<fir::AllocaOp, fir::AllocMemOp>([&](auto op) {
// Unique memory allocation.
type = SourceKind::Allocate;
Expand Down
68 changes: 62 additions & 6 deletions flang/lib/Optimizer/CodeGen/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ struct GenericTarget : public CodeGenSpecifics {
TODO(loc, "passing VALUE BIND(C) derived type for this target");
}

CodeGenSpecifics::Marshalling
structReturnType(mlir::Location loc, fir::RecordType ty) const override {
TODO(loc, "returning BIND(C) derived type for this target");
}

CodeGenSpecifics::Marshalling
integerArgumentType(mlir::Location loc,
mlir::IntegerType argTy) const override {
Expand Down Expand Up @@ -533,14 +538,17 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
/// When \p recTy is a one field record type that can be passed
/// like the field on its own, returns the field type. Returns
/// a null type otherwise.
mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy) const {
mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy,
bool allowComplex = false) const {
auto typeList = recTy.getTypeList();
if (typeList.size() != 1)
return {};
mlir::Type fieldType = typeList[0].second;
if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::LogicalType>(
fieldType))
return fieldType;
if (allowComplex && mlir::isa<mlir::ComplexType>(fieldType))
return fieldType;
if (mlir::isa<fir::CharacterType>(fieldType)) {
// Only CHARACTER(1) are expected in BIND(C) contexts, which is the only
// contexts where derived type may be passed in registers.
Expand Down Expand Up @@ -593,7 +601,7 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
postMerge(byteOffset, Lo, Hi);
if (Lo == ArgClass::Memory || Lo == ArgClass::X87 ||
Lo == ArgClass::ComplexX87)
return passOnTheStack(loc, recTy);
return passOnTheStack(loc, recTy, /*isResult=*/false);
int neededIntRegisters = 0;
int neededSSERegisters = 0;
if (Lo == ArgClass::SSE)
Expand All @@ -609,7 +617,7 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
// all in registers or all on the stack).
if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters,
previousArguments))
return passOnTheStack(loc, recTy);
return passOnTheStack(loc, recTy, /*isResult=*/false);

if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) {
CodeGenSpecifics::Marshalling marshal;
Expand Down Expand Up @@ -641,17 +649,65 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
return marshal;
}

CodeGenSpecifics::Marshalling
structReturnType(mlir::Location loc, fir::RecordType recTy) const override {
std::uint64_t byteOffset = 0;
ArgClass Lo, Hi;
Lo = Hi = ArgClass::NoClass;
byteOffset = classifyStruct(loc, recTy, byteOffset, Lo, Hi);
mlir::MLIRContext *context = recTy.getContext();
postMerge(byteOffset, Lo, Hi);
if (Lo == ArgClass::Memory)
return passOnTheStack(loc, recTy, /*isResult=*/true);

// Note that X87/ComplexX87 are passed in memory, but returned via %st0
// %st1 registers. Here, they are returned as fp80 or {fp80, fp80} by
// passAsFieldIfOneFieldStruct, and LLVM will use the expected registers.

// Note that {_Complex long double} is not 100% clear from an ABI
// perspective because the aggregate post merger rules say it should be
// passed in memory because it is bigger than 2 eight bytes. This has the
// funny effect of
// {_Complex long double} return to be dealt with differently than
// _Complex long double.

if (auto fieldType =
passAsFieldIfOneFieldStruct(recTy, /*allowComplex=*/true)) {
if (auto complexType = mlir::dyn_cast<mlir::ComplexType>(fieldType))
return complexReturnType(loc, complexType.getElementType());
CodeGenSpecifics::Marshalling marshal;
marshal.emplace_back(fieldType, AT{});
return marshal;
}

if (Hi == ArgClass::NoClass || Hi == ArgClass::SSEUp) {
// Return a single integer or floating point argument.
mlir::Type lowType = pickLLVMArgType(loc, context, Lo, byteOffset);
CodeGenSpecifics::Marshalling marshal;
marshal.emplace_back(lowType, AT{});
return marshal;
}
// Will be returned in two different registers. Generate {lowTy, HiTy} for
// the LLVM IR result type.
CodeGenSpecifics::Marshalling marshal;
mlir::Type lowType = pickLLVMArgType(loc, context, Lo, 8u);
mlir::Type hiType = pickLLVMArgType(loc, context, Hi, byteOffset - 8u);
marshal.emplace_back(mlir::TupleType::get(context, {lowType, hiType}),
AT{});
return marshal;
}

/// Marshal an argument that must be passed on the stack.
CodeGenSpecifics::Marshalling passOnTheStack(mlir::Location loc,
mlir::Type ty) const {
CodeGenSpecifics::Marshalling
passOnTheStack(mlir::Location loc, mlir::Type ty, bool isResult) const {
CodeGenSpecifics::Marshalling marshal;
auto sizeAndAlign =
fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap);
// The stack is always 8 byte aligned (note 14 in 3.2.3).
unsigned short align =
std::max(sizeAndAlign.second, static_cast<unsigned short>(8));
marshal.emplace_back(fir::ReferenceType::get(ty),
AT{align, /*byval=*/true, /*sret=*/false});
AT{align, /*byval=*/!isResult, /*sret=*/isResult});
return marshal;
}
};
Expand Down
137 changes: 107 additions & 30 deletions flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,16 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {

mlir::ModuleOp getModule() { return getOperation(); }

template <typename A, typename B, typename C>
template <typename Ty, typename Callback>
std::optional<std::function<mlir::Value(mlir::Operation *)>>
rewriteCallComplexResultType(
mlir::Location loc, A ty, B &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, C &newOpers,
mlir::Value &savedStackPtr) {
if (noComplexConversion) {
newResTys.push_back(ty);
return std::nullopt;
}
auto m = specifics->complexReturnType(loc, ty.getElementType());
// Currently targets mandate COMPLEX is a single aggregate or packed
// scalar, including the sret case.
assert(m.size() == 1 && "target of complex return not supported");
rewriteCallResultType(mlir::Location loc, mlir::Type originalResTy,
Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs,
Callback &newOpers, mlir::Value &savedStackPtr,
fir::CodeGenSpecifics::Marshalling &m) {
// Currently, targets mandate COMPLEX or STRUCT is a single aggregate or
// packed scalar, including the sret case.
assert(m.size() == 1 && "return type not supported on this target");
auto resTy = std::get<mlir::Type>(m[0]);
auto attr = std::get<fir::CodeGenSpecifics::Attributes>(m[0]);
if (attr.isSRet()) {
Expand All @@ -170,7 +166,7 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
newInTyAndAttrs.push_back(m[0]);
newOpers.push_back(stack);
return [=](mlir::Operation *) -> mlir::Value {
auto memTy = fir::ReferenceType::get(ty);
auto memTy = fir::ReferenceType::get(originalResTy);
auto cast = rewriter->create<fir::ConvertOp>(loc, memTy, stack);
return rewriter->create<fir::LoadOp>(loc, cast);
};
Expand All @@ -180,11 +176,41 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
// We are going to generate an alloca, so save the stack pointer.
if (!savedStackPtr)
savedStackPtr = genStackSave(loc);
return this->convertValueInMemory(loc, call->getResult(0), ty,
return this->convertValueInMemory(loc, call->getResult(0), originalResTy,
/*inputMayBeBigger=*/true);
};
}

template <typename Ty, typename Callback>
std::optional<std::function<mlir::Value(mlir::Operation *)>>
rewriteCallComplexResultType(
mlir::Location loc, mlir::ComplexType ty, Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, Callback &newOpers,
mlir::Value &savedStackPtr) {
if (noComplexConversion) {
newResTys.push_back(ty);
return std::nullopt;
}
auto m = specifics->complexReturnType(loc, ty.getElementType());
return rewriteCallResultType(loc, ty, newResTys, newInTyAndAttrs, newOpers,
savedStackPtr, m);
}

template <typename Ty, typename Callback>
std::optional<std::function<mlir::Value(mlir::Operation *)>>
rewriteCallStructResultType(
mlir::Location loc, fir::RecordType recTy, Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, Callback &newOpers,
mlir::Value &savedStackPtr) {
if (noStructConversion) {
newResTys.push_back(recTy);
return std::nullopt;
}
auto m = specifics->structReturnType(loc, recTy);
return rewriteCallResultType(loc, recTy, newResTys, newInTyAndAttrs,
newOpers, savedStackPtr, m);
}

void passArgumentOnStackOrWithNewType(
mlir::Location loc, fir::CodeGenSpecifics::TypeAndAttr newTypeAndAttr,
mlir::Type oldType, mlir::Value oper,
Expand Down Expand Up @@ -356,6 +382,11 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
newInTyAndAttrs, newOpers,
savedStackPtr);
})
.template Case<fir::RecordType>([&](fir::RecordType recTy) {
wrap = rewriteCallStructResultType(loc, recTy, newResTys,
newInTyAndAttrs, newOpers,
savedStackPtr);
})
.Default([&](mlir::Type ty) { newResTys.push_back(ty); });
} else if (fnTy.getResults().size() > 1) {
TODO(loc, "multiple results not supported yet");
Expand Down Expand Up @@ -562,6 +593,24 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
}
}

template <typename Ty>
void
lowerStructSignatureRes(mlir::Location loc, fir::RecordType recTy,
Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs) {
if (noComplexConversion) {
newResTys.push_back(recTy);
return;
} else {
for (auto &tup : specifics->structReturnType(loc, recTy)) {
if (std::get<fir::CodeGenSpecifics::Attributes>(tup).isSRet())
newInTyAndAttrs.push_back(tup);
else
newResTys.push_back(std::get<mlir::Type>(tup));
}
}
}

void
lowerStructSignatureArg(mlir::Location loc, fir::RecordType recTy,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs) {
Expand Down Expand Up @@ -595,6 +644,9 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
.Case<mlir::ComplexType>([&](mlir::ComplexType ty) {
lowerComplexSignatureRes(loc, ty, newResTys, newInTyAndAttrs);
})
.Case<fir::RecordType>([&](fir::RecordType ty) {
lowerStructSignatureRes(loc, ty, newResTys, newInTyAndAttrs);
})
.Default([&](mlir::Type ty) { newResTys.push_back(ty); });
}
llvm::SmallVector<mlir::Type> trailingInTys;
Expand Down Expand Up @@ -696,7 +748,8 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
for (auto ty : func.getResults())
if ((mlir::isa<fir::BoxCharType>(ty) && !noCharacterConversion) ||
(fir::isa_complex(ty) && !noComplexConversion) ||
(mlir::isa<mlir::IntegerType>(ty) && hasCCallingConv)) {
(mlir::isa<mlir::IntegerType>(ty) && hasCCallingConv) ||
(mlir::isa<fir::RecordType>(ty) && !noStructConversion)) {
LLVM_DEBUG(llvm::dbgs() << "rewrite " << signature << " for target\n");
return false;
}
Expand Down Expand Up @@ -770,6 +823,9 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
rewriter->getUnitAttr()));
newResTys.push_back(retTy);
})
.Case<fir::RecordType>([&](fir::RecordType recTy) {
doStructReturn(func, recTy, newResTys, newInTyAndAttrs, fixups);
})
.Default([&](mlir::Type ty) { newResTys.push_back(ty); });

// Saved potential shift in argument. Handling of result can add arguments
Expand Down Expand Up @@ -1062,21 +1118,12 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
return false;
}

/// Convert a complex return value. This can involve converting the return
/// value to a "hidden" first argument or packing the complex into a wide
/// GPR.
template <typename Ty, typename FIXUPS>
void doComplexReturn(mlir::func::FuncOp func, mlir::ComplexType cmplx,
Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs,
FIXUPS &fixups) {
if (noComplexConversion) {
newResTys.push_back(cmplx);
return;
}
auto m =
specifics->complexReturnType(func.getLoc(), cmplx.getElementType());
assert(m.size() == 1);
void doReturn(mlir::func::FuncOp func, Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs,
FIXUPS &fixups, fir::CodeGenSpecifics::Marshalling &m) {
assert(m.size() == 1 &&
"expect result to be turned into single argument or result so far");
auto &tup = m[0];
auto attr = std::get<fir::CodeGenSpecifics::Attributes>(tup);
auto argTy = std::get<mlir::Type>(tup);
Expand Down Expand Up @@ -1117,6 +1164,36 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
newResTys.push_back(argTy);
}

/// Convert a complex return value. This can involve converting the return
/// value to a "hidden" first argument or packing the complex into a wide
/// GPR.
template <typename Ty, typename FIXUPS>
void doComplexReturn(mlir::func::FuncOp func, mlir::ComplexType cmplx,
Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs,
FIXUPS &fixups) {
if (noComplexConversion) {
newResTys.push_back(cmplx);
return;
}
auto m =
specifics->complexReturnType(func.getLoc(), cmplx.getElementType());
doReturn(func, newResTys, newInTyAndAttrs, fixups, m);
}

template <typename Ty, typename FIXUPS>
void doStructReturn(mlir::func::FuncOp func, fir::RecordType recTy,
Ty &newResTys,
fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs,
FIXUPS &fixups) {
if (noStructConversion) {
newResTys.push_back(recTy);
return;
}
auto m = specifics->structReturnType(func.getLoc(), recTy);
doReturn(func, newResTys, newInTyAndAttrs, fixups, m);
}

template <typename FIXUPS>
void
createFuncOpArgFixups(mlir::func::FuncOp func,
Expand Down
69 changes: 65 additions & 4 deletions flang/lib/Optimizer/Transforms/AbstractResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,36 @@ using namespace mlir;
namespace fir {
namespace {

// Helper to only build the symbol table if needed because its build time is
// linear on the number of symbols in the module.
struct LazySymbolTable {
LazySymbolTable(mlir::Operation *op)
: module{op->getParentOfType<mlir::ModuleOp>()} {}
void build() {
if (table)
return;
table = std::make_unique<mlir::SymbolTable>(module);
}

template <typename T>
T lookup(llvm::StringRef name) {
build();
return table->lookup<T>(name);
}

private:
std::unique_ptr<mlir::SymbolTable> table;
mlir::ModuleOp module;
};

bool hasScalarDerivedResult(mlir::FunctionType funTy) {
// C_PTR/C_FUNPTR are results to void* in this pass, do not consider
// them as normal derived types.
return funTy.getNumResults() == 1 &&
mlir::isa<fir::RecordType>(funTy.getResult(0)) &&
!fir::isa_builtin_cptr_type(funTy.getResult(0));
}

static mlir::Type getResultArgumentType(mlir::Type resultType,
bool shouldBoxResult) {
return llvm::TypeSwitch<mlir::Type, mlir::Type>(resultType)
Expand Down Expand Up @@ -190,7 +220,15 @@ class SaveResultOpConversion
llvm::LogicalResult
matchAndRewrite(fir::SaveResultOp op,
mlir::PatternRewriter &rewriter) const override {
rewriter.eraseOp(op);
mlir::Operation *call = op.getValue().getDefiningOp();
mlir::Type type = op.getValue().getType();
if (mlir::isa<fir::RecordType>(type) && call && fir::hasBindcAttr(call) &&
!fir::isa_builtin_cptr_type(type)) {
rewriter.replaceOpWithNewOp<fir::StoreOp>(op, op.getValue(),
op.getMemref());
} else {
rewriter.eraseOp(op);
}
return mlir::success();
}
};
Expand Down Expand Up @@ -300,6 +338,12 @@ class AbstractResultOpt
auto *context = &getContext();
// Convert function type itself if it has an abstract result.
auto funcTy = mlir::cast<mlir::FunctionType>(func.getFunctionType());
// Scalar derived result of BIND(C) function must be returned according
// to the C struct return ABI which is target dependent and implemented in
// the target-rewrite pass.
if (hasScalarDerivedResult(funcTy) &&
fir::hasBindcAttr(func.getOperation()))
return;
if (hasAbstractResult(funcTy)) {
if (fir::isa_builtin_cptr_type(funcTy.getResult(0))) {
func.setType(getCPtrFunctionType(funcTy));
Expand Down Expand Up @@ -395,6 +439,8 @@ class AbstractResultOpt
return;
}

LazySymbolTable symbolTable(op);

mlir::RewritePatternSet patterns(context);
mlir::ConversionTarget target = *context;
const bool shouldBoxResult = this->passResultAsBox.getValue();
Expand All @@ -409,14 +455,29 @@ class AbstractResultOpt
mlir::func::FuncDialect>();
target.addIllegalOp<fir::SaveResultOp>();
target.addDynamicallyLegalOp<fir::CallOp>([](fir::CallOp call) {
return !hasAbstractResult(call.getFunctionType());
mlir::FunctionType funTy = call.getFunctionType();
if (hasScalarDerivedResult(funTy) &&
fir::hasBindcAttr(call.getOperation()))
return true;
return !hasAbstractResult(funTy);
});
target.addDynamicallyLegalOp<fir::AddrOfOp>([](fir::AddrOfOp addrOf) {
if (auto funTy = mlir::dyn_cast<mlir::FunctionType>(addrOf.getType()))
target.addDynamicallyLegalOp<fir::AddrOfOp>([&symbolTable](
fir::AddrOfOp addrOf) {
if (auto funTy = mlir::dyn_cast<mlir::FunctionType>(addrOf.getType())) {
if (hasScalarDerivedResult(funTy)) {
auto func = symbolTable.lookup<mlir::func::FuncOp>(
addrOf.getSymbol().getRootReference().getValue());
return func && fir::hasBindcAttr(func.getOperation());
}
return !hasAbstractResult(funTy);
}
return true;
});
target.addDynamicallyLegalOp<fir::DispatchOp>([](fir::DispatchOp dispatch) {
mlir::FunctionType funTy = dispatch.getFunctionType();
if (hasScalarDerivedResult(funTy) &&
fir::hasBindcAttr(dispatch.getOperation()))
return true;
return !hasAbstractResult(dispatch.getFunctionType());
});

Expand Down
48 changes: 48 additions & 0 deletions flang/test/Analysis/AliasAnalysis/alias-analysis-9.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Use --mlir-disable-threading so that the AA queries are serialized
// as well as its diagnostic output.
// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s

// Fortran source code:
// program TestTmpArrayAssignment
// integer :: a, b, c
// integer :: arrayD(3)
//
// arrayD = [ a, b, c ]
// end program TestTmpArrayAssignment

// CHECK-LABEL: Testing : "_QPTestTmpArrayAssignment"
// CHECK-DAG: ArrayD#0 <-> tmp_array#0: NoAlias
func.func @_QPTestTmpArrayAssignment() attributes {fir.bindc_name = "testtmparrayassignment"} {
%0 = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFEa"}
%1:2 = hlfir.declare %0 {uniq_name = "_QFEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
%c3 = arith.constant 3 : index
%2 = fir.alloca !fir.array<3xi32> {bindc_name = "arrayd", uniq_name = "_QFEarrayd", test.ptr = "ArrayD" }
%3 = fir.shape %c3 : (index) -> !fir.shape<1>
%4:2 = hlfir.declare %2(%3) {uniq_name = "_QFEarrayd"} : (!fir.ref<!fir.array<3xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xi32>>, !fir.ref<!fir.array<3xi32>>)
%5 = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFEb"}
%6:2 = hlfir.declare %5 {uniq_name = "_QFEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
%7 = fir.alloca i32 {bindc_name = "c", uniq_name = "_QFEc"}
%8:2 = hlfir.declare %7 {uniq_name = "_QFEc"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
%c3_0 = arith.constant 3 : index
%c1 = arith.constant 1 : index
%c1_1 = arith.constant 1 : index
%9 = fir.allocmem !fir.array<3xi32> {bindc_name = ".tmp.arrayctor", uniq_name = ""}
%10 = fir.shape %c3_0 : (index) -> !fir.shape<1>
%11:2 = hlfir.declare %9(%10) {uniq_name = ".tmp.arrayctor"} : (!fir.heap<!fir.array<3xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<3xi32>>, !fir.heap<!fir.array<3xi32>>)
%12 = fir.load %1#0 : !fir.ref<i32>
%13 = arith.addi %c1, %c1_1 : index
%14 = hlfir.designate %11#0 (%c1) : (!fir.heap<!fir.array<3xi32>>, index) -> !fir.ref<i32>
hlfir.assign %12 to %14 : i32, !fir.ref<i32>
%15 = fir.load %6#0 : !fir.ref<i32>
%16 = arith.addi %13, %c1_1 : index
%17 = hlfir.designate %11#0 (%13) : (!fir.heap<!fir.array<3xi32>>, index) -> !fir.ref<i32>
hlfir.assign %15 to %17 : i32, !fir.ref<i32>
%18 = fir.load %8#0 : !fir.ref<i32>
%19 = hlfir.designate %11#0 (%16) : (!fir.heap<!fir.array<3xi32>>, index) -> !fir.ref<i32>
hlfir.assign %18 to %19 : i32, !fir.ref<i32>
%true = arith.constant true
%20 = hlfir.as_expr %11#0 move %true {test.ptr = "tmp_array"}: (!fir.heap<!fir.array<3xi32>>, i1) -> !hlfir.expr<3xi32>
hlfir.assign %20 to %4#0 : !hlfir.expr<3xi32>, !fir.ref<!fir.array<3xi32>>
hlfir.destroy %20 : !hlfir.expr<3xi32>
return
}
60 changes: 60 additions & 0 deletions flang/test/Fir/abstract-results-bindc.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Test that bind_c derived type results are not moved to a hidden argument
// by the abstract-result pass. They will be dealt with according to the C
// struct returning ABI for the target in the target-rewrite pass.
// RUN: fir-opt %s --abstract-result | FileCheck %s

!t = !fir.type<t{i:f32, j: i32, k: f32}>
!cptr = !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>

func.func private @foo() -> !t attributes {fir.proc_attrs = #fir.proc_attrs<bind_c>}

func.func @test_call(%x: !fir.ref<!t>) {
%0 = fir.call @foo() proc_attrs<bind_c> : () -> !t
fir.save_result %0 to %x : !t, !fir.ref<!t>
return
}

func.func @test_addr_of() -> (() -> !t) {
%0 = fir.address_of(@foo) : () -> !t
return %0 : () -> !t
}

func.func @test_dispatch(%x: !fir.ref<!t>, %y : !fir.class<!fir.type<somet>>) {
%0 = fir.dispatch "bar"(%y : !fir.class<!fir.type<somet>>) (%y : !fir.class<!fir.type<somet>>) -> !t proc_attrs<bind_c> {pass_arg_pos = 0 : i32}
fir.save_result %0 to %x : !t, !fir.ref<!t>
return
}


func.func private @return_cptr() -> !cptr attributes {fir.proc_attrs = #fir.proc_attrs<bind_c>}
func.func @test_return_cptr(%x: !fir.ref<!cptr>) {
%0 = fir.call @return_cptr() proc_attrs<bind_c> : () -> !cptr
fir.save_result %0 to %x : !cptr, !fir.ref<!cptr>
return
}


// CHECK-LABEL: func.func @test_call(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>>) {
// CHECK: %[[VAL_1:.*]] = fir.call @foo() proc_attrs<bind_c> : () -> !fir.type<t{i:f32,j:i32,k:f32}>
// CHECK: fir.store %[[VAL_1]] to %[[VAL_0]] : !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>>
// CHECK: return
// CHECK: }
// CHECK-LABEL: func.func @test_addr_of() -> (() -> !fir.type<t{i:f32,j:i32,k:f32}>) {
// CHECK: %[[VAL_0:.*]] = fir.address_of(@foo) : () -> !fir.type<t{i:f32,j:i32,k:f32}>
// CHECK: return %[[VAL_0]] : () -> !fir.type<t{i:f32,j:i32,k:f32}>
// CHECK: }
// CHECK-LABEL: func.func @test_dispatch(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>>,
// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.type<somet>>) {
// CHECK: %[[VAL_2:.*]] = fir.dispatch "bar"(%[[VAL_1]] : !fir.class<!fir.type<somet>>) (%[[VAL_1]] : !fir.class<!fir.type<somet>>) -> !fir.type<t{i:f32,j:i32,k:f32}> proc_attrs <bind_c> {pass_arg_pos = 0 : i32}
// CHECK: fir.store %[[VAL_2]] to %[[VAL_0]] : !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>>
// CHECK: return
// CHECK: }
// CHECK-LABEL: func.func @test_return_cptr(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) {
// CHECK: %[[VAL_1:.*]] = fir.call @return_cptr() : () -> !fir.ref<none>
// CHECK: %[[VAL_2:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>
// CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.field) -> !fir.ref<i64>
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<none>) -> i64
// CHECK: fir.store %[[VAL_4]] to %[[VAL_3]] : !fir.ref<i64>
120 changes: 120 additions & 0 deletions flang/test/Fir/struct-return-x86-64.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Test X86-64 ABI rewrite of struct returned by value (BIND(C), VALUE derived types).
// REQUIRES: x86-registered-target
// RUN: fir-opt --target-rewrite %s | FileCheck %s

!fits_in_reg = !fir.type<t1{i:f32,j:i32,k:f32}>
!too_big = !fir.type<t2{i:!fir.array<5xf32>}>

module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {

func.func private @test_inreg() -> !fits_in_reg
func.func @test_call_inreg(%arg0: !fir.ref<!fits_in_reg>) {
%0 = fir.call @test_inreg() : () -> !fits_in_reg
fir.store %0 to %arg0 : !fir.ref<!fits_in_reg>
return
}
func.func @test_addr_of_inreg() -> (() -> ()) {
%0 = fir.address_of(@test_inreg) : () -> !fits_in_reg
%1 = fir.convert %0 : (() -> !fits_in_reg) -> (() -> ())
return %1 : () -> ()
}
func.func @test_dispatch_inreg(%arg0: !fir.ref<!fits_in_reg>, %arg1: !fir.class<!fir.type<somet>>) {
%0 = fir.dispatch "bar"(%arg1 : !fir.class<!fir.type<somet>>) (%arg1 : !fir.class<!fir.type<somet>>) -> !fits_in_reg {pass_arg_pos = 0 : i32}
fir.store %0 to %arg0 : !fir.ref<!fits_in_reg>
return
}

func.func private @test_sret() -> !too_big
func.func @test_call_sret(%arg0: !fir.ref<!too_big>) {
%0 = fir.call @test_sret() : () -> !too_big
fir.store %0 to %arg0 : !fir.ref<!too_big>
return
}
func.func @test_addr_of_sret() -> (() -> ()) {
%0 = fir.address_of(@test_sret) : () -> !too_big
%1 = fir.convert %0 : (() -> !too_big) -> (() -> ())
return %1 : () -> ()
}
func.func @test_dispatch_sret(%arg0: !fir.ref<!too_big>, %arg1: !fir.class<!fir.type<somet>>) {
%0 = fir.dispatch "bar"(%arg1 : !fir.class<!fir.type<somet>>) (%arg1 : !fir.class<!fir.type<somet>>) -> !too_big {pass_arg_pos = 0 : i32}
fir.store %0 to %arg0 : !fir.ref<!too_big>
return
}
func.func private @test_fp_80() -> !fir.type<t3{i:f80}>
func.func private @test_complex_80() -> !fir.type<t4{i:complex<f80>}>
func.func private @test_two_fp_80() -> !fir.type<t5{i:f80,j:f80}>
func.func private @test_fp128() -> !fir.type<t6{i:f128}>
}

// CHECK-LABEL: func.func private @test_inreg() -> tuple<i64, f32>

// CHECK-LABEL: func.func @test_call_inreg(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>) {
// CHECK: %[[VAL_1:.*]] = fir.call @test_inreg() : () -> tuple<i64, f32>
// CHECK: %[[VAL_2:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK: %[[VAL_3:.*]] = fir.alloca tuple<i64, f32>
// CHECK: fir.store %[[VAL_1]] to %[[VAL_3]] : !fir.ref<tuple<i64, f32>>
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<tuple<i64, f32>>) -> !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
// CHECK: llvm.intr.stackrestore %[[VAL_2]] : !llvm.ptr
// CHECK: fir.store %[[VAL_5]] to %[[VAL_0]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
// CHECK: return
// CHECK: }

// CHECK-LABEL: func.func @test_addr_of_inreg() -> (() -> ()) {
// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_inreg) : () -> tuple<i64, f32>
// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (() -> tuple<i64, f32>) -> (() -> ())
// CHECK: return %[[VAL_1]] : () -> ()
// CHECK: }

// CHECK-LABEL: func.func @test_dispatch_inreg(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>,
// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.type<somet>>) {
// CHECK: %[[VAL_2:.*]] = fir.dispatch "bar"(%[[VAL_1]] : !fir.class<!fir.type<somet>>) (%[[VAL_1]] : !fir.class<!fir.type<somet>>) -> tuple<i64, f32> {pass_arg_pos = 0 : i32}
// CHECK: %[[VAL_3:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK: %[[VAL_4:.*]] = fir.alloca tuple<i64, f32>
// CHECK: fir.store %[[VAL_2]] to %[[VAL_4]] : !fir.ref<tuple<i64, f32>>
// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<tuple<i64, f32>>) -> !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
// CHECK: llvm.intr.stackrestore %[[VAL_3]] : !llvm.ptr
// CHECK: fir.store %[[VAL_6]] to %[[VAL_0]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
// CHECK: return
// CHECK: }
// CHECK: func.func private @test_sret(!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> {llvm.align = 8 : i32, llvm.sret = !fir.type<t2{i:!fir.array<5xf32>}>})

// CHECK-LABEL: func.func @test_call_sret(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) {
// CHECK: %[[VAL_1:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.type<t2{i:!fir.array<5xf32>}>
// CHECK: fir.call @test_sret(%[[VAL_2]]) : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()
// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>
// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>
// CHECK: llvm.intr.stackrestore %[[VAL_1]] : !llvm.ptr
// CHECK: fir.store %[[VAL_4]] to %[[VAL_0]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>
// CHECK: return
// CHECK: }

// CHECK-LABEL: func.func @test_addr_of_sret() -> (() -> ()) {
// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_sret) : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()
// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : ((!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()) -> (() -> ())
// CHECK: return %[[VAL_1]] : () -> ()
// CHECK: }

// CHECK-LABEL: func.func @test_dispatch_sret(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>,
// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.type<somet>>) {
// CHECK: %[[VAL_2:.*]] = llvm.intr.stacksave : !llvm.ptr
// CHECK: %[[VAL_3:.*]] = fir.alloca !fir.type<t2{i:!fir.array<5xf32>}>
// CHECK: fir.dispatch "bar"(%[[VAL_1]] : !fir.class<!fir.type<somet>>) (%[[VAL_3]], %[[VAL_1]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>, !fir.class<!fir.type<somet>>) {pass_arg_pos = 1 : i32}
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>
// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>
// CHECK: llvm.intr.stackrestore %[[VAL_2]] : !llvm.ptr
// CHECK: fir.store %[[VAL_5]] to %[[VAL_0]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>
// CHECK: return
// CHECK: }


// CHECK: func.func private @test_fp_80() -> f80
// CHECK: func.func private @test_complex_80(!fir.ref<!fir.type<t4{i:complex<f80>}>> {llvm.align = 16 : i32, llvm.sret = !fir.type<t4{i:complex<f80>}>})
// CHECK: func.func private @test_two_fp_80(!fir.ref<!fir.type<t5{i:f80,j:f80}>> {llvm.align = 16 : i32, llvm.sret = !fir.type<t5{i:f80,j:f80}>})
// CHECK: func.func private @test_fp128() -> f128
24 changes: 14 additions & 10 deletions lldb/CodeOwners.rst → lldb/Maintainers.rst
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
================
LLDB Code Owners
LLDB Maintainers
================

This file is a list of the `code owners <https://llvm.org/docs/DeveloperPolicy.html#code-owners>`_ for LLDB.
This file is a list of the `maintainers <https://llvm.org/docs/DeveloperPolicy.html#maintainers>`_ for LLDB.

.. contents::
:depth: 2
:local:

Current Code Owners
Current Maintainers
===================
The following people are the active code owners for the project. Please reach
The following people are the active maintainers for the project. Please reach
out to them for code reviews, questions about their area of expertise, or other
assistance.

All parts of LLDB not covered by someone else
----------------------------------------------
Lead Maintainer
---------------

Responsible for project as a whole, and for any areas not covered by a specific
maintainer.

| Jonas Devlieghere
| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
Components
----------
These code owners are responsible for particular high-level components within
These maintainers are responsible for particular high-level components within
LLDB.

ABI
Expand Down Expand Up @@ -242,10 +246,10 @@ lldb-dap
| Walter Erquinigo
| a20012251\@gmail.com (email), walter-erquinigo (GitHub), wallace (Discourse), werquinigo (Discord)
Former Code Owners
Former Maintainers
==================
The following people have graciously spent time performing code ownership
responsibilities but are no longer active in that role. Thank you for all your
The following people have graciously spent time performing maintainership
duties but are no longer active in that role. Thank you for all your
help with the success of the project!

| Kamil Rytarowski (kamil\@netbsd.org)
Expand Down
6 changes: 3 additions & 3 deletions llvm/Maintainers.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,10 +354,10 @@ martin@martin.st (email), [mstrorsjo](https://github.com/mstrorsjo) (GitHub)
Michael Spencer \
bigcheesegs@gmail.com (email), [Bigcheese](https://github.com/Bigcheese) (GitHub)

#### Sony PlayStation®4 support
#### Sony PlayStation support

Paul Robinson \
paul.robinson@sony.com (email), [pogo59](https://github.com/pogo59) (GitHub)
Jeremy Morse \
jeremy.morse@sony.com (email), [jmorse](https://github.com/jmorse) (GitHub)

#### Inline assembly

Expand Down
6 changes: 3 additions & 3 deletions llvm/cmake/modules/AddLLVM.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2618,7 +2618,7 @@ function(get_host_tool_path tool_name setting_name exe_var_name target_var_name)
set(target_name "")
elseif(LLVM_USE_HOST_TOOLS)
get_native_tool_path(${tool_name} exe_name)
set(target_name ${exe_name})
set(target_name host_${tool_name})
else()
set(exe_name $<TARGET_FILE:${tool_name}>)
set(target_name ${tool_name})
Expand All @@ -2632,8 +2632,8 @@ function(setup_host_tool tool_name setting_name exe_var_name target_var_name)
# Set up a native tool build if necessary
if(LLVM_USE_HOST_TOOLS AND NOT ${setting_name})
build_native_tool(${tool_name} exe_name DEPENDS ${tool_name})
add_custom_target(${target_var_name} DEPENDS ${exe_name})
add_custom_target(${${target_var_name}} DEPENDS ${exe_name})
get_subproject_title(subproject_title)
set_target_properties(${target_var_name} PROPERTIES FOLDER "${subproject_title}/Native")
set_target_properties(${${target_var_name}} PROPERTIES FOLDER "${subproject_title}/Native")
endif()
endfunction()
31 changes: 30 additions & 1 deletion llvm/docs/HowToAddABuilder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,33 @@ Leave it on the staging buildmaster
impacting the broader community. The sponsoring organization simply
has to take on the responsibility of all bisection and triage.


Managing a Worker From The Web Interface
========================================

Tasks such as clearing pending building requests can be done using
the Buildbot web interface. To do this you must be recognised as an admin
of the worker:

* Set your public GitHub profile email to one that was included in the
``admin`` information you set up on the worker. It does not matter if this
is your primary account email or a "verified email". To confirm this has been
done correctly, go to ``github.com/<your GitHub username>`` and you should
see the email address listed there.

A worker can have many admins, if they are listed in the form
``First Last <first.last@example.com>, First2 Last2 <first2.last2@example.com>``.
You only need to have one of those addresses in your profile to be recognised
as an admin.

If you need to add an email address, you can edit the ``admin`` file and
restart the worker. You should see the new admin details in the web interface
shortly afterwards.

* Connect GitHub to Buildbot by clicking on the "Anonymous" button on the
top right of the page, then "Login with GitHub" and authorise the app.

Some tasks don't give immediate feedback, so if nothing happens within a short
time, try again with the browser's web console open. Sometimes you will see
403 errors and other messages that might indicate you don't have the correct
details set up.

6 changes: 4 additions & 2 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1309,12 +1309,14 @@ Currently, only the following parameter attributes are defined:
structure that is the return value of the function in the source
program. This pointer must be guaranteed by the caller to be valid:
loads and stores to the structure may be assumed by the callee not
to trap and to be properly aligned. This is not a valid attribute
for return values.
to trap and to be properly aligned.

The sret type argument specifies the in memory type, which must be
the same as the pointee type of the argument.

A function that accepts an ``sret`` argument must return ``void``.
A return value may not be ``sret``.

.. _attr_elementtype:

``elementtype(<ty>)``
Expand Down
5 changes: 5 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ Changes to the ARM Backend
the required alignment space with a sequence of `0x0` bytes (the requested
fill value) rather than NOPs.

* When using the `MOVT` or `MOVW` instructions, the Assembler will now check to
ensure that any addend that is used is within a 16-bit signed value range. If the
addend falls outside of this range, the LLVM backend will emit an error like so
`Relocation Not In Range`.

Changes to the AVR Backend
--------------------------

Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/CodeGen/LiveIntervalUnion.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ class LiveIntervalUnion {
Array() = default;
~Array() { clear(); }

Array(Array &&Other) : Size(Other.Size), LIUs(Other.LIUs) {
Other.Size = 0;
Other.LIUs = nullptr;
}

Array(const Array &) = delete;

// Initialize the array to have Size entries.
// Reuse an existing allocation if the size matches.
void init(LiveIntervalUnion::Allocator&, unsigned Size);
Expand Down
44 changes: 37 additions & 7 deletions llvm/include/llvm/CodeGen/LiveRegMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ class MachineFunction;
class TargetRegisterInfo;
class VirtRegMap;

class LiveRegMatrix : public MachineFunctionPass {
class LiveRegMatrix {
friend class LiveRegMatrixWrapperLegacy;
friend class LiveRegMatrixAnalysis;
const TargetRegisterInfo *TRI = nullptr;
LiveIntervals *LIS = nullptr;
VirtRegMap *VRM = nullptr;
Expand All @@ -57,15 +59,17 @@ class LiveRegMatrix : public MachineFunctionPass {
unsigned RegMaskVirtReg = 0;
BitVector RegMaskUsable;

// MachineFunctionPass boilerplate.
void getAnalysisUsage(AnalysisUsage &) const override;
bool runOnMachineFunction(MachineFunction &) override;
void releaseMemory() override;
LiveRegMatrix() = default;
void releaseMemory();

public:
static char ID;
LiveRegMatrix(LiveRegMatrix &&Other)
: TRI(Other.TRI), LIS(Other.LIS), VRM(Other.VRM), UserTag(Other.UserTag),
Matrix(std::move(Other.Matrix)), Queries(std::move(Other.Queries)),
RegMaskTag(Other.RegMaskTag), RegMaskVirtReg(Other.RegMaskVirtReg),
RegMaskUsable(std::move(Other.RegMaskUsable)) {}

LiveRegMatrix();
void init(MachineFunction &MF, LiveIntervals &LIS, VirtRegMap &VRM);

//===--------------------------------------------------------------------===//
// High-level interface.
Expand Down Expand Up @@ -159,6 +163,32 @@ class LiveRegMatrix : public MachineFunctionPass {
Register getOneVReg(unsigned PhysReg) const;
};

class LiveRegMatrixWrapperLegacy : public MachineFunctionPass {
LiveRegMatrix LRM;

public:
static char ID;

LiveRegMatrixWrapperLegacy() : MachineFunctionPass(ID) {}

LiveRegMatrix &getLRM() { return LRM; }
const LiveRegMatrix &getLRM() const { return LRM; }

void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnMachineFunction(MachineFunction &MF) override;
void releaseMemory() override;
};

class LiveRegMatrixAnalysis : public AnalysisInfoMixin<LiveRegMatrixAnalysis> {
friend AnalysisInfoMixin<LiveRegMatrixAnalysis>;
static AnalysisKey Key;

public:
using Result = LiveRegMatrix;

LiveRegMatrix run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM);
};

} // end namespace llvm

#endif // LLVM_CODEGEN_LIVEREGMATRIX_H
7 changes: 4 additions & 3 deletions llvm/include/llvm/CodeGen/MIRParser/MIParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,15 @@ class TargetRegisterClass;
class TargetSubtargetInfo;

struct VRegInfo {
enum uint8_t {
UNKNOWN, NORMAL, GENERIC, REGBANK
} Kind = UNKNOWN;
enum : uint8_t { UNKNOWN, NORMAL, GENERIC, REGBANK } Kind = UNKNOWN;
bool Explicit = false; ///< VReg was explicitly specified in the .mir file.
union {
const TargetRegisterClass *RC;
const RegisterBank *RegBank;
} D;
Register VReg;
Register PreferredReg;
std::vector<uint8_t> Flags;
};

using Name2RegClassMap = StringMap<const TargetRegisterClass *>;
Expand Down Expand Up @@ -150,6 +149,8 @@ struct PerTargetMIParsingState {
/// Return null if the name isn't a register bank.
const RegisterBank *getRegBank(StringRef Name);

bool getVRegFlagValue(StringRef FlagName, uint8_t &FlagValue) const;

PerTargetMIParsingState(const TargetSubtargetInfo &STI)
: Subtarget(STI) {
initNames2RegClasses();
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/MIRYamlMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ struct VirtualRegisterDefinition {
UnsignedValue ID;
StringValue Class;
StringValue PreferredRegister;
std::vector<FlowStringValue> RegisterFlags;

// TODO: Serialize the target specific register hints.

Expand All @@ -206,6 +207,8 @@ template <> struct MappingTraits<VirtualRegisterDefinition> {
YamlIO.mapRequired("class", Reg.Class);
YamlIO.mapOptional("preferred-register", Reg.PreferredRegister,
StringValue()); // Don't print out when it's empty.
YamlIO.mapOptional("flags", Reg.RegisterFlags,
std::vector<FlowStringValue>());
}

static const bool flow = true;
Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/CodeGen/TargetRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,15 @@ class TargetRegisterInfo : public MCRegisterInfo {
virtual bool isNonallocatableRegisterCalleeSave(MCRegister Reg) const {
return false;
}

virtual std::optional<uint8_t> getVRegFlagValue(StringRef Name) const {
return {};
}

virtual SmallVector<StringLiteral>
getVRegFlagsOfReg(Register Reg, const MachineFunction &MF) const {
return {};
}
};

//===----------------------------------------------------------------------===//
Expand Down
302 changes: 171 additions & 131 deletions llvm/include/llvm/CodeGen/VirtRegMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TileShapeInfo.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include <cassert>

Expand All @@ -30,171 +31,210 @@ class MachineRegisterInfo;
class raw_ostream;
class TargetInstrInfo;

class VirtRegMap : public MachineFunctionPass {
MachineRegisterInfo *MRI = nullptr;
const TargetInstrInfo *TII = nullptr;
const TargetRegisterInfo *TRI = nullptr;
MachineFunction *MF = nullptr;

/// Virt2PhysMap - This is a virtual to physical register
/// mapping. Each virtual register is required to have an entry in
/// it; even spilled virtual registers (the register mapped to a
/// spilled register is the temporary used to load it from the
/// stack).
IndexedMap<MCRegister, VirtReg2IndexFunctor> Virt2PhysMap;
class VirtRegMap {
MachineRegisterInfo *MRI = nullptr;
const TargetInstrInfo *TII = nullptr;
const TargetRegisterInfo *TRI = nullptr;
MachineFunction *MF = nullptr;

/// Virt2PhysMap - This is a virtual to physical register
/// mapping. Each virtual register is required to have an entry in
/// it; even spilled virtual registers (the register mapped to a
/// spilled register is the temporary used to load it from the
/// stack).
IndexedMap<MCRegister, VirtReg2IndexFunctor> Virt2PhysMap;

/// Virt2StackSlotMap - This is virtual register to stack slot
/// mapping. Each spilled virtual register has an entry in it
/// which corresponds to the stack slot this register is spilled
/// at.
IndexedMap<int, VirtReg2IndexFunctor> Virt2StackSlotMap;

/// Virt2SplitMap - This is virtual register to splitted virtual register
/// mapping.
IndexedMap<Register, VirtReg2IndexFunctor> Virt2SplitMap;

/// Virt2ShapeMap - For X86 AMX register whose register is bound shape
/// information.
DenseMap<Register, ShapeT> Virt2ShapeMap;

/// createSpillSlot - Allocate a spill slot for RC from MFI.
unsigned createSpillSlot(const TargetRegisterClass *RC);

public:
static constexpr int NO_STACK_SLOT = INT_MAX;

VirtRegMap() : Virt2StackSlotMap(NO_STACK_SLOT) {}
VirtRegMap(const VirtRegMap &) = delete;
VirtRegMap &operator=(const VirtRegMap &) = delete;
VirtRegMap(VirtRegMap &&) = default;

void init(MachineFunction &MF);

MachineFunction &getMachineFunction() const {
assert(MF && "getMachineFunction called before runOnMachineFunction");
return *MF;
}

/// Virt2StackSlotMap - This is virtual register to stack slot
/// mapping. Each spilled virtual register has an entry in it
/// which corresponds to the stack slot this register is spilled
/// at.
IndexedMap<int, VirtReg2IndexFunctor> Virt2StackSlotMap;
MachineRegisterInfo &getRegInfo() const { return *MRI; }
const TargetRegisterInfo &getTargetRegInfo() const { return *TRI; }

/// Virt2SplitMap - This is virtual register to splitted virtual register
/// mapping.
IndexedMap<Register, VirtReg2IndexFunctor> Virt2SplitMap;
void grow();

/// Virt2ShapeMap - For X86 AMX register whose register is bound shape
/// information.
DenseMap<Register, ShapeT> Virt2ShapeMap;
/// returns true if the specified virtual register is
/// mapped to a physical register
bool hasPhys(Register virtReg) const { return getPhys(virtReg).isValid(); }

/// createSpillSlot - Allocate a spill slot for RC from MFI.
unsigned createSpillSlot(const TargetRegisterClass *RC);
/// returns the physical register mapped to the specified
/// virtual register
MCRegister getPhys(Register virtReg) const {
assert(virtReg.isVirtual());
return Virt2PhysMap[virtReg];
}

public:
static char ID;
/// creates a mapping for the specified virtual register to
/// the specified physical register
void assignVirt2Phys(Register virtReg, MCPhysReg physReg);

static constexpr int NO_STACK_SLOT = INT_MAX;
bool isShapeMapEmpty() const { return Virt2ShapeMap.empty(); }

VirtRegMap() : MachineFunctionPass(ID), Virt2StackSlotMap(NO_STACK_SLOT) {}
VirtRegMap(const VirtRegMap &) = delete;
VirtRegMap &operator=(const VirtRegMap &) = delete;
bool hasShape(Register virtReg) const {
return Virt2ShapeMap.contains(virtReg);
}

bool runOnMachineFunction(MachineFunction &MF) override;
ShapeT getShape(Register virtReg) const {
assert(virtReg.isVirtual());
return Virt2ShapeMap.lookup(virtReg);
}

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
}
void assignVirt2Shape(Register virtReg, ShapeT shape) {
Virt2ShapeMap[virtReg] = shape;
}

MachineFunction &getMachineFunction() const {
assert(MF && "getMachineFunction called before runOnMachineFunction");
return *MF;
}
/// clears the specified virtual register's, physical
/// register mapping
void clearVirt(Register virtReg) {
assert(virtReg.isVirtual());
assert(Virt2PhysMap[virtReg] &&
"attempt to clear a not assigned virtual register");
Virt2PhysMap[virtReg] = MCRegister();
}

MachineRegisterInfo &getRegInfo() const { return *MRI; }
const TargetRegisterInfo &getTargetRegInfo() const { return *TRI; }
/// clears all virtual to physical register mappings
void clearAllVirt() {
Virt2PhysMap.clear();
grow();
}

void grow();
/// returns true if VirtReg is assigned to its preferred physreg.
bool hasPreferredPhys(Register VirtReg) const;

/// returns true if the specified virtual register is
/// mapped to a physical register
bool hasPhys(Register virtReg) const { return getPhys(virtReg).isValid(); }
/// returns true if VirtReg has a known preferred register.
/// This returns false if VirtReg has a preference that is a virtual
/// register that hasn't been assigned yet.
bool hasKnownPreference(Register VirtReg) const;

/// returns the physical register mapped to the specified
/// virtual register
MCRegister getPhys(Register virtReg) const {
assert(virtReg.isVirtual());
return Virt2PhysMap[virtReg];
/// records virtReg is a split live interval from SReg.
void setIsSplitFromReg(Register virtReg, Register SReg) {
Virt2SplitMap[virtReg] = SReg;
if (hasShape(SReg)) {
Virt2ShapeMap[virtReg] = getShape(SReg);
}
}

/// creates a mapping for the specified virtual register to
/// the specified physical register
void assignVirt2Phys(Register virtReg, MCPhysReg physReg);
/// returns the live interval virtReg is split from.
Register getPreSplitReg(Register virtReg) const {
return Virt2SplitMap[virtReg];
}

bool isShapeMapEmpty() const { return Virt2ShapeMap.empty(); }
/// getOriginal - Return the original virtual register that VirtReg descends
/// from through splitting.
/// A register that was not created by splitting is its own original.
/// This operation is idempotent.
Register getOriginal(Register VirtReg) const {
Register Orig = getPreSplitReg(VirtReg);
return Orig ? Orig : VirtReg;
}

bool hasShape(Register virtReg) const {
return Virt2ShapeMap.contains(virtReg);
}
/// returns true if the specified virtual register is not
/// mapped to a stack slot or rematerialized.
bool isAssignedReg(Register virtReg) const {
if (getStackSlot(virtReg) == NO_STACK_SLOT)
return true;
// Split register can be assigned a physical register as well as a
// stack slot or remat id.
return (Virt2SplitMap[virtReg] && Virt2PhysMap[virtReg]);
}

ShapeT getShape(Register virtReg) const {
assert(virtReg.isVirtual());
return Virt2ShapeMap.lookup(virtReg);
}
/// returns the stack slot mapped to the specified virtual
/// register
int getStackSlot(Register virtReg) const {
assert(virtReg.isVirtual());
return Virt2StackSlotMap[virtReg];
}

void assignVirt2Shape(Register virtReg, ShapeT shape) {
Virt2ShapeMap[virtReg] = shape;
}
/// create a mapping for the specifed virtual register to
/// the next available stack slot
int assignVirt2StackSlot(Register virtReg);

/// clears the specified virtual register's, physical
/// register mapping
void clearVirt(Register virtReg) {
assert(virtReg.isVirtual());
assert(Virt2PhysMap[virtReg] &&
"attempt to clear a not assigned virtual register");
Virt2PhysMap[virtReg] = MCRegister();
}
/// create a mapping for the specified virtual register to
/// the specified stack slot
void assignVirt2StackSlot(Register virtReg, int SS);

/// clears all virtual to physical register mappings
void clearAllVirt() {
Virt2PhysMap.clear();
grow();
}
void print(raw_ostream &OS, const Module *M = nullptr) const;
void dump() const;
};

/// returns true if VirtReg is assigned to its preferred physreg.
bool hasPreferredPhys(Register VirtReg) const;
inline raw_ostream &operator<<(raw_ostream &OS, const VirtRegMap &VRM) {
VRM.print(OS);
return OS;
}

/// returns true if VirtReg has a known preferred register.
/// This returns false if VirtReg has a preference that is a virtual
/// register that hasn't been assigned yet.
bool hasKnownPreference(Register VirtReg) const;
class VirtRegMapWrapperLegacy : public MachineFunctionPass {
VirtRegMap VRM;

/// records virtReg is a split live interval from SReg.
void setIsSplitFromReg(Register virtReg, Register SReg) {
Virt2SplitMap[virtReg] = SReg;
if (hasShape(SReg)) {
Virt2ShapeMap[virtReg] = getShape(SReg);
}
}
public:
static char ID;

/// returns the live interval virtReg is split from.
Register getPreSplitReg(Register virtReg) const {
return Virt2SplitMap[virtReg];
}
VirtRegMapWrapperLegacy() : MachineFunctionPass(ID) {}

/// getOriginal - Return the original virtual register that VirtReg descends
/// from through splitting.
/// A register that was not created by splitting is its own original.
/// This operation is idempotent.
Register getOriginal(Register VirtReg) const {
Register Orig = getPreSplitReg(VirtReg);
return Orig ? Orig : VirtReg;
}
void print(raw_ostream &OS, const Module *M = nullptr) const override {
VRM.print(OS, M);
}

/// returns true if the specified virtual register is not
/// mapped to a stack slot or rematerialized.
bool isAssignedReg(Register virtReg) const {
if (getStackSlot(virtReg) == NO_STACK_SLOT)
return true;
// Split register can be assigned a physical register as well as a
// stack slot or remat id.
return (Virt2SplitMap[virtReg] && Virt2PhysMap[virtReg]);
}
VirtRegMap &getVRM() { return VRM; }
const VirtRegMap &getVRM() const { return VRM; }

/// returns the stack slot mapped to the specified virtual
/// register
int getStackSlot(Register virtReg) const {
assert(virtReg.isVirtual());
return Virt2StackSlotMap[virtReg];
}
bool runOnMachineFunction(MachineFunction &MF) override {
VRM.init(MF);
return false;
}

/// create a mapping for the specifed virtual register to
/// the next available stack slot
int assignVirt2StackSlot(Register virtReg);
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
}
};

/// create a mapping for the specified virtual register to
/// the specified stack slot
void assignVirt2StackSlot(Register virtReg, int SS);
class VirtRegMapAnalysis : public AnalysisInfoMixin<VirtRegMapAnalysis> {
friend AnalysisInfoMixin<VirtRegMapAnalysis>;
static AnalysisKey Key;

void print(raw_ostream &OS, const Module* M = nullptr) const override;
void dump() const;
};
public:
using Result = VirtRegMap;

inline raw_ostream &operator<<(raw_ostream &OS, const VirtRegMap &VRM) {
VRM.print(OS);
return OS;
}
VirtRegMap run(MachineFunction &MF, MachineFunctionAnalysisManager &MAM);
};

class VirtRegMapPrinterPass : public PassInfoMixin<VirtRegMapPrinterPass> {
raw_ostream &OS;

public:
explicit VirtRegMapPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM);
static bool isRequired() { return true; }
};
} // end llvm namespace

#endif // LLVM_CODEGEN_VIRTREGMAP_H
4 changes: 2 additions & 2 deletions llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void initializeLiveDebugValuesPass(PassRegistry &);
void initializeLiveDebugVariablesPass(PassRegistry &);
void initializeLiveIntervalsWrapperPassPass(PassRegistry &);
void initializeLiveRangeShrinkPass(PassRegistry &);
void initializeLiveRegMatrixPass(PassRegistry &);
void initializeLiveRegMatrixWrapperLegacyPass(PassRegistry &);
void initializeLiveStacksPass(PassRegistry &);
void initializeLiveVariablesWrapperPassPass(PassRegistry &);
void initializeLoadStoreOptPass(PassRegistry &);
Expand Down Expand Up @@ -314,7 +314,7 @@ void initializeUnpackMachineBundlesPass(PassRegistry &);
void initializeUnreachableBlockElimLegacyPassPass(PassRegistry &);
void initializeUnreachableMachineBlockElimPass(PassRegistry &);
void initializeVerifierLegacyPassPass(PassRegistry &);
void initializeVirtRegMapPass(PassRegistry &);
void initializeVirtRegMapWrapperLegacyPass(PassRegistry &);
void initializeVirtRegRewriterPass(PassRegistry &);
void initializeWasmEHPreparePass(PassRegistry &);
void initializeWinEHPreparePass(PassRegistry &);
Expand Down
6 changes: 4 additions & 2 deletions llvm/include/llvm/Passes/MachinePassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ LOOP_PASS("loop-term-fold", LoopTermFoldPass())
// computed. (We still either need to regenerate kill flags after regalloc, or
// preferably fix the scavenger to not depend on them).
MACHINE_FUNCTION_ANALYSIS("live-intervals", LiveIntervalsAnalysis())
MACHINE_FUNCTION_ANALYSIS("live-reg-matrix", LiveRegMatrixAnalysis())
MACHINE_FUNCTION_ANALYSIS("live-vars", LiveVariablesAnalysis())
MACHINE_FUNCTION_ANALYSIS("machine-block-freq", MachineBlockFrequencyAnalysis())
MACHINE_FUNCTION_ANALYSIS("machine-branch-prob",
Expand All @@ -108,6 +109,7 @@ MACHINE_FUNCTION_ANALYSIS("machine-post-dom-tree",
MachinePostDominatorTreeAnalysis())
MACHINE_FUNCTION_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
MACHINE_FUNCTION_ANALYSIS("slot-indexes", SlotIndexesAnalysis())
MACHINE_FUNCTION_ANALYSIS("virtregmap", VirtRegMapAnalysis())
// MACHINE_FUNCTION_ANALYSIS("live-stacks", LiveStacksPass())
// MACHINE_FUNCTION_ANALYSIS("edge-bundles", EdgeBundlesAnalysis())
// MACHINE_FUNCTION_ANALYSIS("lazy-machine-bfi",
Expand All @@ -121,8 +123,7 @@ MACHINE_FUNCTION_ANALYSIS("slot-indexes", SlotIndexesAnalysis())
// MachineRegionInfoPassAnalysis())
// MACHINE_FUNCTION_ANALYSIS("machine-trace-metrics",
// MachineTraceMetricsAnalysis()) MACHINE_FUNCTION_ANALYSIS("reaching-def",
// ReachingDefAnalysisAnalysis()) MACHINE_FUNCTION_ANALYSIS("live-reg-matrix",
// LiveRegMatrixAnalysis()) MACHINE_FUNCTION_ANALYSIS("gc-analysis",
// ReachingDefAnalysisAnalysis()) MACHINE_FUNCTION_ANALYSIS("gc-analysis",
// GCMachineCodeAnalysisPass())
#undef MACHINE_FUNCTION_ANALYSIS

Expand Down Expand Up @@ -150,6 +151,7 @@ MACHINE_FUNCTION_PASS("print<machine-loops>", MachineLoopPrinterPass(dbgs()))
MACHINE_FUNCTION_PASS("print<machine-post-dom-tree>",
MachinePostDominatorTreePrinterPass(dbgs()))
MACHINE_FUNCTION_PASS("print<slot-indexes>", SlotIndexesPrinterPass(dbgs()))
MACHINE_FUNCTION_PASS("print<virtregmap>", VirtRegMapPrinterPass(dbgs()))
MACHINE_FUNCTION_PASS("require-all-machine-function-properties",
RequireAllMachineFunctionPropertiesPass())
MACHINE_FUNCTION_PASS("trigger-verifier-error", TriggerVerifierErrorPass())
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializeUnpackMachineBundlesPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
initializeUnreachableMachineBlockElimPass(Registry);
initializeVirtRegMapPass(Registry);
initializeVirtRegMapWrapperLegacyPass(Registry);
initializeVirtRegRewriterPass(Registry);
initializeWasmEHPreparePass(Registry);
initializeWinEHPreparePass(Registry);
Expand Down
13 changes: 12 additions & 1 deletion llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known,
unsigned Opcode = MI.getOpcode();
LLT DstTy = MRI.getType(R);

#ifndef NDEBUG
if (DstTy.isFixedVector()) {
assert(
DstTy.getNumElements() == DemandedElts.getBitWidth() &&
"DemandedElt width should equal the fixed vector number of elements");
} else {
assert(DemandedElts.getBitWidth() == 1 && DemandedElts == APInt(1, 1) &&
"DemandedElt width should be 1 for scalars or scalable vectors");
}
#endif

// Handle the case where this is called on a register that does not have a
// type constraint (i.e. it has a register class constraint instead). This is
// unlikely to occur except by looking through copies but it is possible for
Expand Down Expand Up @@ -196,7 +207,7 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known,
if (!DemandedElts[i])
continue;

computeKnownBitsImpl(MI.getOperand(i + 1).getReg(), Known2, DemandedElts,
computeKnownBitsImpl(MI.getOperand(i + 1).getReg(), Known2, APInt(1, 1),
Depth + 1);

// Known bits are the values that are shared by every demanded element.
Expand Down
42 changes: 30 additions & 12 deletions llvm/lib/CodeGen/LiveRegMatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,33 @@ using namespace llvm;
STATISTIC(NumAssigned , "Number of registers assigned");
STATISTIC(NumUnassigned , "Number of registers unassigned");

char LiveRegMatrix::ID = 0;
INITIALIZE_PASS_BEGIN(LiveRegMatrix, "liveregmatrix",
char LiveRegMatrixWrapperLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(LiveRegMatrixWrapperLegacy, "liveregmatrix",
"Live Register Matrix", false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_END(LiveRegMatrix, "liveregmatrix",
INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy)
INITIALIZE_PASS_END(LiveRegMatrixWrapperLegacy, "liveregmatrix",
"Live Register Matrix", false, false)

LiveRegMatrix::LiveRegMatrix() : MachineFunctionPass(ID) {}

void LiveRegMatrix::getAnalysisUsage(AnalysisUsage &AU) const {
void LiveRegMatrixWrapperLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequiredTransitive<LiveIntervalsWrapperPass>();
AU.addRequiredTransitive<VirtRegMap>();
AU.addRequiredTransitive<VirtRegMapWrapperLegacy>();
MachineFunctionPass::getAnalysisUsage(AU);
}

bool LiveRegMatrix::runOnMachineFunction(MachineFunction &MF) {
bool LiveRegMatrixWrapperLegacy::runOnMachineFunction(MachineFunction &MF) {
auto &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS();
auto &VRM = getAnalysis<VirtRegMapWrapperLegacy>().getVRM();
LRM.init(MF, LIS, VRM);
return false;
}

void LiveRegMatrix::init(MachineFunction &MF, LiveIntervals &pLIS,
VirtRegMap &pVRM) {
TRI = MF.getSubtarget().getRegisterInfo();
LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
VRM = &getAnalysis<VirtRegMap>();
LIS = &pLIS;
VRM = &pVRM;

unsigned NumRegUnits = TRI->getNumRegUnits();
if (NumRegUnits != Matrix.size())
Expand All @@ -64,9 +70,10 @@ bool LiveRegMatrix::runOnMachineFunction(MachineFunction &MF) {

// Make sure no stale queries get reused.
invalidateVirtRegs();
return false;
}

void LiveRegMatrixWrapperLegacy::releaseMemory() { LRM.releaseMemory(); }

void LiveRegMatrix::releaseMemory() {
for (unsigned i = 0, e = Matrix.size(); i != e; ++i) {
Matrix[i].clear();
Expand Down Expand Up @@ -246,3 +253,14 @@ Register LiveRegMatrix::getOneVReg(unsigned PhysReg) const {

return MCRegister::NoRegister;
}

AnalysisKey LiveRegMatrixAnalysis::Key;

LiveRegMatrix LiveRegMatrixAnalysis::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
auto &LIS = MFAM.getResult<LiveIntervalsAnalysis>(MF);
auto &VRM = MFAM.getResult<VirtRegMapAnalysis>(MF);
LiveRegMatrix LRM;
LRM.init(MF, LIS, VRM);
return LRM;
}
11 changes: 11 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MIParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ bool PerTargetMIParsingState::getRegisterByName(StringRef RegName,
return false;
}

bool PerTargetMIParsingState::getVRegFlagValue(StringRef FlagName,
uint8_t &FlagValue) const {
const auto *TRI = Subtarget.getRegisterInfo();
std::optional<uint8_t> FV = TRI->getVRegFlagValue(FlagName);
if (!FV)
return true;
FlagValue = *FV;
return false;
}

void PerTargetMIParsingState::initNames2InstrOpCodes() {
if (!Names2InstrOpCodes.empty())
return;
Expand Down Expand Up @@ -1776,6 +1786,7 @@ bool MIParser::parseRegisterOperand(MachineOperand &Dest,

MRI.setRegClassOrRegBank(Reg, static_cast<RegisterBank *>(nullptr));
MRI.setType(Reg, Ty);
MRI.noteNewVirtualRegister(Reg);
}
}
} else if (consumeIfPresent(MIToken::lparen)) {
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MIRParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,16 @@ bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS,
VReg.PreferredRegister.Value, Error))
return error(Error, VReg.PreferredRegister.SourceRange);
}

for (const auto &FlagStringValue : VReg.RegisterFlags) {
uint8_t FlagValue;
if (Target->getVRegFlagValue(FlagStringValue.Value, FlagValue))
return error(FlagStringValue.SourceRange.Start,
Twine("use of undefined register flag '") +
FlagStringValue.Value + "'");
Info.Flags.push_back(FlagValue);
}
RegInfo.noteNewVirtualRegister(Info.VReg);
}

// Parse the liveins.
Expand Down
27 changes: 20 additions & 7 deletions llvm/lib/CodeGen/MIRPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ class MIRPrinter {

void print(const MachineFunction &MF);

void convert(yaml::MachineFunction &MF, const MachineRegisterInfo &RegInfo,
void convert(yaml::MachineFunction &YamlMF, const MachineFunction &MF,
const MachineRegisterInfo &RegInfo,
const TargetRegisterInfo *TRI);
void convert(ModuleSlotTracker &MST, yaml::MachineFrameInfo &YamlMFI,
const MachineFrameInfo &MFI);
Expand Down Expand Up @@ -231,7 +232,7 @@ void MIRPrinter::print(const MachineFunction &MF) {
YamlMF.NoVRegs = MF.getProperties().hasProperty(
MachineFunctionProperties::Property::NoVRegs);

convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
convert(YamlMF, MF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo());
MachineModuleSlotTracker MST(MMI, &MF);
MST.incorporateFunction(MF.getFunction());
convert(MST, YamlMF.FrameInfo, MF.getFrameInfo());
Expand Down Expand Up @@ -316,10 +317,21 @@ printStackObjectDbgInfo(const MachineFunction::VariableDbgInfo &DebugVar,
}
}

void MIRPrinter::convert(yaml::MachineFunction &MF,
static void printRegFlags(Register Reg,
std::vector<yaml::FlowStringValue> &RegisterFlags,
const MachineFunction &MF,
const TargetRegisterInfo *TRI) {
auto FlagValues = TRI->getVRegFlagsOfReg(Reg, MF);
for (auto &Flag : FlagValues) {
RegisterFlags.push_back(yaml::FlowStringValue(Flag.str()));
}
}

void MIRPrinter::convert(yaml::MachineFunction &YamlMF,
const MachineFunction &MF,
const MachineRegisterInfo &RegInfo,
const TargetRegisterInfo *TRI) {
MF.TracksRegLiveness = RegInfo.tracksLiveness();
YamlMF.TracksRegLiveness = RegInfo.tracksLiveness();

// Print the virtual register definitions.
for (unsigned I = 0, E = RegInfo.getNumVirtRegs(); I < E; ++I) {
Expand All @@ -332,7 +344,8 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
Register PreferredReg = RegInfo.getSimpleHint(Reg);
if (PreferredReg)
printRegMIR(PreferredReg, VReg.PreferredRegister, TRI);
MF.VirtualRegisters.push_back(VReg);
printRegFlags(Reg, VReg.RegisterFlags, MF, TRI);
YamlMF.VirtualRegisters.push_back(VReg);
}

// Print the live ins.
Expand All @@ -341,7 +354,7 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
printRegMIR(LI.first, LiveIn.Register, TRI);
if (LI.second)
printRegMIR(LI.second, LiveIn.VirtualRegister, TRI);
MF.LiveIns.push_back(LiveIn);
YamlMF.LiveIns.push_back(LiveIn);
}

// Prints the callee saved registers.
Expand All @@ -353,7 +366,7 @@ void MIRPrinter::convert(yaml::MachineFunction &MF,
printRegMIR(*I, Reg, TRI);
CalleeSavedRegisters.push_back(Reg);
}
MF.CalleeSavedRegisters = CalleeSavedRegisters;
YamlMF.CalleeSavedRegisters = CalleeSavedRegisters;
}
}

Expand Down
16 changes: 8 additions & 8 deletions llvm/lib/CodeGen/RegAllocBasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ INITIALIZE_PASS_DEPENDENCY(LiveStacks)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrixWrapperLegacy)
INITIALIZE_PASS_END(RABasic, "regallocbasic", "Basic Register Allocator", false,
false)

Expand Down Expand Up @@ -188,10 +188,10 @@ void RABasic::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreservedID(MachineDominatorsID);
AU.addRequired<MachineLoopInfoWrapperPass>();
AU.addPreserved<MachineLoopInfoWrapperPass>();
AU.addRequired<VirtRegMap>();
AU.addPreserved<VirtRegMap>();
AU.addRequired<LiveRegMatrix>();
AU.addPreserved<LiveRegMatrix>();
AU.addRequired<VirtRegMapWrapperLegacy>();
AU.addPreserved<VirtRegMapWrapperLegacy>();
AU.addRequired<LiveRegMatrixWrapperLegacy>();
AU.addPreserved<LiveRegMatrixWrapperLegacy>();
MachineFunctionPass::getAnalysisUsage(AU);
}

Expand Down Expand Up @@ -307,9 +307,9 @@ bool RABasic::runOnMachineFunction(MachineFunction &mf) {
<< "********** Function: " << mf.getName() << '\n');

MF = &mf;
RegAllocBase::init(getAnalysis<VirtRegMap>(),
RegAllocBase::init(getAnalysis<VirtRegMapWrapperLegacy>().getVRM(),
getAnalysis<LiveIntervalsWrapperPass>().getLIS(),
getAnalysis<LiveRegMatrix>());
getAnalysis<LiveRegMatrixWrapperLegacy>().getLRM());
VirtRegAuxInfo VRAI(
*MF, *LIS, *VRM, getAnalysis<MachineLoopInfoWrapperPass>().getLI(),
getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI());
Expand Down
16 changes: 8 additions & 8 deletions llvm/lib/CodeGen/RegAllocGreedy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ INITIALIZE_PASS_DEPENDENCY(MachineScheduler)
INITIALIZE_PASS_DEPENDENCY(LiveStacks)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrixWrapperLegacy)
INITIALIZE_PASS_DEPENDENCY(EdgeBundles)
INITIALIZE_PASS_DEPENDENCY(SpillPlacement)
INITIALIZE_PASS_DEPENDENCY(MachineOptimizationRemarkEmitterPass)
Expand Down Expand Up @@ -215,10 +215,10 @@ void RAGreedy::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreserved<MachineDominatorTreeWrapperPass>();
AU.addRequired<MachineLoopInfoWrapperPass>();
AU.addPreserved<MachineLoopInfoWrapperPass>();
AU.addRequired<VirtRegMap>();
AU.addPreserved<VirtRegMap>();
AU.addRequired<LiveRegMatrix>();
AU.addPreserved<LiveRegMatrix>();
AU.addRequired<VirtRegMapWrapperLegacy>();
AU.addPreserved<VirtRegMapWrapperLegacy>();
AU.addRequired<LiveRegMatrixWrapperLegacy>();
AU.addPreserved<LiveRegMatrixWrapperLegacy>();
AU.addRequired<EdgeBundles>();
AU.addRequired<SpillPlacement>();
AU.addRequired<MachineOptimizationRemarkEmitterPass>();
Expand Down Expand Up @@ -2716,9 +2716,9 @@ bool RAGreedy::runOnMachineFunction(MachineFunction &mf) {
if (VerifyEnabled)
MF->verify(this, "Before greedy register allocator", &errs());

RegAllocBase::init(getAnalysis<VirtRegMap>(),
RegAllocBase::init(getAnalysis<VirtRegMapWrapperLegacy>().getVRM(),
getAnalysis<LiveIntervalsWrapperPass>().getLIS(),
getAnalysis<LiveRegMatrix>());
getAnalysis<LiveRegMatrixWrapperLegacy>().getLRM());

// Early return if there is no virtual register to be allocated to a
// physical register.
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/CodeGen/RegAllocPBQP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class RegAllocPBQP : public MachineFunctionPass {
initializeSlotIndexesWrapperPassPass(*PassRegistry::getPassRegistry());
initializeLiveIntervalsWrapperPassPass(*PassRegistry::getPassRegistry());
initializeLiveStacksPass(*PassRegistry::getPassRegistry());
initializeVirtRegMapPass(*PassRegistry::getPassRegistry());
initializeVirtRegMapWrapperLegacyPass(*PassRegistry::getPassRegistry());
}

/// Return the pass name.
Expand Down Expand Up @@ -559,8 +559,8 @@ void RegAllocPBQP::getAnalysisUsage(AnalysisUsage &au) const {
au.addPreserved<MachineLoopInfoWrapperPass>();
au.addRequired<MachineDominatorTreeWrapperPass>();
au.addPreserved<MachineDominatorTreeWrapperPass>();
au.addRequired<VirtRegMap>();
au.addPreserved<VirtRegMap>();
au.addRequired<VirtRegMapWrapperLegacy>();
au.addPreserved<VirtRegMapWrapperLegacy>();
MachineFunctionPass::getAnalysisUsage(au);
}

Expand Down Expand Up @@ -795,7 +795,7 @@ bool RegAllocPBQP::runOnMachineFunction(MachineFunction &MF) {
MachineBlockFrequencyInfo &MBFI =
getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI();

VirtRegMap &VRM = getAnalysis<VirtRegMap>();
VirtRegMap &VRM = getAnalysis<VirtRegMapWrapperLegacy>().getVRM();

PBQPVirtRegAuxInfo VRAI(
MF, LIS, VRM, getAnalysis<MachineLoopInfoWrapperPass>().getLI(), MBFI);
Expand Down
30 changes: 23 additions & 7 deletions llvm/lib/CodeGen/VirtRegMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ STATISTIC(NumIdCopies, "Number of identity moves eliminated after rewriting");
// VirtRegMap implementation
//===----------------------------------------------------------------------===//

char VirtRegMap::ID = 0;
char VirtRegMapWrapperLegacy::ID = 0;

INITIALIZE_PASS(VirtRegMap, "virtregmap", "Virtual Register Map", false, false)
INITIALIZE_PASS(VirtRegMapWrapperLegacy, "virtregmap", "Virtual Register Map",
false, false)

bool VirtRegMap::runOnMachineFunction(MachineFunction &mf) {
void VirtRegMap::init(MachineFunction &mf) {
MRI = &mf.getRegInfo();
TII = mf.getSubtarget().getInstrInfo();
TRI = mf.getSubtarget().getRegisterInfo();
Expand All @@ -72,7 +73,6 @@ bool VirtRegMap::runOnMachineFunction(MachineFunction &mf) {
Virt2ShapeMap.clear();

grow();
return false;
}

void VirtRegMap::grow() {
Expand Down Expand Up @@ -169,6 +169,22 @@ LLVM_DUMP_METHOD void VirtRegMap::dump() const {
}
#endif

AnalysisKey VirtRegMapAnalysis::Key;

PreservedAnalyses
VirtRegMapPrinterPass::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
OS << MFAM.getResult<VirtRegMapAnalysis>(MF);
return PreservedAnalyses::all();
}

VirtRegMap VirtRegMapAnalysis::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MAM) {
VirtRegMap VRM;
VRM.init(MF);
return VRM;
}

//===----------------------------------------------------------------------===//
// VirtRegRewriter
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -232,7 +248,7 @@ INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LiveDebugVariables)
INITIALIZE_PASS_DEPENDENCY(LiveStacks)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy)
INITIALIZE_PASS_END(VirtRegRewriter, "virtregrewriter",
"Virtual Register Rewriter", false, false)

Expand All @@ -245,7 +261,7 @@ void VirtRegRewriter::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LiveDebugVariables>();
AU.addRequired<LiveStacks>();
AU.addPreserved<LiveStacks>();
AU.addRequired<VirtRegMap>();
AU.addRequired<VirtRegMapWrapperLegacy>();

if (!ClearVirtRegs)
AU.addPreserved<LiveDebugVariables>();
Expand All @@ -260,7 +276,7 @@ bool VirtRegRewriter::runOnMachineFunction(MachineFunction &fn) {
MRI = &MF->getRegInfo();
Indexes = &getAnalysis<SlotIndexesWrapperPass>().getSI();
LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
VRM = &getAnalysis<VirtRegMap>();
VRM = &getAnalysis<VirtRegMapWrapperLegacy>().getVRM();
DebugVars = &getAnalysis<LiveDebugVariables>();
LLVM_DEBUG(dbgs() << "********** REWRITE VIRTUAL REGISTERS **********\n"
<< "********** Function: " << MF->getName() << '\n');
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
#include "llvm/CodeGen/InterleavedLoadCombine.h"
#include "llvm/CodeGen/JMCInstrumenter.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/LiveRegMatrix.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/LocalStackSlotAllocation.h"
#include "llvm/CodeGen/LowerEmuTLS.h"
Expand Down Expand Up @@ -122,6 +123,7 @@
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TwoAddressInstructionPass.h"
#include "llvm/CodeGen/TypePromotion.h"
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/CodeGen/WasmEHPrepare.h"
#include "llvm/CodeGen/WinEHPrepare.h"
#include "llvm/IR/DebugInfo.h"
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
Subtarget->requiresStrictAlign() ? MaxStoresPerMemcpyOptSize : 16;

MaxStoresPerMemmoveOptSize = 4;
MaxStoresPerMemmove = 4;
MaxStoresPerMemmove =
Subtarget->requiresStrictAlign() ? MaxStoresPerMemmoveOptSize : 16;

MaxLoadsPerMemcmpOptSize = 4;
MaxLoadsPerMemcmp =
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/AMDGPU/AMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ FunctionPass *createSIFixSGPRCopiesLegacyPass();
FunctionPass *createLowerWWMCopiesPass();
FunctionPass *createSIMemoryLegalizerPass();
FunctionPass *createSIInsertWaitcntsPass();
FunctionPass *createSIPreAllocateWWMRegsPass();
FunctionPass *createSIPreAllocateWWMRegsLegacyPass();
FunctionPass *createSIFormMemoryClausesPass();

FunctionPass *createSIPostRABundlerPass();
Expand Down Expand Up @@ -212,8 +212,8 @@ extern char &SILateBranchLoweringPassID;
void initializeSIOptimizeExecMaskingPass(PassRegistry &);
extern char &SIOptimizeExecMaskingID;

void initializeSIPreAllocateWWMRegsPass(PassRegistry &);
extern char &SIPreAllocateWWMRegsID;
void initializeSIPreAllocateWWMRegsLegacyPass(PassRegistry &);
extern char &SIPreAllocateWWMRegsLegacyID;

void initializeAMDGPUImageIntrinsicOptimizerPass(PassRegistry &);
extern char &AMDGPUImageIntrinsicOptimizerID;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUPassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,6 @@ MACHINE_FUNCTION_PASS("gcn-dpp-combine", GCNDPPCombinePass())
MACHINE_FUNCTION_PASS("si-load-store-opt", SILoadStoreOptimizerPass())
MACHINE_FUNCTION_PASS("si-lower-sgpr-spills", SILowerSGPRSpillsPass())
MACHINE_FUNCTION_PASS("si-peephole-sdwa", SIPeepholeSDWAPass())
MACHINE_FUNCTION_PASS("si-pre-allocate-wwm-regs", SIPreAllocateWWMRegsPass())
MACHINE_FUNCTION_PASS("si-shrink-instructions", SIShrinkInstructionsPass())
#undef MACHINE_FUNCTION_PASS
63 changes: 48 additions & 15 deletions llvm/lib/Target/AMDGPU/AMDGPUSplitModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,29 @@ void SplitGraph::Node::visitAllDependencies(
}
}

/// Checks if \p I has MD_callees and if it does, parse it and put the function
/// in \p Callees.
///
/// \returns true if there was metadata and it was parsed correctly. false if
/// there was no MD or if it contained unknown entries and parsing failed.
/// If this returns false, \p Callees will contain incomplete information
/// and must not be used.
static bool handleCalleesMD(const Instruction &I,
SetVector<Function *> &Callees) {
auto *MD = I.getMetadata(LLVMContext::MD_callees);
if (!MD)
return false;

for (const auto &Op : MD->operands()) {
Function *Callee = mdconst::extract_or_null<Function>(Op);
if (!Callee)
return false;
Callees.insert(Callee);
}

return true;
}

void SplitGraph::buildGraph(CallGraph &CG) {
SplitModuleTimer SMT("buildGraph", "graph construction");
LLVM_DEBUG(
Expand Down Expand Up @@ -519,28 +542,38 @@ void SplitGraph::buildGraph(CallGraph &CG) {
Fn.printAsOperand(dbgs());
dbgs() << " - analyzing function\n");

bool HasIndirectCall = false;
SetVector<Function *> KnownCallees;
bool HasUnknownIndirectCall = false;
for (const auto &Inst : instructions(Fn)) {
// look at all calls without a direct callee.
if (const auto *CB = dyn_cast<CallBase>(&Inst);
CB && !CB->getCalledFunction()) {
// inline assembly can be ignored, unless InlineAsmIsIndirectCall is
// true.
if (CB->isInlineAsm()) {
LLVM_DEBUG(dbgs() << " found inline assembly\n");
continue;
}

// everything else is handled conservatively.
HasIndirectCall = true;
break;
const auto *CB = dyn_cast<CallBase>(&Inst);
if (!CB || CB->getCalledFunction())
continue;

// inline assembly can be ignored, unless InlineAsmIsIndirectCall is
// true.
if (CB->isInlineAsm()) {
LLVM_DEBUG(dbgs() << " found inline assembly\n");
continue;
}

if (handleCalleesMD(Inst, KnownCallees))
continue;
// If we failed to parse any !callees MD, or some was missing,
// the entire KnownCallees list is now unreliable.
KnownCallees.clear();

// Everything else is handled conservatively. If we fall into the
// conservative case don't bother analyzing further.
HasUnknownIndirectCall = true;
break;
}

if (HasIndirectCall) {
if (HasUnknownIndirectCall) {
LLVM_DEBUG(dbgs() << " indirect call found\n");
FnsWithIndirectCalls.push_back(&Fn);
}
} else if (!KnownCallees.empty())
DirectCallees.insert(KnownCallees.begin(), KnownCallees.end());
}

Node &N = getNode(Cache, Fn);
Expand Down
18 changes: 15 additions & 3 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "SIMachineFunctionInfo.h"
#include "SIMachineScheduler.h"
#include "SIPeepholeSDWA.h"
#include "SIPreAllocateWWMRegs.h"
#include "SIShrinkInstructions.h"
#include "TargetInfo/AMDGPUTargetInfo.h"
#include "Utils/AMDGPUBaseInfo.h"
Expand Down Expand Up @@ -508,7 +509,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUTarget() {
initializeSILateBranchLoweringPass(*PR);
initializeSIMemoryLegalizerPass(*PR);
initializeSIOptimizeExecMaskingPass(*PR);
initializeSIPreAllocateWWMRegsPass(*PR);
initializeSIPreAllocateWWMRegsLegacyPass(*PR);
initializeSIFormMemoryClausesPass(*PR);
initializeSIPostRABundlerPass(*PR);
initializeGCNCreateVOPDPass(*PR);
Expand Down Expand Up @@ -1506,7 +1507,7 @@ bool GCNPassConfig::addRegAssignAndRewriteFast() {
addPass(&SILowerSGPRSpillsLegacyID);

// To Allocate wwm registers used in whole quad mode operations (for shaders).
addPass(&SIPreAllocateWWMRegsID);
addPass(&SIPreAllocateWWMRegsLegacyID);

// For allocating other wwm register operands.
addPass(createWWMRegAllocPass(false));
Expand Down Expand Up @@ -1543,7 +1544,7 @@ bool GCNPassConfig::addRegAssignAndRewriteOptimized() {
addPass(&SILowerSGPRSpillsLegacyID);

// To Allocate wwm registers used in whole quad mode operations (for shaders).
addPass(&SIPreAllocateWWMRegsID);
addPass(&SIPreAllocateWWMRegsLegacyID);

// For allocating other whole wave mode registers.
addPass(createWWMRegAllocPass(true));
Expand Down Expand Up @@ -1718,6 +1719,17 @@ bool GCNTargetMachine::parseMachineFunctionInfo(
MFI->reserveWWMRegister(ParsedReg);
}

for (const auto &[_, Info] : PFS.VRegInfosNamed) {
for (uint8_t Flag : Info->Flags) {
MFI->setFlag(Info->VReg, Flag);
}
}
for (const auto &[_, Info] : PFS.VRegInfos) {
for (uint8_t Flag : Info->Flags) {
MFI->setFlag(Info->VReg, Flag);
}
}

auto parseAndCheckArgument = [&](const std::optional<yaml::SIArgument> &A,
const TargetRegisterClass &RC,
ArgDescriptor &Arg, unsigned UserSGPRs,
Expand Down
12 changes: 6 additions & 6 deletions llvm/lib/Target/AMDGPU/GCNNSAReassign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class GCNNSAReassign : public MachineFunctionPass {

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LiveIntervalsWrapperPass>();
AU.addRequired<VirtRegMap>();
AU.addRequired<LiveRegMatrix>();
AU.addRequired<VirtRegMapWrapperLegacy>();
AU.addRequired<LiveRegMatrixWrapperLegacy>();
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
}
Expand Down Expand Up @@ -95,8 +95,8 @@ class GCNNSAReassign : public MachineFunctionPass {
INITIALIZE_PASS_BEGIN(GCNNSAReassign, DEBUG_TYPE, "GCN NSA Reassign",
false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrixWrapperLegacy)
INITIALIZE_PASS_END(GCNNSAReassign, DEBUG_TYPE, "GCN NSA Reassign",
false, false)

Expand Down Expand Up @@ -242,8 +242,8 @@ bool GCNNSAReassign::runOnMachineFunction(MachineFunction &MF) {

MRI = &MF.getRegInfo();
TRI = ST->getRegisterInfo();
VRM = &getAnalysis<VirtRegMap>();
LRM = &getAnalysis<LiveRegMatrix>();
VRM = &getAnalysis<VirtRegMapWrapperLegacy>().getVRM();
LRM = &getAnalysis<LiveRegMatrixWrapperLegacy>().getLRM();
LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();

const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/SILowerSGPRSpills.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ char SILowerSGPRSpillsLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(SILowerSGPRSpillsLegacy, DEBUG_TYPE,
"SI lower SGPR spill instructions", false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass)
INITIALIZE_PASS_END(SILowerSGPRSpillsLegacy, DEBUG_TYPE,
"SI lower SGPR spill instructions", false, false)

Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/AMDGPU/SILowerWWMCopies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class SILowerWWMCopies : public MachineFunctionPass {
INITIALIZE_PASS_BEGIN(SILowerWWMCopies, DEBUG_TYPE, "SI Lower WWM Copies",
false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(VirtRegMapWrapperLegacy)
INITIALIZE_PASS_END(SILowerWWMCopies, DEBUG_TYPE, "SI Lower WWM Copies", false,
false)

Expand Down Expand Up @@ -105,7 +105,8 @@ bool SILowerWWMCopies::runOnMachineFunction(MachineFunction &MF) {
LIS = LISWrapper ? &LISWrapper->getLIS() : nullptr;
auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>();
Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr;
VRM = getAnalysisIfAvailable<VirtRegMap>();
auto *VRMWrapper = getAnalysisIfAvailable<VirtRegMapWrapperLegacy>();
VRM = VRMWrapper ? &VRMWrapper->getVRM() : nullptr;
TRI = ST.getRegisterInfo();
MRI = &MF.getRegInfo();

Expand Down
Loading