diff --git a/llvm/include/llvm/AsmParser/LLLexer.h b/llvm/include/llvm/AsmParser/LLLexer.h --- a/llvm/include/llvm/AsmParser/LLLexer.h +++ b/llvm/include/llvm/AsmParser/LLLexer.h @@ -37,7 +37,7 @@ lltok::Kind CurKind; std::string StrVal; unsigned UIntVal; - Type *TyVal; + Type *TyVal = nullptr; APFloat APFloatVal; APSInt APSIntVal; diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h --- a/llvm/include/llvm/AsmParser/LLParser.h +++ b/llvm/include/llvm/AsmParser/LLParser.h @@ -88,6 +88,8 @@ typedef LLLexer::LocTy LocTy; private: LLVMContext &Context; + // Lexer to determine whether to use opaque pointers or not. + LLLexer OPLex; LLLexer Lex; // Module being parsed, null if we are only parsing summary index. Module *M; @@ -150,8 +152,9 @@ LLParser(StringRef F, SourceMgr &SM, SMDiagnostic &Err, Module *M, ModuleSummaryIndex *Index, LLVMContext &Context, SlotMapping *Slots = nullptr) - : Context(Context), Lex(F, SM, Err, Context), M(M), Index(Index), - Slots(Slots), BlockAddressPFS(nullptr) {} + : Context(Context), OPLex(F, SM, Err, Context), + Lex(F, SM, Err, Context), M(M), Index(Index), Slots(Slots), + BlockAddressPFS(nullptr) {} bool Run( bool UpgradeDebugInfo, DataLayoutCallbackTy DataLayoutCallback = [](StringRef) { return None; }); diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -304,13 +304,16 @@ /// LLVMContext is used by compilation. void setOptPassGate(OptPassGate&); - /// Enable opaque pointers. Can only be called before creating the first - /// pointer type. - void enableOpaquePointers() const; - /// Whether typed pointers are supported. If false, all pointers are opaque. bool supportsTypedPointers() const; + /// Whether we've decided to use opaque or typed pointers yet. + /// + /// By default we determine if we use opaque/typed pointers based on the first + /// pointer type constructed. That behavior is overridable via + /// --opaque-pointers[=0], which makes this always return true. + bool hasOpaquePointerValue() const; + private: // Module needs access to the add/removeModule methods. friend class Module; diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -59,9 +59,36 @@ return Tmp.str(); } +static void setContextOpaquePointers(LLLexer &L, LLVMContext &C) { + while (true) { + lltok::Kind K = L.Lex(); + if (K == lltok::star) { + // Create a typed pointer type to force the LLVMContext into typed pointer + // mode. + Type::getInt8PtrTy(C); + return; + } + if (K == lltok::Error || K == lltok::Eof || + isa_and_nonnull(L.getTyVal())) { + // If we've errored, reached eof, or created a pointer type (which only + // happens in the lexer with opaque pointers) we're done. + return; + } + } +} + /// Run: module ::= toplevelentity* bool LLParser::Run(bool UpgradeDebugInfo, 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. The first pointer type constructed will determine if + // we're using opaque pointers or not. + // 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.hasOpaquePointerValue()) + setContextOpaquePointers(OPLex, Context); + // Prime the lexer. Lex.Lex(); diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -346,12 +346,10 @@ return std::move(pImpl->DiagHandler); } -void LLVMContext::enableOpaquePointers() const { - assert(pImpl->PointerTypes.empty() && pImpl->ASPointerTypes.empty() && - "Must be called before creating any pointer types"); - pImpl->setOpaquePointers(true); +bool LLVMContext::supportsTypedPointers() const { + return pImpl->hasOpaquePointersValue() && !pImpl->getOpaquePointers(); } -bool LLVMContext::supportsTypedPointers() const { - return !pImpl->getOpaquePointers(); +bool LLVMContext::hasOpaquePointerValue() const { + return pImpl->hasOpaquePointersValue(); } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1556,6 +1556,7 @@ // types. bool getOpaquePointers(); void setOpaquePointers(bool OP); + bool hasOpaquePointersValue(); private: Optional OpaquePointers; diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -47,7 +47,10 @@ X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID), PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID), 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() { // NOTE: We need to delete the contents of OwnedModules, but Module's dtor @@ -246,9 +249,13 @@ } bool LLVMContextImpl::getOpaquePointers() { - if (LLVM_UNLIKELY(!(OpaquePointers.hasValue()))) - OpaquePointers = OpaquePointersCL; + assert(hasOpaquePointersValue() && + "getOpaquePointers() without OpaquePointers being set"); return *OpaquePointers; } void LLVMContextImpl::setOpaquePointers(bool OP) { OpaquePointers = OP; } + +bool LLVMContextImpl::hasOpaquePointersValue() { + return OpaquePointers.hasValue(); +} diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -731,6 +731,8 @@ LLVMContextImpl *CImpl = EltTy->getContext().pImpl; // Automatically convert typed pointers to opaque pointers. + if (LLVM_UNLIKELY(!CImpl->hasOpaquePointersValue())) + CImpl->setOpaquePointers(false); if (CImpl->getOpaquePointers()) return get(EltTy->getContext(), AddressSpace); @@ -745,6 +747,8 @@ PointerType *PointerType::get(LLVMContext &C, unsigned AddressSpace) { LLVMContextImpl *CImpl = C.pImpl; + if (LLVM_UNLIKELY(!CImpl->hasOpaquePointersValue())) + CImpl->setOpaquePointers(true); assert(CImpl->getOpaquePointers() && "Can only create opaque pointers in opaque pointer mode"); diff --git a/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll b/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll --- a/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll +++ b/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll @@ -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: error: expected type diff --git a/llvm/test/Other/force-opaque-ptrs-typed-dis.ll b/llvm/test/Bitcode/opaque-ptr.ll rename from llvm/test/Other/force-opaque-ptrs-typed-dis.ll rename to llvm/test/Bitcode/opaque-ptr.ll --- a/llvm/test/Other/force-opaque-ptrs-typed-dis.ll +++ b/llvm/test/Bitcode/opaque-ptr.ll @@ -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 diff --git a/llvm/test/Other/mixed-opaque-ptrs-2.ll b/llvm/test/Other/mixed-opaque-ptrs-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/mixed-opaque-ptrs-2.ll @@ -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 +} diff --git a/llvm/test/Other/mixed-opaque-ptrs.ll b/llvm/test/Other/mixed-opaque-ptrs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/mixed-opaque-ptrs.ll @@ -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 +} diff --git a/llvm/test/Other/force-opaque-ptrs.ll b/llvm/test/Other/opaque-ptrs.ll rename from llvm/test/Other/force-opaque-ptrs.ll rename to llvm/test/Other/opaque-ptrs.ll --- a/llvm/test/Other/force-opaque-ptrs.ll +++ b/llvm/test/Other/opaque-ptrs.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature -; RUN: llvm-as --opaque-pointers < %s | llvm-dis --opaque-pointers | FileCheck %s +; RUN: llvm-as --opaque-pointers < %s | llvm-dis | FileCheck %s ; RUN: llvm-as < %s | llvm-dis --opaque-pointers | FileCheck %s ; RUN: opt --opaque-pointers < %s -S | FileCheck %s ; RUN: verify-uselistorder --opaque-pointers < %s diff --git a/llvm/unittests/IR/TypesTest.cpp b/llvm/unittests/IR/TypesTest.cpp --- a/llvm/unittests/IR/TypesTest.cpp +++ b/llvm/unittests/IR/TypesTest.cpp @@ -36,7 +36,6 @@ TEST(TypesTest, CopyPointerType) { LLVMContext COpaquePointers; - COpaquePointers.enableOpaquePointers(); PointerType *P1 = PointerType::get(COpaquePointers, 1); EXPECT_TRUE(P1->isOpaque());