Skip to content

Commit 294c5cb

Browse files
jayfoadnikic
andauthored
[IR] Add TargetExtType::CanBeLocal property (#99016)
Add a property to allow marking target extension types that cannot be used in an alloca instruction or byval argument, similar to CanBeGlobal for global variables. --------- Co-authored-by: Nikita Popov <[email protected]>
1 parent ef20644 commit 294c5cb

File tree

6 files changed

+112
-13
lines changed

6 files changed

+112
-13
lines changed

clang/test/CodeGen/amdgpu-barrier-type-debug-info.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
// CHECK: name: "__amdgpu_named_workgroup_barrier_t",{{.*}}baseType: ![[BT:[0-9]+]]
55
// CHECK: [[BT]] = !DIBasicType(name: "__amdgpu_named_workgroup_barrier_t", size: 128, encoding: DW_ATE_unsigned)
66
void test_locals(void) {
7-
__amdgpu_named_workgroup_barrier_t k0;
7+
__amdgpu_named_workgroup_barrier_t *k0;
88
}

llvm/include/llvm/IR/DerivedTypes.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ class StructType : public Type {
228228
SCDB_NotContainsScalableVector = 32,
229229
SCDB_ContainsNonGlobalTargetExtType = 64,
230230
SCDB_NotContainsNonGlobalTargetExtType = 128,
231+
SCDB_ContainsNonLocalTargetExtType = 64,
232+
SCDB_NotContainsNonLocalTargetExtType = 128,
231233
};
232234

233235
/// For a named struct that actually has a name, this is a pointer to the
@@ -302,6 +304,12 @@ class StructType : public Type {
302304
containsNonGlobalTargetExtType(SmallPtrSetImpl<const Type *> &Visited) const;
303305
using Type::containsNonGlobalTargetExtType;
304306

307+
/// Return true if this type is or contains a target extension type that
308+
/// disallows being used as a local.
309+
bool
310+
containsNonLocalTargetExtType(SmallPtrSetImpl<const Type *> &Visited) const;
311+
using Type::containsNonLocalTargetExtType;
312+
305313
/// Returns true if this struct contains homogeneous scalable vector types.
306314
/// Note that the definition of homogeneous scalable vector type is not
307315
/// recursive here. That means the following structure will return false
@@ -798,6 +806,9 @@ class TargetExtType : public Type {
798806
HasZeroInit = 1U << 0,
799807
/// This type may be used as the value type of a global variable.
800808
CanBeGlobal = 1U << 1,
809+
/// This type may be allocated on the stack, either as the allocated type
810+
/// of an alloca instruction or as a byval function parameter.
811+
CanBeLocal = 1U << 2,
801812
};
802813

803814
/// Returns true if the target extension type contains the given property.

llvm/include/llvm/IR/Type.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,12 @@ class Type {
215215
containsNonGlobalTargetExtType(SmallPtrSetImpl<const Type *> &Visited) const;
216216
bool containsNonGlobalTargetExtType() const;
217217

218+
/// Return true if this type is or contains a target extension type that
219+
/// disallows being used as a local.
220+
bool
221+
containsNonLocalTargetExtType(SmallPtrSetImpl<const Type *> &Visited) const;
222+
bool containsNonLocalTargetExtType() const;
223+
218224
/// Return true if this is a FP type or a vector of FP.
219225
bool isFPOrFPVectorTy() const { return getScalarType()->isFloatingPointTy(); }
220226

llvm/lib/IR/Type.cpp

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ bool Type::containsNonGlobalTargetExtType() const {
8888
return containsNonGlobalTargetExtType(Visited);
8989
}
9090

91+
bool Type::containsNonLocalTargetExtType(
92+
SmallPtrSetImpl<const Type *> &Visited) const {
93+
if (const auto *ATy = dyn_cast<ArrayType>(this))
94+
return ATy->getElementType()->containsNonLocalTargetExtType(Visited);
95+
if (const auto *STy = dyn_cast<StructType>(this))
96+
return STy->containsNonLocalTargetExtType(Visited);
97+
if (auto *TT = dyn_cast<TargetExtType>(this))
98+
return !TT->hasProperty(TargetExtType::CanBeLocal);
99+
return false;
100+
}
101+
102+
bool Type::containsNonLocalTargetExtType() const {
103+
SmallPtrSet<const Type *, 4> Visited;
104+
return containsNonLocalTargetExtType(Visited);
105+
}
106+
91107
const fltSemantics &Type::getFltSemantics() const {
92108
switch (getTypeID()) {
93109
case HalfTyID: return APFloat::IEEEhalf();
@@ -469,6 +485,34 @@ bool StructType::containsNonGlobalTargetExtType(
469485
return false;
470486
}
471487

488+
bool StructType::containsNonLocalTargetExtType(
489+
SmallPtrSetImpl<const Type *> &Visited) const {
490+
if ((getSubclassData() & SCDB_ContainsNonLocalTargetExtType) != 0)
491+
return true;
492+
493+
if ((getSubclassData() & SCDB_NotContainsNonLocalTargetExtType) != 0)
494+
return false;
495+
496+
if (!Visited.insert(this).second)
497+
return false;
498+
499+
for (Type *Ty : elements()) {
500+
if (Ty->containsNonLocalTargetExtType(Visited)) {
501+
const_cast<StructType *>(this)->setSubclassData(
502+
getSubclassData() | SCDB_ContainsNonLocalTargetExtType);
503+
return true;
504+
}
505+
}
506+
507+
// For structures that are opaque, return false but do not set the
508+
// SCDB_NotContainsNonLocalTargetExtType flag since it may gain non-local
509+
// target extension types when it becomes non-opaque.
510+
if (!isOpaque())
511+
const_cast<StructType *>(this)->setSubclassData(
512+
getSubclassData() | SCDB_NotContainsNonLocalTargetExtType);
513+
return false;
514+
}
515+
472516
bool StructType::containsHomogeneousScalableVectorTypes() const {
473517
if (getNumElements() <= 0 || !isa<ScalableVectorType>(elements().front()))
474518
return false;
@@ -922,15 +966,18 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
922966
LLVMContext &C = Ty->getContext();
923967
StringRef Name = Ty->getName();
924968
if (Name == "spirv.Image")
925-
return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal);
969+
return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal,
970+
TargetExtType::CanBeLocal);
926971
if (Name.starts_with("spirv."))
927972
return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::HasZeroInit,
928-
TargetExtType::CanBeGlobal);
973+
TargetExtType::CanBeGlobal,
974+
TargetExtType::CanBeLocal);
929975

930976
// Opaque types in the AArch64 name space.
931977
if (Name == "aarch64.svcount")
932978
return TargetTypeInfo(ScalableVectorType::get(Type::getInt1Ty(C), 16),
933-
TargetExtType::HasZeroInit);
979+
TargetExtType::HasZeroInit,
980+
TargetExtType::CanBeLocal);
934981

935982
// RISC-V vector tuple type. The layout is represented as the type that needs
936983
// the same number of vector registers(VREGS) as this tuple type, represented
@@ -942,12 +989,14 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
942989
RISCV::RVVBitsPerBlock / 8) *
943990
Ty->getIntParameter(0);
944991
return TargetTypeInfo(
945-
ScalableVectorType::get(Type::getInt8Ty(C), TotalNumElts));
992+
ScalableVectorType::get(Type::getInt8Ty(C), TotalNumElts),
993+
TargetExtType::CanBeLocal);
946994
}
947995

