29 changes: 25 additions & 4 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ struct IndirectLocalPathEntry {
GslReferenceInit,
GslPointerInit,
GslPointerAssignment,
DefaultArg,
} Kind;
Expr *E;
union {
Expand Down Expand Up @@ -609,15 +610,22 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
for (unsigned I = 0,
N = std::min<unsigned>(Callee->getNumParams(), Args.size());
I != N; ++I) {
Expr *Arg = Args[I];
RevertToOldSizeRAII RAII(Path);
if (auto *DAE = dyn_cast<CXXDefaultArgExpr>(Arg)) {
Path.push_back(
{IndirectLocalPathEntry::DefaultArg, DAE, DAE->getParam()});
Arg = DAE->getExpr();
}
if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
else if (EnableGSLAnalysis && I == 0) {
// Perform GSL analysis for the first argument
if (shouldTrackFirstArgument(Callee)) {
VisitGSLPointerArg(Callee, Args[0]);
VisitGSLPointerArg(Callee, Arg);
} else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call);
Ctor && shouldTrackFirstArgumentForConstructor(Ctor)) {
VisitGSLPointerArg(Ctor->getConstructor(), Args[0]);
VisitGSLPointerArg(Ctor->getConstructor(), Arg);
}
}
}
Expand Down Expand Up @@ -1060,6 +1068,9 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
if (!Path[I].Capture->capturesVariable())
continue;
return Path[I].E->getSourceRange();

case IndirectLocalPathEntry::DefaultArg:
return cast<CXXDefaultArgExpr>(Path[I].E)->getUsedLocation();
}
}
return E->getSourceRange();
Expand Down Expand Up @@ -1370,7 +1381,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
break;
}

case IndirectLocalPathEntry::LambdaCaptureInit:
case IndirectLocalPathEntry::LambdaCaptureInit: {
if (!Elem.Capture->capturesVariable())
break;
// FIXME: We can't easily tell apart an init-capture from a nested
Expand All @@ -1383,6 +1394,16 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
<< nextPathEntryRange(Path, I + 1, L);
break;
}

case IndirectLocalPathEntry::DefaultArg: {
const auto *DAE = cast<CXXDefaultArgExpr>(Elem.E);
const ParmVarDecl *Param = DAE->getParam();
SemaRef.Diag(Param->getDefaultArgRange().getBegin(),
diag::note_init_with_default_argument)
<< Param << nextPathEntryRange(Path, I + 1, L);
break;
}
}
}

// We didn't lifetime-extend, so don't go any further; we don't need more
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ struct BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
if (Record->isCompleteDefinition())
return *this;
assert(Fields.count("h") > 0 &&
"Subscript operator must be added after the handle.");

ASTContext &AST = Record->getASTContext();
QualType ElemTy = AST.Char8Ty;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3215,6 +3215,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// Array parameter types are treated as fundamental types.
case Type::ArrayParameter:
break;

case Type::HLSLAttributedResource:
T = cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr();
}

if (Queue.empty())
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1798,6 +1798,23 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return ICS;
}

if (S.getLangOpts().HLSL && ToType->isHLSLAttributedResourceType() &&
FromType->isHLSLAttributedResourceType()) {
auto *ToResType = cast<HLSLAttributedResourceType>(ToType);
auto *FromResType = cast<HLSLAttributedResourceType>(FromType);
if (S.Context.hasSameUnqualifiedType(ToResType->getWrappedType(),
FromResType->getWrappedType()) &&
S.Context.hasSameUnqualifiedType(ToResType->getContainedType(),
FromResType->getContainedType()) &&
ToResType->getAttrs() == FromResType->getAttrs()) {
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ToType);
return ICS;
}
}

return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
AllowExplicit, InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6074,6 +6074,13 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}

bool UnnamedLocalNoLinkageFinder::VisitHLSLAttributedResourceType(
const HLSLAttributedResourceType *T) {
if (T->hasContainedType() && Visit(T->getContainedType()))
return true;
return Visit(T->getWrappedType());
}

bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
case Type::PackExpansion:
case Type::Pipe:
case Type::ArrayParameter:
case Type::HLSLAttributedResource:
// No template argument deduction for these types
return TemplateDeductionResult::Success;

Expand Down Expand Up @@ -6844,6 +6845,16 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
OnlyDeduced, Depth, Used);
break;

case Type::HLSLAttributedResource:
MarkUsedTemplateParameters(
Ctx, cast<HLSLAttributedResourceType>(T)->getWrappedType(), OnlyDeduced,
Depth, Used);
if (cast<HLSLAttributedResourceType>(T)->hasContainedType())
MarkUsedTemplateParameters(
Ctx, cast<HLSLAttributedResourceType>(T)->getContainedType(),
OnlyDeduced, Depth, Used);
break;

// None of these types have any template parameters in them.
case Type::Builtin:
case Type::VariableArray:
Expand Down
2 changes: 0 additions & 2 deletions clang/test/AST/HLSL/RWBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
Expand All @@ -59,5 +58,4 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
2 changes: 0 additions & 2 deletions clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ StructuredBuffer<float> Buffer;
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
Expand Down Expand Up @@ -62,5 +61,4 @@ StructuredBuffer<float> Buffer;
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
18 changes: 18 additions & 0 deletions clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s

// NOTE: The type name number and whether the struct is packed or not will mostly
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
// and theinterim field of the contained type is removed.

// CHECK: %"class.hlsl::RWBuffer" = type <{ target("dx.TypedBuffer", i16, 1, 0, 1)
// CHECK: %"class.hlsl::RWBuffer.0" = type <{ target("dx.TypedBuffer", i16, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.2" = type { target("dx.TypedBuffer", i32, 1, 0, 1)
// CHECK: %"class.hlsl::RWBuffer.3" = type { target("dx.TypedBuffer", i32, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.4" = type { target("dx.TypedBuffer", i64, 1, 0, 1)
// CHECK: %"class.hlsl::RWBuffer.5" = type { target("dx.TypedBuffer", i64, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.6" = type <{ target("dx.TypedBuffer", half, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.8" = type { target("dx.TypedBuffer", float, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.9" = type { target("dx.TypedBuffer", double, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.10" = type { target("dx.TypedBuffer", <4 x i16>, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.11" = type { target("dx.TypedBuffer", <3 x i32>, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.12" = type { target("dx.TypedBuffer", <2 x half>, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.13" = type { target("dx.TypedBuffer", <3 x float>, 1, 0, 0)

RWBuffer<int16_t> BufI16;
RWBuffer<uint16_t> BufU16;
RWBuffer<int> BufI32;
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s

// NOTE: The number in type name and whether the struct is packed or not will mostly
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
// and theinterim field of the contained type is removed.

// CHECK: %"class.hlsl::StructuredBuffer" = type <{ target("dx.RawBuffer", i16, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.2" = type { target("dx.RawBuffer", i32, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.3" = type { target("dx.RawBuffer", i32, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.4" = type { target("dx.RawBuffer", i64, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.5" = type { target("dx.RawBuffer", i64, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.8" = type { target("dx.RawBuffer", float, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.9" = type { target("dx.RawBuffer", double, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 1, 0)

StructuredBuffer<int16_t> BufI16;
StructuredBuffer<uint16_t> BufU16;
StructuredBuffer<int> BufI32;
Expand Down
56 changes: 50 additions & 6 deletions clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
Original file line number Diff line number Diff line change
@@ -1,9 +1,53 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O1 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -emit-llvm -o - %s | FileCheck %s

void foo(__hlsl_resource_t res);
using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]];

// CHECK: define void @_Z3baru17__hlsl_resource_t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %[[PARAM:[a-zA-Z0-9]+]])
// CHECK: call void @_Z3foou17__hlsl_resource_t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %[[PARAM]])
void bar(__hlsl_resource_t a) {
foo(a);
// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 1, 0)

// CHECK: define void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a)
// CHECK: call void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %0)
// CHECK: declare void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0))

void foo1(handle_float_t res);

void fa(handle_float_t a) {
foo1(a);
}

// CHECK: define void @_Z2fbU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a)
void fb(handle_float_t a) {
handle_float_t b = a;
}

// CHECK: define void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 16 %a)
// CHECK: call void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 16 %agg.tmp)
// CHECK: declare void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 16)
void foo2(RWBuffer<float4> buf);

void fc(RWBuffer<float4> a) {
foo2(a);
}

void fd(RWBuffer<float4> a) {
RWBuffer<float4> b = a;
}

struct MyStruct {
float4 f;
int2 i;
};

// CHECK: define void @_Z2feN4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 16 %a)
// CHECK: call void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 16 %agg.tmp)
// CHECK: declare void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 16)
void foo3(StructuredBuffer<MyStruct> buf);

void fe(StructuredBuffer<MyStruct> a) {
foo3(a);
}

void ff(StructuredBuffer<MyStruct> a) {
StructuredBuffer<MyStruct> b = a;
}

13 changes: 5 additions & 8 deletions clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@

typedef vector<float, 4> float4;

// CHECK: -TypeAliasDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:1, col:83>
// CHECK: -TypeAliasDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:83>
// CHECK: -HLSLAttributedResourceType 0x{{[0-9a-f]+}} '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(int)]]
// CHECK-SAME: ' sugar
using ResourceIntAliasT = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(int)]];
ResourceIntAliasT h1;

// CHECK: -VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:82> col:82 h2 '__hlsl_resource_t
// CHECK: -VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:82> col:82 h2 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float4)]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float4)]] h2;

// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 7]]:1, line:[[# @LINE + 9]]:1> line:[[# @LINE + 7]]:30 S
// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 6]]:1, line:[[# @LINE + 8]]:1> line:[[# @LINE + 6]]:30 S
// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:11, col:20> col:20 referenced typename depth 0 index 0 T
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:23, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:30 struct S definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:3, col:79> col:79 h '__hlsl_resource_t
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:23, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:30 struct S definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:79> col:79 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(T)]]
// CHECK-SAME: ':'__hlsl_resource_t'
template <typename T> struct S {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(T)]] h;
};
9 changes: 3 additions & 6 deletions clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:3, col:68> col:68 h '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:68> col:68 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME: ':'__hlsl_resource_t'
struct MyBuffer {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov]] h;
};

// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:66> col:66 res '__hlsl_resource_t
// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:66> col:66 res '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::is_rov]] [[hlsl::resource_class(SRV)]] res;

// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:1, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:6 f 'void ()
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:6 f 'void ()
// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 r '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME: ':'__hlsl_resource_t'
void f() {
__hlsl_resource_t [[hlsl::resource_class(Sampler)]] [[hlsl::is_rov]] r;
}
9 changes: 3 additions & 6 deletions clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:3, col:72> col:72 h1 '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:72> col:72 h1 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME: ':'__hlsl_resource_t'
struct MyBuffer {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h1;
};

// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:70> col:70 h2 '__hlsl_resource_t
// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:70> col:70 h2 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::raw_buffer]] [[hlsl::resource_class(SRV)]] h2;

// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:1, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:6 f 'void ()
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:6 f 'void ()
// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 h3 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME: ':'__hlsl_resource_t'
void f() {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h3;
}
17 changes: 6 additions & 11 deletions clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
struct MyBuffer {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] h;
};

// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:49> col:49 res '__hlsl_resource_t
// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 2]]:1, col:49> col:49 res '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::resource_class(SRV)]] res;

// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:6 f 'void ()
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, line:[[# @LINE + 5]]:1> line:[[# @LINE + 3]]:6 f 'void ()
// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:55> col:55 r '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
// CHECK-SAME: ':'__hlsl_resource_t'
void f() {
__hlsl_resource_t [[hlsl::resource_class(Sampler)]] r;
}

// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 7]]:1, line:[[# @LINE + 9]]:1> line:[[# @LINE + 7]]:29 MyBuffer2
// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 6]]:1, line:[[# @LINE + 8]]:1> line:[[# @LINE + 6]]:29 MyBuffer2
// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:10, col:19> col:19 typename depth 0 index 0 T
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:29 struct MyBuffer2 definition
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:29 struct MyBuffer2 definition
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
template<typename T> struct MyBuffer2 {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] h;
};
Expand All @@ -38,5 +34,4 @@ template<typename T> struct MyBuffer2 {
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE - 7]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
MyBuffer2<float> myBuffer2;
2 changes: 0 additions & 2 deletions clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RWBuffer<float> Buffer1;

Expand All @@ -18,6 +17,5 @@ RWBuffer<float> Buffer1;
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<float, 4>)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4];
31 changes: 31 additions & 0 deletions clang/test/SemaCXX/attr-lifetimebound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ namespace std {
using std::operator""s;
using std::operator""sv;

namespace default_args {
using IntArray = int[];
const int *defaultparam1(const int &def1 [[clang::lifetimebound]] = 0); // #def1
const int &defaultparam_array([[clang::lifetimebound]] const int *p = IntArray{1, 2, 3}); // #def2
struct A {
A(const char *, const int &def3 [[clang::lifetimebound]] = 0); // #def3
};
const int &defaultparam2(const int &def4 [[clang::lifetimebound]] = 0); // #def4
const int &defaultparam3(const int &def5 [[clang::lifetimebound]] = defaultparam2(), const int &def6 [[clang::lifetimebound]] = 0); // #def5 #def6
std::string_view defaultparam4(std::string_view s [[clang::lifetimebound]] = std::string()); // #def7

const int *test_default_args() {
const int *c = defaultparam1(); // expected-warning {{temporary whose address is used as value of local variable 'c' will be destroyed at the end of the full-expression}} expected-note@#def1 {{initializing parameter 'def1' with default argument}}
A a = A(""); // expected-warning {{temporary whose address is used as value of local variable 'a' will be destroyed at the end of the full-expression}} expected-note@#def3 {{initializing parameter 'def3' with default argument}}
const int &s = defaultparam2(); // expected-warning {{temporary bound to local reference 's' will be destroyed at the end of the full-expression}} expected-note@#def4 {{initializing parameter 'def4' with default argument}}
const int &t = defaultparam3(); // expected-warning {{temporary bound to local reference 't' will be destroyed at the end of the full-expression}} expected-note@#def4 {{initializing parameter 'def4' with default argument}} expected-note@#def5 {{initializing parameter 'def5' with default argument}} expected-warning {{temporary bound to local reference 't' will be destroyed at the end of the full-expression}} expected-note@#def6 {{initializing parameter 'def6' with default argument}}
const int &u = defaultparam_array(); // expected-warning {{temporary bound to local reference 'u' will be destroyed at the end of the full-expression}} expected-note@#def2 {{initializing parameter 'p' with default argument}}
int local;
const int &v = defaultparam2(local); // no warning
const int &w = defaultparam2(1); // expected-warning {{temporary bound to local reference 'w' will be destroyed at the end of the full-expression}}
if (false) {
return &defaultparam2(); // expected-warning {{returning address of local temporary object}}
}
if (false) {
return &defaultparam2(0); // expected-warning {{returning address of local temporary object}} expected-note@#def4 {{initializing parameter 'def4' with default argument}}
}
std::string_view sv = defaultparam4(); // expected-warning {{temporary whose address is used as value of local variable 'sv' will be destroyed at the end of the full-expression}} expected-note@#def7 {{initializing parameter 's' with default argument}}
return nullptr;
}
} // namespace default_args

namespace p0936r0_examples {
std::string_view s = "foo"s; // expected-warning {{temporary}}

Expand Down
2 changes: 2 additions & 0 deletions flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ end
* A local data object may appear in a specification expression, even
when it is not a dummy argument or in COMMON, so long as it is
has the SAVE attribute and was initialized.
* `PRINT namelistname` is accepted and interpreted as
`WRITE(*,NML=namelistname)`, a near-universal extension.

### Extensions supported when enabled by options

Expand Down
8 changes: 4 additions & 4 deletions flang/include/flang/Common/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
NonBindCInteroperability, CudaManaged, CudaUnified,
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
SavedLocalInSpecExpr)
SavedLocalInSpecExpr, PrintNamelist)

// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
Expand All @@ -63,9 +63,9 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
F202XAllocatableBreakingChange, OptionalMustBePresent, CommonBlockPadding,
LogicalVsCBool, BindCCharLength, ProcDummyArgShapes, ExternalNameConflict,
FoldingException, FoldingAvoidsRuntimeCrash, FoldingValueChecks,
FoldingFailure, FoldingLimit, Interoperability, Bounds, Preprocessing,
Scanning, OpenAccUsage, ProcPointerCompatibility, VoidMold,
KnownBadImplicitInterface, EmptyCase, CaseOverflow, CUDAUsage,
FoldingFailure, FoldingLimit, Interoperability, CharacterInteroperability,
Bounds, Preprocessing, Scanning, OpenAccUsage, ProcPointerCompatibility,
VoidMold, KnownBadImplicitInterface, EmptyCase, CaseOverflow, CUDAUsage,
IgnoreTKRUsage, ExternalInterfaceMismatch, DefinedOperatorArgs, Final,
ZeroDoStep, UnusedForallIndex, OpenMPUsage, ModuleFile, DataLength,
IgnoredDirective, HomonymousSpecific, HomonymousResult,
Expand Down
116 changes: 116 additions & 0 deletions flang/include/flang/Common/erfc-scaled.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//===-- include/flang/Common/erfc-scaled.h-----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_COMMON_ERFC_SCALED_H_
#define FORTRAN_COMMON_ERFC_SCALED_H_

namespace Fortran::common {
template <typename T> inline T ErfcScaled(T arg) {
// Coefficients for approximation to erfc in the first interval.
static const T a[5] = {3.16112374387056560e00, 1.13864154151050156e02,
3.77485237685302021e02, 3.20937758913846947e03, 1.85777706184603153e-1};
static const T b[4] = {2.36012909523441209e01, 2.44024637934444173e02,
1.28261652607737228e03, 2.84423683343917062e03};

// Coefficients for approximation to erfc in the second interval.
static const T c[9] = {5.64188496988670089e-1, 8.88314979438837594e00,
6.61191906371416295e01, 2.98635138197400131e02, 8.81952221241769090e02,
1.71204761263407058e03, 2.05107837782607147e03, 1.23033935479799725e03,
2.15311535474403846e-8};
static const T d[8] = {1.57449261107098347e01, 1.17693950891312499e02,
5.37181101862009858e02, 1.62138957456669019e03, 3.29079923573345963e03,
4.36261909014324716e03, 3.43936767414372164e03, 1.23033935480374942e03};

// Coefficients for approximation to erfc in the third interval.
static const T p[6] = {3.05326634961232344e-1, 3.60344899949804439e-1,
1.25781726111229246e-1, 1.60837851487422766e-2, 6.58749161529837803e-4,
1.63153871373020978e-2};
static const T q[5] = {2.56852019228982242e00, 1.87295284992346047e00,
5.27905102951428412e-1, 6.05183413124413191e-2, 2.33520497626869185e-3};

constexpr T sqrtpi{1.7724538509078120380404576221783883301349L};
constexpr T rsqrtpi{0.5641895835477562869480794515607725858440L};
constexpr T epsilonby2{std::numeric_limits<T>::epsilon() * 0.5};
constexpr T xneg{-26.628e0};
constexpr T xhuge{6.71e7};
constexpr T thresh{0.46875e0};
constexpr T zero{0.0};
constexpr T one{1.0};
constexpr T four{4.0};
constexpr T sixteen{16.0};
constexpr T xmax{1.0 / (sqrtpi * std::numeric_limits<T>::min())};
static_assert(xmax > xhuge, "xmax must be greater than xhuge");

T ysq;
T xnum;
T xden;
T del;
T result;

auto x{arg};
auto y{std::fabs(x)};

if (y <= thresh) {
// evaluate erf for |x| <= 0.46875
ysq = zero;
if (y > epsilonby2) {
ysq = y * y;
}
xnum = a[4] * ysq;
xden = ysq;
for (int i{0}; i < 3; i++) {
xnum = (xnum + a[i]) * ysq;
xden = (xden + b[i]) * ysq;
}
result = x * (xnum + a[3]) / (xden + b[3]);
result = one - result;
result = std::exp(ysq) * result;
return result;
} else if (y <= four) {
// evaluate erfc for 0.46875 < |x| <= 4.0
xnum = c[8] * y;
xden = y;
for (int i{0}; i < 7; ++i) {
xnum = (xnum + c[i]) * y;
xden = (xden + d[i]) * y;
}
result = (xnum + c[7]) / (xden + d[7]);
} else {
// evaluate erfc for |x| > 4.0
result = zero;
if (y >= xhuge) {
if (y < xmax) {
result = rsqrtpi / y;
}
} else {
ysq = one / (y * y);
xnum = p[5] * ysq;
xden = ysq;
for (int i{0}; i < 4; ++i) {
xnum = (xnum + p[i]) * ysq;
xden = (xden + q[i]) * ysq;
}
result = ysq * (xnum + p[4]) / (xden + q[4]);
result = (rsqrtpi - result) / y;
}
}
// fix up for negative argument, erf, etc.
if (x < zero) {
if (x < xneg) {
result = std::numeric_limits<T>::max();
} else {
ysq = trunc(x * sixteen) / sixteen;
del = (x - ysq) * (x + ysq);
y = std::exp((ysq * ysq)) * std::exp((del));
result = (y + y) - result;
}
}
return result;
}
} // namespace Fortran::common
#endif // FORTRAN_COMMON_ERFC_SCALED_H_
6 changes: 5 additions & 1 deletion flang/include/flang/Evaluate/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -1252,8 +1252,12 @@ class ArrayConstantBoundChanger {
// Predicate: should two expressions be considered identical for the purposes
// of determining whether two procedure interfaces are compatible, modulo
// naming of corresponding dummy arguments?
std::optional<bool> AreEquivalentInInterface(
template <typename T>
std::optional<bool> AreEquivalentInInterface(const Expr<T> &, const Expr<T> &);
extern template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
const Expr<SubscriptInteger> &, const Expr<SubscriptInteger> &);
extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
const Expr<SomeInteger> &, const Expr<SomeInteger> &);

