Skip to content

Commit 2f6e4ed

Browse files
authored
[IR] Check parameters of target extension types on construction (#107268)
Since IR Types are immutable it makes sense to check them on construction instead of in the IR Verifier pass. This patch checks that some TargetExtTypes are well-formed in the sense that they have the expected number of type parameters and integer parameters. When called from LLParser it gives a diagnostic message. When called from anywhere else it just asserts that they are well-formed.
1 parent 56b2be4 commit 2f6e4ed

File tree

5 files changed

+69
-9
lines changed

5 files changed

+69
-9
lines changed

llvm/include/llvm/IR/DerivedTypes.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace llvm {
3232
class Value;
3333
class APInt;
3434
class LLVMContext;
35+
template <typename T> class Expected;
3536

3637
/// Class to represent integer types. Note that this class is also used to
3738
/// represent the built-in integer types: Int1Ty, Int8Ty, Int16Ty, Int32Ty and
@@ -735,6 +736,19 @@ class TargetExtType : public Type {
735736
ArrayRef<Type *> Types = std::nullopt,
736737
ArrayRef<unsigned> Ints = std::nullopt);
737738

739+
/// Return a target extension type having the specified name and optional
740+
/// type and integer parameters, or an appropriate Error if it fails the
741+
/// parameters check.
742+
static Expected<TargetExtType *>
743+
getOrError(LLVMContext &Context, StringRef Name,
744+
ArrayRef<Type *> Types = std::nullopt,
745+
ArrayRef<unsigned> Ints = std::nullopt);
746+
747+
/// Check that a newly created target extension type has the expected number
748+
/// of type parameters and integer parameters, returning the type itself if OK
749+
/// or an appropriate Error if not.
750+
static Expected<TargetExtType *> checkParams(TargetExtType *TTy);
751+
738752
/// Return the name for this target extension type. Two distinct target
739753
/// extension types may have the same name if their type or integer parameters
740754
/// differ.

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3530,7 +3530,12 @@ bool LLParser::parseTargetExtType(Type *&Result) {
35303530
if (parseToken(lltok::rparen, "expected ')' in target extension type"))
35313531
return true;
35323532

3533-
Result = TargetExtType::get(Context, TypeName, TypeParams, IntParams);
3533+
auto TTy =
3534+
TargetExtType::getOrError(Context, TypeName, TypeParams, IntParams);
3535+
if (auto E = TTy.takeError())
3536+
return tokError(toString(std::move(E)));
3537+
3538+
Result = *TTy;
35343539
return false;
35353540
}
35363541

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2679,7 +2679,11 @@ Error BitcodeReader::parseTypeTableBody() {
26792679
return error("Integer parameter too large");
26802680
IntParams.push_back(Record[i]);
26812681
}
2682-
ResultTy = TargetExtType::get(Context, TypeName, TypeParams, IntParams);
2682+
auto TTy =
2683+
TargetExtType::getOrError(Context, TypeName, TypeParams, IntParams);
2684+
if (auto E = TTy.takeError())
2685+
return E;
2686+
ResultTy = *TTy;
26832687
TypeName.clear();
26842688
break;
26852689
}

llvm/lib/IR/Type.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/IR/LLVMContext.h"
2323
#include "llvm/IR/Value.h"
2424
#include "llvm/Support/Casting.h"
25+
#include "llvm/Support/Error.h"
2526
#include "llvm/Support/TypeSize.h"
2627
#include "llvm/Support/raw_ostream.h"
2728
#include "llvm/TargetParser/RISCVTargetParser.h"
@@ -792,28 +793,52 @@ TargetExtType::TargetExtType(LLVMContext &C, StringRef Name,
792793
TargetExtType *TargetExtType::get(LLVMContext &C, StringRef Name,
793794
ArrayRef<Type *> Types,
794795
ArrayRef<unsigned> Ints) {
796+
return cantFail(getOrError(C, Name, Types, Ints));
797+
}
798+
799+
Expected<TargetExtType *> TargetExtType::getOrError(LLVMContext &C,
800+
StringRef Name,
801+
ArrayRef<Type *> Types,
802+
ArrayRef<unsigned> Ints) {
795803
const TargetExtTypeKeyInfo::KeyTy Key(Name, Types, Ints);
796804
TargetExtType *TT;
797805
// Since we only want to allocate a fresh target type in case none is found
798806
// and we don't want to perform two lookups (one for checking if existent and
799807
// one for inserting the newly allocated one), here we instead lookup based on
800808
// Key and update the reference to the target type in-place to a newly
801809
// allocated one if not found.
802-
auto Insertion = C.pImpl->TargetExtTypes.insert_as(nullptr, Key);
803-
if (Insertion.second) {
810+
auto [Iter, Inserted] = C.pImpl->TargetExtTypes.insert_as(nullptr, Key);
811+
if (Inserted) {
804812
// The target type was not found. Allocate one and update TargetExtTypes
805813
// in-place.
806814
TT = (TargetExtType *)C.pImpl->Alloc.Allocate(
807815
sizeof(TargetExtType) + sizeof(Type *) * Types.size() +
808816
sizeof(unsigned) * Ints.size(),
809817
alignof(TargetExtType));
810818
new (TT) TargetExtType(C, Name, Types, Ints);
811-
*Insertion.first = TT;
812-
} else {
813-
// The target type was found. Just return it.
814-
TT = *Insertion.first;
819+
*Iter = TT;
820+
return checkParams(TT);
815821
}
816-
return TT;
822+
823+
// The target type was found. Just return it.
824+
return *Iter;
825+
}
826+
827+
Expected<TargetExtType *> TargetExtType::checkParams(TargetExtType *TTy) {
828+
// Opaque types in the AArch64 name space.
829+
if (TTy->Name == "aarch64.svcount" &&
830+
(TTy->getNumTypeParameters() != 0 || TTy->getNumIntParameters() != 0))
831+
return createStringError(
832+
"target extension type aarch64.svcount should have no parameters");
833+
834+
// Opaque types in the RISC-V name space.
835+
if (TTy->Name == "riscv.vector.tuple" &&
836+
(TTy->getNumTypeParameters() != 1 || TTy->getNumIntParameters() != 1))
837+
return createStringError(
838+
"target extension type riscv.vector.tuple should have one "
839+
"type parameter and one integer parameter");
840+
841+
return TTy;
817842
}
818843

819844
namespace {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; RUN: split-file %s %t
2+
; RUN: not llvm-as < %t/aarch64-svcount.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-AARCH64-SVCOUNT %s
3+
; RUN: not llvm-as < %t/riscv-vector-tuple.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-RISCV-VECTOR-TUPLE %s
4+
; Check target extension type properties are verified in the assembler.
5+
6+
;--- aarch64-svcount.ll
7+
declare target("aarch64.svcount", i32) @aarch64_svcount()
8+
; CHECK-AARCH64-SVCOUNT: error: target extension type aarch64.svcount should have no parameters
9+
10+
;--- riscv-vector-tuple.ll
11+
declare target("riscv.vector.tuple", 99) @riscv_vector_tuple()
12+
; CHECK-RISCV-VECTOR-TUPLE: target extension type riscv.vector.tuple should have one type parameter and one integer parameter

0 commit comments

Comments
 (0)