[llvm] [AsmParser] Supprt non-consecutive global value numbers (PR #80013)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 30 06:50:23 PST 2024


https://github.com/nikic created https://github.com/llvm/llvm-project/pull/80013

https://github.com/llvm/llvm-project/pull/78171 added support for non-consecutive local value numbers. This extends the support for global value numbers (for globals and functions).

This means that it is now possible to delete an unnamed global definition/declaration without breaking the IR.

This is a lot less common than unnamed local values, but it seems like something we should support for consistency.  (Unnamed globals are used a lot in Rust though.)

>From dc10048276a09cca99f1ce19b134de8b159ff6c0 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 30 Jan 2024 14:16:07 +0100
Subject: [PATCH] [AsmParser] Supprt non-consecutive global value numbers

https://github.com/llvm/llvm-project/pull/78171 added support for
local value numbers to have gaps. This extends the support for
global value numbers (for globals and functions).

This means that it is now possible to delete an unnamed global
definition/declaration without breaking the IR.

This is a lot less common than unnamed local values, but it seems
like something we should support for consistency. (Unnamed globals
are also common in rustc IR).
---
 llvm/include/llvm/AsmParser/LLParser.h        | 34 +++----
 llvm/include/llvm/AsmParser/NumberedValues.h  | 35 +++++++
 llvm/include/llvm/AsmParser/SlotMapping.h     |  3 +-
 llvm/lib/AsmParser/LLParser.cpp               | 91 ++++++++++---------
 llvm/lib/CodeGen/MIRParser/MIParser.cpp       |  4 +-
 .../Assembler/skip-value-numbers-globals.ll   | 47 ++++++++++
 .../Assembler/skip-value-numbers-invalid.ll   | 18 ++++
 llvm/unittests/AsmParser/AsmParserTest.cpp    |  4 +-
 8 files changed, 168 insertions(+), 68 deletions(-)
 create mode 100644 llvm/include/llvm/AsmParser/NumberedValues.h
 create mode 100644 llvm/test/Assembler/skip-value-numbers-globals.ll

diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index cf358c384f520..f07f4c61f9d64 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -15,6 +15,7 @@
 
 #include "LLLexer.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/AsmParser/NumberedValues.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/FMF.h"
@@ -133,7 +134,7 @@ namespace llvm {
     // Global Value reference information.
     std::map<std::string, std::pair<GlobalValue*, LocTy> > ForwardRefVals;
     std::map<unsigned, std::pair<GlobalValue*, LocTy> > ForwardRefValIDs;
-    std::vector<GlobalValue*> NumberedVals;
+    NumberedValues<GlobalValue *> NumberedVals;
 
     // Comdat forward reference information.
     std::map<std::string, LocTy> ForwardRefComdats;
@@ -346,14 +347,15 @@ namespace llvm {
     bool parseGlobalType(bool &IsConstant);
     bool parseUnnamedGlobal();
     bool parseNamedGlobal();
-    bool parseGlobal(const std::string &Name, LocTy NameLoc, unsigned Linkage,
-                     bool HasLinkage, unsigned Visibility,
+    bool parseGlobal(const std::string &Name, unsigned NameID, LocTy NameLoc,
+                     unsigned Linkage, bool HasLinkage, unsigned Visibility,
                      unsigned DLLStorageClass, bool DSOLocal,
                      GlobalVariable::ThreadLocalMode TLM,
                      GlobalVariable::UnnamedAddr UnnamedAddr);
-    bool parseAliasOrIFunc(const std::string &Name, LocTy NameLoc, unsigned L,
-                           unsigned Visibility, unsigned DLLStorageClass,
-                           bool DSOLocal, GlobalVariable::ThreadLocalMode TLM,
+    bool parseAliasOrIFunc(const std::string &Name, unsigned NameID,
+                           LocTy NameLoc, unsigned L, unsigned Visibility,
+                           unsigned DLLStorageClass, bool DSOLocal,
+                           GlobalVariable::ThreadLocalMode TLM,
                            GlobalVariable::UnnamedAddr UnnamedAddr);
     bool parseComdat();
     bool parseStandaloneMetadata();
@@ -452,27 +454,13 @@ namespace llvm {
     bool parseFunctionType(Type *&Result);
     bool parseTargetExtType(Type *&Result);
 
-    class NumberedValues {
-      DenseMap<unsigned, Value *> Vals;
-      unsigned NextUnusedID = 0;
-
-    public:
-      unsigned getNext() const { return NextUnusedID; }
-      Value *get(unsigned ID) const { return Vals.lookup(ID); }
-      void add(unsigned ID, Value *V) {
-        assert(ID >= NextUnusedID && "Invalid value ID");
-        Vals.insert({ID, V});
-        NextUnusedID = ID + 1;
-      }
-    };
-
     // Function Semantic Analysis.
     class PerFunctionState {
       LLParser &P;
       Function &F;
       std::map<std::string, std::pair<Value*, LocTy> > ForwardRefVals;
       std::map<unsigned, std::pair<Value*, LocTy> > ForwardRefValIDs;
-      NumberedValues NumberedVals;
+      NumberedValues<Value *> NumberedVals;
 
       /// FunctionNumber - If this is an unnamed function, this is the slot
       /// number of it, otherwise it is -1.
@@ -614,8 +602,10 @@ namespace llvm {
                            SmallVectorImpl<unsigned> &UnnamedArgNums,
                            bool &IsVarArg);
     bool parseFunctionHeader(Function *&Fn, bool IsDefine,
+                             unsigned &FunctionNumber,
                              SmallVectorImpl<unsigned> &UnnamedArgNums);
-    bool parseFunctionBody(Function &Fn, ArrayRef<unsigned> UnnamedArgNums);
+    bool parseFunctionBody(Function &Fn, unsigned FunctionNumber,
+                           ArrayRef<unsigned> UnnamedArgNums);
     bool parseBasicBlock(PerFunctionState &PFS);
 
     enum TailCallType { TCT_None, TCT_Tail, TCT_MustTail };
diff --git a/llvm/include/llvm/AsmParser/NumberedValues.h b/llvm/include/llvm/AsmParser/NumberedValues.h
new file mode 100644
index 0000000000000..50c977de611b7
--- /dev/null
+++ b/llvm/include/llvm/AsmParser/NumberedValues.h
@@ -0,0 +1,35 @@
+//===-- NumberedValues.h - --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ASMPARSER_NUMBEREDVALUES_H
+#define LLVM_ASMPARSER_NUMBEREDVALUES_H
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace llvm {
+
+/// Mapping from value ID to value, which also remembers what the next unused
+/// ID is.
+template <class T>
+class NumberedValues {
+  DenseMap<unsigned, T> Vals;
+  unsigned NextUnusedID = 0;
+
+public:
+  unsigned getNext() const { return NextUnusedID; }
+  T get(unsigned ID) const { return Vals.lookup(ID); }
+  void add(unsigned ID, T V) {
+    assert(ID >= NextUnusedID && "Invalid value ID");
+    Vals.insert({ID, V});
+    NextUnusedID = ID + 1;
+  }
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/AsmParser/SlotMapping.h b/llvm/include/llvm/AsmParser/SlotMapping.h
index 0e95eb816b4c6..2d2b8d8400bd7 100644
--- a/llvm/include/llvm/AsmParser/SlotMapping.h
+++ b/llvm/include/llvm/AsmParser/SlotMapping.h
@@ -14,6 +14,7 @@
 #define LLVM_ASMPARSER_SLOTMAPPING_H
 
 #include "llvm/ADT/StringMap.h"
+#include "llvm/AsmParser/NumberedValues.h"
 #include "llvm/IR/TrackingMDRef.h"
 #include <map>
 #include <vector>
@@ -30,7 +31,7 @@ class Type;
 /// textual references to the values in the module can be parsed outside of the
 /// module's source.
 struct SlotMapping {
-  std::vector<GlobalValue *> GlobalValues;
+  NumberedValues<GlobalValue *> GlobalValues;
   std::map<unsigned, TrackingMDNodeRef> MetadataNodes;
   StringMap<Type *> NamedTypes;
   std::map<unsigned, Type *> Types;
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index d6c5993797de1..111304f40b430 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -254,8 +254,8 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
     GlobalValue *GV = nullptr;
     if (GVRef.Kind == ValID::t_GlobalName) {
       GV = M->getNamedValue(GVRef.StrVal);
-    } else if (GVRef.UIntVal < NumberedVals.size()) {
-      GV = dyn_cast<GlobalValue>(NumberedVals[GVRef.UIntVal]);
+    } else {
+      GV = NumberedVals.get(GVRef.UIntVal);
     }
 
     if (!GV)
@@ -664,8 +664,9 @@ bool LLParser::parseDeclare() {
   }
 
   Function *F;
+  unsigned FunctionNumber = -1;
   SmallVector<unsigned> UnnamedArgNums;
-  if (parseFunctionHeader(F, false, UnnamedArgNums))
+  if (parseFunctionHeader(F, false, FunctionNumber, UnnamedArgNums))
     return true;
   for (auto &MD : MDs)
     F->addMetadata(MD.first, *MD.second);
@@ -679,10 +680,11 @@ bool LLParser::parseDefine() {
   Lex.Lex();
 
   Function *F;
+  unsigned FunctionNumber = -1;
   SmallVector<unsigned> UnnamedArgNums;
-  return parseFunctionHeader(F, true, UnnamedArgNums) ||
+  return parseFunctionHeader(F, true, FunctionNumber, UnnamedArgNums) ||
          parseOptionalFunctionMetadata(*F) ||
-         parseFunctionBody(*F, UnnamedArgNums);
+         parseFunctionBody(*F, FunctionNumber, UnnamedArgNums);
 }
 
 /// parseGlobalType
@@ -723,19 +725,21 @@ bool LLParser::parseOptionalUnnamedAddr(
 ///                OptionalDLLStorageClass
 ///                                                     ...   -> global variable
 bool LLParser::parseUnnamedGlobal() {
-  unsigned VarID = NumberedVals.size();
+  unsigned VarID;
   std::string Name;
   LocTy NameLoc = Lex.getLoc();
 
   // Handle the GlobalID form.
   if (Lex.getKind() == lltok::GlobalID) {
-    if (Lex.getUIntVal() != VarID)
-      return error(Lex.getLoc(),
-                   "variable expected to be numbered '%" + Twine(VarID) + "'");
-    Lex.Lex(); // eat GlobalID;
+    VarID = Lex.getUIntVal();
+    if (checkValueID(NameLoc, "global", "@", NumberedVals.getNext(), VarID))
+      return true;
 
+    Lex.Lex(); // eat GlobalID;
     if (parseToken(lltok::equal, "expected '=' after name"))
       return true;
+  } else {
+    VarID = NumberedVals.getNext();
   }
 
   bool HasLinkage;
@@ -750,11 +754,11 @@ bool LLParser::parseUnnamedGlobal() {
 
   switch (Lex.getKind()) {
   default:
-    return parseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
+    return parseGlobal(Name, VarID, NameLoc, Linkage, HasLinkage, Visibility,
                        DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
   case lltok::kw_alias:
   case lltok::kw_ifunc:
-    return parseAliasOrIFunc(Name, NameLoc, Linkage, Visibility,
+    return parseAliasOrIFunc(Name, VarID, NameLoc, Linkage, Visibility,
                              DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
   }
 }
@@ -783,11 +787,11 @@ bool LLParser::parseNamedGlobal() {
 
   switch (Lex.getKind()) {
   default:
-    return parseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
+    return parseGlobal(Name, -1, NameLoc, Linkage, HasLinkage, Visibility,
                        DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
   case lltok::kw_alias:
   case lltok::kw_ifunc:
-    return parseAliasOrIFunc(Name, NameLoc, Linkage, Visibility,
+    return parseAliasOrIFunc(Name, -1, NameLoc, Linkage, Visibility,
                              DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
   }
 }
@@ -1083,8 +1087,8 @@ static void maybeSetDSOLocal(bool DSOLocal, GlobalValue &GV) {
 ///
 /// Everything through OptionalUnnamedAddr has already been parsed.
 ///
-bool LLParser::parseAliasOrIFunc(const std::string &Name, LocTy NameLoc,
-                                 unsigned L, unsigned Visibility,
+bool LLParser::parseAliasOrIFunc(const std::string &Name, unsigned NameID,
+                                 LocTy NameLoc, unsigned L, unsigned Visibility,
                                  unsigned DLLStorageClass, bool DSOLocal,
                                  GlobalVariable::ThreadLocalMode TLM,
                                  GlobalVariable::UnnamedAddr UnnamedAddr) {
@@ -1153,7 +1157,7 @@ bool LLParser::parseAliasOrIFunc(const std::string &Name, LocTy NameLoc,
       return error(NameLoc, "redefinition of global '@" + Name + "'");
     }
   } else {
-    auto I = ForwardRefValIDs.find(NumberedVals.size());
+    auto I = ForwardRefValIDs.find(NameID);
     if (I != ForwardRefValIDs.end()) {
       GVal = I->second.first;
       ForwardRefValIDs.erase(I);
@@ -1197,7 +1201,7 @@ bool LLParser::parseAliasOrIFunc(const std::string &Name, LocTy NameLoc,
   }
 
   if (Name.empty())
-    NumberedVals.push_back(GV);
+    NumberedVals.add(NameID, GV);
 
   if (GVal) {
     // Verify that types agree.
@@ -1274,8 +1278,8 @@ bool LLParser::parseSanitizer(GlobalVariable *GV) {
 /// Everything up to and including OptionalUnnamedAddr has been parsed
 /// already.
 ///
-bool LLParser::parseGlobal(const std::string &Name, LocTy NameLoc,
-                           unsigned Linkage, bool HasLinkage,
+bool LLParser::parseGlobal(const std::string &Name, unsigned NameID,
+                           LocTy NameLoc, unsigned Linkage, bool HasLinkage,
                            unsigned Visibility, unsigned DLLStorageClass,
                            bool DSOLocal, GlobalVariable::ThreadLocalMode TLM,
                            GlobalVariable::UnnamedAddr UnnamedAddr) {
@@ -1325,7 +1329,12 @@ bool LLParser::parseGlobal(const std::string &Name, LocTy NameLoc,
       return error(NameLoc, "redefinition of global '@" + Name + "'");
     }
   } else {
-    auto I = ForwardRefValIDs.find(NumberedVals.size());
+    // Handle @"", where a name is syntactically specified, but semantically
+    // missing.
+    if (NameID == (unsigned)-1)
+      NameID = NumberedVals.getNext();
+
+    auto I = ForwardRefValIDs.find(NameID);
     if (I != ForwardRefValIDs.end()) {
       GVal = I->second.first;
       ForwardRefValIDs.erase(I);
@@ -1337,7 +1346,7 @@ bool LLParser::parseGlobal(const std::string &Name, LocTy NameLoc,
       GlobalVariable::NotThreadLocal, AddrSpace);
 
   if (Name.empty())
-    NumberedVals.push_back(GV);
+    NumberedVals.add(NameID, GV);
 
   // Set the parsed properties on the global.
   if (Init)
@@ -1724,7 +1733,7 @@ GlobalValue *LLParser::getGlobalVal(unsigned ID, Type *Ty, LocTy Loc) {
     return nullptr;
   }
 
-  GlobalValue *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr;
+  GlobalValue *Val = NumberedVals.get(ID);
 
   // If this is a forward reference for the value, see if we already created a
   // forward ref record.
@@ -3780,8 +3789,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
     // Try to find the function (but skip it if it's forward-referenced).
     GlobalValue *GV = nullptr;
     if (Fn.Kind == ValID::t_GlobalID) {
-      if (Fn.UIntVal < NumberedVals.size())
-        GV = NumberedVals[Fn.UIntVal];
+      GV = NumberedVals.get(Fn.UIntVal);
     } else if (!ForwardRefVals.count(Fn.StrVal)) {
       GV = M->getNamedValue(Fn.StrVal);
     }
@@ -3870,8 +3878,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
     // Try to find the function (but skip it if it's forward-referenced).
     GlobalValue *GV = nullptr;
     if (Fn.Kind == ValID::t_GlobalID) {
-      if (Fn.UIntVal < NumberedVals.size())
-        GV = NumberedVals[Fn.UIntVal];
+      GV = NumberedVals.get(Fn.UIntVal);
     } else if (!ForwardRefVals.count(Fn.StrVal)) {
       GV = M->getNamedValue(Fn.StrVal);
     }
@@ -6018,6 +6025,7 @@ bool LLParser::parseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
 ///       '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign
 ///       OptGC OptionalPrefix OptionalPrologue OptPersonalityFn
 bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
+                                   unsigned &FunctionNumber,
                                    SmallVectorImpl<unsigned> &UnnamedArgNums) {
   // parse the linkage.
   LocTy LinkageLoc = Lex.getLoc();
@@ -6076,11 +6084,10 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
   if (Lex.getKind() == lltok::GlobalVar) {
     FunctionName = Lex.getStrVal();
   } else if (Lex.getKind() == lltok::GlobalID) {     // @42 is ok.
-    unsigned NameID = Lex.getUIntVal();
-
-    if (NameID != NumberedVals.size())
-      return tokError("function expected to be numbered '%" +
-                      Twine(NumberedVals.size()) + "'");
+    FunctionNumber = Lex.getUIntVal();
+    if (checkValueID(NameLoc, "function", "@", NumberedVals.getNext(),
+                     FunctionNumber))
+      return true;
   } else {
     return tokError("expected function name");
   }
@@ -6178,14 +6185,19 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
     }
 
   } else {
+    // Handle @"", where a name is syntactically specified, but semantically
+    // missing.
+    if (FunctionNumber == (unsigned)-1)
+      FunctionNumber = NumberedVals.getNext();
+
     // If this is a definition of a forward referenced function, make sure the
     // types agree.
-    auto I = ForwardRefValIDs.find(NumberedVals.size());
+    auto I = ForwardRefValIDs.find(FunctionNumber);
     if (I != ForwardRefValIDs.end()) {
       FwdFn = I->second.first;
       if (FwdFn->getType() != PFT)
         return error(NameLoc, "type of definition and forward reference of '@" +
-                                  Twine(NumberedVals.size()) +
+                                  Twine(FunctionNumber) +
                                   "' disagree: "
                                   "expected '" +
                                   getTypeString(PFT) + "' but was '" +
@@ -6200,7 +6212,7 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
   assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS");
 
   if (FunctionName.empty())
-    NumberedVals.push_back(Fn);
+    NumberedVals.add(FunctionNumber, Fn);
 
   Fn->setLinkage((GlobalValue::LinkageTypes)Linkage);
   maybeSetDSOLocal(DSOLocal, *Fn);
@@ -6246,7 +6258,7 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
   ValID ID;
   if (FunctionName.empty()) {
     ID.Kind = ValID::t_GlobalID;
-    ID.UIntVal = NumberedVals.size() - 1;
+    ID.UIntVal = FunctionNumber;
   } else {
     ID.Kind = ValID::t_GlobalName;
     ID.StrVal = FunctionName;
@@ -6301,15 +6313,12 @@ bool LLParser::PerFunctionState::resolveForwardRefBlockAddresses() {
 
 /// parseFunctionBody
 ///   ::= '{' BasicBlock+ UseListOrderDirective* '}'
-bool LLParser::parseFunctionBody(Function &Fn,
+bool LLParser::parseFunctionBody(Function &Fn, unsigned FunctionNumber,
                                  ArrayRef<unsigned> UnnamedArgNums) {
   if (Lex.getKind() != lltok::lbrace)
     return tokError("expected '{' in function body");
   Lex.Lex();  // eat the {.
 
-  int FunctionNumber = -1;
-  if (!Fn.hasName()) FunctionNumber = NumberedVals.size()-1;
-
   PerFunctionState PFS(*this, Fn, FunctionNumber, UnnamedArgNums);
 
   // Resolve block addresses and allow basic blocks to be forward-declared
@@ -8244,7 +8253,7 @@ bool LLParser::parseUseListOrderBB() {
   if (Fn.Kind == ValID::t_GlobalName)
     GV = M->getNamedValue(Fn.StrVal);
   else if (Fn.Kind == ValID::t_GlobalID)
-    GV = Fn.UIntVal < NumberedVals.size() ? NumberedVals[Fn.UIntVal] : nullptr;
+    GV = NumberedVals.get(Fn.UIntVal);
   else
     return error(Fn.Loc, "expected function name in uselistorder_bb");
   if (!GV)
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 1a31e2ed809af..d41fc97cb8060 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2181,10 +2181,10 @@ static bool parseGlobalValue(const MIToken &Token,
     unsigned GVIdx;
     if (getUnsigned(Token, GVIdx, ErrCB))
       return true;
-    if (GVIdx >= PFS.IRSlots.GlobalValues.size())
+    GV = PFS.IRSlots.GlobalValues.get(GVIdx);
+    if (!GV)
       return ErrCB(Token.location(), Twine("use of undefined global value '@") +
                                          Twine(GVIdx) + "'");
-    GV = PFS.IRSlots.GlobalValues[GVIdx];
     break;
   }
   default:
diff --git a/llvm/test/Assembler/skip-value-numbers-globals.ll b/llvm/test/Assembler/skip-value-numbers-globals.ll
new file mode 100644
index 0000000000000..95f60299752e7
--- /dev/null
+++ b/llvm/test/Assembler/skip-value-numbers-globals.ll
@@ -0,0 +1,47 @@
+; RUN: opt -S < %s | FileCheck %s
+
+ at 5 = global i8 0
+@"" = global i8 1
+ at 10 = alias i8, ptr @5
+ at 15 = ifunc ptr(), ptr @20
+
+define ptr @20() {
+  ret ptr null
+}
+
+declare void @25()
+
+declare ptr @""(ptr)
+
+define void @test(ptr %p) {
+  store ptr @5, ptr %p
+  store ptr @6, ptr %p
+  store ptr @10, ptr %p
+  store ptr @15, ptr %p
+  store ptr @20, ptr %p
+  store ptr @25, ptr %p
+  store ptr @26, ptr %p
+  ret void
+}
+
+; CHECK: @0 = global i8 0
+; CHECK: @1 = global i8 1
+; CHECK: @2 = alias i8, ptr @0
+; CHECK: @3 = ifunc ptr (), ptr @4
+
+; CHECK-LABEL: define ptr @4() {
+; CHECK-NEXT:  ret ptr null
+
+; CHECK: declare void @5()
+
+; CHECK: declare ptr @6(ptr)
+
+; CHECK-LABEL: define void @test(ptr %p) {
+; CHECK-NEXT: store ptr @0, ptr %p, align 8
+; CHECK-NEXT: store ptr @1, ptr %p, align 8
+; CHECK-NEXT: store ptr @2, ptr %p, align 8
+; CHECK-NEXT: store ptr @3, ptr %p, align 8
+; CHECK-NEXT: store ptr @4, ptr %p, align 8
+; CHECK-NEXT: store ptr @5, ptr %p, align 8
+; CHECK-NEXT: store ptr @6, ptr %p, align 8
+; CHECK-NEXT: ret void
diff --git a/llvm/test/Assembler/skip-value-numbers-invalid.ll b/llvm/test/Assembler/skip-value-numbers-invalid.ll
index 67e6b10196bc8..b8173bbaf018c 100644
--- a/llvm/test/Assembler/skip-value-numbers-invalid.ll
+++ b/llvm/test/Assembler/skip-value-numbers-invalid.ll
@@ -2,6 +2,8 @@
 ; RUN: not llvm-as < %s %t/instr_smaller_id.ll 2>&1 | FileCheck %s --check-prefix=INSTR-SMALLER-ID
 ; RUN: not llvm-as < %s %t/arg_smaller_id.ll 2>&1 | FileCheck %s --check-prefix=ARG-SMALLER-ID
 ; RUN: not llvm-as < %s %t/block_smaller_id.ll 2>&1 | FileCheck %s --check-prefix=BLOCK-SMALLER-ID
+; RUN: not llvm-as < %s %t/global_smaller_id.ll 2>&1 | FileCheck %s --check-prefix=GLOBAL-SMALLER-ID
+; RUN: not llvm-as < %s %t/function_smaller_id.ll 2>&1 | FileCheck %s --check-prefix=FUNCTION-SMALLER-ID
 
 ;--- instr_smaller_id.ll
 
@@ -29,3 +31,19 @@ define i32 @test() {
 5:
   ret i32 0
 }
+
+;--- global_smaller_id.ll
+
+; GLOBAL-SMALLER-ID: error: global expected to be numbered '@11' or greater
+
+ at 10 = external global i8
+ at 5 = external global i8
+
+;--- function_smaller_id.ll
+
+; FUNCTION-SMALLER-ID: error: function expected to be numbered '@11' or greater
+
+define void @10() {
+  ret void
+}
+declare void @5()
diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp
index 77dba5bfd4cae..f296848ed665f 100644
--- a/llvm/unittests/AsmParser/AsmParserTest.cpp
+++ b/llvm/unittests/AsmParser/AsmParserTest.cpp
@@ -57,8 +57,8 @@ TEST(AsmParserTest, SlotMappingTest) {
   EXPECT_TRUE(Mod != nullptr);
   EXPECT_TRUE(Error.getMessage().empty());
 
-  ASSERT_EQ(Mapping.GlobalValues.size(), 1u);
-  EXPECT_TRUE(isa<GlobalVariable>(Mapping.GlobalValues[0]));
+  ASSERT_EQ(Mapping.GlobalValues.getNext(), 1u);
+  EXPECT_TRUE(isa<GlobalVariable>(Mapping.GlobalValues.get(0)));
 
   EXPECT_EQ(Mapping.MetadataNodes.size(), 2u);
   EXPECT_EQ(Mapping.MetadataNodes.count(0), 1u);



More information about the llvm-commits mailing list