bool CheckForCoindexedObject(parser::ContextualMessages &,
const std::optional<ActualArgument> &, const std::string &procName,
Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def CufImplicitDeviceGlobal :
def CUFAddConstructor : Pass<"cuf-add-constructor", "mlir::ModuleOp"> {
let summary = "Add constructor to register CUDA Fortran allocators";
let dependentDialects = [
"mlir::func::FuncDialect"
"cuf::CUFDialect", "mlir::func::FuncDialect"
];
}

Expand Down
1 change: 1 addition & 0 deletions flang/include/flang/Semantics/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class ParamValue {
return category_ == that.category_ && expr_ == that.expr_;
}
bool operator!=(const ParamValue &that) const { return !(*this == that); }
bool IsEquivalentInInterface(const ParamValue &) const;
std::string AsFortran() const;

private:
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Common/Fortran-features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnUsage_.set(UsageWarning::FoldingFailure);
warnUsage_.set(UsageWarning::FoldingLimit);
warnUsage_.set(UsageWarning::Interoperability);
// CharacterInteroperability warnings about length are off by default
warnUsage_.set(UsageWarning::Bounds);
warnUsage_.set(UsageWarning::Preprocessing);
warnUsage_.set(UsageWarning::Scanning);
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Evaluate/intrinsics-library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "flang/Evaluate/intrinsics-library.h"
#include "fold-implementation.h"
#include "host.h"
#include "flang/Common/erfc-scaled.h"
#include "flang/Common/static-multimap-view.h"
#include "flang/Evaluate/expression.h"
#include <cfloat>
Expand Down Expand Up @@ -231,6 +232,7 @@ struct HostRuntimeLibrary<HostT, LibraryVersion::Libm> {
FolderFactory<F, F{std::cosh}>::Create("cosh"),
FolderFactory<F, F{std::erf}>::Create("erf"),
FolderFactory<F, F{std::erfc}>::Create("erfc"),
FolderFactory<F, F{common::ErfcScaled}>::Create("erfc_scaled"),
FolderFactory<F, F{std::exp}>::Create("exp"),
FolderFactory<F, F{std::tgamma}>::Create("gamma"),
FolderFactory<F, F{std::log}>::Create("log"),
Expand Down
45 changes: 33 additions & 12 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2861,12 +2861,22 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
}
} else if (!IsInteroperableIntrinsicType(
*type, &context.languageFeatures())
.value_or(true) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type %s"_warn_en_US,
type->AsFortran());
.value_or(true)) {
if (type->category() == TypeCategory::Character &&
type->kind() == 1) {
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::CharacterInteroperability)) {
context.messages().Say(
common::UsageWarning::CharacterInteroperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable character length %s"_warn_en_US,
type->AsFortran());
}
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type or kind %s"_warn_en_US,
type->AsFortran());
}
}
if (ExtractCoarrayRef(*expr)) {
context.messages().Say(at,
Expand Down Expand Up @@ -2963,12 +2973,23 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
context.messages().Say(arguments[0]->sourceLocation(),
"C_LOC() argument may not be zero-length character"_err_en_US);
} else if (typeAndShape->type().category() != TypeCategory::Derived &&
!IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable intrinsic type, kind, or length"_warn_en_US);
!IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true)) {
if (typeAndShape->type().category() == TypeCategory::Character &&
typeAndShape->type().kind() == 1) {
// Default character kind, but length is not known to be 1
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::CharacterInteroperability)) {
context.messages().Say(
common::UsageWarning::CharacterInteroperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable character length"_warn_en_US);
}
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable intrinsic type or kind"_warn_en_US);
}
}

