Skip to content

[IR] Disallow recursive types #114799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4386,7 +4386,7 @@ is defined inline with other types (e.g. ``[2 x {i32, i32}]``) whereas
identified types are always defined at the top level with a name.
Literal types are uniqued by their contents and can never be recursive
or opaque since there is no way to write one. Identified types can be
recursive, can be opaqued, and are never uniqued.
opaqued and are never uniqued. Identified types must not be recursive.

:Syntax:

Expand Down
2 changes: 2 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Makes programs 10x faster by doing Special New Thing.
Changes to the LLVM IR
----------------------

* Types are no longer allowed to be recursive.

* The `x86_mmx` IR type has been removed. It will be translated to
the standard vector type `<1 x i64>` in bitcode upgrade.
* Renamed `llvm.experimental.stepvector` intrinsic to `llvm.stepvector`.
Expand Down
12 changes: 11 additions & 1 deletion llvm/include/llvm/IR/DerivedTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Value;
class APInt;
class LLVMContext;
template <typename T> class Expected;
class Error;

/// Class to represent integer types. Note that this class is also used to
/// represent the built-in integer types: Int1Ty, Int8Ty, Int16Ty, Int32Ty and
Expand Down Expand Up @@ -317,9 +318,18 @@ class StructType : public Type {
/// suffix if there is a collision. Do not call this on an literal type.
void setName(StringRef Name);

/// Specify a body for an opaque identified type.
/// Specify a body for an opaque identified type, which must not make the type
/// recursive.
void setBody(ArrayRef<Type*> Elements, bool isPacked = false);

/// Specify a body for an opaque identified type or return an error if it
/// would make the type recursive.
Error setBodyOrError(ArrayRef<Type *> Elements, bool isPacked = false);

/// Return an error if the body for an opaque identified type would make it
/// recursive.
Error checkBody(ArrayRef<Type *> Elements);

template <typename... Tys>
std::enable_if_t<are_base_of<Type, Tys...>::value, void>
setBody(Type *elt1, Tys *... elts) {
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3391,7 +3391,9 @@ bool LLParser::parseStructDefinition(SMLoc TypeLoc, StringRef Name,
(isPacked && parseToken(lltok::greater, "expected '>' in packed struct")))
return true;

STy->setBody(Body, isPacked);
if (auto E = STy->setBodyOrError(Body, isPacked))
return tokError(toString(std::move(E)));

ResultTy = STy;
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2659,7 +2659,8 @@ Error BitcodeReader::parseTypeTableBody() {
}
if (EltTys.size() != Record.size()-1)
return error("Invalid named struct record");
Res->setBody(EltTys, Record[0]);
if (auto E = Res->setBodyOrError(EltTys, Record[0]))
return E;
ContainedIDs.append(Record.begin() + 1, Record.end());
ResultTy = Res;
break;
Expand Down
28 changes: 23 additions & 5 deletions llvm/lib/IR/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "llvm/IR/Type.h"
#include "LLVMContextImpl.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -436,20 +437,37 @@ bool StructType::containsHomogeneousTypes() const {
}

void StructType::setBody(ArrayRef<Type*> Elements, bool isPacked) {
cantFail(setBodyOrError(Elements, isPacked));
}

Error StructType::setBodyOrError(ArrayRef<Type *> Elements, bool isPacked) {
assert(isOpaque() && "Struct body already set!");

if (auto E = checkBody(Elements))
return E;

setSubclassData(getSubclassData() | SCDB_HasBody);
if (isPacked)
setSubclassData(getSubclassData() | SCDB_Packed);

NumContainedTys = Elements.size();
ContainedTys = Elements.empty()
? nullptr
: Elements.copy(getContext().pImpl->Alloc).data();

if (Elements.empty()) {
ContainedTys = nullptr;
return;
}
return Error::success();
}

ContainedTys = Elements.copy(getContext().pImpl->Alloc).data();
Error StructType::checkBody(ArrayRef<Type *> Elements) {
SmallSetVector<Type *, 4> Worklist(Elements.begin(), Elements.end());
for (unsigned I = 0; I < Worklist.size(); ++I) {
Type *Ty = Worklist[I];
if (Ty == this)
return createStringError(Twine("identified structure type '") +
getName() + "' is recursive");
Worklist.insert(Ty->subtype_begin(), Ty->subtype_end());
}
return Error::success();
}

void StructType::setName(StringRef Name) {
Expand Down
22 changes: 12 additions & 10 deletions llvm/lib/Linker/IRMover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
#include <utility>
using namespace llvm;

/// Most of the errors produced by this module are inconvertible StringErrors.
/// This convenience function lets us return one of those more easily.
static Error stringErr(const Twine &T) {
return make_error<StringError>(T, inconvertibleErrorCode());
}

//===----------------------------------------------------------------------===//
// TypeMap implementation.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -69,7 +75,7 @@ class TypeMapTy : public ValueMapTypeRemapper {

/// Produce a body for an opaque type in the dest module from a type
/// definition in the source module.
void linkDefinedTypeBodies();
Error linkDefinedTypeBodies();

/// Return the mapped type to use for the specified input type from the
/// source module.
Expand Down Expand Up @@ -207,7 +213,7 @@ bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) {
return true;
}

void TypeMapTy::linkDefinedTypeBodies() {
Error TypeMapTy::linkDefinedTypeBodies() {
SmallVector<Type *, 16> Elements;
for (StructType *SrcSTy : SrcDefinitionsToResolve) {
StructType *DstSTy = cast<StructType>(MappedTypes[SrcSTy]);
Expand All @@ -218,11 +224,13 @@ void TypeMapTy::linkDefinedTypeBodies() {
for (unsigned I = 0, E = Elements.size(); I != E; ++I)
Elements[I] = get(SrcSTy->getElementType(I));

DstSTy->setBody(Elements, SrcSTy->isPacked());
if (auto E = DstSTy->setBodyOrError(Elements, SrcSTy->isPacked()))
return E;
DstStructTypesSet.switchToNonOpaque(DstSTy);
}
SrcDefinitionsToResolve.clear();
DstResolvedOpaqueTypes.clear();
return Error::success();
}

void TypeMapTy::finishType(StructType *DTy, StructType *STy,
Expand Down Expand Up @@ -439,12 +447,6 @@ class IRLinker {
FoundError = std::move(E);
}

/// Most of the errors produced by this module are inconvertible StringErrors.
/// This convenience function lets us return one of those more easily.
Error stringErr(const Twine &T) {
return make_error<StringError>(T, inconvertibleErrorCode());
}

/// Entry point for mapping values and alternate context for mapping aliases.
ValueMapper Mapper;
unsigned IndirectSymbolMCID;
Expand Down Expand Up @@ -875,7 +877,7 @@ void IRLinker::computeTypeMapping() {

// Now that we have discovered all of the type equivalences, get a body for
// any 'opaque' types in the dest module that are now resolved.
TypeMap.linkDefinedTypeBodies();
setError(TypeMap.linkDefinedTypeBodies());
}

static void getArrayElements(const Constant *C,
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Assembler/mutually-recursive-types.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s

; CHECK: error: identified structure type 'rt3' is recursive

%rt1 = type { i32, { i8, %rt2, i8 }, i32 }
%rt2 = type { i64, { i6, %rt3 } }
%rt3 = type { %rt1 }
6 changes: 1 addition & 5 deletions llvm/test/Assembler/unsized-recursive-type.ll
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
; RUN: not llvm-as < %s 2>&1 | FileCheck %s

; CHECK: base element of getelementptr must be sized
; CHECK: error: identified structure type 'myTy' is recursive

%myTy = type { %myTy }
define void @foo(ptr %p){
getelementptr %myTy, ptr %p, i64 1
ret void
}
7 changes: 2 additions & 5 deletions llvm/test/Linker/pr22807.ll
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
; RUN: llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807-1.ll %p/Inputs/pr22807-2.ll | FileCheck %s
; RUN: not llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807-1.ll %p/Inputs/pr22807-2.ll 2>&1 | FileCheck %s

; CHECK-NOT: type
; CHECK: %struct.B = type { %struct.A }
; CHECK-NEXT: %struct.A = type { %struct.B }
; CHECK-NOT: type
; CHECK: error: identified structure type 'struct.A' is recursive

%struct.B = type { %struct.A }
%struct.A = type opaque
Expand Down
15 changes: 0 additions & 15 deletions llvm/test/Verifier/recursive-struct-param.ll

This file was deleted.

12 changes: 0 additions & 12 deletions llvm/test/Verifier/recursive-type-1.ll

This file was deleted.

14 changes: 0 additions & 14 deletions llvm/test/Verifier/recursive-type-2.ll

This file was deleted.

12 changes: 0 additions & 12 deletions llvm/test/Verifier/recursive-type-load.ll

This file was deleted.

12 changes: 0 additions & 12 deletions llvm/test/Verifier/recursive-type-store.ll

This file was deleted.

2 changes: 1 addition & 1 deletion llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class TargetLibraryInfoTest : public testing::Test {

// Check that we don't accept egregiously incorrect prototypes.
TEST_F(TargetLibraryInfoTest, InvalidProto) {
parseAssembly("%foo = type { %foo }\n");
parseAssembly("%foo = type opaque\n");

auto *StructTy = StructType::getTypeByName(Context, "foo");
auto *InvalidFTy = FunctionType::get(StructTy, /*isVarArg=*/false);
Expand Down
Loading