Skip to content

[AsmParser] Don't require value numbers to be consecutive #78171

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 3 commits into from
Jan 19, 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
12 changes: 7 additions & 5 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,13 @@ lexical features of LLVM:
#. Comments are delimited with a '``;``' and go until the end of line.
#. Unnamed temporaries are created when the result of a computation is
not assigned to a named value.
#. Unnamed temporaries are numbered sequentially (using a per-function
incrementing counter, starting with 0). Note that basic blocks and unnamed
function parameters are included in this numbering. For example, if the
entry basic block is not given a label name and all function parameters are
named, then it will get number 0.
#. By default, unnamed temporaries are numbered sequentially (using a
per-function incrementing counter, starting with 0). However, when explicitly
specifying temporary numbers, it is allowed to skip over numbers.

Note that basic blocks and unnamed function parameters are included in this
numbering. For example, if the entry basic block is not given a label name
and all function parameters are named, then it will get number 0.

It also shows a convention that we follow in this document. When
demonstrating instructions, we will follow an instruction with a comment
Expand Down
32 changes: 27 additions & 5 deletions llvm/include/llvm/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ namespace llvm {
bool error(LocTy L, const Twine &Msg) const { return Lex.Error(L, Msg); }
bool tokError(const Twine &Msg) const { return error(Lex.getLoc(), Msg); }

bool checkValueID(LocTy L, StringRef Kind, StringRef Prefix,
unsigned NextID, unsigned ID) const;

/// Restore the internal name and slot mappings using the mappings that
/// were created at an earlier parsing stage.
void restoreParsingState(const SlotMapping *Slots);
Expand Down Expand Up @@ -448,19 +451,35 @@ 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;
std::vector<Value*> NumberedVals;
NumberedValues NumberedVals;

/// FunctionNumber - If this is an unnamed function, this is the slot
/// number of it, otherwise it is -1.
int FunctionNumber;

public:
PerFunctionState(LLParser &p, Function &f, int functionNumber);
PerFunctionState(LLParser &p, Function &f, int functionNumber,
ArrayRef<unsigned> UnnamedArgNums);
~PerFunctionState();

Function &getFunction() const { return F; }
Expand Down Expand Up @@ -590,9 +609,12 @@ namespace llvm {
ArgInfo(LocTy L, Type *ty, AttributeSet Attr, const std::string &N)
: Loc(L), Ty(ty), Attrs(Attr), Name(N) {}
};
bool parseArgumentList(SmallVectorImpl<ArgInfo> &ArgList, bool &IsVarArg);
bool parseFunctionHeader(Function *&Fn, bool IsDefine);
bool parseFunctionBody(Function &Fn);
bool parseArgumentList(SmallVectorImpl<ArgInfo> &ArgList,
SmallVectorImpl<unsigned> &UnnamedArgNums,
bool &IsVarArg);
bool parseFunctionHeader(Function *&Fn, bool IsDefine,
SmallVectorImpl<unsigned> &UnnamedArgNums);
bool parseFunctionBody(Function &Fn, ArrayRef<unsigned> UnnamedArgNums);
bool parseBasicBlock(PerFunctionState &PFS);

enum TailCallType { TCT_None, TCT_Tail, TCT_MustTail };
Expand Down
106 changes: 69 additions & 37 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,8 @@ bool LLParser::parseDeclare() {
}

Function *F;
if (parseFunctionHeader(F, false))
SmallVector<unsigned> UnnamedArgNums;
if (parseFunctionHeader(F, false, UnnamedArgNums))
return true;
for (auto &MD : MDs)
F->addMetadata(MD.first, *MD.second);
Expand All @@ -586,8 +587,10 @@ bool LLParser::parseDefine() {
Lex.Lex();

Function *F;
return parseFunctionHeader(F, true) || parseOptionalFunctionMetadata(*F) ||
parseFunctionBody(*F);
SmallVector<unsigned> UnnamedArgNums;
return parseFunctionHeader(F, true, UnnamedArgNums) ||
parseOptionalFunctionMetadata(*F) ||
parseFunctionBody(*F, UnnamedArgNums);
}

/// parseGlobalType
Expand Down Expand Up @@ -2925,6 +2928,15 @@ bool LLParser::parseOptionalOperandBundles(
return false;
}

bool LLParser::checkValueID(LocTy Loc, StringRef Kind, StringRef Prefix,
unsigned NextID, unsigned ID) const {
if (ID < NextID)
return error(Loc, Kind + " expected to be numbered '" + Prefix +
Twine(NextID) + "' or greater");

return false;
}

/// parseArgumentList - parse the argument list for a function type or function
/// prototype.
/// ::= '(' ArgTypeListI ')'
Expand All @@ -2935,6 +2947,7 @@ bool LLParser::parseOptionalOperandBundles(
/// ::= ArgType (',' ArgType)*
///
bool LLParser::parseArgumentList(SmallVectorImpl<ArgInfo> &ArgList,
SmallVectorImpl<unsigned> &UnnamedArgNums,
bool &IsVarArg) {
unsigned CurValID = 0;
IsVarArg = false;
Expand All @@ -2961,12 +2974,19 @@ bool LLParser::parseArgumentList(SmallVectorImpl<ArgInfo> &ArgList,
if (Lex.getKind() == lltok::LocalVar) {
Name = Lex.getStrVal();
Lex.Lex();
} else if (Lex.getKind() == lltok::LocalVarID) {
if (Lex.getUIntVal() != CurValID)
return error(TypeLoc, "argument expected to be numbered '%" +
Twine(CurValID) + "'");
++CurValID;
Lex.Lex();
} else {
unsigned ArgID;
if (Lex.getKind() == lltok::LocalVarID) {
ArgID = Lex.getUIntVal();
if (checkValueID(TypeLoc, "argument", "%", CurValID, ArgID))
return true;
Lex.Lex();
} else {
ArgID = CurValID;
}

UnnamedArgNums.push_back(ArgID);
CurValID = ArgID + 1;
}

if (!FunctionType::isValidArgumentType(ArgTy))
Expand Down Expand Up @@ -2995,13 +3015,17 @@ bool LLParser::parseArgumentList(SmallVectorImpl<ArgInfo> &ArgList,
Name = Lex.getStrVal();
Lex.Lex();
} else {
unsigned ArgID;
if (Lex.getKind() == lltok::LocalVarID) {
if (Lex.getUIntVal() != CurValID)
return error(TypeLoc, "argument expected to be numbered '%" +
Twine(CurValID) + "'");
ArgID = Lex.getUIntVal();
if (checkValueID(TypeLoc, "argument", "%", CurValID, ArgID))
return true;
Lex.Lex();
} else {
ArgID = CurValID;
}
++CurValID;
UnnamedArgNums.push_back(ArgID);
CurValID = ArgID + 1;
Name = "";
}

Expand All @@ -3027,7 +3051,8 @@ bool LLParser::parseFunctionType(Type *&Result) {

SmallVector<ArgInfo, 8> ArgList;
bool IsVarArg;
if (parseArgumentList(ArgList, IsVarArg))
SmallVector<unsigned> UnnamedArgNums;
if (parseArgumentList(ArgList, UnnamedArgNums, IsVarArg))
return true;

// Reject names on the arguments lists.
Expand Down Expand Up @@ -3263,13 +3288,18 @@ bool LLParser::parseTargetExtType(Type *&Result) {
//===----------------------------------------------------------------------===//

LLParser::PerFunctionState::PerFunctionState(LLParser &p, Function &f,
int functionNumber)
int functionNumber,
ArrayRef<unsigned> UnnamedArgNums)
: P(p), F(f), FunctionNumber(functionNumber) {

// Insert unnamed arguments into the NumberedVals list.
for (Argument &A : F.args())
if (!A.hasName())
NumberedVals.push_back(&A);
auto It = UnnamedArgNums.begin();
for (Argument &A : F.args()) {
if (!A.hasName()) {
unsigned ArgNum = *It++;
NumberedVals.add(ArgNum, &A);
}
}
}

LLParser::PerFunctionState::~PerFunctionState() {
Expand Down Expand Up @@ -3350,7 +3380,7 @@ Value *LLParser::PerFunctionState::getVal(const std::string &Name, Type *Ty,

Value *LLParser::PerFunctionState::getVal(unsigned ID, Type *Ty, LocTy Loc) {
// Look this name up in the normal function symbol table.
Value *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr;
Value *Val = NumberedVals.get(ID);

// If this is a forward reference for the value, see if we already created a
// forward ref record.
Expand Down Expand Up @@ -3398,11 +3428,11 @@ bool LLParser::PerFunctionState::setInstName(int NameID,
if (NameStr.empty()) {
// If neither a name nor an ID was specified, just use the next ID.
if (NameID == -1)
NameID = NumberedVals.size();
NameID = NumberedVals.getNext();

if (unsigned(NameID) != NumberedVals.size())
return P.error(NameLoc, "instruction expected to be numbered '%" +
Twine(NumberedVals.size()) + "'");
if (P.checkValueID(NameLoc, "instruction", "%", NumberedVals.getNext(),
NameID))
return true;

auto FI = ForwardRefValIDs.find(NameID);
if (FI != ForwardRefValIDs.end()) {
Expand All @@ -3417,7 +3447,7 @@ bool LLParser::PerFunctionState::setInstName(int NameID,
ForwardRefValIDs.erase(FI);
}

NumberedVals.push_back(Inst);
NumberedVals.add(NameID, Inst);
return false;
}

Expand Down Expand Up @@ -3464,15 +3494,15 @@ BasicBlock *LLParser::PerFunctionState::defineBB(const std::string &Name,
int NameID, LocTy Loc) {
BasicBlock *BB;
if (Name.empty()) {
if (NameID != -1 && unsigned(NameID) != NumberedVals.size()) {
P.error(Loc, "label expected to be numbered '" +
Twine(NumberedVals.size()) + "'");
return nullptr;
if (NameID != -1) {
if (P.checkValueID(Loc, "label", "", NumberedVals.getNext(), NameID))
return nullptr;
} else {
NameID = NumberedVals.getNext();
}
BB = getBB(NumberedVals.size(), Loc);
BB = getBB(NameID, Loc);
if (!BB) {
P.error(Loc, "unable to create block numbered '" +
Twine(NumberedVals.size()) + "'");
P.error(Loc, "unable to create block numbered '" + Twine(NameID) + "'");
return nullptr;
}
} else {
Expand All @@ -3489,8 +3519,8 @@ BasicBlock *LLParser::PerFunctionState::defineBB(const std::string &Name,

// Remove the block from forward ref sets.
if (Name.empty()) {
ForwardRefValIDs.erase(NumberedVals.size());
NumberedVals.push_back(BB);
ForwardRefValIDs.erase(NameID);
NumberedVals.add(NameID, BB);
} else {
// BB forward references are already in the function symbol table.
ForwardRefVals.erase(Name);
Expand Down Expand Up @@ -5934,7 +5964,8 @@ bool LLParser::parseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
/// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
/// '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign
/// OptGC OptionalPrefix OptionalPrologue OptPersonalityFn
bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine) {
bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine,
SmallVectorImpl<unsigned> &UnnamedArgNums) {
// parse the linkage.
LocTy LinkageLoc = Lex.getLoc();
unsigned Linkage;
Expand Down Expand Up @@ -6022,7 +6053,7 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine) {
Constant *PersonalityFn = nullptr;
Comdat *C;

if (parseArgumentList(ArgList, IsVarArg) ||
if (parseArgumentList(ArgList, UnnamedArgNums, IsVarArg) ||
parseOptionalUnnamedAddr(UnnamedAddr) ||
parseOptionalProgramAddrSpace(AddrSpace) ||
parseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
Expand Down Expand Up @@ -6217,15 +6248,16 @@ bool LLParser::PerFunctionState::resolveForwardRefBlockAddresses() {

/// parseFunctionBody
/// ::= '{' BasicBlock+ UseListOrderDirective* '}'
bool LLParser::parseFunctionBody(Function &Fn) {
bool LLParser::parseFunctionBody(Function &Fn,
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);
PerFunctionState PFS(*this, Fn, FunctionNumber, UnnamedArgNums);

// Resolve block addresses and allow basic blocks to be forward-declared
// within this function.
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Assembler/call-nonzero-program-addrspace-2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

; Check that numbered variables in a nonzero program address space 200 can be used in a call instruction

define i8 @test_unnamed(ptr, ptr addrspace(42) %0) {
define i8 @test_unnamed(ptr, ptr addrspace(42) %1) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bug in the previous implementation: While %0 is written here, it was actually interpreted as %1.

; Calls with explicit address spaces are fine:
call addrspace(0) i8 %0(i32 0)
call addrspace(42) i8 %1(i32 0)
Expand Down
6 changes: 0 additions & 6 deletions llvm/test/Assembler/invalid-arg-num-1.ll

This file was deleted.

6 changes: 0 additions & 6 deletions llvm/test/Assembler/invalid-arg-num-2.ll

This file was deleted.

6 changes: 0 additions & 6 deletions llvm/test/Assembler/invalid-arg-num-3.ll

This file was deleted.

7 changes: 0 additions & 7 deletions llvm/test/Assembler/invalid-block-label-num.ll

This file was deleted.

31 changes: 31 additions & 0 deletions llvm/test/Assembler/skip-value-numbers-invalid.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
; RUN: split-file %s %t
; 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

;--- instr_smaller_id.ll

; INSTR-SMALLER-ID: error: instruction expected to be numbered '%11' or greater
define i32 @test() {
%10 = add i32 1, 2
%5 = add i32 %10, 3
ret i32 %5
}

;--- arg_smaller_id.ll

; ARG-SMALLER-ID: error: argument expected to be numbered '%11' or greater
define i32 @test(i32 %10, i32 %5) {
ret i32 %5
}

;--- block_smaller_id.ll

; BLOCK-SMALLER-ID: error: label expected to be numbered '11' or greater
define i32 @test() {
10:
br label %5

5:
ret i32 0
}
Loading