characteristics::DummyDataObject ddo{std::move(*typeAndShape)};
Expand Down
16 changes: 14 additions & 2 deletions flang/lib/Evaluate/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1320,8 +1320,10 @@ std::optional<Expr<SomeType>> HollerithToBOZ(FoldingContext &context,

// Extracts a whole symbol being used as a bound of a dummy argument,
// possibly wrapped with parentheses or MAX(0, ...).
// Works with any integer expression.
template <typename T> const Symbol *GetBoundSymbol(const Expr<T> &);
template <int KIND>
static const Symbol *GetBoundSymbol(
const Symbol *GetBoundSymbol(
const Expr<Type<TypeCategory::Integer, KIND>> &expr) {
using T = Type<TypeCategory::Integer, KIND>;
return common::visit(
Expand Down Expand Up @@ -1358,9 +1360,15 @@ static const Symbol *GetBoundSymbol(
},
expr.u);
}
template <>
const Symbol *GetBoundSymbol<SomeInteger>(const Expr<SomeInteger> &expr) {
return common::visit(
[](const auto &kindExpr) { return GetBoundSymbol(kindExpr); }, expr.u);
}

template <typename T>
std::optional<bool> AreEquivalentInInterface(
const Expr<SubscriptInteger> &x, const Expr<SubscriptInteger> &y) {
const Expr<T> &x, const Expr<T> &y) {
auto xVal{ToInt64(x)};
auto yVal{ToInt64(y)};
if (xVal && yVal) {
Expand Down Expand Up @@ -1394,6 +1402,10 @@ std::optional<bool> AreEquivalentInInterface(
return std::nullopt; // not sure
}
}
template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
const Expr<SubscriptInteger> &, const Expr<SubscriptInteger> &);
template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
const Expr<SomeInteger> &, const Expr<SomeInteger> &);

bool CheckForCoindexedObject(parser::ContextualMessages &messages,
const std::optional<ActualArgument> &arg, const std::string &procName,
Expand Down
5 changes: 4 additions & 1 deletion flang/lib/Evaluate/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,10 @@ static bool AreSameDerivedType(

bool DynamicType::IsEquivalentTo(const DynamicType &that) const {
return category_ == that.category_ && kind_ == that.kind_ &&
PointeeComparison(charLengthParamValue_, that.charLengthParamValue_) &&
(charLengthParamValue_ == that.charLengthParamValue_ ||
(charLengthParamValue_ && that.charLengthParamValue_ &&
charLengthParamValue_->IsEquivalentInInterface(
*that.charLengthParamValue_))) &&
knownLength().has_value() == that.knownLength().has_value() &&
(!knownLength() || *knownLength() == *that.knownLength()) &&
AreSameDerivedType(derived_, that.derived_);
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Optimizer/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_flang_library(FIRTransforms
HLFIRDialect
MLIRAffineUtils
MLIRFuncDialect
MLIRGPUDialect
MLIRLLVMDialect
MLIRLLVMCommonConversion
MLIRMathTransforms
Expand Down
20 changes: 18 additions & 2 deletions flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Runtime/entry-names.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Pass/Pass.h"
#include "llvm/ADT/SmallVector.h"
Expand All @@ -23,6 +24,8 @@ namespace fir {

namespace {

static constexpr llvm::StringRef cudaModName{"cuda_device_mod"};

static constexpr llvm::StringRef cudaFortranCtorName{
"__cudaFortranConstructor"};

Expand All @@ -31,6 +34,7 @@ struct CUFAddConstructor

void runOnOperation() override {
mlir::ModuleOp mod = getOperation();
mlir::SymbolTable symTab(mod);
mlir::OpBuilder builder{mod.getBodyRegion()};
builder.setInsertionPointToEnd(mod.getBody());
mlir::Location loc = mod.getLoc();
Expand All @@ -48,13 +52,25 @@ struct CUFAddConstructor
mod.getContext(), RTNAME_STRING(CUFRegisterAllocator));
builder.setInsertionPointToEnd(mod.getBody());

// Create the constructor function that cal CUFRegisterAllocator.
builder.setInsertionPointToEnd(mod.getBody());
// Create the constructor function that call CUFRegisterAllocator.
auto func = builder.create<mlir::LLVM::LLVMFuncOp>(loc, cudaFortranCtorName,
funcTy);
func.setLinkage(mlir::LLVM::Linkage::Internal);
builder.setInsertionPointToStart(func.addEntryBlock(builder));
builder.create<mlir::LLVM::CallOp>(loc, funcTy, cufRegisterAllocatorRef);

// Register kernels
auto gpuMod = symTab.lookup<mlir::gpu::GPUModuleOp>(cudaModName);
if (gpuMod) {
for (auto func : gpuMod.getOps<mlir::gpu::GPUFuncOp>()) {
if (func.isKernel()) {
auto kernelName = mlir::SymbolRefAttr::get(
builder.getStringAttr(cudaModName),
{mlir::SymbolRefAttr::get(builder.getContext(), func.getName())});
builder.create<cuf::RegisterKernelOp>(loc, kernelName);
}
}
}
builder.create<mlir::LLVM::ReturnOp>(loc, mlir::ValueRange{});

// Create the llvm.global_ctor with the function.
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Parser/parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
messages_, *currentCooked_, preprocessor_, options.features};
prescanner.set_fixedForm(options.isFixedForm)
.set_fixedFormColumnLimit(options.fixedFormColumns)
.set_preprocessingOnly(options.prescanAndReformat)
.set_expandIncludeLines(!options.prescanAndReformat ||
options.expandIncludeLinesInPreprocessedOutput)
.AddCompilerDirectiveSentinel("dir$");
Expand Down
8 changes: 5 additions & 3 deletions flang/lib/Parser/prescan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Prescanner::Prescanner(const Prescanner &that, Preprocessor &prepro,
bool isNestedInIncludeDirective)
: messages_{that.messages_}, cooked_{that.cooked_}, preprocessor_{prepro},
allSources_{that.allSources_}, features_{that.features_},
preprocessingOnly_{that.preprocessingOnly_},
expandIncludeLines_{that.expandIncludeLines_},
isNestedInIncludeDirective_{isNestedInIncludeDirective},
backslashFreeFormContinuation_{that.backslashFreeFormContinuation_},
inFixedForm_{that.inFixedForm_},
Expand Down Expand Up @@ -288,8 +290,8 @@ void Prescanner::Statement() {
break;
case LineClassification::Kind::Source:
if (inFixedForm_) {
if (preprocessed->HasBlanks(/*after column*/ 6)) {
preprocessed->RemoveBlanks(/*after column*/ 6);
if (!preprocessingOnly_ && preprocessed->HasBlanks()) {
preprocessed->RemoveBlanks();
}
} else {
while (SourceLineContinuation(*preprocessed)) {
Expand Down Expand Up @@ -622,7 +624,7 @@ const char *Prescanner::SkipCComment(const char *p) const {

bool Prescanner::NextToken(TokenSequence &tokens) {
CHECK(at_ >= start_ && at_ < limit_);
if (InFixedFormSource()) {
if (InFixedFormSource() && !preprocessingOnly_) {
SkipSpaces();
} else {
if (*at_ == '/' && IsCComment(at_)) {
Expand Down
5 changes: 5 additions & 0 deletions flang/lib/Parser/prescan.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class Prescanner {
Preprocessor &preprocessor() { return preprocessor_; }
common::LanguageFeatureControl &features() { return features_; }

Prescanner &set_preprocessingOnly(bool yes) {
preprocessingOnly_ = yes;
return *this;
}
Prescanner &set_expandIncludeLines(bool yes) {
expandIncludeLines_ = yes;
return *this;
Expand Down Expand Up @@ -213,6 +217,7 @@ class Prescanner {
Preprocessor &preprocessor_;
AllSources &allSources_;
common::LanguageFeatureControl features_;
bool preprocessingOnly_{false};
bool expandIncludeLines_{true};
bool isNestedInIncludeDirective_{false};
bool backslashFreeFormContinuation_{false};
Expand Down
27 changes: 26 additions & 1 deletion flang/lib/Semantics/rewrite-parse-tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ using namespace parser::literals;
class RewriteMutator {
public:
RewriteMutator(SemanticsContext &context)
: errorOnUnresolvedName_{!context.AnyFatalError()},
: context_{context}, errorOnUnresolvedName_{!context.AnyFatalError()},
messages_{context.messages()} {}

// Default action for a parse tree node is to visit children.
Expand All @@ -42,6 +42,7 @@ class RewriteMutator {
void Post(parser::Name &);
void Post(parser::SpecificationPart &);
bool Pre(parser::ExecutionPart &);
bool Pre(parser::ActionStmt &);
void Post(parser::ReadStmt &);
void Post(parser::WriteStmt &);

Expand All @@ -66,6 +67,7 @@ class RewriteMutator {
private:
using stmtFuncType =
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>;
SemanticsContext &context_;
bool errorOnUnresolvedName_{true};
parser::Messages &messages_;
std::list<stmtFuncType> stmtFuncsToConvert_;
Expand Down Expand Up @@ -130,6 +132,29 @@ bool RewriteMutator::Pre(parser::ExecutionPart &x) {
return true;
}

// Rewrite PRINT NML -> WRITE(*,NML=NML)
bool RewriteMutator::Pre(parser::ActionStmt &x) {
if (auto *print{std::get_if<common::Indirection<parser::PrintStmt>>(&x.u)};
print &&
std::get<std::list<parser::OutputItem>>(print->value().t).empty()) {
auto &format{std::get<parser::Format>(print->value().t)};
if (std::holds_alternative<parser::Expr>(format.u)) {
if (auto *name{parser::Unwrap<parser::Name>(format)}; name &&
name->symbol && name->symbol->GetUltimate().has<NamelistDetails>() &&
context_.IsEnabled(common::LanguageFeature::PrintNamelist)) {
context_.Warn(common::LanguageFeature::PrintNamelist, name->source,
"nonstandard: namelist in PRINT statement"_port_en_US);
std::list<parser::IoControlSpec> controls;
controls.emplace_back(std::move(*name));
x.u = common::Indirection<parser::WriteStmt>::Make(
parser::IoUnit{parser::Star{}}, std::optional<parser::Format>{},
std::move(controls), std::list<parser::OutputItem>{});
}
}
}
return true;
}

// When a namelist group name appears (without NML=) in a READ or WRITE
// statement in such a way that it can be misparsed as a format expression,
// rewrite the I/O statement's parse tree node as if the namelist group
Expand Down
6 changes: 6 additions & 0 deletions flang/lib/Semantics/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,12 @@ void ParamValue::SetExplicit(SomeIntExpr &&x) {
expr_ = std::move(x);
}

bool ParamValue::IsEquivalentInInterface(const ParamValue &that) const {
return (category_ == that.category_ &&
expr_.has_value() == that.expr_.has_value() &&
(!expr_ || evaluate::AreEquivalentInInterface(*expr_, *that.expr_)));
}

std::string ParamValue::AsFortran() const {
switch (category_) {
SWITCH_COVERS_ALL_CASES
Expand Down
102 changes: 2 additions & 100 deletions flang/runtime/numeric-templates.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "terminator.h"
#include "tools.h"
#include "flang/Common/api-attrs.h"
#include "flang/Common/erfc-scaled.h"
#include "flang/Common/float128.h"
#include <cstdint>
#include <limits>
Expand Down Expand Up @@ -362,106 +363,7 @@ template <int PREC, typename T> inline RT_API_ATTRS T Spacing(T x) {

// ERFC_SCALED (16.9.71)
template <typename T> inline RT_API_ATTRS T ErfcScaled(T arg) {
// Coefficients for approximation to erfc in the first interval.
static const T a[5] = {3.16112374387056560e00, 1.13864154151050156e02,
3.77485237685302021e02, 3.20937758913846947e03, 1.85777706184603153e-1};
static const T b[4] = {2.36012909523441209e01, 2.44024637934444173e02,
1.28261652607737228e03, 2.84423683343917062e03};

// Coefficients for approximation to erfc in the second interval.
static const T c[9] = {5.64188496988670089e-1, 8.88314979438837594e00,
6.61191906371416295e01, 2.98635138197400131e02, 8.81952221241769090e02,
1.71204761263407058e03, 2.05107837782607147e03, 1.23033935479799725e03,
2.15311535474403846e-8};
static const T d[8] = {1.57449261107098347e01, 1.17693950891312499e02,
5.37181101862009858e02, 1.62138957456669019e03, 3.29079923573345963e03,
4.36261909014324716e03, 3.43936767414372164e03, 1.23033935480374942e03};

// Coefficients for approximation to erfc in the third interval.
static const T p[6] = {3.05326634961232344e-1, 3.60344899949804439e-1,
1.25781726111229246e-1, 1.60837851487422766e-2, 6.58749161529837803e-4,
1.63153871373020978e-2};
static const T q[5] = {2.56852019228982242e00, 1.87295284992346047e00,
5.27905102951428412e-1, 6.05183413124413191e-2, 2.33520497626869185e-3};

constexpr T sqrtpi{1.7724538509078120380404576221783883301349L};
constexpr T rsqrtpi{0.5641895835477562869480794515607725858440L};
constexpr T epsilonby2{std::numeric_limits<T>::epsilon() * 0.5};
constexpr T xneg{-26.628e0};
constexpr T xhuge{6.71e7};
constexpr T thresh{0.46875e0};
constexpr T zero{0.0};
constexpr T one{1.0};
constexpr T four{4.0};
constexpr T sixteen{16.0};
constexpr T xmax{1.0 / (sqrtpi * std::numeric_limits<T>::min())};
static_assert(xmax > xhuge, "xmax must be greater than xhuge");

T ysq;
T xnum;
T xden;
T del;
T result;

auto x{arg};
auto y{std::fabs(x)};

if (y <= thresh) {
// evaluate erf for |x| <= 0.46875
ysq = zero;
if (y > epsilonby2) {
ysq = y * y;
}
xnum = a[4] * ysq;
xden = ysq;
for (int i{0}; i < 3; i++) {
xnum = (xnum + a[i]) * ysq;
xden = (xden + b[i]) * ysq;
}
result = x * (xnum + a[3]) / (xden + b[3]);
result = one - result;
result = std::exp(ysq) * result;
return result;
} else if (y <= four) {
// evaluate erfc for 0.46875 < |x| <= 4.0
xnum = c[8] * y;
xden = y;
for (int i{0}; i < 7; ++i) {
xnum = (xnum + c[i]) * y;
xden = (xden + d[i]) * y;
}
result = (xnum + c[7]) / (xden + d[7]);
} else {
// evaluate erfc for |x| > 4.0
result = zero;
if (y >= xhuge) {
if (y < xmax) {
result = rsqrtpi / y;
}
} else {
ysq = one / (y * y);
xnum = p[5] * ysq;
xden = ysq;
for (int i{0}; i < 4; ++i) {
xnum = (xnum + p[i]) * ysq;
xden = (xden + q[i]) * ysq;
}
result = ysq * (xnum + p[4]) / (xden + q[4]);
result = (rsqrtpi - result) / y;
}
}
// fix up for negative argument, erf, etc.
if (x < zero) {
if (x < xneg) {
result = std::numeric_limits<T>::max();
} else {
ysq = trunc(x * sixteen) / sixteen;
del = (x - ysq) * (x + ysq);
y = std::exp((ysq * ysq)) * std::exp((del));
result = (y + y) - result;
}
}
return result;
return common::ErfcScaled(arg);
}

} // namespace Fortran::runtime
Expand Down
7 changes: 7 additions & 0 deletions flang/test/Evaluate/fold-erfc-scaled.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
! RUN: %python %S/test_folding.py %s %flang_fc1
module m
real(4), parameter :: x20_4 = erfc_scaled(20._4)
logical, parameter :: t20_4 = x20_4 == 0.02817435003817081451416015625_4
real(8), parameter :: x20_8 = erfc_scaled(20._8)
logical, parameter :: t20_8 = x20_8 == 0.0281743487410513193669459042212110944092273712158203125_8
end
8 changes: 2 additions & 6 deletions flang/test/Fir/CUDA/cuda-register-func.fir
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: fir-opt %s | FileCheck %s
// RUN: fir-opt --cuf-add-constructor %s | FileCheck %s

module attributes {gpu.container_module} {
gpu.module @cuda_device_mod {
Expand All @@ -9,12 +9,8 @@ module attributes {gpu.container_module} {
gpu.return
}
}
llvm.func internal @__cudaFortranConstructor() {
cuf.register_kernel @cuda_device_mod::@_QPsub_device1
cuf.register_kernel @cuda_device_mod::@_QPsub_device2
llvm.return
}
}

// CHECK-LABEL: llvm.func internal @__cudaFortranConstructor()
// CHECK: cuf.register_kernel @cuda_device_mod::@_QPsub_device1
// CHECK: cuf.register_kernel @cuda_device_mod::@_QPsub_device2
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
! RUN: %flang_fc1 -fopenmp -fopenacc -E %s 2>&1 | FileCheck %s
program main
! CHECK: k01=1+1
! CHECK: k01=1+ 1
k01=1+
!$ & 1

Expand Down
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/pp029.F
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: if (777 .eq. 777) then
! CHECK: if (77 7.eq. 777) then
* \ newline allowed in #define
integer, parameter :: KWM = 666
#define KWM 77\
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Preprocessing/pp031.F
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: if (777//Ccomment.eq.777)then
! CHECK: print *, 'pp031.F no: ', 777//Ccomment
! CHECK: if (777 // C comment.eq. 777) then
! CHECK: print *, 'pp031.F no: ', 777 // C comment
* // C++ comment NOT erased from #define
integer, parameter :: KWM = 666
#define KWM 777 // C comment
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/pp041.F
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s 2>&1 | FileCheck %s
! CHECK: j = 666WMj=j+1WM211
! CHECK: j = 666WMj= j+ 1WM211
* use KWM expansion as continuation indicators
#define KWM 0
#define KWM2 1
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Preprocessing/renaming.F
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
! RUN: %flang -E %s | FileCheck %s
! CHECK: ((1)*10000+(11)*100)
! CHECK: ((1) * 10000 + (11) * 100)
! Ensure that a keyword-like macro can be used to rename a
! function-like macro.
#define TO_VERSION2(MAJOR, MINOR) ((MAJOR) * 10000 + (MINOR) * 100)
Expand Down
5 changes: 4 additions & 1 deletion flang/test/Semantics/c_f_pointer.f90
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ program test
end type
type(notBindCType), pointer :: notBindC
character(2), pointer :: c2ptr
character(1,4), pointer :: unicodePtr
rankTwoArray = reshape([1, 2, 3, 4], shape(rankTwoArray))
call c_f_pointer(scalarC, scalarIntF) ! ok
call c_f_pointer(scalarC, arrayIntF, [1_8]) ! ok
Expand Down Expand Up @@ -48,6 +49,8 @@ program test
call c_f_pointer(scalarC, unlimited)
!WARNING: FPTR= argument to C_F_POINTER() should not have a derived type that is not BIND(C)
call c_f_pointer(scalarC, notBindC)
!WARNING: FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type CHARACTER(KIND=1,LEN=2_8)
!WARNING: FPTR= argument to C_F_POINTER() should not have the non-interoperable character length CHARACTER(KIND=1,LEN=2_8)
call c_f_pointer(scalarC, c2ptr)
!WARNING: FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type or kind CHARACTER(KIND=4,LEN=1_8)
call c_f_pointer(scalarC, unicodePtr)
end program
5 changes: 4 additions & 1 deletion flang/test/Semantics/c_loc01.f90
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ subroutine test(assumedType, poly, nclen, n)
type(hasLen(*)), target :: nclen
integer, intent(in) :: n
character(2), target :: ch
character(1,4), target :: unicode
real :: arr1(purefun1(c_loc(targ))) ! ok
real :: arr2(purefun2(c_funloc(subr))) ! ok
character(:), allocatable, target :: deferred
Expand All @@ -40,8 +41,10 @@ subroutine test(assumedType, poly, nclen, n)
cp = c_loc(nclen)
!ERROR: C_LOC() argument may not be zero-length character
cp = c_loc(ch(2:1))
!WARNING: C_LOC() argument has non-interoperable intrinsic type, kind, or length
!WARNING: C_LOC() argument has non-interoperable character length
cp = c_loc(ch)
!WARNING: C_LOC() argument has non-interoperable intrinsic type or kind
cp = c_loc(unicode)
cp = c_loc(ch(1:1)) ! ok
cp = c_loc(deferred) ! ok
cp = c_loc(p2ch) ! ok
Expand Down
8 changes: 8 additions & 0 deletions flang/test/Semantics/rewrite02.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
!RUN: %flang_fc1 -fdebug-unparse -pedantic %s 2>&1 | FileCheck %s
!Test rewrite of "PRINT namelistname" into "WRITE(*,NML=namelistname)"
!CHECK: nonstandard: namelist in PRINT statement
namelist /nml/x
x = 123.
!CHECK: WRITE (*, NML=nml)
print nml
end
23 changes: 23 additions & 0 deletions flang/test/Semantics/smp-def01.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
!RUN: %flang -fsyntax-only %s 2>&1 | FileCheck --allow-empty %s
!Ensure no bogus error message about incompatible character length
!CHECK-NOT: error

module m1
integer :: n = 1
end

module m2
interface
module subroutine s(a,b)
use m1
character(n) :: a
character(n) :: b
end
end interface
end

submodule(m2) m2s1
contains
module procedure s
end
end
13 changes: 13 additions & 0 deletions libc/src/setjmp/setjmp_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,22 @@
// public header setjmp.h which is also included. here.
#include "hdr/types/jmp_buf.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/compiler.h"

namespace LIBC_NAMESPACE_DECL {

// TODO(https://github.com/llvm/llvm-project/issues/112427)
// Some of the architecture-specific definitions are marked `naked`, which in
// GCC implies `nothrow`.
//
// Right now, our aliases aren't marked `nothrow`, so we wind up in a situation
// where clang will emit -Wmissing-exception-spec if we add `nothrow` here, but
// GCC will emit -Wmissing-attributes here without `nothrow`. We need to update
// LLVM_LIBC_FUNCTION to denote when a function throws or not.

#ifdef LIBC_COMPILER_IS_GCC
[[gnu::nothrow]]
#endif
int setjmp(jmp_buf buf);

} // namespace LIBC_NAMESPACE_DECL
Expand Down
2 changes: 1 addition & 1 deletion libc/src/setjmp/x86_64/setjmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
namespace LIBC_NAMESPACE_DECL {

[[gnu::naked]]
LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
asm(R"(
mov %%rbx, %c[rbx](%%rdi)
mov %%rbp, %c[rbp](%%rdi)
Expand Down
4 changes: 2 additions & 2 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,7 @@ void LinkerDriver::maybeCreateECExportThunk(StringRef name, Symbol *&sym) {
if (!sym)
return;
if (auto undef = dyn_cast<Undefined>(sym))
def = undef->getWeakAlias();
def = undef->getDefinedWeakAlias();
else
def = dyn_cast<Defined>(sym);
if (!def)
Expand Down Expand Up @@ -1376,7 +1376,7 @@ void LinkerDriver::createECExportThunks() {
continue;
Defined *targetSym;
if (auto undef = dyn_cast<Undefined>(sym))
targetSym = undef->getWeakAlias();
targetSym = undef->getDefinedWeakAlias();
else
targetSym = dyn_cast<Defined>(sym);
if (!targetSym)
Expand Down
8 changes: 4 additions & 4 deletions lld/COFF/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,20 @@ DefinedImportThunk::DefinedImportThunk(COFFLinkerContext &ctx, StringRef name,
ImportThunkChunk *chunk)
: Defined(DefinedImportThunkKind, name), wrappedSym(s), data(chunk) {}

Defined *Undefined::getWeakAlias() {
Symbol *Undefined::getWeakAlias() {
// A weak alias may be a weak alias to another symbol, so check recursively.
DenseSet<Symbol *> weakChain;
for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias) {
if (auto *d = dyn_cast<Defined>(a))
return d;
if (!isa<Undefined>(a))
return a;
if (!weakChain.insert(a).second)
break; // We have a cycle.
}
return nullptr;
}

bool Undefined::resolveWeakAlias() {
Defined *d = getWeakAlias();
Defined *d = getDefinedWeakAlias();
if (!d)
return false;

Expand Down
5 changes: 4 additions & 1 deletion lld/COFF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ class Undefined : public Symbol {
// If this symbol is external weak, try to resolve it to a defined
// symbol by searching the chain of fallback symbols. Returns the symbol if
// successful, otherwise returns null.
Defined *getWeakAlias();
Symbol *getWeakAlias();
Defined *getDefinedWeakAlias() {
return dyn_cast_or_null<Defined>(getWeakAlias());
}

// If this symbol is external weak, replace this object with aliased symbol.
bool resolveWeakAlias();
Expand Down
18 changes: 18 additions & 0 deletions lld/test/COFF/weak-lazy.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# REQUIRES: x86

# RUN: llvm-mc -filetype=obj -triple=i686-windows %s -o %t.obj
# RUN: llvm-lib -machine:x86 -out:%t-func.lib %t.obj

# -export:func creates a weak alias to a lazy symbol. Make sure we can handle that when processing -export:func2=func.
# RUN: lld-link -dll -noentry -machine:x86 -out:%t.dll %t-func.lib -export:func -export:func2=func

.text
.def @feat.00;
.scl 3;
.type 0;
.endef
.globl @feat.00
.set @feat.00, 1
.globl _func@0
_func@0:
retl
13 changes: 13 additions & 0 deletions lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
lldb_tablegen(DynamicLoaderDarwinProperties.inc -gen-lldb-property-defs
SOURCE DynamicLoaderDarwinProperties.td
TARGET LLDBPluginDynamicLoaderDarwinPropertiesGen)

lldb_tablegen(DynamicLoaderDarwinPropertiesEnum.inc -gen-lldb-property-enum-defs
SOURCE DynamicLoaderDarwinProperties.td
TARGET LLDBPluginDynamicLoaderDarwinPropertiesEnumGen)

add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN
DynamicLoaderMacOSXDYLD.cpp
DynamicLoaderMacOS.cpp
DynamicLoaderDarwin.cpp
DynamicLoaderDarwinProperties.cpp

LINK_LIBS
lldbBreakpoint
Expand All @@ -16,3 +25,7 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN
Support
TargetParser
)

add_dependencies(lldbPluginDynamicLoaderMacOSXDYLD
LLDBPluginDynamicLoaderDarwinPropertiesGen
LLDBPluginDynamicLoaderDarwinPropertiesEnumGen)
102 changes: 72 additions & 30 deletions lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "DynamicLoaderDarwin.h"

#include "DynamicLoaderDarwinProperties.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
Expand All @@ -31,6 +32,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
#include "llvm/Support/ThreadPool.h"

#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
Expand Down Expand Up @@ -77,6 +79,17 @@ void DynamicLoaderDarwin::DidLaunch() {
SetNotificationBreakpoint();
}

void DynamicLoaderDarwin::CreateSettings(lldb_private::Debugger &debugger) {
if (!PluginManager::GetSettingForDynamicLoaderPlugin(
debugger, DynamicLoaderDarwinProperties::GetSettingName())) {
const bool is_global_setting = true;
PluginManager::CreateSettingForDynamicLoaderPlugin(
debugger,
DynamicLoaderDarwinProperties::GetGlobal().GetValueProperties(),
"Properties for the DynamicLoaderDarwin plug-in.", is_global_setting);
}
}

// Clear out the state of this class.
void DynamicLoaderDarwin::Clear(bool clear_process) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
Expand All @@ -88,7 +101,7 @@ void DynamicLoaderDarwin::Clear(bool clear_process) {
}

ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
ImageInfo &image_info, bool can_create, bool *did_create_ptr) {
const ImageInfo &image_info, bool can_create, bool *did_create_ptr) {
if (did_create_ptr)
*did_create_ptr = false;

Expand Down Expand Up @@ -517,44 +530,43 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo(
return true;
}

void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos(
ImageInfo::collection &image_infos) {
void DynamicLoaderDarwin::UpdateSpecialBinariesFromPreloadedModules(
std::vector<std::pair<ImageInfo, ModuleSP>> &images) {
uint32_t exe_idx = UINT32_MAX;
uint32_t dyld_idx = UINT32_MAX;
Target &target = m_process->GetTarget();
Log *log = GetLog(LLDBLog::DynamicLoader);
ConstString g_dyld_sim_filename("dyld_sim");

ArchSpec target_arch = target.GetArchitecture();
const size_t image_infos_size = image_infos.size();
for (size_t i = 0; i < image_infos_size; i++) {
if (image_infos[i].header.filetype == llvm::MachO::MH_DYLINKER) {
const size_t images_size = images.size();
for (size_t i = 0; i < images_size; i++) {
const auto &image_info = images[i].first;
if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) {
// In a "simulator" process we will have two dyld modules --
// a "dyld" that we want to keep track of, and a "dyld_sim" which
// we don't need to keep track of here. dyld_sim will have a non-macosx
// OS.
if (target_arch.GetTriple().getEnvironment() == llvm::Triple::Simulator &&
image_infos[i].os_type != llvm::Triple::OSType::MacOSX) {
image_info.os_type != llvm::Triple::OSType::MacOSX) {
continue;
}

dyld_idx = i;
}
if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) {
if (image_info.header.filetype == llvm::MachO::MH_EXECUTE) {
exe_idx = i;
}
}

// Set the target executable if we haven't found one so far.
if (exe_idx != UINT32_MAX && !target.GetExecutableModule()) {
const bool can_create = true;
ModuleSP exe_module_sp(FindTargetModuleForImageInfo(image_infos[exe_idx],
can_create, nullptr));
ModuleSP exe_module_sp = images[exe_idx].second;
if (exe_module_sp) {
LLDB_LOGF(log, "Found executable module: %s",
exe_module_sp->GetFileSpec().GetPath().c_str());
target.GetImages().AppendIfNeeded(exe_module_sp);
UpdateImageLoadAddress(exe_module_sp.get(), image_infos[exe_idx]);
UpdateImageLoadAddress(exe_module_sp.get(), images[exe_idx].first);
if (exe_module_sp.get() != target.GetExecutableModulePointer())
target.SetExecutableModule(exe_module_sp, eLoadDependentsNo);

Expand All @@ -581,14 +593,12 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos(
}

if (dyld_idx != UINT32_MAX) {
const bool can_create = true;
ModuleSP dyld_sp = FindTargetModuleForImageInfo(image_infos[dyld_idx],
can_create, nullptr);
ModuleSP dyld_sp = images[dyld_idx].second;
if (dyld_sp.get()) {
LLDB_LOGF(log, "Found dyld module: %s",
dyld_sp->GetFileSpec().GetPath().c_str());
target.GetImages().AppendIfNeeded(dyld_sp);
UpdateImageLoadAddress(dyld_sp.get(), image_infos[dyld_idx]);
UpdateImageLoadAddress(dyld_sp.get(), images[dyld_idx].first);
SetDYLDModule(dyld_sp);
}
}
Expand Down Expand Up @@ -642,26 +652,58 @@ ModuleSP DynamicLoaderDarwin::GetDYLDModule() {

void DynamicLoaderDarwin::ClearDYLDModule() { m_dyld_module_wp.reset(); }

std::vector<std::pair<DynamicLoaderDarwin::ImageInfo, ModuleSP>>
DynamicLoaderDarwin::PreloadModulesFromImageInfos(
const ImageInfo::collection &image_infos) {
const auto size = image_infos.size();
std::vector<std::pair<DynamicLoaderDarwin::ImageInfo, ModuleSP>> images(size);
auto LoadImage = [&](size_t i, ImageInfo::collection::const_iterator it) {
const auto &image_info = *it;
images[i] = std::make_pair(
image_info, FindTargetModuleForImageInfo(image_info, true, nullptr));
};
auto it = image_infos.begin();
bool is_parallel_load =
DynamicLoaderDarwinProperties::GetGlobal().GetEnableParallelImageLoad();
if (is_parallel_load) {
llvm::ThreadPoolTaskGroup taskGroup(Debugger::GetThreadPool());
for (size_t i = 0; i < size; ++i, ++it) {
taskGroup.async(LoadImage, i, it);
}
taskGroup.wait();
} else {
for (size_t i = 0; i < size; ++i, ++it) {
LoadImage(i, it);
}
}
return images;
}

bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
ImageInfo::collection &image_infos) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
auto images = PreloadModulesFromImageInfos(image_infos);
return AddModulesUsingPreloadedModules(images);
}

bool DynamicLoaderDarwin::AddModulesUsingPreloadedModules(
std::vector<std::pair<ImageInfo, ModuleSP>> &images) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Now add these images to the main list.
ModuleList loaded_module_list;
Log *log = GetLog(LLDBLog::DynamicLoader);
Target &target = m_process->GetTarget();
ModuleList &target_images = target.GetImages();

for (uint32_t idx = 0; idx < image_infos.size(); ++idx) {
for (uint32_t idx = 0; idx < images.size(); ++idx) {
auto &image_info = images[idx].first;
const auto &image_module_sp = images[idx].second;
if (log) {
LLDB_LOGF(log, "Adding new image at address=0x%16.16" PRIx64 ".",
image_infos[idx].address);
image_infos[idx].PutToLog(log);
image_info.address);
image_info.PutToLog(log);
}

m_dyld_image_infos.push_back(image_infos[idx]);

ModuleSP image_module_sp(
FindTargetModuleForImageInfo(image_infos[idx], true, nullptr));
m_dyld_image_infos.push_back(image_info);

if (image_module_sp) {
ObjectFile *objfile = image_module_sp->GetObjectFile();
Expand All @@ -673,7 +715,7 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
sections->FindSectionByName(commpage_dbstr).get();
if (commpage_section) {
ModuleSpec module_spec(objfile->GetFileSpec(),
image_infos[idx].GetArchitecture());
image_info.GetArchitecture());
module_spec.GetObjectName() = commpage_dbstr;
ModuleSP commpage_image_module_sp(
target_images.FindFirstModule(module_spec));
Expand All @@ -686,17 +728,17 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
if (!commpage_image_module_sp ||
commpage_image_module_sp->GetObjectFile() == nullptr) {
commpage_image_module_sp = m_process->ReadModuleFromMemory(
image_infos[idx].file_spec, image_infos[idx].address);
image_info.file_spec, image_info.address);
// Always load a memory image right away in the target in case
// we end up trying to read the symbol table from memory... The
// __LINKEDIT will need to be mapped so we can figure out where
// the symbol table bits are...
bool changed = false;
UpdateImageLoadAddress(commpage_image_module_sp.get(),
image_infos[idx]);
image_info);
target.GetImages().Append(commpage_image_module_sp);
if (changed) {
image_infos[idx].load_stop_id = m_process->GetStopID();
image_info.load_stop_id = m_process->GetStopID();
loaded_module_list.AppendIfNeeded(commpage_image_module_sp);
}
}
Expand All @@ -709,14 +751,14 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
// address. We need to check this so we don't mention that all loaded
// shared libraries are newly loaded each time we hit out dyld breakpoint
// since dyld will list all shared libraries each time.
if (UpdateImageLoadAddress(image_module_sp.get(), image_infos[idx])) {
if (UpdateImageLoadAddress(image_module_sp.get(), image_info)) {
target_images.AppendIfNeeded(image_module_sp);
loaded_module_list.AppendIfNeeded(image_module_sp);
}

// To support macCatalyst and legacy iOS simulator,
// update the module's platform with the DYLD info.
ArchSpec dyld_spec = image_infos[idx].GetArchitecture();
ArchSpec dyld_spec = image_info.GetArchitecture();
auto &dyld_triple = dyld_spec.GetTriple();
if ((dyld_triple.getEnvironment() == llvm::Triple::MacABI &&
dyld_triple.getOS() == llvm::Triple::IOS) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {

std::optional<lldb_private::Address> GetStartAddress() override;

static void CreateSettings(lldb_private::Debugger &debugger);

protected:
void PrivateInitialize(lldb_private::Process *process);

Expand Down Expand Up @@ -174,7 +176,7 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {

bool UnloadModuleSections(lldb_private::Module *module, ImageInfo &info);

lldb::ModuleSP FindTargetModuleForImageInfo(ImageInfo &image_info,
lldb::ModuleSP FindTargetModuleForImageInfo(const ImageInfo &image_info,
bool can_create,
bool *did_create_ptr);

Expand All @@ -201,11 +203,18 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
lldb_private::StructuredData::ObjectSP image_details,
ImageInfo::collection &image_infos);

// If image_infos contains / may contain dyld or executable image, call this
// method
// to keep our internal record keeping of the special binaries up-to-date.
void
UpdateSpecialBinariesFromNewImageInfos(ImageInfo::collection &image_infos);
// Finds/loads modules for a given `image_infos` and returns pairs
// (ImageInfo, ModuleSP).
// Prefer using this method rather than calling `FindTargetModuleForImageInfo`
// directly as this method may load the modules in parallel.
std::vector<std::pair<ImageInfo, lldb::ModuleSP>>
PreloadModulesFromImageInfos(const ImageInfo::collection &image_infos);

// If `images` contains / may contain dyld or executable image, call this
// method to keep our internal record keeping of the special binaries
// up-to-date.
void UpdateSpecialBinariesFromPreloadedModules(
std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images);

// if image_info is a dyld binary, call this method
bool UpdateDYLDImageInfoFromNewImageInfo(ImageInfo &image_info);
Expand All @@ -215,6 +224,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
void AddExecutableModuleIfInImageInfos(ImageInfo::collection &image_infos);

bool AddModulesUsingImageInfos(ImageInfo::collection &image_infos);
bool AddModulesUsingPreloadedModules(
std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images);

// Whether we should use the new dyld SPI to get shared library information,
// or read
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===-- DynamicLoaderDarwinProperties.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "DynamicLoaderDarwinProperties.h"

using namespace lldb_private;

#define LLDB_PROPERTIES_dynamicloaderdarwin_experimental
#include "DynamicLoaderDarwinProperties.inc"

enum {
#define LLDB_PROPERTIES_dynamicloaderdarwin_experimental
#include "DynamicLoaderDarwinPropertiesEnum.inc"
};

llvm::StringRef DynamicLoaderDarwinProperties::GetSettingName() {
static constexpr llvm::StringLiteral g_setting_name("darwin");
return g_setting_name;
}

DynamicLoaderDarwinProperties::ExperimentalProperties::ExperimentalProperties()
: Properties(std::make_shared<OptionValueProperties>(
GetExperimentalSettingsName())) {
m_collection_sp->Initialize(g_dynamicloaderdarwin_experimental_properties);
}

DynamicLoaderDarwinProperties::DynamicLoaderDarwinProperties()
: Properties(std::make_shared<OptionValueProperties>(GetSettingName())),
m_experimental_properties(std::make_unique<ExperimentalProperties>()) {
m_collection_sp->AppendProperty(
Properties::GetExperimentalSettingsName(),
"Experimental settings - setting these won't produce errors if the "
"setting is not present.",
true, m_experimental_properties->GetValueProperties());
}

bool DynamicLoaderDarwinProperties::GetEnableParallelImageLoad() const {
return m_experimental_properties->GetPropertyAtIndexAs<bool>(
ePropertyEnableParallelImageLoad,
g_dynamicloaderdarwin_experimental_properties
[ePropertyEnableParallelImageLoad]
.default_uint_value != 0);
}

DynamicLoaderDarwinProperties &DynamicLoaderDarwinProperties::GetGlobal() {
static DynamicLoaderDarwinProperties g_settings;
return g_settings;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- DynamicLoaderDarwinProperties.h -------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H
#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H

#include "lldb/Core/UserSettingsController.h"

namespace lldb_private {

class DynamicLoaderDarwinProperties : public Properties {
public:
class ExperimentalProperties : public Properties {
public:
ExperimentalProperties();
};
static llvm::StringRef GetSettingName();
static DynamicLoaderDarwinProperties &GetGlobal();
DynamicLoaderDarwinProperties();
~DynamicLoaderDarwinProperties() override = default;
bool GetEnableParallelImageLoad() const;

private:
std::unique_ptr<ExperimentalProperties> m_experimental_properties;
};

} // namespace lldb_private

#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include "../../../../include/lldb/Core/PropertiesBase.td"

let Definition = "dynamicloaderdarwin_experimental" in {
def EnableParallelImageLoad: Property<"enable-parallel-image-load", "Boolean">,
Global,
DefaultTrue,
Desc<"Load images in parallel.">;
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,9 @@ void DynamicLoaderMacOS::DoInitialImageFetch() {
LLDB_LOGF(log, "Initial module fetch: Adding %" PRId64 " modules.\n",
(uint64_t)image_infos.size());

UpdateSpecialBinariesFromNewImageInfos(image_infos);
AddModulesUsingImageInfos(image_infos);
auto images = PreloadModulesFromImageInfos(image_infos);
UpdateSpecialBinariesFromPreloadedModules(images);
AddModulesUsingPreloadedModules(images);
}
}

Expand Down Expand Up @@ -425,8 +426,9 @@ void DynamicLoaderMacOS::AddBinaries(
->GetAsArray()
->GetSize() == load_addresses.size()) {
if (JSONImageInformationIntoImageInfo(binaries_info_sp, image_infos)) {
UpdateSpecialBinariesFromNewImageInfos(image_infos);
AddModulesUsingImageInfos(image_infos);
auto images = PreloadModulesFromImageInfos(image_infos);
UpdateSpecialBinariesFromPreloadedModules(images);
AddModulesUsingPreloadedModules(images);
}
m_dyld_image_infos_stop_id = m_process->GetStopID();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,9 @@ bool DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress(
->GetSize() == image_infos_count) {
bool return_value = false;
if (JSONImageInformationIntoImageInfo(image_infos_json_sp, image_infos)) {
UpdateSpecialBinariesFromNewImageInfos(image_infos);
return_value = AddModulesUsingImageInfos(image_infos);
auto images = PreloadModulesFromImageInfos(image_infos);
UpdateSpecialBinariesFromPreloadedModules(images);
return_value = AddModulesUsingPreloadedModules(images);
}
m_dyld_image_infos_stop_id = m_process->GetStopID();
return return_value;
Expand Down Expand Up @@ -1147,7 +1148,8 @@ bool DynamicLoaderMacOSXDYLD::IsFullyInitialized() {

void DynamicLoaderMacOSXDYLD::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance);
GetPluginDescriptionStatic(), CreateInstance,
DebuggerInitialize);
DynamicLoaderMacOS::Initialize();
}

Expand All @@ -1156,6 +1158,11 @@ void DynamicLoaderMacOSXDYLD::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}

void DynamicLoaderMacOSXDYLD::DebuggerInitialize(
lldb_private::Debugger &debugger) {
CreateSettings(debugger);
}

llvm::StringRef DynamicLoaderMacOSXDYLD::GetPluginDescriptionStatic() {
return "Dynamic loader plug-in that watches for shared library loads/unloads "
"in MacOSX user processes.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoaderDarwin {
static lldb_private::DynamicLoader *
CreateInstance(lldb_private::Process *process, bool force);

static void DebuggerInitialize(lldb_private::Debugger &debugger);

/// Called after attaching a process.
///
/// Allow DynamicLoader plug-ins to execute some code after
Expand Down
6 changes: 5 additions & 1 deletion lldb/test/API/lang/cpp/stl/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
CXX_SOURCES := main.cpp

USE_SYSTEM_STDLIB := 1
ifneq ($(OS),Darwin)
USE_LIBSTDCPP := 1
else
USE_SYSTEM_STDLIB := 1
endif

include Makefile.rules
5 changes: 4 additions & 1 deletion lldb/test/API/lang/cpp/stl/TestStdCXXDisassembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ def test_stdcxx_disasm(self):
# At this point, lib_stdcxx is the full path to the stdc++ library and
# module is the corresponding SBModule.

self.expect(lib_stdcxx, "Library StdC++ is located", exe=False, substrs=["lib"])
if "lib" not in lib_stdcxx:
self.skipTest(
"This test requires libstdc++.so or libc++.dylib in the target's module list."
)

self.runCmd("image dump symtab '%s'" % lib_stdcxx)
raw_output = self.res.GetOutput()
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,6 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath,
Log << " [" << Idx << "]: " << gii.Name << " @ " << gii.Dir
<< '/' << gii.Base << ':' << gii.Line << '\n';
}
DwarfInlineInfos = DICtx.getInliningInfoForAddress(SectAddr, DLIS);
Gsym->dump(Log, *FI);
}
continue;
Expand Down
11 changes: 0 additions & 11 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1718,17 +1718,6 @@ 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
10 changes: 0 additions & 10 deletions llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3851,13 +3851,3 @@ SIRegisterInfo::getSubRegAlignmentNumBits(const TargetRegisterClass *RC,
}
return 0;
}

SmallVector<StringLiteral>
SIRegisterInfo::getVRegFlagsOfReg(Register Reg,
const MachineFunction &MF) const {
SmallVector<StringLiteral> RegFlags;
const SIMachineFunctionInfo *FuncInfo = MF.getInfo<SIMachineFunctionInfo>();
if (FuncInfo->checkFlag(Reg, AMDGPU::VirtRegFlag::WWM_REG))
RegFlags.push_back("WWM_REG");
return RegFlags;
}
8 changes: 0 additions & 8 deletions llvm/lib/Target/AMDGPU/SIRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,6 @@ class SIRegisterInfo final : public AMDGPUGenRegisterInfo {
// No check if the subreg is supported by the current RC is made.
unsigned getSubRegAlignmentNumBits(const TargetRegisterClass *RC,
unsigned SubReg) const;

std::optional<uint8_t> getVRegFlagValue(StringRef Name) const override {
return Name == "WWM_REG" ? AMDGPU::VirtRegFlag::WWM_REG
: std::optional<uint8_t>{};
}

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

namespace AMDGPU {
Expand Down
54 changes: 13 additions & 41 deletions llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1291,62 +1291,35 @@ bool PPCAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
llvm_unreachable("Implement any new match types added!");
}

#define GET_REGISTER_MATCHER
#include "PPCGenAsmMatcher.inc"

MCRegister PPCAsmParser::matchRegisterName(int64_t &IntVal) {
if (getParser().getTok().is(AsmToken::Percent))
getParser().Lex(); // Eat the '%'.

if (!getParser().getTok().is(AsmToken::Identifier))
return MCRegister();

MCRegister RegNo;
StringRef Name = getParser().getTok().getString();
MCRegister RegNo = MatchRegisterName(Name);
if (!RegNo)
return RegNo;

Name.substr(Name.find_first_of("1234567890")).getAsInteger(10, IntVal);

// MatchRegisterName doesn't seem to have special handling for 64bit vs 32bit
// register types.
if (Name.equals_insensitive("lr")) {
RegNo = isPPC64() ? PPC::LR8 : PPC::LR;
IntVal = 8;
} else if (Name.equals_insensitive("ctr")) {
RegNo = isPPC64() ? PPC::CTR8 : PPC::CTR;
IntVal = 9;
} else if (Name.equals_insensitive("vrsave")) {
RegNo = PPC::VRSAVE;
} else if (Name.equals_insensitive("vrsave"))
IntVal = 256;
} else if (Name.starts_with_insensitive("r") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
else if (Name.starts_with_insensitive("r"))
RegNo = isPPC64() ? XRegs[IntVal] : RRegs[IntVal];
} else if (Name.starts_with_insensitive("f") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = FRegs[IntVal];
} else if (Name.starts_with_insensitive("vs") &&
!Name.substr(2).getAsInteger(10, IntVal) && IntVal < 64) {
RegNo = VSRegs[IntVal];
} else if (Name.starts_with_insensitive("v") &&
!Name.substr(1).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = VRegs[IntVal];
} else if (Name.starts_with_insensitive("cr") &&
!Name.substr(2).getAsInteger(10, IntVal) && IntVal < 8) {
RegNo = CRRegs[IntVal];
} else if (Name.starts_with_insensitive("acc") &&
!Name.substr(3).getAsInteger(10, IntVal) && IntVal < 8) {
RegNo = ACCRegs[IntVal];
} else if (Name.starts_with_insensitive("wacc_hi") &&
!Name.substr(7).getAsInteger(10, IntVal) && IntVal < 8) {
RegNo = ACCRegs[IntVal];
} else if (Name.starts_with_insensitive("wacc") &&
!Name.substr(4).getAsInteger(10, IntVal) && IntVal < 8) {
RegNo = WACCRegs[IntVal];
} else if (Name.starts_with_insensitive("dmrrowp") &&
!Name.substr(7).getAsInteger(10, IntVal) && IntVal < 32) {
RegNo = DMRROWpRegs[IntVal];
} else if (Name.starts_with_insensitive("dmrrow") &&
!Name.substr(6).getAsInteger(10, IntVal) && IntVal < 64) {
RegNo = DMRROWRegs[IntVal];
} else if (Name.starts_with_insensitive("dmrp") &&
!Name.substr(4).getAsInteger(10, IntVal) && IntVal < 4) {
RegNo = DMRROWpRegs[IntVal];
} else if (Name.starts_with_insensitive("dmr") &&
!Name.substr(3).getAsInteger(10, IntVal) && IntVal < 8) {
RegNo = DMRRegs[IntVal];
} else
return MCRegister();

getParser().Lex();
return RegNo;
Expand Down Expand Up @@ -1874,7 +1847,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCAsmParser() {
RegisterMCAsmParser<PPCAsmParser> D(getThePPC64LETarget());
}

#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#define GET_MNEMONIC_SPELL_CHECKER
#include "PPCGenAsmMatcher.inc"
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/PowerPC/PPC.td
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,8 @@ def PPCAsmWriter : AsmWriter {
}

def PPCAsmParser : AsmParser {
let ShouldEmitMatchRegisterName = 0;
let ShouldEmitMatchRegisterName = 1;
let AllowDuplicateRegisterNames = 1;
}

def PPCAsmParserVariant : AsmParserVariant {
Expand Down
20 changes: 7 additions & 13 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,6 @@ getFloorFullVectorNumberOfElements(const TargetTransformInfo &TTI, Type *Ty,
if (NumParts == 0 || NumParts >= Sz)
return bit_floor(Sz);
unsigned RegVF = bit_ceil(divideCeil(Sz, NumParts));
if (RegVF > Sz)
return bit_floor(Sz);
return (Sz / RegVF) * RegVF;
}

Expand Down Expand Up @@ -19073,16 +19071,18 @@ class HorizontalReduction {

unsigned ReduxWidth = NumReducedVals;
if (!VectorizeNonPowerOf2 || !has_single_bit(ReduxWidth + 1))
ReduxWidth = getFloorFullVectorNumberOfElements(
*TTI, Candidates.front()->getType(), ReduxWidth);
ReduxWidth = bit_floor(ReduxWidth);
ReduxWidth = std::min(ReduxWidth, MaxElts);

unsigned Start = 0;
unsigned Pos = Start;
// Restarts vectorization attempt with lower vector factor.
unsigned PrevReduxWidth = ReduxWidth;
bool CheckForReusedReductionOpsLocal = false;
auto AdjustReducedVals = [&](bool IgnoreVL = false) {
auto &&AdjustReducedVals = [&Pos, &Start, &ReduxWidth, NumReducedVals,
&CheckForReusedReductionOpsLocal,
&PrevReduxWidth, &V,
&IgnoreList](bool IgnoreVL = false) {
bool IsAnyRedOpGathered = !IgnoreVL && V.isAnyGathered(IgnoreList);
if (!CheckForReusedReductionOpsLocal && PrevReduxWidth == ReduxWidth) {
// Check if any of the reduction ops are gathered. If so, worth
Expand All @@ -19093,10 +19093,7 @@ class HorizontalReduction {
if (Pos < NumReducedVals - ReduxWidth + 1)
return IsAnyRedOpGathered;
Pos = Start;
--ReduxWidth;
if (ReduxWidth > 1)
ReduxWidth = getFloorFullVectorNumberOfElements(
*TTI, Candidates.front()->getType(), ReduxWidth);
ReduxWidth = bit_ceil(ReduxWidth) / 2;
return IsAnyRedOpGathered;
};
bool AnyVectorized = false;
Expand Down Expand Up @@ -19328,10 +19325,7 @@ class HorizontalReduction {
}
Pos += ReduxWidth;
Start = Pos;
ReduxWidth = NumReducedVals - Pos;
if (ReduxWidth > 1)
ReduxWidth = getFloorFullVectorNumberOfElements(
*TTI, Candidates.front()->getType(), NumReducedVals - Pos);
ReduxWidth = llvm::bit_floor(NumReducedVals - Pos);
AnyVectorized = true;
}
if (OptReusedScalars && !AnyVectorized) {
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Transforms/Vectorize/VPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,16 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
MayWriteToMemory(CI.mayWriteToMemory()),
MayHaveSideEffects(CI.mayHaveSideEffects()) {}

VPWidenIntrinsicRecipe(Intrinsic::ID VectorIntrinsicID,
ArrayRef<VPValue *> CallArguments, Type *Ty,
bool MayReadFromMemory, bool MayWriteToMemory,
bool MayHaveSideEffects, DebugLoc DL = {})
: VPRecipeWithIRFlags(VPDef::VPWidenIntrinsicSC, CallArguments),
VectorIntrinsicID(VectorIntrinsicID), ResultTy(Ty),
MayReadFromMemory(MayReadFromMemory),
MayWriteToMemory(MayWriteToMemory),
MayHaveSideEffects(MayHaveSideEffects) {}

~VPWidenIntrinsicRecipe() override = default;

VPWidenIntrinsicRecipe *clone() override {
Expand Down Expand Up @@ -1706,6 +1716,8 @@ class VPWidenIntrinsicRecipe : public VPRecipeWithIRFlags {
void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
#endif

bool onlyFirstLaneUsed(const VPValue *Op) const override;
};

/// A recipe for widening Call instructions using library calls.
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
case Instruction::ICmp:
case VPInstruction::ActiveLaneMask:
return inferScalarType(R->getOperand(1));
case VPInstruction::ExplicitVectorLength:
return Type::getIntNTy(Ctx, 32);
case VPInstruction::FirstOrderRecurrenceSplice:
case VPInstruction::Not:
return SetResultTyFromOp();
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ bool VPRecipeBase::mayWriteToMemory() const {
return !cast<VPWidenCallRecipe>(this)
->getCalledScalarFunction()
->onlyReadsMemory();
case VPWidenIntrinsicSC:
return cast<VPWidenIntrinsicRecipe>(this)->mayWriteToMemory();
case VPBranchOnMaskSC:
case VPScalarIVStepsSC:
Expand Down Expand Up @@ -1042,6 +1041,14 @@ StringRef VPWidenIntrinsicRecipe::getIntrinsicName() const {
return Intrinsic::getBaseName(VectorIntrinsicID);
}

bool VPWidenIntrinsicRecipe::onlyFirstLaneUsed(const VPValue *Op) const {
assert(is_contained(operands(), Op) && "Op must be an operand of the recipe");
// Vector predication intrinsics only demand the the first lane the last
// operand (the EVL operand).
return VPIntrinsic::isVPIntrinsic(VectorIntrinsicID) &&
Op == getOperand(getNumOperands() - 1);
}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void VPWidenIntrinsicRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,7 @@ void VPlanTransforms::addActiveLaneMask(
/// Replace recipes with their EVL variants.
static void transformRecipestoEVLRecipes(VPlan &Plan, VPValue &EVL) {
SmallVector<VPValue *> HeaderMasks = collectAllHeaderMasks(Plan);
VPTypeAnalysis TypeInfo(Plan.getCanonicalIV()->getScalarType());
for (VPValue *HeaderMask : collectAllHeaderMasks(Plan)) {
for (VPUser *U : collectUsersRecursively(HeaderMask)) {
auto *CurRecipe = dyn_cast<VPRecipeBase>(U);
Expand Down Expand Up @@ -1384,6 +1385,14 @@ static void transformRecipestoEVLRecipes(VPlan &Plan, VPValue &EVL) {
VPValue *NewMask = GetNewMask(Red->getCondOp());
return new VPReductionEVLRecipe(*Red, EVL, NewMask);
})
.Case<VPWidenSelectRecipe>([&](VPWidenSelectRecipe *Sel) {
SmallVector<VPValue *> Ops(Sel->operands());
Ops.push_back(&EVL);
return new VPWidenIntrinsicRecipe(Intrinsic::vp_select, Ops,
TypeInfo.inferScalarType(Sel),
false, false, false);
})

.Default([&](VPRecipeBase *R) { return nullptr; });

if (!NewRecipe)
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ bool VPlanVerifier::verifyEVLRecipe(const VPInstruction &EVL) const {
};
for (const VPUser *U : EVL.users()) {
if (!TypeSwitch<const VPUser *, bool>(U)
.Case<VPWidenIntrinsicRecipe>(
[&](const VPWidenIntrinsicRecipe *S) {
return VerifyEVLUse(*S, S->getNumOperands() - 1);
})
.Case<VPWidenStoreEVLRecipe>([&](const VPWidenStoreEVLRecipe *S) {
return VerifyEVLUse(*S, 2);
})
Expand Down
15 changes: 0 additions & 15 deletions llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir
Original file line number Diff line number Diff line change
Expand Up @@ -578,18 +578,3 @@ body: |
SI_RETURN

...
---
name: vregs
# FULL: registers:
# FULL-NEXT: - { id: 0, class: vgpr_32, preferred-register: '$vgpr1', flags: [ WWM_REG ] }
# FULL-NEXT: - { id: 1, class: sgpr_64, preferred-register: '$sgpr0_sgpr1', flags: [ ] }
# FULL-NEXT: - { id: 2, class: sgpr_64, preferred-register: '', flags: [ ] }
registers:
- { id: 0, class: vgpr_32, preferred-register: $vgpr1, flags: [ WWM_REG ]}
- { id: 1, class: sgpr_64, preferred-register: $sgpr0_sgpr1 }
- { id: 2, class: sgpr_64, flags: [ ] }
body: |
bb.0:
%2:sgpr_64 = COPY %1
%1:sgpr_64 = COPY %0
...
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ define i32 @cond_add(ptr %a, i64 %n, i32 %start) {
; IF-EVL-INLOOP-NEXT: [[TMP18:%.*]] = getelementptr inbounds i32, ptr [[TMP17]], i32 0
; IF-EVL-INLOOP-NEXT: [[VP_OP_LOAD:%.*]] = call <vscale x 4 x i32> @llvm.vp.load.nxv4i32.p0(ptr align 4 [[TMP18]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer), i32 [[TMP12]])
; IF-EVL-INLOOP-NEXT: [[TMP19:%.*]] = icmp sgt <vscale x 4 x i32> [[VP_OP_LOAD]], shufflevector (<vscale x 4 x i32> insertelement (<vscale x 4 x i32> poison, i32 3, i64 0), <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer)
; IF-EVL-INLOOP-NEXT: [[TMP20:%.*]] = select <vscale x 4 x i1> [[TMP19]], <vscale x 4 x i32> [[VP_OP_LOAD]], <vscale x 4 x i32> zeroinitializer
; IF-EVL-INLOOP-NEXT: [[TMP20:%.*]] = call <vscale x 4 x i32> @llvm.vp.select.nxv4i32(<vscale x 4 x i1> [[TMP19]], <vscale x 4 x i32> [[VP_OP_LOAD]], <vscale x 4 x i32> zeroinitializer, i32 [[TMP12]])
; IF-EVL-INLOOP-NEXT: [[TMP21:%.*]] = call i32 @llvm.vp.reduce.add.nxv4i32(i32 0, <vscale x 4 x i32> [[TMP20]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer), i32 [[TMP12]])
; IF-EVL-INLOOP-NEXT: [[TMP22]] = add i32 [[TMP21]], [[VEC_PHI]]
; IF-EVL-INLOOP-NEXT: [[TMP23:%.*]] = zext i32 [[TMP12]] to i64
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
; REQUIRES: asserts

; RUN: opt -passes=loop-vectorize -debug-only=loop-vectorize \
; RUN: -force-tail-folding-style=data-with-evl \
; RUN: -prefer-predicate-over-epilogue=predicate-dont-vectorize \
; RUN: -mtriple=riscv64 -mattr=+v -riscv-v-vector-bits-max=128 -disable-output < %s 2>&1 | FileCheck --check-prefix=IF-EVL %s

define void @vp_select(ptr noalias %a, ptr noalias %b, ptr noalias %c, i64 %N) {
; IF-EVL: VPlan 'Final VPlan for VF={vscale x 1,vscale x 2,vscale x 4},UF={1}' {
; IF-EVL-NEXT: Live-in vp<[[VFUF:%[0-9]+]]> = VF * UF
; IF-EVL-NEXT: Live-in vp<[[VTC:%[0-9]+]]> = vector-trip-count
; IF-EVL-NEXT: Live-in ir<%N> = original trip-count

; IF-EVL: vector.ph:
; IF-EVL-NEXT: Successor(s): vector loop

; IF-EVL: <x1> vector loop: {
; IF-EVL-NEXT: vector.body:
; IF-EVL-NEXT: EMIT vp<[[IV:%[0-9]+]]> = CANONICAL-INDUCTION
; IF-EVL-NEXT: EXPLICIT-VECTOR-LENGTH-BASED-IV-PHI vp<[[EVL_PHI:%[0-9]+]]> = phi ir<0>, vp<[[IV_NEX:%[0-9]+]]>
; IF-EVL-NEXT: EMIT vp<[[AVL:%.+]]> = sub ir<%N>, vp<[[EVL_PHI]]>
; IF-EVL-NEXT: EMIT vp<[[EVL:%.+]]> = EXPLICIT-VECTOR-LENGTH vp<[[AVL]]>
; IF-EVL-NEXT: vp<[[ST:%[0-9]+]]> = SCALAR-STEPS vp<[[EVL_PHI]]>, ir<1>
; IF-EVL-NEXT: CLONE ir<[[GEP1:%.+]]> = getelementptr inbounds ir<%b>, vp<[[ST]]>
; IF-EVL-NEXT: vp<[[PTR1:%[0-9]+]]> = vector-pointer ir<[[GEP1]]>
; IF-EVL-NEXT: WIDEN ir<[[LD1:%.+]]> = vp.load vp<[[PTR1]]>, vp<[[EVL]]>
; IF-EVL-NEXT: CLONE ir<[[GEP2:%.+]]> = getelementptr inbounds ir<%c>, vp<[[ST]]>
; IF-EVL-NEXT: vp<[[PTR2:%[0-9]+]]> = vector-pointer ir<[[GEP2]]>
; IF-EVL-NEXT: WIDEN ir<[[LD2:%.+]]> = vp.load vp<[[PTR2]]>, vp<[[EVL]]>
; IF-EVL-NEXT: WIDEN ir<[[CMP:%.+]]> = icmp sgt ir<[[LD1]]>, ir<[[LD2]]>
; IF-EVL-NEXT: WIDEN ir<[[SUB:%.+]]> = vp.sub ir<0>, ir<[[LD2]]>, vp<[[EVL]]>
; IF-EVL-NEXT: WIDEN-INTRINSIC vp<[[SELECT:%.+]]> = call llvm.vp.select(ir<[[CMP]]>, ir<%1>, ir<%2>, vp<[[EVL]]>)
; IF-EVL-NEXT: WIDEN ir<[[ADD:%.+]]> = vp.add vp<[[SELECT]]>, ir<[[LD1]]>, vp<[[EVL]]>
; IF-EVL-NEXT: CLONE ir<[[GEP3:%.+]]> = getelementptr inbounds ir<%a>, vp<[[ST]]>
; IF-EVL-NEXT: vp<[[PTR3:%.+]]> = vector-pointer ir<[[GEP3]]>
; IF-EVL-NEXT: WIDEN vp.store vp<[[PTR3]]>, ir<[[ADD]]>, vp<[[EVL]]>
; IF-EVL-NEXT: SCALAR-CAST vp<[[CAST:%[0-9]+]]> = zext vp<[[EVL]]> to i64
; IF-EVL-NEXT: EMIT vp<[[IV_NEX]]> = add vp<[[CAST]]>, vp<[[EVL_PHI]]>
; IF-EVL-NEXT: EMIT vp<[[IV_NEXT_EXIT:%[0-9]+]]> = add vp<[[IV]]>, vp<[[VFUF]]>
; IF-EVL-NEXT: EMIT branch-on-count vp<[[IV_NEXT_EXIT]]>, vp<[[VTC]]>
; IF-EVL-NEXT: No successors
; IF-EVL-NEXT: }

entry:
br label %for.body

for.body:
%indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %entry ]
%arrayidx = getelementptr inbounds i32, ptr %b, i64 %indvars.iv
%0 = load i32, ptr %arrayidx, align 4
%arrayidx3 = getelementptr inbounds i32, ptr %c, i64 %indvars.iv
%1 = load i32, ptr %arrayidx3, align 4
%cmp4 = icmp sgt i32 %0, %1
%2 = sub i32 0, %1
%cond.p = select i1 %cmp4, i32 %1, i32 %2
%cond = add i32 %cond.p, %0
%arrayidx15 = getelementptr inbounds i32, ptr %a, i64 %indvars.iv
store i32 %cond, ptr %arrayidx15, align 4
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%exitcond.not = icmp eq i64 %indvars.iv.next, %N
br i1 %exitcond.not, label %exit, label %for.body

exit:
ret void
}
Loading