948996
// DirectX resources
949997
if (Name.starts_with("dx."))
950-
return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal);
998+
return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal,
999+
TargetExtType::CanBeLocal);
9511000

9521001
// Opaque types in the AMDGPU name space.
9531002
if (Name == "amdgcn.named.barrier") {

llvm/lib/IR/Verifier.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,11 +2026,15 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, Type *Ty,
20262026
"huge alignment values are unsupported", V);
20272027
}
20282028
if (Attrs.hasAttribute(Attribute::ByVal)) {
2029+
Type *ByValTy = Attrs.getByValType();
20292030
SmallPtrSet<Type *, 4> Visited;
2030-
Check(Attrs.getByValType()->isSized(&Visited),
2031+
Check(ByValTy->isSized(&Visited),
20312032
"Attribute 'byval' does not support unsized types!", V);
2032-
Check(DL.getTypeAllocSize(Attrs.getByValType()).getKnownMinValue() <
2033-
(1ULL << 32),
2033+
// Check if it is or contains a target extension type that disallows being
2034+
// used on the stack.
2035+
Check(!ByValTy->containsNonLocalTargetExtType(),
2036+
"'byval' argument has illegal target extension type", V);
2037+
Check(DL.getTypeAllocSize(ByValTy).getKnownMinValue() < (1ULL << 32),
20342038
"huge 'byval' arguments are unsupported", V);
20352039
}
20362040
if (Attrs.hasAttribute(Attribute::ByRef)) {
@@ -4323,9 +4327,13 @@ void Verifier::verifySwiftErrorValue(const Value *SwiftErrorVal) {
43234327
}
43244328

43254329
void Verifier::visitAllocaInst(AllocaInst &AI) {
4330+
Type *Ty = AI.getAllocatedType();
43264331
SmallPtrSet<Type*, 4> Visited;
4327-
Check(AI.getAllocatedType()->isSized(&Visited),
4328-
"Cannot allocate unsized type", &AI);
4332+
Check(Ty->isSized(&Visited), "Cannot allocate unsized type", &AI);
4333+
// Check if it's a target extension type that disallows being used on the
4334+
// stack.
4335+
Check(!Ty->containsNonLocalTargetExtType(),
4336+
"Alloca has illegal target extension type", &AI);
43294337
Check(AI.getArraySize()->getType()->isIntegerTy(),
43304338
"Alloca array size must have integer type", &AI);
43314339
if (MaybeAlign A = AI.getAlign()) {
@@ -4334,8 +4342,7 @@ void Verifier::visitAllocaInst(AllocaInst &AI) {
43344342
}
43354343

43364344
if (AI.isSwiftError()) {
4337-
Check(AI.getAllocatedType()->isPointerTy(),
4338-
"swifterror alloca must have pointer type", &AI);
4345+
Check(Ty->isPointerTy(), "swifterror alloca must have pointer type", &AI);
43394346
Check(!AI.isArrayAllocation(),
43404347
"swifterror alloca must not be array allocation", &AI);
43414348
verifySwiftErrorValue(&AI);

llvm/test/Assembler/target-type-properties.ll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
; RUN: not llvm-as < %t/global-var.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-GLOBAL-VAR %s
44
; RUN: not llvm-as < %t/global-array.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-GLOBAL-ARRAY %s
55
; RUN: not llvm-as < %t/global-struct.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-GLOBAL-STRUCT %s
6+
; RUN: not llvm-as < %t/alloca.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-ALLOCA %s
7+
; RUN: not llvm-as < %t/alloca-struct.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-ALLOCA-STRUCT %s
8+
; RUN: not llvm-as < %t/byval.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BYVAL %s
9+
; RUN: not llvm-as < %t/byval-array.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BYVAL-ARRAY %s
610
; Check target extension type properties are verified in the assembler.
711

812
;--- zeroinit-error.ll
@@ -24,3 +28,25 @@ define void @foo() {
2428
;--- global-struct.ll
2529
@global_struct = external global {target("unknown_target_type")}
2630
; CHECK-GLOBAL-STRUCT: Global @global_struct has illegal target extension type
31+
32+
;--- alloca.ll
33+
define void @foo() {
34+
%val = alloca target("amdgcn.named.barrier", 0)
35+
; CHECK-ALLOCA: Alloca has illegal target extension type
36+
ret void
37+
}
38+
39+
;--- alloca-struct.ll
40+
define void @foo() {
41+
%val = alloca {target("amdgcn.named.barrier", 0), target("amdgcn.named.barrier", 0)}
42+
; CHECK-ALLOCA-STRUCT: Alloca has illegal target extension type
43+
ret void
44+
}
45+
46+
;--- byval.ll
47+
declare void @foo(ptr byval(target("amdgcn.named.barrier", 0)))
48+
; CHECK-BYVAL: 'byval' argument has illegal target extension type
49+
50+
;--- byval-array.ll
51+
declare void @foo(ptr byval([4 x target("amdgcn.named.barrier", 0)]))
52+
; CHECK-BYVAL-ARRAY: 'byval' argument has illegal target extension type

0 commit comments

Comments
 (0)