[OpaquePtr][LLParser] Automatically detect opaque pointers in .ll files

This allows us to not have to specify -opaque-pointers when updating
IR tests from typed pointers to opaque pointers.

We detect opaque pointers in .ll files by looking for relevant tokens,
either "ptr" or "*".

Reviewed By: #opaque-pointers, nikic

Differential Revision: https://reviews.llvm.org/D119482
This commit is contained in:
Arthur Eubanks 2022-02-10 11:56:14 -08:00
parent 6c0af92612
commit 295172ef51
12 changed files with 62 additions and 8 deletions

View File

@ -37,7 +37,7 @@ namespace llvm {
lltok::Kind CurKind; lltok::Kind CurKind;
std::string StrVal; std::string StrVal;
unsigned UIntVal; unsigned UIntVal;
Type *TyVal; Type *TyVal = nullptr;
APFloat APFloatVal; APFloat APFloatVal;
APSInt APSIntVal; APSInt APSIntVal;

View File

@ -95,6 +95,8 @@ namespace llvm {
typedef LLLexer::LocTy LocTy; typedef LLLexer::LocTy LocTy;
private: private:
LLVMContext &Context; LLVMContext &Context;
// Lexer to determine whether to use opaque pointers or not.
LLLexer OPLex;
LLLexer Lex; LLLexer Lex;
// Module being parsed, null if we are only parsing summary index. // Module being parsed, null if we are only parsing summary index.
Module *M; Module *M;
@ -157,8 +159,9 @@ namespace llvm {
LLParser(StringRef F, SourceMgr &SM, SMDiagnostic &Err, Module *M, LLParser(StringRef F, SourceMgr &SM, SMDiagnostic &Err, Module *M,
ModuleSummaryIndex *Index, LLVMContext &Context, ModuleSummaryIndex *Index, LLVMContext &Context,
SlotMapping *Slots = nullptr) SlotMapping *Slots = nullptr)
: Context(Context), Lex(F, SM, Err, Context), M(M), Index(Index), : Context(Context), OPLex(F, SM, Err, Context),
Slots(Slots), BlockAddressPFS(nullptr) {} Lex(F, SM, Err, Context), M(M), Index(Index), Slots(Slots),
BlockAddressPFS(nullptr) {}
bool Run( bool Run(
bool UpgradeDebugInfo, DataLayoutCallbackTy DataLayoutCallback = bool UpgradeDebugInfo, DataLayoutCallbackTy DataLayoutCallback =
[](StringRef) { return None; }); [](StringRef) { return None; });

View File

@ -305,6 +305,9 @@ public:
/// LLVMContext is used by compilation. /// LLVMContext is used by compilation.
void setOptPassGate(OptPassGate&); void setOptPassGate(OptPassGate&);
/// Whether we've decided on using opaque pointers or typed pointers yet.
bool hasSetOpaquePointersValue() const;
/// Enable opaque pointers. Can only be called before creating the first /// Enable opaque pointers. Can only be called before creating the first
/// pointer type. /// pointer type.
void enableOpaquePointers() const; void enableOpaquePointers() const;

View File

@ -860,7 +860,10 @@ lltok::Kind LLLexer::LexIdentifier() {
TYPEKEYWORD("token", Type::getTokenTy(Context)); TYPEKEYWORD("token", Type::getTokenTy(Context));
if (Keyword == "ptr") { if (Keyword == "ptr") {
if (Context.supportsTypedPointers()) { // enableOpaquePointers() must be called before creating any pointer types.
if (!Context.hasSetOpaquePointersValue()) {
Context.enableOpaquePointers();
} else if (Context.supportsTypedPointers()) {
Warning("ptr type is only supported in -opaque-pointers mode"); Warning("ptr type is only supported in -opaque-pointers mode");
return lltok::Error; return lltok::Error;
} }

View File

@ -59,9 +59,29 @@ static std::string getTypeString(Type *T) {
return Tmp.str(); return Tmp.str();
} }
static void setContextOpaquePointers(LLLexer &L, LLVMContext &C) {
while (true) {
lltok::Kind K = L.Lex();
// LLLexer will set the opaque pointers option in LLVMContext if it sees an
// explicit "ptr".
if (K == lltok::star || K == lltok::Error || K == lltok::Eof ||
isa_and_nonnull<PointerType>(L.getTyVal())) {
return;
}
}
}
/// Run: module ::= toplevelentity* /// Run: module ::= toplevelentity*
bool LLParser::Run(bool UpgradeDebugInfo, bool LLParser::Run(bool UpgradeDebugInfo,
DataLayoutCallbackTy DataLayoutCallback) { DataLayoutCallbackTy DataLayoutCallback) {
// If we haven't decided on whether or not we're using opaque pointers, do a
// quick lex over the tokens to see if we explicitly construct any typed or
// opaque pointer types.
// Don't bail out on an error so we do the same work in the parsing below
// regardless of if --opaque-pointers is set.
if (!Context.hasSetOpaquePointersValue())
setContextOpaquePointers(OPLex, Context);
// Prime the lexer. // Prime the lexer.
Lex.Lex(); Lex.Lex();

View File

@ -351,6 +351,10 @@ std::unique_ptr<DiagnosticHandler> LLVMContext::getDiagnosticHandler() {
return std::move(pImpl->DiagHandler); return std::move(pImpl->DiagHandler);
} }
bool LLVMContext::hasSetOpaquePointersValue() const {
return pImpl->hasOpaquePointersValue();
}
void LLVMContext::enableOpaquePointers() const { void LLVMContext::enableOpaquePointers() const {
assert(pImpl->PointerTypes.empty() && pImpl->ASPointerTypes.empty() && assert(pImpl->PointerTypes.empty() && pImpl->ASPointerTypes.empty() &&
"Must be called before creating any pointer types"); "Must be called before creating any pointer types");

View File

@ -47,7 +47,11 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID), X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID),
PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID), PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID),
X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8), X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8),
Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {} Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {
if (OpaquePointersCL.getNumOccurrences()) {
OpaquePointers = OpaquePointersCL;
}
}
LLVMContextImpl::~LLVMContextImpl() { LLVMContextImpl::~LLVMContextImpl() {
// NOTE: We need to delete the contents of OwnedModules, but Module's dtor // NOTE: We need to delete the contents of OwnedModules, but Module's dtor
@ -245,9 +249,13 @@ void LLVMContextImpl::setOptPassGate(OptPassGate& OPG) {
this->OPG = &OPG; this->OPG = &OPG;
} }
bool LLVMContextImpl::hasOpaquePointersValue() {
return OpaquePointers.hasValue();
}
bool LLVMContextImpl::getOpaquePointers() { bool LLVMContextImpl::getOpaquePointers() {
if (LLVM_UNLIKELY(!(OpaquePointers.hasValue()))) if (LLVM_UNLIKELY(!(OpaquePointers.hasValue())))
OpaquePointers = OpaquePointersCL; OpaquePointers = false;
return *OpaquePointers; return *OpaquePointers;
} }

View File

@ -1555,6 +1555,7 @@ public:
// TODO: clean up the following after we no longer support non-opaque pointer // TODO: clean up the following after we no longer support non-opaque pointer
// types. // types.
bool getOpaquePointers(); bool getOpaquePointers();
bool hasOpaquePointersValue();
void setOpaquePointers(bool OP); void setOpaquePointers(bool OP);
private: private:

View File

@ -1,4 +1,4 @@
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s ; RUN: not llvm-as < %s -disable-output --opaque-pointers=0 2>&1 | FileCheck %s
; CHECK: warning: ptr type is only supported in -opaque-pointers mode ; CHECK: warning: ptr type is only supported in -opaque-pointers mode
; CHECK: error: expected type ; CHECK: error: expected type

View File

@ -1,4 +1,4 @@
; RUN: llvm-as --opaque-pointers < %s | not llvm-dis 2>&1 | FileCheck %s ; RUN: llvm-as --opaque-pointers < %s | not llvm-dis --opaque-pointers=0 2>&1 | FileCheck %s
; CHECK: error: Opaque pointers are only supported in -opaque-pointers mode ; CHECK: error: Opaque pointers are only supported in -opaque-pointers mode

View File

@ -0,0 +1,6 @@
; RUN: llvm-as -disable-output %s 2>&1
; FIXME: this should err out saying not to mix `ptr` and `foo*`
define void @f(ptr) {
%a = alloca i32*
ret void
}

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
; CHECK: ptr type is only supported in -opaque-pointers mode
define void @f(i32*) {
%a = alloca ptr
ret void
}