mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
7e4be9501b
Add a calling convention called amdgpu_gfx for real function calls within graphics shaders. For the moment, this uses the same calling convention as other calls in amdgpu, with registers excluded for return address, stack pointer and stack buffer descriptor. Differential Revision: https://reviews.llvm.org/D88540
9463 lines
318 KiB
C++
9463 lines
318 KiB
C++
//===-- LLParser.cpp - Parser Class ---------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the parser class for .ll files.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "LLParser.h"
|
|
#include "LLToken.h"
|
|
#include "llvm/ADT/APSInt.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/None.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/AsmParser/SlotMapping.h"
|
|
#include "llvm/BinaryFormat/Dwarf.h"
|
|
#include "llvm/IR/Argument.h"
|
|
#include "llvm/IR/AutoUpgrade.h"
|
|
#include "llvm/IR/BasicBlock.h"
|
|
#include "llvm/IR/CallingConv.h"
|
|
#include "llvm/IR/Comdat.h"
|
|
#include "llvm/IR/ConstantRange.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalIFunc.h"
|
|
#include "llvm/IR/GlobalObject.h"
|
|
#include "llvm/IR/InlineAsm.h"
|
|
#include "llvm/IR/Intrinsics.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Metadata.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Value.h"
|
|
#include "llvm/IR/ValueSymbolTable.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/SaveAndRestore.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <iterator>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
|
|
static std::string getTypeString(Type *T) {
|
|
std::string Result;
|
|
raw_string_ostream Tmp(Result);
|
|
Tmp << *T;
|
|
return Tmp.str();
|
|
}
|
|
|
|
/// Run: module ::= toplevelentity*
|
|
bool LLParser::Run(bool UpgradeDebugInfo,
|
|
DataLayoutCallbackTy DataLayoutCallback) {
|
|
// Prime the lexer.
|
|
Lex.Lex();
|
|
|
|
if (Context.shouldDiscardValueNames())
|
|
return error(
|
|
Lex.getLoc(),
|
|
"Can't read textual IR with a Context that discards named Values");
|
|
|
|
if (M) {
|
|
if (parseTargetDefinitions())
|
|
return true;
|
|
|
|
if (auto LayoutOverride = DataLayoutCallback(M->getTargetTriple()))
|
|
M->setDataLayout(*LayoutOverride);
|
|
}
|
|
|
|
return parseTopLevelEntities() || validateEndOfModule(UpgradeDebugInfo) ||
|
|
validateEndOfIndex();
|
|
}
|
|
|
|
bool LLParser::parseStandaloneConstantValue(Constant *&C,
|
|
const SlotMapping *Slots) {
|
|
restoreParsingState(Slots);
|
|
Lex.Lex();
|
|
|
|
Type *Ty = nullptr;
|
|
if (parseType(Ty) || parseConstantValue(Ty, C))
|
|
return true;
|
|
if (Lex.getKind() != lltok::Eof)
|
|
return error(Lex.getLoc(), "expected end of string");
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseTypeAtBeginning(Type *&Ty, unsigned &Read,
|
|
const SlotMapping *Slots) {
|
|
restoreParsingState(Slots);
|
|
Lex.Lex();
|
|
|
|
Read = 0;
|
|
SMLoc Start = Lex.getLoc();
|
|
Ty = nullptr;
|
|
if (parseType(Ty))
|
|
return true;
|
|
SMLoc End = Lex.getLoc();
|
|
Read = End.getPointer() - Start.getPointer();
|
|
|
|
return false;
|
|
}
|
|
|
|
void LLParser::restoreParsingState(const SlotMapping *Slots) {
|
|
if (!Slots)
|
|
return;
|
|
NumberedVals = Slots->GlobalValues;
|
|
NumberedMetadata = Slots->MetadataNodes;
|
|
for (const auto &I : Slots->NamedTypes)
|
|
NamedTypes.insert(
|
|
std::make_pair(I.getKey(), std::make_pair(I.second, LocTy())));
|
|
for (const auto &I : Slots->Types)
|
|
NumberedTypes.insert(
|
|
std::make_pair(I.first, std::make_pair(I.second, LocTy())));
|
|
}
|
|
|
|
/// validateEndOfModule - Do final validity and sanity checks at the end of the
|
|
/// module.
|
|
bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
|
|
if (!M)
|
|
return false;
|
|
// Handle any function attribute group forward references.
|
|
for (const auto &RAG : ForwardRefAttrGroups) {
|
|
Value *V = RAG.first;
|
|
const std::vector<unsigned> &Attrs = RAG.second;
|
|
AttrBuilder B;
|
|
|
|
for (const auto &Attr : Attrs)
|
|
B.merge(NumberedAttrBuilders[Attr]);
|
|
|
|
if (Function *Fn = dyn_cast<Function>(V)) {
|
|
AttributeList AS = Fn->getAttributes();
|
|
AttrBuilder FnAttrs(AS.getFnAttributes());
|
|
AS = AS.removeAttributes(Context, AttributeList::FunctionIndex);
|
|
|
|
FnAttrs.merge(B);
|
|
|
|
// If the alignment was parsed as an attribute, move to the alignment
|
|
// field.
|
|
if (FnAttrs.hasAlignmentAttr()) {
|
|
Fn->setAlignment(FnAttrs.getAlignment());
|
|
FnAttrs.removeAttribute(Attribute::Alignment);
|
|
}
|
|
|
|
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
|
AttributeSet::get(Context, FnAttrs));
|
|
Fn->setAttributes(AS);
|
|
} else if (CallInst *CI = dyn_cast<CallInst>(V)) {
|
|
AttributeList AS = CI->getAttributes();
|
|
AttrBuilder FnAttrs(AS.getFnAttributes());
|
|
AS = AS.removeAttributes(Context, AttributeList::FunctionIndex);
|
|
FnAttrs.merge(B);
|
|
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
|
AttributeSet::get(Context, FnAttrs));
|
|
CI->setAttributes(AS);
|
|
} else if (InvokeInst *II = dyn_cast<InvokeInst>(V)) {
|
|
AttributeList AS = II->getAttributes();
|
|
AttrBuilder FnAttrs(AS.getFnAttributes());
|
|
AS = AS.removeAttributes(Context, AttributeList::FunctionIndex);
|
|
FnAttrs.merge(B);
|
|
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
|
AttributeSet::get(Context, FnAttrs));
|
|
II->setAttributes(AS);
|
|
} else if (CallBrInst *CBI = dyn_cast<CallBrInst>(V)) {
|
|
AttributeList AS = CBI->getAttributes();
|
|
AttrBuilder FnAttrs(AS.getFnAttributes());
|
|
AS = AS.removeAttributes(Context, AttributeList::FunctionIndex);
|
|
FnAttrs.merge(B);
|
|
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
|
AttributeSet::get(Context, FnAttrs));
|
|
CBI->setAttributes(AS);
|
|
} else if (auto *GV = dyn_cast<GlobalVariable>(V)) {
|
|
AttrBuilder Attrs(GV->getAttributes());
|
|
Attrs.merge(B);
|
|
GV->setAttributes(AttributeSet::get(Context,Attrs));
|
|
} else {
|
|
llvm_unreachable("invalid object with forward attribute group reference");
|
|
}
|
|
}
|
|
|
|
// If there are entries in ForwardRefBlockAddresses at this point, the
|
|
// function was never defined.
|
|
if (!ForwardRefBlockAddresses.empty())
|
|
return error(ForwardRefBlockAddresses.begin()->first.Loc,
|
|
"expected function name in blockaddress");
|
|
|
|
for (const auto &NT : NumberedTypes)
|
|
if (NT.second.second.isValid())
|
|
return error(NT.second.second,
|
|
"use of undefined type '%" + Twine(NT.first) + "'");
|
|
|
|
for (StringMap<std::pair<Type*, LocTy> >::iterator I =
|
|
NamedTypes.begin(), E = NamedTypes.end(); I != E; ++I)
|
|
if (I->second.second.isValid())
|
|
return error(I->second.second,
|
|
"use of undefined type named '" + I->getKey() + "'");
|
|
|
|
if (!ForwardRefComdats.empty())
|
|
return error(ForwardRefComdats.begin()->second,
|
|
"use of undefined comdat '$" +
|
|
ForwardRefComdats.begin()->first + "'");
|
|
|
|
if (!ForwardRefVals.empty())
|
|
return error(ForwardRefVals.begin()->second.second,
|
|
"use of undefined value '@" + ForwardRefVals.begin()->first +
|
|
"'");
|
|
|
|
if (!ForwardRefValIDs.empty())
|
|
return error(ForwardRefValIDs.begin()->second.second,
|
|
"use of undefined value '@" +
|
|
Twine(ForwardRefValIDs.begin()->first) + "'");
|
|
|
|
if (!ForwardRefMDNodes.empty())
|
|
return error(ForwardRefMDNodes.begin()->second.second,
|
|
"use of undefined metadata '!" +
|
|
Twine(ForwardRefMDNodes.begin()->first) + "'");
|
|
|
|
// Resolve metadata cycles.
|
|
for (auto &N : NumberedMetadata) {
|
|
if (N.second && !N.second->isResolved())
|
|
N.second->resolveCycles();
|
|
}
|
|
|
|
for (auto *Inst : InstsWithTBAATag) {
|
|
MDNode *MD = Inst->getMetadata(LLVMContext::MD_tbaa);
|
|
assert(MD && "UpgradeInstWithTBAATag should have a TBAA tag");
|
|
auto *UpgradedMD = UpgradeTBAANode(*MD);
|
|
if (MD != UpgradedMD)
|
|
Inst->setMetadata(LLVMContext::MD_tbaa, UpgradedMD);
|
|
}
|
|
|
|
// Look for intrinsic functions and CallInst that need to be upgraded
|
|
for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; )
|
|
UpgradeCallsToIntrinsic(&*FI++); // must be post-increment, as we remove
|
|
|
|
// Some types could be renamed during loading if several modules are
|
|
// loaded in the same LLVMContext (LTO scenario). In this case we should
|
|
// remangle intrinsics names as well.
|
|
for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ) {
|
|
Function *F = &*FI++;
|
|
if (auto Remangled = Intrinsic::remangleIntrinsicFunction(F)) {
|
|
F->replaceAllUsesWith(Remangled.getValue());
|
|
F->eraseFromParent();
|
|
}
|
|
}
|
|
|
|
if (UpgradeDebugInfo)
|
|
llvm::UpgradeDebugInfo(*M);
|
|
|
|
UpgradeModuleFlags(*M);
|
|
UpgradeSectionAttributes(*M);
|
|
|
|
if (!Slots)
|
|
return false;
|
|
// Initialize the slot mapping.
|
|
// Because by this point we've parsed and validated everything, we can "steal"
|
|
// the mapping from LLParser as it doesn't need it anymore.
|
|
Slots->GlobalValues = std::move(NumberedVals);
|
|
Slots->MetadataNodes = std::move(NumberedMetadata);
|
|
for (const auto &I : NamedTypes)
|
|
Slots->NamedTypes.insert(std::make_pair(I.getKey(), I.second.first));
|
|
for (const auto &I : NumberedTypes)
|
|
Slots->Types.insert(std::make_pair(I.first, I.second.first));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Do final validity and sanity checks at the end of the index.
|
|
bool LLParser::validateEndOfIndex() {
|
|
if (!Index)
|
|
return false;
|
|
|
|
if (!ForwardRefValueInfos.empty())
|
|
return error(ForwardRefValueInfos.begin()->second.front().second,
|
|
"use of undefined summary '^" +
|
|
Twine(ForwardRefValueInfos.begin()->first) + "'");
|
|
|
|
if (!ForwardRefAliasees.empty())
|
|
return error(ForwardRefAliasees.begin()->second.front().second,
|
|
"use of undefined summary '^" +
|
|
Twine(ForwardRefAliasees.begin()->first) + "'");
|
|
|
|
if (!ForwardRefTypeIds.empty())
|
|
return error(ForwardRefTypeIds.begin()->second.front().second,
|
|
"use of undefined type id summary '^" +
|
|
Twine(ForwardRefTypeIds.begin()->first) + "'");
|
|
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Top-Level Entities
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool LLParser::parseTargetDefinitions() {
|
|
while (true) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_target:
|
|
if (parseTargetDefinition())
|
|
return true;
|
|
break;
|
|
case lltok::kw_source_filename:
|
|
if (parseSourceFileName())
|
|
return true;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LLParser::parseTopLevelEntities() {
|
|
// If there is no Module, then parse just the summary index entries.
|
|
if (!M) {
|
|
while (true) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::Eof:
|
|
return false;
|
|
case lltok::SummaryID:
|
|
if (parseSummaryEntry())
|
|
return true;
|
|
break;
|
|
case lltok::kw_source_filename:
|
|
if (parseSourceFileName())
|
|
return true;
|
|
break;
|
|
default:
|
|
// Skip everything else
|
|
Lex.Lex();
|
|
}
|
|
}
|
|
}
|
|
while (true) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected top-level entity");
|
|
case lltok::Eof: return false;
|
|
case lltok::kw_declare:
|
|
if (parseDeclare())
|
|
return true;
|
|
break;
|
|
case lltok::kw_define:
|
|
if (parseDefine())
|
|
return true;
|
|
break;
|
|
case lltok::kw_module:
|
|
if (parseModuleAsm())
|
|
return true;
|
|
break;
|
|
case lltok::kw_deplibs:
|
|
if (parseDepLibs())
|
|
return true;
|
|
break;
|
|
case lltok::LocalVarID:
|
|
if (parseUnnamedType())
|
|
return true;
|
|
break;
|
|
case lltok::LocalVar:
|
|
if (parseNamedType())
|
|
return true;
|
|
break;
|
|
case lltok::GlobalID:
|
|
if (parseUnnamedGlobal())
|
|
return true;
|
|
break;
|
|
case lltok::GlobalVar:
|
|
if (parseNamedGlobal())
|
|
return true;
|
|
break;
|
|
case lltok::ComdatVar: if (parseComdat()) return true; break;
|
|
case lltok::exclaim:
|
|
if (parseStandaloneMetadata())
|
|
return true;
|
|
break;
|
|
case lltok::SummaryID:
|
|
if (parseSummaryEntry())
|
|
return true;
|
|
break;
|
|
case lltok::MetadataVar:
|
|
if (parseNamedMetadata())
|
|
return true;
|
|
break;
|
|
case lltok::kw_attributes:
|
|
if (parseUnnamedAttrGrp())
|
|
return true;
|
|
break;
|
|
case lltok::kw_uselistorder:
|
|
if (parseUseListOrder())
|
|
return true;
|
|
break;
|
|
case lltok::kw_uselistorder_bb:
|
|
if (parseUseListOrderBB())
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= 'module' 'asm' STRINGCONSTANT
|
|
bool LLParser::parseModuleAsm() {
|
|
assert(Lex.getKind() == lltok::kw_module);
|
|
Lex.Lex();
|
|
|
|
std::string AsmStr;
|
|
if (parseToken(lltok::kw_asm, "expected 'module asm'") ||
|
|
parseStringConstant(AsmStr))
|
|
return true;
|
|
|
|
M->appendModuleInlineAsm(AsmStr);
|
|
return false;
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= 'target' 'triple' '=' STRINGCONSTANT
|
|
/// ::= 'target' 'datalayout' '=' STRINGCONSTANT
|
|
bool LLParser::parseTargetDefinition() {
|
|
assert(Lex.getKind() == lltok::kw_target);
|
|
std::string Str;
|
|
switch (Lex.Lex()) {
|
|
default:
|
|
return tokError("unknown target property");
|
|
case lltok::kw_triple:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' after target triple") ||
|
|
parseStringConstant(Str))
|
|
return true;
|
|
M->setTargetTriple(Str);
|
|
return false;
|
|
case lltok::kw_datalayout:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' after target datalayout") ||
|
|
parseStringConstant(Str))
|
|
return true;
|
|
M->setDataLayout(Str);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= 'source_filename' '=' STRINGCONSTANT
|
|
bool LLParser::parseSourceFileName() {
|
|
assert(Lex.getKind() == lltok::kw_source_filename);
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' after source_filename") ||
|
|
parseStringConstant(SourceFileName))
|
|
return true;
|
|
if (M)
|
|
M->setSourceFileName(SourceFileName);
|
|
return false;
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= 'deplibs' '=' '[' ']'
|
|
/// ::= 'deplibs' '=' '[' STRINGCONSTANT (',' STRINGCONSTANT)* ']'
|
|
/// FIXME: Remove in 4.0. Currently parse, but ignore.
|
|
bool LLParser::parseDepLibs() {
|
|
assert(Lex.getKind() == lltok::kw_deplibs);
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' after deplibs") ||
|
|
parseToken(lltok::lsquare, "expected '=' after deplibs"))
|
|
return true;
|
|
|
|
if (EatIfPresent(lltok::rsquare))
|
|
return false;
|
|
|
|
do {
|
|
std::string Str;
|
|
if (parseStringConstant(Str))
|
|
return true;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
return parseToken(lltok::rsquare, "expected ']' at end of list");
|
|
}
|
|
|
|
/// parseUnnamedType:
|
|
/// ::= LocalVarID '=' 'type' type
|
|
bool LLParser::parseUnnamedType() {
|
|
LocTy TypeLoc = Lex.getLoc();
|
|
unsigned TypeID = Lex.getUIntVal();
|
|
Lex.Lex(); // eat LocalVarID;
|
|
|
|
if (parseToken(lltok::equal, "expected '=' after name") ||
|
|
parseToken(lltok::kw_type, "expected 'type' after '='"))
|
|
return true;
|
|
|
|
Type *Result = nullptr;
|
|
if (parseStructDefinition(TypeLoc, "", NumberedTypes[TypeID], Result))
|
|
return true;
|
|
|
|
if (!isa<StructType>(Result)) {
|
|
std::pair<Type*, LocTy> &Entry = NumberedTypes[TypeID];
|
|
if (Entry.first)
|
|
return error(TypeLoc, "non-struct types may not be recursive");
|
|
Entry.first = Result;
|
|
Entry.second = SMLoc();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= LocalVar '=' 'type' type
|
|
bool LLParser::parseNamedType() {
|
|
std::string Name = Lex.getStrVal();
|
|
LocTy NameLoc = Lex.getLoc();
|
|
Lex.Lex(); // eat LocalVar.
|
|
|
|
if (parseToken(lltok::equal, "expected '=' after name") ||
|
|
parseToken(lltok::kw_type, "expected 'type' after name"))
|
|
return true;
|
|
|
|
Type *Result = nullptr;
|
|
if (parseStructDefinition(NameLoc, Name, NamedTypes[Name], Result))
|
|
return true;
|
|
|
|
if (!isa<StructType>(Result)) {
|
|
std::pair<Type*, LocTy> &Entry = NamedTypes[Name];
|
|
if (Entry.first)
|
|
return error(NameLoc, "non-struct types may not be recursive");
|
|
Entry.first = Result;
|
|
Entry.second = SMLoc();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= 'declare' FunctionHeader
|
|
bool LLParser::parseDeclare() {
|
|
assert(Lex.getKind() == lltok::kw_declare);
|
|
Lex.Lex();
|
|
|
|
std::vector<std::pair<unsigned, MDNode *>> MDs;
|
|
while (Lex.getKind() == lltok::MetadataVar) {
|
|
unsigned MDK;
|
|
MDNode *N;
|
|
if (parseMetadataAttachment(MDK, N))
|
|
return true;
|
|
MDs.push_back({MDK, N});
|
|
}
|
|
|
|
Function *F;
|
|
if (parseFunctionHeader(F, false))
|
|
return true;
|
|
for (auto &MD : MDs)
|
|
F->addMetadata(MD.first, *MD.second);
|
|
return false;
|
|
}
|
|
|
|
/// toplevelentity
|
|
/// ::= 'define' FunctionHeader (!dbg !56)* '{' ...
|
|
bool LLParser::parseDefine() {
|
|
assert(Lex.getKind() == lltok::kw_define);
|
|
Lex.Lex();
|
|
|
|
Function *F;
|
|
return parseFunctionHeader(F, true) || parseOptionalFunctionMetadata(*F) ||
|
|
parseFunctionBody(*F);
|
|
}
|
|
|
|
/// parseGlobalType
|
|
/// ::= 'constant'
|
|
/// ::= 'global'
|
|
bool LLParser::parseGlobalType(bool &IsConstant) {
|
|
if (Lex.getKind() == lltok::kw_constant)
|
|
IsConstant = true;
|
|
else if (Lex.getKind() == lltok::kw_global)
|
|
IsConstant = false;
|
|
else {
|
|
IsConstant = false;
|
|
return tokError("expected 'global' or 'constant'");
|
|
}
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseOptionalUnnamedAddr(
|
|
GlobalVariable::UnnamedAddr &UnnamedAddr) {
|
|
if (EatIfPresent(lltok::kw_unnamed_addr))
|
|
UnnamedAddr = GlobalValue::UnnamedAddr::Global;
|
|
else if (EatIfPresent(lltok::kw_local_unnamed_addr))
|
|
UnnamedAddr = GlobalValue::UnnamedAddr::Local;
|
|
else
|
|
UnnamedAddr = GlobalValue::UnnamedAddr::None;
|
|
return false;
|
|
}
|
|
|
|
/// parseUnnamedGlobal:
|
|
/// OptionalVisibility (ALIAS | IFUNC) ...
|
|
/// OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
|
|
/// OptionalDLLStorageClass
|
|
/// ... -> global variable
|
|
/// GlobalID '=' OptionalVisibility (ALIAS | IFUNC) ...
|
|
/// GlobalID '=' OptionalLinkage OptionalPreemptionSpecifier
|
|
/// OptionalVisibility
|
|
/// OptionalDLLStorageClass
|
|
/// ... -> global variable
|
|
bool LLParser::parseUnnamedGlobal() {
|
|
unsigned VarID = NumberedVals.size();
|
|
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;
|
|
|
|
if (parseToken(lltok::equal, "expected '=' after name"))
|
|
return true;
|
|
}
|
|
|
|
bool HasLinkage;
|
|
unsigned Linkage, Visibility, DLLStorageClass;
|
|
bool DSOLocal;
|
|
GlobalVariable::ThreadLocalMode TLM;
|
|
GlobalVariable::UnnamedAddr UnnamedAddr;
|
|
if (parseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass,
|
|
DSOLocal) ||
|
|
parseOptionalThreadLocal(TLM) || parseOptionalUnnamedAddr(UnnamedAddr))
|
|
return true;
|
|
|
|
if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc)
|
|
return parseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
|
|
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
|
|
|
|
return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility,
|
|
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
|
|
}
|
|
|
|
/// parseNamedGlobal:
|
|
/// GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ...
|
|
/// GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
|
|
/// OptionalVisibility OptionalDLLStorageClass
|
|
/// ... -> global variable
|
|
bool LLParser::parseNamedGlobal() {
|
|
assert(Lex.getKind() == lltok::GlobalVar);
|
|
LocTy NameLoc = Lex.getLoc();
|
|
std::string Name = Lex.getStrVal();
|
|
Lex.Lex();
|
|
|
|
bool HasLinkage;
|
|
unsigned Linkage, Visibility, DLLStorageClass;
|
|
bool DSOLocal;
|
|
GlobalVariable::ThreadLocalMode TLM;
|
|
GlobalVariable::UnnamedAddr UnnamedAddr;
|
|
if (parseToken(lltok::equal, "expected '=' in global variable") ||
|
|
parseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass,
|
|
DSOLocal) ||
|
|
parseOptionalThreadLocal(TLM) || parseOptionalUnnamedAddr(UnnamedAddr))
|
|
return true;
|
|
|
|
if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc)
|
|
return parseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
|
|
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
|
|
|
|
return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility,
|
|
DLLStorageClass, DSOLocal, TLM, UnnamedAddr);
|
|
}
|
|
|
|
bool LLParser::parseComdat() {
|
|
assert(Lex.getKind() == lltok::ComdatVar);
|
|
std::string Name = Lex.getStrVal();
|
|
LocTy NameLoc = Lex.getLoc();
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::equal, "expected '=' here"))
|
|
return true;
|
|
|
|
if (parseToken(lltok::kw_comdat, "expected comdat keyword"))
|
|
return tokError("expected comdat type");
|
|
|
|
Comdat::SelectionKind SK;
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("unknown selection kind");
|
|
case lltok::kw_any:
|
|
SK = Comdat::Any;
|
|
break;
|
|
case lltok::kw_exactmatch:
|
|
SK = Comdat::ExactMatch;
|
|
break;
|
|
case lltok::kw_largest:
|
|
SK = Comdat::Largest;
|
|
break;
|
|
case lltok::kw_noduplicates:
|
|
SK = Comdat::NoDuplicates;
|
|
break;
|
|
case lltok::kw_samesize:
|
|
SK = Comdat::SameSize;
|
|
break;
|
|
}
|
|
Lex.Lex();
|
|
|
|
// See if the comdat was forward referenced, if so, use the comdat.
|
|
Module::ComdatSymTabType &ComdatSymTab = M->getComdatSymbolTable();
|
|
Module::ComdatSymTabType::iterator I = ComdatSymTab.find(Name);
|
|
if (I != ComdatSymTab.end() && !ForwardRefComdats.erase(Name))
|
|
return error(NameLoc, "redefinition of comdat '$" + Name + "'");
|
|
|
|
Comdat *C;
|
|
if (I != ComdatSymTab.end())
|
|
C = &I->second;
|
|
else
|
|
C = M->getOrInsertComdat(Name);
|
|
C->setSelectionKind(SK);
|
|
|
|
return false;
|
|
}
|
|
|
|
// MDString:
|
|
// ::= '!' STRINGCONSTANT
|
|
bool LLParser::parseMDString(MDString *&Result) {
|
|
std::string Str;
|
|
if (parseStringConstant(Str))
|
|
return true;
|
|
Result = MDString::get(Context, Str);
|
|
return false;
|
|
}
|
|
|
|
// MDNode:
|
|
// ::= '!' MDNodeNumber
|
|
bool LLParser::parseMDNodeID(MDNode *&Result) {
|
|
// !{ ..., !42, ... }
|
|
LocTy IDLoc = Lex.getLoc();
|
|
unsigned MID = 0;
|
|
if (parseUInt32(MID))
|
|
return true;
|
|
|
|
// If not a forward reference, just return it now.
|
|
if (NumberedMetadata.count(MID)) {
|
|
Result = NumberedMetadata[MID];
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, create MDNode forward reference.
|
|
auto &FwdRef = ForwardRefMDNodes[MID];
|
|
FwdRef = std::make_pair(MDTuple::getTemporary(Context, None), IDLoc);
|
|
|
|
Result = FwdRef.first.get();
|
|
NumberedMetadata[MID].reset(Result);
|
|
return false;
|
|
}
|
|
|
|
/// parseNamedMetadata:
|
|
/// !foo = !{ !1, !2 }
|
|
bool LLParser::parseNamedMetadata() {
|
|
assert(Lex.getKind() == lltok::MetadataVar);
|
|
std::string Name = Lex.getStrVal();
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::equal, "expected '=' here") ||
|
|
parseToken(lltok::exclaim, "Expected '!' here") ||
|
|
parseToken(lltok::lbrace, "Expected '{' here"))
|
|
return true;
|
|
|
|
NamedMDNode *NMD = M->getOrInsertNamedMetadata(Name);
|
|
if (Lex.getKind() != lltok::rbrace)
|
|
do {
|
|
MDNode *N = nullptr;
|
|
// parse DIExpressions inline as a special case. They are still MDNodes,
|
|
// so they can still appear in named metadata. Remove this logic if they
|
|
// become plain Metadata.
|
|
if (Lex.getKind() == lltok::MetadataVar &&
|
|
Lex.getStrVal() == "DIExpression") {
|
|
if (parseDIExpression(N, /*IsDistinct=*/false))
|
|
return true;
|
|
} else if (parseToken(lltok::exclaim, "Expected '!' here") ||
|
|
parseMDNodeID(N)) {
|
|
return true;
|
|
}
|
|
NMD->addOperand(N);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
return parseToken(lltok::rbrace, "expected end of metadata node");
|
|
}
|
|
|
|
/// parseStandaloneMetadata:
|
|
/// !42 = !{...}
|
|
bool LLParser::parseStandaloneMetadata() {
|
|
assert(Lex.getKind() == lltok::exclaim);
|
|
Lex.Lex();
|
|
unsigned MetadataID = 0;
|
|
|
|
MDNode *Init;
|
|
if (parseUInt32(MetadataID) || parseToken(lltok::equal, "expected '=' here"))
|
|
return true;
|
|
|
|
// Detect common error, from old metadata syntax.
|
|
if (Lex.getKind() == lltok::Type)
|
|
return tokError("unexpected type in metadata definition");
|
|
|
|
bool IsDistinct = EatIfPresent(lltok::kw_distinct);
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
if (parseSpecializedMDNode(Init, IsDistinct))
|
|
return true;
|
|
} else if (parseToken(lltok::exclaim, "Expected '!' here") ||
|
|
parseMDTuple(Init, IsDistinct))
|
|
return true;
|
|
|
|
// See if this was forward referenced, if so, handle it.
|
|
auto FI = ForwardRefMDNodes.find(MetadataID);
|
|
if (FI != ForwardRefMDNodes.end()) {
|
|
FI->second.first->replaceAllUsesWith(Init);
|
|
ForwardRefMDNodes.erase(FI);
|
|
|
|
assert(NumberedMetadata[MetadataID] == Init && "Tracking VH didn't work");
|
|
} else {
|
|
if (NumberedMetadata.count(MetadataID))
|
|
return tokError("Metadata id is already used");
|
|
NumberedMetadata[MetadataID].reset(Init);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Skips a single module summary entry.
|
|
bool LLParser::skipModuleSummaryEntry() {
|
|
// Each module summary entry consists of a tag for the entry
|
|
// type, followed by a colon, then the fields which may be surrounded by
|
|
// nested sets of parentheses. The "tag:" looks like a Label. Once parsing
|
|
// support is in place we will look for the tokens corresponding to the
|
|
// expected tags.
|
|
if (Lex.getKind() != lltok::kw_gv && Lex.getKind() != lltok::kw_module &&
|
|
Lex.getKind() != lltok::kw_typeid && Lex.getKind() != lltok::kw_flags &&
|
|
Lex.getKind() != lltok::kw_blockcount)
|
|
return tokError(
|
|
"Expected 'gv', 'module', 'typeid', 'flags' or 'blockcount' at the "
|
|
"start of summary entry");
|
|
if (Lex.getKind() == lltok::kw_flags)
|
|
return parseSummaryIndexFlags();
|
|
if (Lex.getKind() == lltok::kw_blockcount)
|
|
return parseBlockCount();
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' at start of summary entry") ||
|
|
parseToken(lltok::lparen, "expected '(' at start of summary entry"))
|
|
return true;
|
|
// Now walk through the parenthesized entry, until the number of open
|
|
// parentheses goes back down to 0 (the first '(' was parsed above).
|
|
unsigned NumOpenParen = 1;
|
|
do {
|
|
switch (Lex.getKind()) {
|
|
case lltok::lparen:
|
|
NumOpenParen++;
|
|
break;
|
|
case lltok::rparen:
|
|
NumOpenParen--;
|
|
break;
|
|
case lltok::Eof:
|
|
return tokError("found end of file while parsing summary entry");
|
|
default:
|
|
// Skip everything in between parentheses.
|
|
break;
|
|
}
|
|
Lex.Lex();
|
|
} while (NumOpenParen > 0);
|
|
return false;
|
|
}
|
|
|
|
/// SummaryEntry
|
|
/// ::= SummaryID '=' GVEntry | ModuleEntry | TypeIdEntry
|
|
bool LLParser::parseSummaryEntry() {
|
|
assert(Lex.getKind() == lltok::SummaryID);
|
|
unsigned SummaryID = Lex.getUIntVal();
|
|
|
|
// For summary entries, colons should be treated as distinct tokens,
|
|
// not an indication of the end of a label token.
|
|
Lex.setIgnoreColonInIdentifiers(true);
|
|
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' here"))
|
|
return true;
|
|
|
|
// If we don't have an index object, skip the summary entry.
|
|
if (!Index)
|
|
return skipModuleSummaryEntry();
|
|
|
|
bool result = false;
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_gv:
|
|
result = parseGVEntry(SummaryID);
|
|
break;
|
|
case lltok::kw_module:
|
|
result = parseModuleEntry(SummaryID);
|
|
break;
|
|
case lltok::kw_typeid:
|
|
result = parseTypeIdEntry(SummaryID);
|
|
break;
|
|
case lltok::kw_typeidCompatibleVTable:
|
|
result = parseTypeIdCompatibleVtableEntry(SummaryID);
|
|
break;
|
|
case lltok::kw_flags:
|
|
result = parseSummaryIndexFlags();
|
|
break;
|
|
case lltok::kw_blockcount:
|
|
result = parseBlockCount();
|
|
break;
|
|
default:
|
|
result = error(Lex.getLoc(), "unexpected summary kind");
|
|
break;
|
|
}
|
|
Lex.setIgnoreColonInIdentifiers(false);
|
|
return result;
|
|
}
|
|
|
|
static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
|
|
return !GlobalValue::isLocalLinkage((GlobalValue::LinkageTypes)L) ||
|
|
(GlobalValue::VisibilityTypes)V == GlobalValue::DefaultVisibility;
|
|
}
|
|
|
|
// If there was an explicit dso_local, update GV. In the absence of an explicit
|
|
// dso_local we keep the default value.
|
|
static void maybeSetDSOLocal(bool DSOLocal, GlobalValue &GV) {
|
|
if (DSOLocal)
|
|
GV.setDSOLocal(true);
|
|
}
|
|
|
|
/// parseIndirectSymbol:
|
|
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
|
|
/// OptionalVisibility OptionalDLLStorageClass
|
|
/// OptionalThreadLocal OptionalUnnamedAddr
|
|
/// 'alias|ifunc' IndirectSymbol IndirectSymbolAttr*
|
|
///
|
|
/// IndirectSymbol
|
|
/// ::= TypeAndValue
|
|
///
|
|
/// IndirectSymbolAttr
|
|
/// ::= ',' 'partition' StringConstant
|
|
///
|
|
/// Everything through OptionalUnnamedAddr has already been parsed.
|
|
///
|
|
bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
|
|
unsigned L, unsigned Visibility,
|
|
unsigned DLLStorageClass, bool DSOLocal,
|
|
GlobalVariable::ThreadLocalMode TLM,
|
|
GlobalVariable::UnnamedAddr UnnamedAddr) {
|
|
bool IsAlias;
|
|
if (Lex.getKind() == lltok::kw_alias)
|
|
IsAlias = true;
|
|
else if (Lex.getKind() == lltok::kw_ifunc)
|
|
IsAlias = false;
|
|
else
|
|
llvm_unreachable("Not an alias or ifunc!");
|
|
Lex.Lex();
|
|
|
|
GlobalValue::LinkageTypes Linkage = (GlobalValue::LinkageTypes) L;
|
|
|
|
if(IsAlias && !GlobalAlias::isValidLinkage(Linkage))
|
|
return error(NameLoc, "invalid linkage type for alias");
|
|
|
|
if (!isValidVisibilityForLinkage(Visibility, L))
|
|
return error(NameLoc,
|
|
"symbol with local linkage must have default visibility");
|
|
|
|
Type *Ty;
|
|
LocTy ExplicitTypeLoc = Lex.getLoc();
|
|
if (parseType(Ty) ||
|
|
parseToken(lltok::comma, "expected comma after alias or ifunc's type"))
|
|
return true;
|
|
|
|
Constant *Aliasee;
|
|
LocTy AliaseeLoc = Lex.getLoc();
|
|
if (Lex.getKind() != lltok::kw_bitcast &&
|
|
Lex.getKind() != lltok::kw_getelementptr &&
|
|
Lex.getKind() != lltok::kw_addrspacecast &&
|
|
Lex.getKind() != lltok::kw_inttoptr) {
|
|
if (parseGlobalTypeAndValue(Aliasee))
|
|
return true;
|
|
} else {
|
|
// The bitcast dest type is not present, it is implied by the dest type.
|
|
ValID ID;
|
|
if (parseValID(ID))
|
|
return true;
|
|
if (ID.Kind != ValID::t_Constant)
|
|
return error(AliaseeLoc, "invalid aliasee");
|
|
Aliasee = ID.ConstantVal;
|
|
}
|
|
|
|
Type *AliaseeType = Aliasee->getType();
|
|
auto *PTy = dyn_cast<PointerType>(AliaseeType);
|
|
if (!PTy)
|
|
return error(AliaseeLoc, "An alias or ifunc must have pointer type");
|
|
unsigned AddrSpace = PTy->getAddressSpace();
|
|
|
|
if (IsAlias && Ty != PTy->getElementType())
|
|
return error(ExplicitTypeLoc,
|
|
"explicit pointee type doesn't match operand's pointee type");
|
|
|
|
if (!IsAlias && !PTy->getElementType()->isFunctionTy())
|
|
return error(ExplicitTypeLoc,
|
|
"explicit pointee type should be a function type");
|
|
|
|
GlobalValue *GVal = nullptr;
|
|
|
|
// See if the alias was forward referenced, if so, prepare to replace the
|
|
// forward reference.
|
|
if (!Name.empty()) {
|
|
GVal = M->getNamedValue(Name);
|
|
if (GVal) {
|
|
if (!ForwardRefVals.erase(Name))
|
|
return error(NameLoc, "redefinition of global '@" + Name + "'");
|
|
}
|
|
} else {
|
|
auto I = ForwardRefValIDs.find(NumberedVals.size());
|
|
if (I != ForwardRefValIDs.end()) {
|
|
GVal = I->second.first;
|
|
ForwardRefValIDs.erase(I);
|
|
}
|
|
}
|
|
|
|
// Okay, create the alias but do not insert it into the module yet.
|
|
std::unique_ptr<GlobalIndirectSymbol> GA;
|
|
if (IsAlias)
|
|
GA.reset(GlobalAlias::create(Ty, AddrSpace,
|
|
(GlobalValue::LinkageTypes)Linkage, Name,
|
|
Aliasee, /*Parent*/ nullptr));
|
|
else
|
|
GA.reset(GlobalIFunc::create(Ty, AddrSpace,
|
|
(GlobalValue::LinkageTypes)Linkage, Name,
|
|
Aliasee, /*Parent*/ nullptr));
|
|
GA->setThreadLocalMode(TLM);
|
|
GA->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
|
GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
|
|
GA->setUnnamedAddr(UnnamedAddr);
|
|
maybeSetDSOLocal(DSOLocal, *GA);
|
|
|
|
// At this point we've parsed everything except for the IndirectSymbolAttrs.
|
|
// Now parse them if there are any.
|
|
while (Lex.getKind() == lltok::comma) {
|
|
Lex.Lex();
|
|
|
|
if (Lex.getKind() == lltok::kw_partition) {
|
|
Lex.Lex();
|
|
GA->setPartition(Lex.getStrVal());
|
|
if (parseToken(lltok::StringConstant, "expected partition string"))
|
|
return true;
|
|
} else {
|
|
return tokError("unknown alias or ifunc property!");
|
|
}
|
|
}
|
|
|
|
if (Name.empty())
|
|
NumberedVals.push_back(GA.get());
|
|
|
|
if (GVal) {
|
|
// Verify that types agree.
|
|
if (GVal->getType() != GA->getType())
|
|
return error(
|
|
ExplicitTypeLoc,
|
|
"forward reference and definition of alias have different types");
|
|
|
|
// If they agree, just RAUW the old value with the alias and remove the
|
|
// forward ref info.
|
|
GVal->replaceAllUsesWith(GA.get());
|
|
GVal->eraseFromParent();
|
|
}
|
|
|
|
// Insert into the module, we know its name won't collide now.
|
|
if (IsAlias)
|
|
M->getAliasList().push_back(cast<GlobalAlias>(GA.get()));
|
|
else
|
|
M->getIFuncList().push_back(cast<GlobalIFunc>(GA.get()));
|
|
assert(GA->getName() == Name && "Should not be a name conflict!");
|
|
|
|
// The module owns this now
|
|
GA.release();
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseGlobal
|
|
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
|
|
/// OptionalVisibility OptionalDLLStorageClass
|
|
/// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace
|
|
/// OptionalExternallyInitialized GlobalType Type Const OptionalAttrs
|
|
/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
|
|
/// OptionalDLLStorageClass OptionalThreadLocal OptionalUnnamedAddr
|
|
/// OptionalAddrSpace OptionalExternallyInitialized GlobalType Type
|
|
/// Const OptionalAttrs
|
|
///
|
|
/// Everything up to and including OptionalUnnamedAddr has been parsed
|
|
/// already.
|
|
///
|
|
bool LLParser::parseGlobal(const std::string &Name, LocTy NameLoc,
|
|
unsigned Linkage, bool HasLinkage,
|
|
unsigned Visibility, unsigned DLLStorageClass,
|
|
bool DSOLocal, GlobalVariable::ThreadLocalMode TLM,
|
|
GlobalVariable::UnnamedAddr UnnamedAddr) {
|
|
if (!isValidVisibilityForLinkage(Visibility, Linkage))
|
|
return error(NameLoc,
|
|
"symbol with local linkage must have default visibility");
|
|
|
|
unsigned AddrSpace;
|
|
bool IsConstant, IsExternallyInitialized;
|
|
LocTy IsExternallyInitializedLoc;
|
|
LocTy TyLoc;
|
|
|
|
Type *Ty = nullptr;
|
|
if (parseOptionalAddrSpace(AddrSpace) ||
|
|
parseOptionalToken(lltok::kw_externally_initialized,
|
|
IsExternallyInitialized,
|
|
&IsExternallyInitializedLoc) ||
|
|
parseGlobalType(IsConstant) || parseType(Ty, TyLoc))
|
|
return true;
|
|
|
|
// If the linkage is specified and is external, then no initializer is
|
|
// present.
|
|
Constant *Init = nullptr;
|
|
if (!HasLinkage ||
|
|
!GlobalValue::isValidDeclarationLinkage(
|
|
(GlobalValue::LinkageTypes)Linkage)) {
|
|
if (parseGlobalValue(Ty, Init))
|
|
return true;
|
|
}
|
|
|
|
if (Ty->isFunctionTy() || !PointerType::isValidElementType(Ty))
|
|
return error(TyLoc, "invalid type for global variable");
|
|
|
|
GlobalValue *GVal = nullptr;
|
|
|
|
// See if the global was forward referenced, if so, use the global.
|
|
if (!Name.empty()) {
|
|
GVal = M->getNamedValue(Name);
|
|
if (GVal) {
|
|
if (!ForwardRefVals.erase(Name))
|
|
return error(NameLoc, "redefinition of global '@" + Name + "'");
|
|
}
|
|
} else {
|
|
auto I = ForwardRefValIDs.find(NumberedVals.size());
|
|
if (I != ForwardRefValIDs.end()) {
|
|
GVal = I->second.first;
|
|
ForwardRefValIDs.erase(I);
|
|
}
|
|
}
|
|
|
|
GlobalVariable *GV;
|
|
if (!GVal) {
|
|
GV = new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, nullptr,
|
|
Name, nullptr, GlobalVariable::NotThreadLocal,
|
|
AddrSpace);
|
|
} else {
|
|
if (GVal->getValueType() != Ty)
|
|
return error(
|
|
TyLoc,
|
|
"forward reference and definition of global have different types");
|
|
|
|
GV = cast<GlobalVariable>(GVal);
|
|
|
|
// Move the forward-reference to the correct spot in the module.
|
|
M->getGlobalList().splice(M->global_end(), M->getGlobalList(), GV);
|
|
}
|
|
|
|
if (Name.empty())
|
|
NumberedVals.push_back(GV);
|
|
|
|
// Set the parsed properties on the global.
|
|
if (Init)
|
|
GV->setInitializer(Init);
|
|
GV->setConstant(IsConstant);
|
|
GV->setLinkage((GlobalValue::LinkageTypes)Linkage);
|
|
maybeSetDSOLocal(DSOLocal, *GV);
|
|
GV->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
|
GV->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
|
|
GV->setExternallyInitialized(IsExternallyInitialized);
|
|
GV->setThreadLocalMode(TLM);
|
|
GV->setUnnamedAddr(UnnamedAddr);
|
|
|
|
// parse attributes on the global.
|
|
while (Lex.getKind() == lltok::comma) {
|
|
Lex.Lex();
|
|
|
|
if (Lex.getKind() == lltok::kw_section) {
|
|
Lex.Lex();
|
|
GV->setSection(Lex.getStrVal());
|
|
if (parseToken(lltok::StringConstant, "expected global section string"))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::kw_partition) {
|
|
Lex.Lex();
|
|
GV->setPartition(Lex.getStrVal());
|
|
if (parseToken(lltok::StringConstant, "expected partition string"))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::kw_align) {
|
|
MaybeAlign Alignment;
|
|
if (parseOptionalAlignment(Alignment))
|
|
return true;
|
|
GV->setAlignment(Alignment);
|
|
} else if (Lex.getKind() == lltok::MetadataVar) {
|
|
if (parseGlobalObjectMetadataAttachment(*GV))
|
|
return true;
|
|
} else {
|
|
Comdat *C;
|
|
if (parseOptionalComdat(Name, C))
|
|
return true;
|
|
if (C)
|
|
GV->setComdat(C);
|
|
else
|
|
return tokError("unknown global variable property!");
|
|
}
|
|
}
|
|
|
|
AttrBuilder Attrs;
|
|
LocTy BuiltinLoc;
|
|
std::vector<unsigned> FwdRefAttrGrps;
|
|
if (parseFnAttributeValuePairs(Attrs, FwdRefAttrGrps, false, BuiltinLoc))
|
|
return true;
|
|
if (Attrs.hasAttributes() || !FwdRefAttrGrps.empty()) {
|
|
GV->setAttributes(AttributeSet::get(Context, Attrs));
|
|
ForwardRefAttrGroups[GV] = FwdRefAttrGrps;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseUnnamedAttrGrp
|
|
/// ::= 'attributes' AttrGrpID '=' '{' AttrValPair+ '}'
|
|
bool LLParser::parseUnnamedAttrGrp() {
|
|
assert(Lex.getKind() == lltok::kw_attributes);
|
|
LocTy AttrGrpLoc = Lex.getLoc();
|
|
Lex.Lex();
|
|
|
|
if (Lex.getKind() != lltok::AttrGrpID)
|
|
return tokError("expected attribute group id");
|
|
|
|
unsigned VarID = Lex.getUIntVal();
|
|
std::vector<unsigned> unused;
|
|
LocTy BuiltinLoc;
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::equal, "expected '=' here") ||
|
|
parseToken(lltok::lbrace, "expected '{' here") ||
|
|
parseFnAttributeValuePairs(NumberedAttrBuilders[VarID], unused, true,
|
|
BuiltinLoc) ||
|
|
parseToken(lltok::rbrace, "expected end of attribute group"))
|
|
return true;
|
|
|
|
if (!NumberedAttrBuilders[VarID].hasAttributes())
|
|
return error(AttrGrpLoc, "attribute group has no attributes");
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseFnAttributeValuePairs
|
|
/// ::= <attr> | <attr> '=' <value>
|
|
bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
|
|
std::vector<unsigned> &FwdRefAttrGrps,
|
|
bool inAttrGrp, LocTy &BuiltinLoc) {
|
|
bool HaveError = false;
|
|
|
|
B.clear();
|
|
|
|
while (true) {
|
|
lltok::Kind Token = Lex.getKind();
|
|
if (Token == lltok::kw_builtin)
|
|
BuiltinLoc = Lex.getLoc();
|
|
switch (Token) {
|
|
default:
|
|
if (!inAttrGrp) return HaveError;
|
|
return error(Lex.getLoc(), "unterminated attribute group");
|
|
case lltok::rbrace:
|
|
// Finished.
|
|
return false;
|
|
|
|
case lltok::AttrGrpID: {
|
|
// Allow a function to reference an attribute group:
|
|
//
|
|
// define void @foo() #1 { ... }
|
|
if (inAttrGrp)
|
|
HaveError |= error(
|
|
Lex.getLoc(),
|
|
"cannot have an attribute group reference in an attribute group");
|
|
|
|
unsigned AttrGrpNum = Lex.getUIntVal();
|
|
if (inAttrGrp) break;
|
|
|
|
// Save the reference to the attribute group. We'll fill it in later.
|
|
FwdRefAttrGrps.push_back(AttrGrpNum);
|
|
break;
|
|
}
|
|
// Target-dependent attributes:
|
|
case lltok::StringConstant: {
|
|
if (parseStringAttribute(B))
|
|
return true;
|
|
continue;
|
|
}
|
|
|
|
// Target-independent attributes:
|
|
case lltok::kw_align: {
|
|
// As a hack, we allow function alignment to be initially parsed as an
|
|
// attribute on a function declaration/definition or added to an attribute
|
|
// group and later moved to the alignment field.
|
|
MaybeAlign Alignment;
|
|
if (inAttrGrp) {
|
|
Lex.Lex();
|
|
uint32_t Value = 0;
|
|
if (parseToken(lltok::equal, "expected '=' here") || parseUInt32(Value))
|
|
return true;
|
|
Alignment = Align(Value);
|
|
} else {
|
|
if (parseOptionalAlignment(Alignment))
|
|
return true;
|
|
}
|
|
B.addAlignmentAttr(Alignment);
|
|
continue;
|
|
}
|
|
case lltok::kw_alignstack: {
|
|
unsigned Alignment;
|
|
if (inAttrGrp) {
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' here") ||
|
|
parseUInt32(Alignment))
|
|
return true;
|
|
} else {
|
|
if (parseOptionalStackAlignment(Alignment))
|
|
return true;
|
|
}
|
|
B.addStackAlignmentAttr(Alignment);
|
|
continue;
|
|
}
|
|
case lltok::kw_allocsize: {
|
|
unsigned ElemSizeArg;
|
|
Optional<unsigned> NumElemsArg;
|
|
// inAttrGrp doesn't matter; we only support allocsize(a[, b])
|
|
if (parseAllocSizeArguments(ElemSizeArg, NumElemsArg))
|
|
return true;
|
|
B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
|
|
continue;
|
|
}
|
|
case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break;
|
|
case lltok::kw_argmemonly: B.addAttribute(Attribute::ArgMemOnly); break;
|
|
case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break;
|
|
case lltok::kw_cold: B.addAttribute(Attribute::Cold); break;
|
|
case lltok::kw_convergent: B.addAttribute(Attribute::Convergent); break;
|
|
case lltok::kw_inaccessiblememonly:
|
|
B.addAttribute(Attribute::InaccessibleMemOnly); break;
|
|
case lltok::kw_inaccessiblemem_or_argmemonly:
|
|
B.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); break;
|
|
case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break;
|
|
case lltok::kw_jumptable: B.addAttribute(Attribute::JumpTable); break;
|
|
case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break;
|
|
case lltok::kw_mustprogress:
|
|
B.addAttribute(Attribute::MustProgress);
|
|
break;
|
|
case lltok::kw_naked: B.addAttribute(Attribute::Naked); break;
|
|
case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin); break;
|
|
case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break;
|
|
case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break;
|
|
case lltok::kw_noimplicitfloat:
|
|
B.addAttribute(Attribute::NoImplicitFloat); break;
|
|
case lltok::kw_noinline: B.addAttribute(Attribute::NoInline); break;
|
|
case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break;
|
|
case lltok::kw_nomerge: B.addAttribute(Attribute::NoMerge); break;
|
|
case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break;
|
|
case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break;
|
|
case lltok::kw_nosync: B.addAttribute(Attribute::NoSync); break;
|
|
case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
|
|
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
|
|
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
|
|
case lltok::kw_null_pointer_is_valid:
|
|
B.addAttribute(Attribute::NullPointerIsValid); break;
|
|
case lltok::kw_optforfuzzing:
|
|
B.addAttribute(Attribute::OptForFuzzing); break;
|
|
case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break;
|
|
case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break;
|
|
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
|
|
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
|
|
case lltok::kw_returns_twice:
|
|
B.addAttribute(Attribute::ReturnsTwice); break;
|
|
case lltok::kw_speculatable: B.addAttribute(Attribute::Speculatable); break;
|
|
case lltok::kw_nossp:
|
|
B.addAttribute(Attribute::NoStackProtect);
|
|
break;
|
|
case lltok::kw_ssp: B.addAttribute(Attribute::StackProtect); break;
|
|
case lltok::kw_sspreq: B.addAttribute(Attribute::StackProtectReq); break;
|
|
case lltok::kw_sspstrong:
|
|
B.addAttribute(Attribute::StackProtectStrong); break;
|
|
case lltok::kw_safestack: B.addAttribute(Attribute::SafeStack); break;
|
|
case lltok::kw_shadowcallstack:
|
|
B.addAttribute(Attribute::ShadowCallStack); break;
|
|
case lltok::kw_sanitize_address:
|
|
B.addAttribute(Attribute::SanitizeAddress); break;
|
|
case lltok::kw_sanitize_hwaddress:
|
|
B.addAttribute(Attribute::SanitizeHWAddress); break;
|
|
case lltok::kw_sanitize_memtag:
|
|
B.addAttribute(Attribute::SanitizeMemTag); break;
|
|
case lltok::kw_sanitize_thread:
|
|
B.addAttribute(Attribute::SanitizeThread); break;
|
|
case lltok::kw_sanitize_memory:
|
|
B.addAttribute(Attribute::SanitizeMemory); break;
|
|
case lltok::kw_speculative_load_hardening:
|
|
B.addAttribute(Attribute::SpeculativeLoadHardening);
|
|
break;
|
|
case lltok::kw_strictfp: B.addAttribute(Attribute::StrictFP); break;
|
|
case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break;
|
|
case lltok::kw_willreturn: B.addAttribute(Attribute::WillReturn); break;
|
|
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
|
|
case lltok::kw_preallocated: {
|
|
Type *Ty;
|
|
if (parsePreallocated(Ty))
|
|
return true;
|
|
B.addPreallocatedAttr(Ty);
|
|
break;
|
|
}
|
|
|
|
// error handling.
|
|
case lltok::kw_inreg:
|
|
case lltok::kw_signext:
|
|
case lltok::kw_zeroext:
|
|
HaveError |=
|
|
error(Lex.getLoc(), "invalid use of attribute on a function");
|
|
break;
|
|
case lltok::kw_byval:
|
|
case lltok::kw_dereferenceable:
|
|
case lltok::kw_dereferenceable_or_null:
|
|
case lltok::kw_inalloca:
|
|
case lltok::kw_nest:
|
|
case lltok::kw_noalias:
|
|
case lltok::kw_noundef:
|
|
case lltok::kw_nocapture:
|
|
case lltok::kw_nonnull:
|
|
case lltok::kw_returned:
|
|
case lltok::kw_sret:
|
|
case lltok::kw_swifterror:
|
|
case lltok::kw_swiftself:
|
|
case lltok::kw_immarg:
|
|
case lltok::kw_byref:
|
|
HaveError |=
|
|
error(Lex.getLoc(),
|
|
"invalid use of parameter-only attribute on a function");
|
|
break;
|
|
}
|
|
|
|
// parsePreallocated() consumes token
|
|
if (Token != lltok::kw_preallocated)
|
|
Lex.Lex();
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// GlobalValue Reference/Resolution Routines.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy,
|
|
const std::string &Name) {
|
|
if (auto *FT = dyn_cast<FunctionType>(PTy->getElementType()))
|
|
return Function::Create(FT, GlobalValue::ExternalWeakLinkage,
|
|
PTy->getAddressSpace(), Name, M);
|
|
else
|
|
return new GlobalVariable(*M, PTy->getElementType(), false,
|
|
GlobalValue::ExternalWeakLinkage, nullptr, Name,
|
|
nullptr, GlobalVariable::NotThreadLocal,
|
|
PTy->getAddressSpace());
|
|
}
|
|
|
|
Value *LLParser::checkValidVariableType(LocTy Loc, const Twine &Name, Type *Ty,
|
|
Value *Val, bool IsCall) {
|
|
if (Val->getType() == Ty)
|
|
return Val;
|
|
// For calls we also accept variables in the program address space.
|
|
Type *SuggestedTy = Ty;
|
|
if (IsCall && isa<PointerType>(Ty)) {
|
|
Type *TyInProgAS = cast<PointerType>(Ty)->getElementType()->getPointerTo(
|
|
M->getDataLayout().getProgramAddressSpace());
|
|
SuggestedTy = TyInProgAS;
|
|
if (Val->getType() == TyInProgAS)
|
|
return Val;
|
|
}
|
|
if (Ty->isLabelTy())
|
|
error(Loc, "'" + Name + "' is not a basic block");
|
|
else
|
|
error(Loc, "'" + Name + "' defined with type '" +
|
|
getTypeString(Val->getType()) + "' but expected '" +
|
|
getTypeString(SuggestedTy) + "'");
|
|
return nullptr;
|
|
}
|
|
|
|
/// getGlobalVal - Get a value with the specified name or ID, creating a
|
|
/// forward reference record if needed. This can return null if the value
|
|
/// exists but does not have the right type.
|
|
GlobalValue *LLParser::getGlobalVal(const std::string &Name, Type *Ty,
|
|
LocTy Loc, bool IsCall) {
|
|
PointerType *PTy = dyn_cast<PointerType>(Ty);
|
|
if (!PTy) {
|
|
error(Loc, "global variable reference must have pointer type");
|
|
return nullptr;
|
|
}
|
|
|
|
// Look this name up in the normal function symbol table.
|
|
GlobalValue *Val =
|
|
cast_or_null<GlobalValue>(M->getValueSymbolTable().lookup(Name));
|
|
|
|
// If this is a forward reference for the value, see if we already created a
|
|
// forward ref record.
|
|
if (!Val) {
|
|
auto I = ForwardRefVals.find(Name);
|
|
if (I != ForwardRefVals.end())
|
|
Val = I->second.first;
|
|
}
|
|
|
|
// If we have the value in the symbol table or fwd-ref table, return it.
|
|
if (Val)
|
|
return cast_or_null<GlobalValue>(
|
|
checkValidVariableType(Loc, "@" + Name, Ty, Val, IsCall));
|
|
|
|
// Otherwise, create a new forward reference for this value and remember it.
|
|
GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name);
|
|
ForwardRefVals[Name] = std::make_pair(FwdVal, Loc);
|
|
return FwdVal;
|
|
}
|
|
|
|
GlobalValue *LLParser::getGlobalVal(unsigned ID, Type *Ty, LocTy Loc,
|
|
bool IsCall) {
|
|
PointerType *PTy = dyn_cast<PointerType>(Ty);
|
|
if (!PTy) {
|
|
error(Loc, "global variable reference must have pointer type");
|
|
return nullptr;
|
|
}
|
|
|
|
GlobalValue *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr;
|
|
|
|
// If this is a forward reference for the value, see if we already created a
|
|
// forward ref record.
|
|
if (!Val) {
|
|
auto I = ForwardRefValIDs.find(ID);
|
|
if (I != ForwardRefValIDs.end())
|
|
Val = I->second.first;
|
|
}
|
|
|
|
// If we have the value in the symbol table or fwd-ref table, return it.
|
|
if (Val)
|
|
return cast_or_null<GlobalValue>(
|
|
checkValidVariableType(Loc, "@" + Twine(ID), Ty, Val, IsCall));
|
|
|
|
// Otherwise, create a new forward reference for this value and remember it.
|
|
GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, "");
|
|
ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc);
|
|
return FwdVal;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Comdat Reference/Resolution Routines.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
Comdat *LLParser::getComdat(const std::string &Name, LocTy Loc) {
|
|
// Look this name up in the comdat symbol table.
|
|
Module::ComdatSymTabType &ComdatSymTab = M->getComdatSymbolTable();
|
|
Module::ComdatSymTabType::iterator I = ComdatSymTab.find(Name);
|
|
if (I != ComdatSymTab.end())
|
|
return &I->second;
|
|
|
|
// Otherwise, create a new forward reference for this value and remember it.
|
|
Comdat *C = M->getOrInsertComdat(Name);
|
|
ForwardRefComdats[Name] = Loc;
|
|
return C;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Helper Routines.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseToken - If the current token has the specified kind, eat it and return
|
|
/// success. Otherwise, emit the specified error and return failure.
|
|
bool LLParser::parseToken(lltok::Kind T, const char *ErrMsg) {
|
|
if (Lex.getKind() != T)
|
|
return tokError(ErrMsg);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseStringConstant
|
|
/// ::= StringConstant
|
|
bool LLParser::parseStringConstant(std::string &Result) {
|
|
if (Lex.getKind() != lltok::StringConstant)
|
|
return tokError("expected string constant");
|
|
Result = Lex.getStrVal();
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseUInt32
|
|
/// ::= uint32
|
|
bool LLParser::parseUInt32(uint32_t &Val) {
|
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
|
|
return tokError("expected integer");
|
|
uint64_t Val64 = Lex.getAPSIntVal().getLimitedValue(0xFFFFFFFFULL+1);
|
|
if (Val64 != unsigned(Val64))
|
|
return tokError("expected 32-bit integer (too large)");
|
|
Val = Val64;
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseUInt64
|
|
/// ::= uint64
|
|
bool LLParser::parseUInt64(uint64_t &Val) {
|
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
|
|
return tokError("expected integer");
|
|
Val = Lex.getAPSIntVal().getLimitedValue();
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseTLSModel
|
|
/// := 'localdynamic'
|
|
/// := 'initialexec'
|
|
/// := 'localexec'
|
|
bool LLParser::parseTLSModel(GlobalVariable::ThreadLocalMode &TLM) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected localdynamic, initialexec or localexec");
|
|
case lltok::kw_localdynamic:
|
|
TLM = GlobalVariable::LocalDynamicTLSModel;
|
|
break;
|
|
case lltok::kw_initialexec:
|
|
TLM = GlobalVariable::InitialExecTLSModel;
|
|
break;
|
|
case lltok::kw_localexec:
|
|
TLM = GlobalVariable::LocalExecTLSModel;
|
|
break;
|
|
}
|
|
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalThreadLocal
|
|
/// := /*empty*/
|
|
/// := 'thread_local'
|
|
/// := 'thread_local' '(' tlsmodel ')'
|
|
bool LLParser::parseOptionalThreadLocal(GlobalVariable::ThreadLocalMode &TLM) {
|
|
TLM = GlobalVariable::NotThreadLocal;
|
|
if (!EatIfPresent(lltok::kw_thread_local))
|
|
return false;
|
|
|
|
TLM = GlobalVariable::GeneralDynamicTLSModel;
|
|
if (Lex.getKind() == lltok::lparen) {
|
|
Lex.Lex();
|
|
return parseTLSModel(TLM) ||
|
|
parseToken(lltok::rparen, "expected ')' after thread local model");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalAddrSpace
|
|
/// := /*empty*/
|
|
/// := 'addrspace' '(' uint32 ')'
|
|
bool LLParser::parseOptionalAddrSpace(unsigned &AddrSpace, unsigned DefaultAS) {
|
|
AddrSpace = DefaultAS;
|
|
if (!EatIfPresent(lltok::kw_addrspace))
|
|
return false;
|
|
return parseToken(lltok::lparen, "expected '(' in address space") ||
|
|
parseUInt32(AddrSpace) ||
|
|
parseToken(lltok::rparen, "expected ')' in address space");
|
|
}
|
|
|
|
/// parseStringAttribute
|
|
/// := StringConstant
|
|
/// := StringConstant '=' StringConstant
|
|
bool LLParser::parseStringAttribute(AttrBuilder &B) {
|
|
std::string Attr = Lex.getStrVal();
|
|
Lex.Lex();
|
|
std::string Val;
|
|
if (EatIfPresent(lltok::equal) && parseStringConstant(Val))
|
|
return true;
|
|
B.addAttribute(Attr, Val);
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalParamAttrs - parse a potentially empty list of parameter
|
|
/// attributes.
|
|
bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) {
|
|
bool HaveError = false;
|
|
|
|
B.clear();
|
|
|
|
while (true) {
|
|
lltok::Kind Token = Lex.getKind();
|
|
switch (Token) {
|
|
default: // End of attributes.
|
|
return HaveError;
|
|
case lltok::StringConstant: {
|
|
if (parseStringAttribute(B))
|
|
return true;
|
|
continue;
|
|
}
|
|
case lltok::kw_align: {
|
|
MaybeAlign Alignment;
|
|
if (parseOptionalAlignment(Alignment, true))
|
|
return true;
|
|
B.addAlignmentAttr(Alignment);
|
|
continue;
|
|
}
|
|
case lltok::kw_byval: {
|
|
Type *Ty;
|
|
if (parseOptionalTypeAttr(Ty, lltok::kw_byval))
|
|
return true;
|
|
B.addByValAttr(Ty);
|
|
continue;
|
|
}
|
|
case lltok::kw_sret: {
|
|
Type *Ty;
|
|
if (parseOptionalTypeAttr(Ty, lltok::kw_sret))
|
|
return true;
|
|
B.addStructRetAttr(Ty);
|
|
continue;
|
|
}
|
|
case lltok::kw_preallocated: {
|
|
Type *Ty;
|
|
if (parsePreallocated(Ty))
|
|
return true;
|
|
B.addPreallocatedAttr(Ty);
|
|
continue;
|
|
}
|
|
case lltok::kw_dereferenceable: {
|
|
uint64_t Bytes;
|
|
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
|
|
return true;
|
|
B.addDereferenceableAttr(Bytes);
|
|
continue;
|
|
}
|
|
case lltok::kw_dereferenceable_or_null: {
|
|
uint64_t Bytes;
|
|
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
|
|
return true;
|
|
B.addDereferenceableOrNullAttr(Bytes);
|
|
continue;
|
|
}
|
|
case lltok::kw_byref: {
|
|
Type *Ty;
|
|
if (parseByRef(Ty))
|
|
return true;
|
|
B.addByRefAttr(Ty);
|
|
continue;
|
|
}
|
|
case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break;
|
|
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
|
|
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
|
|
case lltok::kw_noundef:
|
|
B.addAttribute(Attribute::NoUndef);
|
|
break;
|
|
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
|
|
case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break;
|
|
case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break;
|
|
case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break;
|
|
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
|
|
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
|
|
case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
|
|
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
|
|
case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break;
|
|
case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
|
|
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
|
|
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
|
|
case lltok::kw_immarg: B.addAttribute(Attribute::ImmArg); break;
|
|
|
|
case lltok::kw_alignstack:
|
|
case lltok::kw_alwaysinline:
|
|
case lltok::kw_argmemonly:
|
|
case lltok::kw_builtin:
|
|
case lltok::kw_inlinehint:
|
|
case lltok::kw_jumptable:
|
|
case lltok::kw_minsize:
|
|
case lltok::kw_mustprogress:
|
|
case lltok::kw_naked:
|
|
case lltok::kw_nobuiltin:
|
|
case lltok::kw_noduplicate:
|
|
case lltok::kw_noimplicitfloat:
|
|
case lltok::kw_noinline:
|
|
case lltok::kw_nonlazybind:
|
|
case lltok::kw_nomerge:
|
|
case lltok::kw_noredzone:
|
|
case lltok::kw_noreturn:
|
|
case lltok::kw_nocf_check:
|
|
case lltok::kw_nounwind:
|
|
case lltok::kw_optforfuzzing:
|
|
case lltok::kw_optnone:
|
|
case lltok::kw_optsize:
|
|
case lltok::kw_returns_twice:
|
|
case lltok::kw_sanitize_address:
|
|
case lltok::kw_sanitize_hwaddress:
|
|
case lltok::kw_sanitize_memtag:
|
|
case lltok::kw_sanitize_memory:
|
|
case lltok::kw_sanitize_thread:
|
|
case lltok::kw_speculative_load_hardening:
|
|
case lltok::kw_nossp:
|
|
case lltok::kw_ssp:
|
|
case lltok::kw_sspreq:
|
|
case lltok::kw_sspstrong:
|
|
case lltok::kw_safestack:
|
|
case lltok::kw_shadowcallstack:
|
|
case lltok::kw_strictfp:
|
|
case lltok::kw_uwtable:
|
|
HaveError |=
|
|
error(Lex.getLoc(), "invalid use of function-only attribute");
|
|
break;
|
|
}
|
|
|
|
Lex.Lex();
|
|
}
|
|
}
|
|
|
|
/// parseOptionalReturnAttrs - parse a potentially empty list of return
|
|
/// attributes.
|
|
bool LLParser::parseOptionalReturnAttrs(AttrBuilder &B) {
|
|
bool HaveError = false;
|
|
|
|
B.clear();
|
|
|
|
while (true) {
|
|
lltok::Kind Token = Lex.getKind();
|
|
switch (Token) {
|
|
default: // End of attributes.
|
|
return HaveError;
|
|
case lltok::StringConstant: {
|
|
if (parseStringAttribute(B))
|
|
return true;
|
|
continue;
|
|
}
|
|
case lltok::kw_dereferenceable: {
|
|
uint64_t Bytes;
|
|
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
|
|
return true;
|
|
B.addDereferenceableAttr(Bytes);
|
|
continue;
|
|
}
|
|
case lltok::kw_dereferenceable_or_null: {
|
|
uint64_t Bytes;
|
|
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable_or_null, Bytes))
|
|
return true;
|
|
B.addDereferenceableOrNullAttr(Bytes);
|
|
continue;
|
|
}
|
|
case lltok::kw_align: {
|
|
MaybeAlign Alignment;
|
|
if (parseOptionalAlignment(Alignment))
|
|
return true;
|
|
B.addAlignmentAttr(Alignment);
|
|
continue;
|
|
}
|
|
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
|
|
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
|
|
case lltok::kw_noundef:
|
|
B.addAttribute(Attribute::NoUndef);
|
|
break;
|
|
case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break;
|
|
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
|
|
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
|
|
|
|
// error handling.
|
|
case lltok::kw_byval:
|
|
case lltok::kw_inalloca:
|
|
case lltok::kw_nest:
|
|
case lltok::kw_nocapture:
|
|
case lltok::kw_returned:
|
|
case lltok::kw_sret:
|
|
case lltok::kw_swifterror:
|
|
case lltok::kw_swiftself:
|
|
case lltok::kw_immarg:
|
|
case lltok::kw_byref:
|
|
HaveError |=
|
|
error(Lex.getLoc(), "invalid use of parameter-only attribute");
|
|
break;
|
|
|
|
case lltok::kw_alignstack:
|
|
case lltok::kw_alwaysinline:
|
|
case lltok::kw_argmemonly:
|
|
case lltok::kw_builtin:
|
|
case lltok::kw_cold:
|
|
case lltok::kw_inlinehint:
|
|
case lltok::kw_jumptable:
|
|
case lltok::kw_minsize:
|
|
case lltok::kw_mustprogress:
|
|
case lltok::kw_naked:
|
|
case lltok::kw_nobuiltin:
|
|
case lltok::kw_noduplicate:
|
|
case lltok::kw_noimplicitfloat:
|
|
case lltok::kw_noinline:
|
|
case lltok::kw_nonlazybind:
|
|
case lltok::kw_nomerge:
|
|
case lltok::kw_noredzone:
|
|
case lltok::kw_noreturn:
|
|
case lltok::kw_nocf_check:
|
|
case lltok::kw_nounwind:
|
|
case lltok::kw_optforfuzzing:
|
|
case lltok::kw_optnone:
|
|
case lltok::kw_optsize:
|
|
case lltok::kw_returns_twice:
|
|
case lltok::kw_sanitize_address:
|
|
case lltok::kw_sanitize_hwaddress:
|
|
case lltok::kw_sanitize_memtag:
|
|
case lltok::kw_sanitize_memory:
|
|
case lltok::kw_sanitize_thread:
|
|
case lltok::kw_speculative_load_hardening:
|
|
case lltok::kw_nossp:
|
|
case lltok::kw_ssp:
|
|
case lltok::kw_sspreq:
|
|
case lltok::kw_sspstrong:
|
|
case lltok::kw_safestack:
|
|
case lltok::kw_shadowcallstack:
|
|
case lltok::kw_strictfp:
|
|
case lltok::kw_uwtable:
|
|
HaveError |=
|
|
error(Lex.getLoc(), "invalid use of function-only attribute");
|
|
break;
|
|
case lltok::kw_readnone:
|
|
case lltok::kw_readonly:
|
|
HaveError |=
|
|
error(Lex.getLoc(), "invalid use of attribute on return type");
|
|
break;
|
|
case lltok::kw_preallocated:
|
|
HaveError |=
|
|
error(Lex.getLoc(),
|
|
"invalid use of parameter-only/call site-only attribute");
|
|
break;
|
|
}
|
|
|
|
Lex.Lex();
|
|
}
|
|
}
|
|
|
|
static unsigned parseOptionalLinkageAux(lltok::Kind Kind, bool &HasLinkage) {
|
|
HasLinkage = true;
|
|
switch (Kind) {
|
|
default:
|
|
HasLinkage = false;
|
|
return GlobalValue::ExternalLinkage;
|
|
case lltok::kw_private:
|
|
return GlobalValue::PrivateLinkage;
|
|
case lltok::kw_internal:
|
|
return GlobalValue::InternalLinkage;
|
|
case lltok::kw_weak:
|
|
return GlobalValue::WeakAnyLinkage;
|
|
case lltok::kw_weak_odr:
|
|
return GlobalValue::WeakODRLinkage;
|
|
case lltok::kw_linkonce:
|
|
return GlobalValue::LinkOnceAnyLinkage;
|
|
case lltok::kw_linkonce_odr:
|
|
return GlobalValue::LinkOnceODRLinkage;
|
|
case lltok::kw_available_externally:
|
|
return GlobalValue::AvailableExternallyLinkage;
|
|
case lltok::kw_appending:
|
|
return GlobalValue::AppendingLinkage;
|
|
case lltok::kw_common:
|
|
return GlobalValue::CommonLinkage;
|
|
case lltok::kw_extern_weak:
|
|
return GlobalValue::ExternalWeakLinkage;
|
|
case lltok::kw_external:
|
|
return GlobalValue::ExternalLinkage;
|
|
}
|
|
}
|
|
|
|
/// parseOptionalLinkage
|
|
/// ::= /*empty*/
|
|
/// ::= 'private'
|
|
/// ::= 'internal'
|
|
/// ::= 'weak'
|
|
/// ::= 'weak_odr'
|
|
/// ::= 'linkonce'
|
|
/// ::= 'linkonce_odr'
|
|
/// ::= 'available_externally'
|
|
/// ::= 'appending'
|
|
/// ::= 'common'
|
|
/// ::= 'extern_weak'
|
|
/// ::= 'external'
|
|
bool LLParser::parseOptionalLinkage(unsigned &Res, bool &HasLinkage,
|
|
unsigned &Visibility,
|
|
unsigned &DLLStorageClass, bool &DSOLocal) {
|
|
Res = parseOptionalLinkageAux(Lex.getKind(), HasLinkage);
|
|
if (HasLinkage)
|
|
Lex.Lex();
|
|
parseOptionalDSOLocal(DSOLocal);
|
|
parseOptionalVisibility(Visibility);
|
|
parseOptionalDLLStorageClass(DLLStorageClass);
|
|
|
|
if (DSOLocal && DLLStorageClass == GlobalValue::DLLImportStorageClass) {
|
|
return error(Lex.getLoc(), "dso_location and DLL-StorageClass mismatch");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LLParser::parseOptionalDSOLocal(bool &DSOLocal) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
DSOLocal = false;
|
|
break;
|
|
case lltok::kw_dso_local:
|
|
DSOLocal = true;
|
|
Lex.Lex();
|
|
break;
|
|
case lltok::kw_dso_preemptable:
|
|
DSOLocal = false;
|
|
Lex.Lex();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// parseOptionalVisibility
|
|
/// ::= /*empty*/
|
|
/// ::= 'default'
|
|
/// ::= 'hidden'
|
|
/// ::= 'protected'
|
|
///
|
|
void LLParser::parseOptionalVisibility(unsigned &Res) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
Res = GlobalValue::DefaultVisibility;
|
|
return;
|
|
case lltok::kw_default:
|
|
Res = GlobalValue::DefaultVisibility;
|
|
break;
|
|
case lltok::kw_hidden:
|
|
Res = GlobalValue::HiddenVisibility;
|
|
break;
|
|
case lltok::kw_protected:
|
|
Res = GlobalValue::ProtectedVisibility;
|
|
break;
|
|
}
|
|
Lex.Lex();
|
|
}
|
|
|
|
/// parseOptionalDLLStorageClass
|
|
/// ::= /*empty*/
|
|
/// ::= 'dllimport'
|
|
/// ::= 'dllexport'
|
|
///
|
|
void LLParser::parseOptionalDLLStorageClass(unsigned &Res) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
Res = GlobalValue::DefaultStorageClass;
|
|
return;
|
|
case lltok::kw_dllimport:
|
|
Res = GlobalValue::DLLImportStorageClass;
|
|
break;
|
|
case lltok::kw_dllexport:
|
|
Res = GlobalValue::DLLExportStorageClass;
|
|
break;
|
|
}
|
|
Lex.Lex();
|
|
}
|
|
|
|
/// parseOptionalCallingConv
|
|
/// ::= /*empty*/
|
|
/// ::= 'ccc'
|
|
/// ::= 'fastcc'
|
|
/// ::= 'intel_ocl_bicc'
|
|
/// ::= 'coldcc'
|
|
/// ::= 'cfguard_checkcc'
|
|
/// ::= 'x86_stdcallcc'
|
|
/// ::= 'x86_fastcallcc'
|
|
/// ::= 'x86_thiscallcc'
|
|
/// ::= 'x86_vectorcallcc'
|
|
/// ::= 'arm_apcscc'
|
|
/// ::= 'arm_aapcscc'
|
|
/// ::= 'arm_aapcs_vfpcc'
|
|
/// ::= 'aarch64_vector_pcs'
|
|
/// ::= 'aarch64_sve_vector_pcs'
|
|
/// ::= 'msp430_intrcc'
|
|
/// ::= 'avr_intrcc'
|
|
/// ::= 'avr_signalcc'
|
|
/// ::= 'ptx_kernel'
|
|
/// ::= 'ptx_device'
|
|
/// ::= 'spir_func'
|
|
/// ::= 'spir_kernel'
|
|
/// ::= 'x86_64_sysvcc'
|
|
/// ::= 'win64cc'
|
|
/// ::= 'webkit_jscc'
|
|
/// ::= 'anyregcc'
|
|
/// ::= 'preserve_mostcc'
|
|
/// ::= 'preserve_allcc'
|
|
/// ::= 'ghccc'
|
|
/// ::= 'swiftcc'
|
|
/// ::= 'x86_intrcc'
|
|
/// ::= 'hhvmcc'
|
|
/// ::= 'hhvm_ccc'
|
|
/// ::= 'cxx_fast_tlscc'
|
|
/// ::= 'amdgpu_vs'
|
|
/// ::= 'amdgpu_ls'
|
|
/// ::= 'amdgpu_hs'
|
|
/// ::= 'amdgpu_es'
|
|
/// ::= 'amdgpu_gs'
|
|
/// ::= 'amdgpu_ps'
|
|
/// ::= 'amdgpu_cs'
|
|
/// ::= 'amdgpu_kernel'
|
|
/// ::= 'tailcc'
|
|
/// ::= 'cc' UINT
|
|
///
|
|
bool LLParser::parseOptionalCallingConv(unsigned &CC) {
|
|
switch (Lex.getKind()) {
|
|
default: CC = CallingConv::C; return false;
|
|
case lltok::kw_ccc: CC = CallingConv::C; break;
|
|
case lltok::kw_fastcc: CC = CallingConv::Fast; break;
|
|
case lltok::kw_coldcc: CC = CallingConv::Cold; break;
|
|
case lltok::kw_cfguard_checkcc: CC = CallingConv::CFGuard_Check; break;
|
|
case lltok::kw_x86_stdcallcc: CC = CallingConv::X86_StdCall; break;
|
|
case lltok::kw_x86_fastcallcc: CC = CallingConv::X86_FastCall; break;
|
|
case lltok::kw_x86_regcallcc: CC = CallingConv::X86_RegCall; break;
|
|
case lltok::kw_x86_thiscallcc: CC = CallingConv::X86_ThisCall; break;
|
|
case lltok::kw_x86_vectorcallcc:CC = CallingConv::X86_VectorCall; break;
|
|
case lltok::kw_arm_apcscc: CC = CallingConv::ARM_APCS; break;
|
|
case lltok::kw_arm_aapcscc: CC = CallingConv::ARM_AAPCS; break;
|
|
case lltok::kw_arm_aapcs_vfpcc:CC = CallingConv::ARM_AAPCS_VFP; break;
|
|
case lltok::kw_aarch64_vector_pcs:CC = CallingConv::AArch64_VectorCall; break;
|
|
case lltok::kw_aarch64_sve_vector_pcs:
|
|
CC = CallingConv::AArch64_SVE_VectorCall;
|
|
break;
|
|
case lltok::kw_msp430_intrcc: CC = CallingConv::MSP430_INTR; break;
|
|
case lltok::kw_avr_intrcc: CC = CallingConv::AVR_INTR; break;
|
|
case lltok::kw_avr_signalcc: CC = CallingConv::AVR_SIGNAL; break;
|
|
case lltok::kw_ptx_kernel: CC = CallingConv::PTX_Kernel; break;
|
|
case lltok::kw_ptx_device: CC = CallingConv::PTX_Device; break;
|
|
case lltok::kw_spir_kernel: CC = CallingConv::SPIR_KERNEL; break;
|
|
case lltok::kw_spir_func: CC = CallingConv::SPIR_FUNC; break;
|
|
case lltok::kw_intel_ocl_bicc: CC = CallingConv::Intel_OCL_BI; break;
|
|
case lltok::kw_x86_64_sysvcc: CC = CallingConv::X86_64_SysV; break;
|
|
case lltok::kw_win64cc: CC = CallingConv::Win64; break;
|
|
case lltok::kw_webkit_jscc: CC = CallingConv::WebKit_JS; break;
|
|
case lltok::kw_anyregcc: CC = CallingConv::AnyReg; break;
|
|
case lltok::kw_preserve_mostcc:CC = CallingConv::PreserveMost; break;
|
|
case lltok::kw_preserve_allcc: CC = CallingConv::PreserveAll; break;
|
|
case lltok::kw_ghccc: CC = CallingConv::GHC; break;
|
|
case lltok::kw_swiftcc: CC = CallingConv::Swift; break;
|
|
case lltok::kw_x86_intrcc: CC = CallingConv::X86_INTR; break;
|
|
case lltok::kw_hhvmcc: CC = CallingConv::HHVM; break;
|
|
case lltok::kw_hhvm_ccc: CC = CallingConv::HHVM_C; break;
|
|
case lltok::kw_cxx_fast_tlscc: CC = CallingConv::CXX_FAST_TLS; break;
|
|
case lltok::kw_amdgpu_vs: CC = CallingConv::AMDGPU_VS; break;
|
|
case lltok::kw_amdgpu_gfx: CC = CallingConv::AMDGPU_Gfx; break;
|
|
case lltok::kw_amdgpu_ls: CC = CallingConv::AMDGPU_LS; break;
|
|
case lltok::kw_amdgpu_hs: CC = CallingConv::AMDGPU_HS; break;
|
|
case lltok::kw_amdgpu_es: CC = CallingConv::AMDGPU_ES; break;
|
|
case lltok::kw_amdgpu_gs: CC = CallingConv::AMDGPU_GS; break;
|
|
case lltok::kw_amdgpu_ps: CC = CallingConv::AMDGPU_PS; break;
|
|
case lltok::kw_amdgpu_cs: CC = CallingConv::AMDGPU_CS; break;
|
|
case lltok::kw_amdgpu_kernel: CC = CallingConv::AMDGPU_KERNEL; break;
|
|
case lltok::kw_tailcc: CC = CallingConv::Tail; break;
|
|
case lltok::kw_cc: {
|
|
Lex.Lex();
|
|
return parseUInt32(CC);
|
|
}
|
|
}
|
|
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseMetadataAttachment
|
|
/// ::= !dbg !42
|
|
bool LLParser::parseMetadataAttachment(unsigned &Kind, MDNode *&MD) {
|
|
assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata attachment");
|
|
|
|
std::string Name = Lex.getStrVal();
|
|
Kind = M->getMDKindID(Name);
|
|
Lex.Lex();
|
|
|
|
return parseMDNode(MD);
|
|
}
|
|
|
|
/// parseInstructionMetadata
|
|
/// ::= !dbg !42 (',' !dbg !57)*
|
|
bool LLParser::parseInstructionMetadata(Instruction &Inst) {
|
|
do {
|
|
if (Lex.getKind() != lltok::MetadataVar)
|
|
return tokError("expected metadata after comma");
|
|
|
|
unsigned MDK;
|
|
MDNode *N;
|
|
if (parseMetadataAttachment(MDK, N))
|
|
return true;
|
|
|
|
Inst.setMetadata(MDK, N);
|
|
if (MDK == LLVMContext::MD_tbaa)
|
|
InstsWithTBAATag.push_back(&Inst);
|
|
|
|
// If this is the end of the list, we're done.
|
|
} while (EatIfPresent(lltok::comma));
|
|
return false;
|
|
}
|
|
|
|
/// parseGlobalObjectMetadataAttachment
|
|
/// ::= !dbg !57
|
|
bool LLParser::parseGlobalObjectMetadataAttachment(GlobalObject &GO) {
|
|
unsigned MDK;
|
|
MDNode *N;
|
|
if (parseMetadataAttachment(MDK, N))
|
|
return true;
|
|
|
|
GO.addMetadata(MDK, *N);
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalFunctionMetadata
|
|
/// ::= (!dbg !57)*
|
|
bool LLParser::parseOptionalFunctionMetadata(Function &F) {
|
|
while (Lex.getKind() == lltok::MetadataVar)
|
|
if (parseGlobalObjectMetadataAttachment(F))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalAlignment
|
|
/// ::= /* empty */
|
|
/// ::= 'align' 4
|
|
bool LLParser::parseOptionalAlignment(MaybeAlign &Alignment, bool AllowParens) {
|
|
Alignment = None;
|
|
if (!EatIfPresent(lltok::kw_align))
|
|
return false;
|
|
LocTy AlignLoc = Lex.getLoc();
|
|
uint32_t Value = 0;
|
|
|
|
LocTy ParenLoc = Lex.getLoc();
|
|
bool HaveParens = false;
|
|
if (AllowParens) {
|
|
if (EatIfPresent(lltok::lparen))
|
|
HaveParens = true;
|
|
}
|
|
|
|
if (parseUInt32(Value))
|
|
return true;
|
|
|
|
if (HaveParens && !EatIfPresent(lltok::rparen))
|
|
return error(ParenLoc, "expected ')'");
|
|
|
|
if (!isPowerOf2_32(Value))
|
|
return error(AlignLoc, "alignment is not a power of two");
|
|
if (Value > Value::MaximumAlignment)
|
|
return error(AlignLoc, "huge alignments are not supported yet");
|
|
Alignment = Align(Value);
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalDerefAttrBytes
|
|
/// ::= /* empty */
|
|
/// ::= AttrKind '(' 4 ')'
|
|
///
|
|
/// where AttrKind is either 'dereferenceable' or 'dereferenceable_or_null'.
|
|
bool LLParser::parseOptionalDerefAttrBytes(lltok::Kind AttrKind,
|
|
uint64_t &Bytes) {
|
|
assert((AttrKind == lltok::kw_dereferenceable ||
|
|
AttrKind == lltok::kw_dereferenceable_or_null) &&
|
|
"contract!");
|
|
|
|
Bytes = 0;
|
|
if (!EatIfPresent(AttrKind))
|
|
return false;
|
|
LocTy ParenLoc = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::lparen))
|
|
return error(ParenLoc, "expected '('");
|
|
LocTy DerefLoc = Lex.getLoc();
|
|
if (parseUInt64(Bytes))
|
|
return true;
|
|
ParenLoc = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::rparen))
|
|
return error(ParenLoc, "expected ')'");
|
|
if (!Bytes)
|
|
return error(DerefLoc, "dereferenceable bytes must be non-zero");
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalCommaAlign
|
|
/// ::=
|
|
/// ::= ',' align 4
|
|
///
|
|
/// This returns with AteExtraComma set to true if it ate an excess comma at the
|
|
/// end.
|
|
bool LLParser::parseOptionalCommaAlign(MaybeAlign &Alignment,
|
|
bool &AteExtraComma) {
|
|
AteExtraComma = false;
|
|
while (EatIfPresent(lltok::comma)) {
|
|
// Metadata at the end is an early exit.
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
AteExtraComma = true;
|
|
return false;
|
|
}
|
|
|
|
if (Lex.getKind() != lltok::kw_align)
|
|
return error(Lex.getLoc(), "expected metadata or 'align'");
|
|
|
|
if (parseOptionalAlignment(Alignment))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalCommaAddrSpace
|
|
/// ::=
|
|
/// ::= ',' addrspace(1)
|
|
///
|
|
/// This returns with AteExtraComma set to true if it ate an excess comma at the
|
|
/// end.
|
|
bool LLParser::parseOptionalCommaAddrSpace(unsigned &AddrSpace, LocTy &Loc,
|
|
bool &AteExtraComma) {
|
|
AteExtraComma = false;
|
|
while (EatIfPresent(lltok::comma)) {
|
|
// Metadata at the end is an early exit.
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
AteExtraComma = true;
|
|
return false;
|
|
}
|
|
|
|
Loc = Lex.getLoc();
|
|
if (Lex.getKind() != lltok::kw_addrspace)
|
|
return error(Lex.getLoc(), "expected metadata or 'addrspace'");
|
|
|
|
if (parseOptionalAddrSpace(AddrSpace))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseAllocSizeArguments(unsigned &BaseSizeArg,
|
|
Optional<unsigned> &HowManyArg) {
|
|
Lex.Lex();
|
|
|
|
auto StartParen = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::lparen))
|
|
return error(StartParen, "expected '('");
|
|
|
|
if (parseUInt32(BaseSizeArg))
|
|
return true;
|
|
|
|
if (EatIfPresent(lltok::comma)) {
|
|
auto HowManyAt = Lex.getLoc();
|
|
unsigned HowMany;
|
|
if (parseUInt32(HowMany))
|
|
return true;
|
|
if (HowMany == BaseSizeArg)
|
|
return error(HowManyAt,
|
|
"'allocsize' indices can't refer to the same parameter");
|
|
HowManyArg = HowMany;
|
|
} else
|
|
HowManyArg = None;
|
|
|
|
auto EndParen = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::rparen))
|
|
return error(EndParen, "expected ')'");
|
|
return false;
|
|
}
|
|
|
|
/// parseScopeAndOrdering
|
|
/// if isAtomic: ::= SyncScope? AtomicOrdering
|
|
/// else: ::=
|
|
///
|
|
/// This sets Scope and Ordering to the parsed values.
|
|
bool LLParser::parseScopeAndOrdering(bool IsAtomic, SyncScope::ID &SSID,
|
|
AtomicOrdering &Ordering) {
|
|
if (!IsAtomic)
|
|
return false;
|
|
|
|
return parseScope(SSID) || parseOrdering(Ordering);
|
|
}
|
|
|
|
/// parseScope
|
|
/// ::= syncscope("singlethread" | "<target scope>")?
|
|
///
|
|
/// This sets synchronization scope ID to the ID of the parsed value.
|
|
bool LLParser::parseScope(SyncScope::ID &SSID) {
|
|
SSID = SyncScope::System;
|
|
if (EatIfPresent(lltok::kw_syncscope)) {
|
|
auto StartParenAt = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::lparen))
|
|
return error(StartParenAt, "Expected '(' in syncscope");
|
|
|
|
std::string SSN;
|
|
auto SSNAt = Lex.getLoc();
|
|
if (parseStringConstant(SSN))
|
|
return error(SSNAt, "Expected synchronization scope name");
|
|
|
|
auto EndParenAt = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::rparen))
|
|
return error(EndParenAt, "Expected ')' in syncscope");
|
|
|
|
SSID = Context.getOrInsertSyncScopeID(SSN);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseOrdering
|
|
/// ::= AtomicOrdering
|
|
///
|
|
/// This sets Ordering to the parsed value.
|
|
bool LLParser::parseOrdering(AtomicOrdering &Ordering) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("Expected ordering on atomic instruction");
|
|
case lltok::kw_unordered: Ordering = AtomicOrdering::Unordered; break;
|
|
case lltok::kw_monotonic: Ordering = AtomicOrdering::Monotonic; break;
|
|
// Not specified yet:
|
|
// case lltok::kw_consume: Ordering = AtomicOrdering::Consume; break;
|
|
case lltok::kw_acquire: Ordering = AtomicOrdering::Acquire; break;
|
|
case lltok::kw_release: Ordering = AtomicOrdering::Release; break;
|
|
case lltok::kw_acq_rel: Ordering = AtomicOrdering::AcquireRelease; break;
|
|
case lltok::kw_seq_cst:
|
|
Ordering = AtomicOrdering::SequentiallyConsistent;
|
|
break;
|
|
}
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseOptionalStackAlignment
|
|
/// ::= /* empty */
|
|
/// ::= 'alignstack' '(' 4 ')'
|
|
bool LLParser::parseOptionalStackAlignment(unsigned &Alignment) {
|
|
Alignment = 0;
|
|
if (!EatIfPresent(lltok::kw_alignstack))
|
|
return false;
|
|
LocTy ParenLoc = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::lparen))
|
|
return error(ParenLoc, "expected '('");
|
|
LocTy AlignLoc = Lex.getLoc();
|
|
if (parseUInt32(Alignment))
|
|
return true;
|
|
ParenLoc = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::rparen))
|
|
return error(ParenLoc, "expected ')'");
|
|
if (!isPowerOf2_32(Alignment))
|
|
return error(AlignLoc, "stack alignment is not a power of two");
|
|
return false;
|
|
}
|
|
|
|
/// parseIndexList - This parses the index list for an insert/extractvalue
|
|
/// instruction. This sets AteExtraComma in the case where we eat an extra
|
|
/// comma at the end of the line and find that it is followed by metadata.
|
|
/// Clients that don't allow metadata can call the version of this function that
|
|
/// only takes one argument.
|
|
///
|
|
/// parseIndexList
|
|
/// ::= (',' uint32)+
|
|
///
|
|
bool LLParser::parseIndexList(SmallVectorImpl<unsigned> &Indices,
|
|
bool &AteExtraComma) {
|
|
AteExtraComma = false;
|
|
|
|
if (Lex.getKind() != lltok::comma)
|
|
return tokError("expected ',' as start of index list");
|
|
|
|
while (EatIfPresent(lltok::comma)) {
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
if (Indices.empty())
|
|
return tokError("expected index");
|
|
AteExtraComma = true;
|
|
return false;
|
|
}
|
|
unsigned Idx = 0;
|
|
if (parseUInt32(Idx))
|
|
return true;
|
|
Indices.push_back(Idx);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Type Parsing.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseType - parse a type.
|
|
bool LLParser::parseType(Type *&Result, const Twine &Msg, bool AllowVoid) {
|
|
SMLoc TypeLoc = Lex.getLoc();
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError(Msg);
|
|
case lltok::Type:
|
|
// Type ::= 'float' | 'void' (etc)
|
|
Result = Lex.getTyVal();
|
|
Lex.Lex();
|
|
break;
|
|
case lltok::lbrace:
|
|
// Type ::= StructType
|
|
if (parseAnonStructType(Result, false))
|
|
return true;
|
|
break;
|
|
case lltok::lsquare:
|
|
// Type ::= '[' ... ']'
|
|
Lex.Lex(); // eat the lsquare.
|
|
if (parseArrayVectorType(Result, false))
|
|
return true;
|
|
break;
|
|
case lltok::less: // Either vector or packed struct.
|
|
// Type ::= '<' ... '>'
|
|
Lex.Lex();
|
|
if (Lex.getKind() == lltok::lbrace) {
|
|
if (parseAnonStructType(Result, true) ||
|
|
parseToken(lltok::greater, "expected '>' at end of packed struct"))
|
|
return true;
|
|
} else if (parseArrayVectorType(Result, true))
|
|
return true;
|
|
break;
|
|
case lltok::LocalVar: {
|
|
// Type ::= %foo
|
|
std::pair<Type*, LocTy> &Entry = NamedTypes[Lex.getStrVal()];
|
|
|
|
// If the type hasn't been defined yet, create a forward definition and
|
|
// remember where that forward def'n was seen (in case it never is defined).
|
|
if (!Entry.first) {
|
|
Entry.first = StructType::create(Context, Lex.getStrVal());
|
|
Entry.second = Lex.getLoc();
|
|
}
|
|
Result = Entry.first;
|
|
Lex.Lex();
|
|
break;
|
|
}
|
|
|
|
case lltok::LocalVarID: {
|
|
// Type ::= %4
|
|
std::pair<Type*, LocTy> &Entry = NumberedTypes[Lex.getUIntVal()];
|
|
|
|
// If the type hasn't been defined yet, create a forward definition and
|
|
// remember where that forward def'n was seen (in case it never is defined).
|
|
if (!Entry.first) {
|
|
Entry.first = StructType::create(Context);
|
|
Entry.second = Lex.getLoc();
|
|
}
|
|
Result = Entry.first;
|
|
Lex.Lex();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// parse the type suffixes.
|
|
while (true) {
|
|
switch (Lex.getKind()) {
|
|
// End of type.
|
|
default:
|
|
if (!AllowVoid && Result->isVoidTy())
|
|
return error(TypeLoc, "void type only allowed for function results");
|
|
return false;
|
|
|
|
// Type ::= Type '*'
|
|
case lltok::star:
|
|
if (Result->isLabelTy())
|
|
return tokError("basic block pointers are invalid");
|
|
if (Result->isVoidTy())
|
|
return tokError("pointers to void are invalid - use i8* instead");
|
|
if (!PointerType::isValidElementType(Result))
|
|
return tokError("pointer to this type is invalid");
|
|
Result = PointerType::getUnqual(Result);
|
|
Lex.Lex();
|
|
break;
|
|
|
|
// Type ::= Type 'addrspace' '(' uint32 ')' '*'
|
|
case lltok::kw_addrspace: {
|
|
if (Result->isLabelTy())
|
|
return tokError("basic block pointers are invalid");
|
|
if (Result->isVoidTy())
|
|
return tokError("pointers to void are invalid; use i8* instead");
|
|
if (!PointerType::isValidElementType(Result))
|
|
return tokError("pointer to this type is invalid");
|
|
unsigned AddrSpace;
|
|
if (parseOptionalAddrSpace(AddrSpace) ||
|
|
parseToken(lltok::star, "expected '*' in address space"))
|
|
return true;
|
|
|
|
Result = PointerType::get(Result, AddrSpace);
|
|
break;
|
|
}
|
|
|
|
/// Types '(' ArgTypeListI ')' OptFuncAttrs
|
|
case lltok::lparen:
|
|
if (parseFunctionType(Result))
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// parseParameterList
|
|
/// ::= '(' ')'
|
|
/// ::= '(' Arg (',' Arg)* ')'
|
|
/// Arg
|
|
/// ::= Type OptionalAttributes Value OptionalAttributes
|
|
bool LLParser::parseParameterList(SmallVectorImpl<ParamInfo> &ArgList,
|
|
PerFunctionState &PFS, bool IsMustTailCall,
|
|
bool InVarArgsFunc) {
|
|
if (parseToken(lltok::lparen, "expected '(' in call"))
|
|
return true;
|
|
|
|
while (Lex.getKind() != lltok::rparen) {
|
|
// If this isn't the first argument, we need a comma.
|
|
if (!ArgList.empty() &&
|
|
parseToken(lltok::comma, "expected ',' in argument list"))
|
|
return true;
|
|
|
|
// parse an ellipsis if this is a musttail call in a variadic function.
|
|
if (Lex.getKind() == lltok::dotdotdot) {
|
|
const char *Msg = "unexpected ellipsis in argument list for ";
|
|
if (!IsMustTailCall)
|
|
return tokError(Twine(Msg) + "non-musttail call");
|
|
if (!InVarArgsFunc)
|
|
return tokError(Twine(Msg) + "musttail call in non-varargs function");
|
|
Lex.Lex(); // Lex the '...', it is purely for readability.
|
|
return parseToken(lltok::rparen, "expected ')' at end of argument list");
|
|
}
|
|
|
|
// parse the argument.
|
|
LocTy ArgLoc;
|
|
Type *ArgTy = nullptr;
|
|
AttrBuilder ArgAttrs;
|
|
Value *V;
|
|
if (parseType(ArgTy, ArgLoc))
|
|
return true;
|
|
|
|
if (ArgTy->isMetadataTy()) {
|
|
if (parseMetadataAsValue(V, PFS))
|
|
return true;
|
|
} else {
|
|
// Otherwise, handle normal operands.
|
|
if (parseOptionalParamAttrs(ArgAttrs) || parseValue(ArgTy, V, PFS))
|
|
return true;
|
|
}
|
|
ArgList.push_back(ParamInfo(
|
|
ArgLoc, V, AttributeSet::get(V->getContext(), ArgAttrs)));
|
|
}
|
|
|
|
if (IsMustTailCall && InVarArgsFunc)
|
|
return tokError("expected '...' at end of argument list for musttail call "
|
|
"in varargs function");
|
|
|
|
Lex.Lex(); // Lex the ')'.
|
|
return false;
|
|
}
|
|
|
|
/// parseByValWithOptionalType
|
|
/// ::= byval
|
|
/// ::= byval(<ty>)
|
|
bool LLParser::parseOptionalTypeAttr(Type *&Result, lltok::Kind AttrName) {
|
|
Result = nullptr;
|
|
if (!EatIfPresent(AttrName))
|
|
return true;
|
|
if (!EatIfPresent(lltok::lparen))
|
|
return false;
|
|
if (parseType(Result))
|
|
return true;
|
|
if (!EatIfPresent(lltok::rparen))
|
|
return error(Lex.getLoc(), "expected ')'");
|
|
return false;
|
|
}
|
|
|
|
/// parseRequiredTypeAttr
|
|
/// ::= attrname(<ty>)
|
|
bool LLParser::parseRequiredTypeAttr(Type *&Result, lltok::Kind AttrName) {
|
|
Result = nullptr;
|
|
if (!EatIfPresent(AttrName))
|
|
return true;
|
|
if (!EatIfPresent(lltok::lparen))
|
|
return error(Lex.getLoc(), "expected '('");
|
|
if (parseType(Result))
|
|
return true;
|
|
if (!EatIfPresent(lltok::rparen))
|
|
return error(Lex.getLoc(), "expected ')'");
|
|
return false;
|
|
}
|
|
|
|
/// parsePreallocated
|
|
/// ::= preallocated(<ty>)
|
|
bool LLParser::parsePreallocated(Type *&Result) {
|
|
return parseRequiredTypeAttr(Result, lltok::kw_preallocated);
|
|
}
|
|
|
|
/// parseByRef
|
|
/// ::= byref(<type>)
|
|
bool LLParser::parseByRef(Type *&Result) {
|
|
return parseRequiredTypeAttr(Result, lltok::kw_byref);
|
|
}
|
|
|
|
/// parseOptionalOperandBundles
|
|
/// ::= /*empty*/
|
|
/// ::= '[' OperandBundle [, OperandBundle ]* ']'
|
|
///
|
|
/// OperandBundle
|
|
/// ::= bundle-tag '(' ')'
|
|
/// ::= bundle-tag '(' Type Value [, Type Value ]* ')'
|
|
///
|
|
/// bundle-tag ::= String Constant
|
|
bool LLParser::parseOptionalOperandBundles(
|
|
SmallVectorImpl<OperandBundleDef> &BundleList, PerFunctionState &PFS) {
|
|
LocTy BeginLoc = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::lsquare))
|
|
return false;
|
|
|
|
while (Lex.getKind() != lltok::rsquare) {
|
|
// If this isn't the first operand bundle, we need a comma.
|
|
if (!BundleList.empty() &&
|
|
parseToken(lltok::comma, "expected ',' in input list"))
|
|
return true;
|
|
|
|
std::string Tag;
|
|
if (parseStringConstant(Tag))
|
|
return true;
|
|
|
|
if (parseToken(lltok::lparen, "expected '(' in operand bundle"))
|
|
return true;
|
|
|
|
std::vector<Value *> Inputs;
|
|
while (Lex.getKind() != lltok::rparen) {
|
|
// If this isn't the first input, we need a comma.
|
|
if (!Inputs.empty() &&
|
|
parseToken(lltok::comma, "expected ',' in input list"))
|
|
return true;
|
|
|
|
Type *Ty = nullptr;
|
|
Value *Input = nullptr;
|
|
if (parseType(Ty) || parseValue(Ty, Input, PFS))
|
|
return true;
|
|
Inputs.push_back(Input);
|
|
}
|
|
|
|
BundleList.emplace_back(std::move(Tag), std::move(Inputs));
|
|
|
|
Lex.Lex(); // Lex the ')'.
|
|
}
|
|
|
|
if (BundleList.empty())
|
|
return error(BeginLoc, "operand bundle set must not be empty");
|
|
|
|
Lex.Lex(); // Lex the ']'.
|
|
return false;
|
|
}
|
|
|
|
/// parseArgumentList - parse the argument list for a function type or function
|
|
/// prototype.
|
|
/// ::= '(' ArgTypeListI ')'
|
|
/// ArgTypeListI
|
|
/// ::= /*empty*/
|
|
/// ::= '...'
|
|
/// ::= ArgTypeList ',' '...'
|
|
/// ::= ArgType (',' ArgType)*
|
|
///
|
|
bool LLParser::parseArgumentList(SmallVectorImpl<ArgInfo> &ArgList,
|
|
bool &IsVarArg) {
|
|
unsigned CurValID = 0;
|
|
IsVarArg = false;
|
|
assert(Lex.getKind() == lltok::lparen);
|
|
Lex.Lex(); // eat the (.
|
|
|
|
if (Lex.getKind() == lltok::rparen) {
|
|
// empty
|
|
} else if (Lex.getKind() == lltok::dotdotdot) {
|
|
IsVarArg = true;
|
|
Lex.Lex();
|
|
} else {
|
|
LocTy TypeLoc = Lex.getLoc();
|
|
Type *ArgTy = nullptr;
|
|
AttrBuilder Attrs;
|
|
std::string Name;
|
|
|
|
if (parseType(ArgTy) || parseOptionalParamAttrs(Attrs))
|
|
return true;
|
|
|
|
if (ArgTy->isVoidTy())
|
|
return error(TypeLoc, "argument can not have void type");
|
|
|
|
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();
|
|
}
|
|
|
|
if (!FunctionType::isValidArgumentType(ArgTy))
|
|
return error(TypeLoc, "invalid type for function argument");
|
|
|
|
ArgList.emplace_back(TypeLoc, ArgTy,
|
|
AttributeSet::get(ArgTy->getContext(), Attrs),
|
|
std::move(Name));
|
|
|
|
while (EatIfPresent(lltok::comma)) {
|
|
// Handle ... at end of arg list.
|
|
if (EatIfPresent(lltok::dotdotdot)) {
|
|
IsVarArg = true;
|
|
break;
|
|
}
|
|
|
|
// Otherwise must be an argument type.
|
|
TypeLoc = Lex.getLoc();
|
|
if (parseType(ArgTy) || parseOptionalParamAttrs(Attrs))
|
|
return true;
|
|
|
|
if (ArgTy->isVoidTy())
|
|
return error(TypeLoc, "argument can not have void type");
|
|
|
|
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) + "'");
|
|
Lex.Lex();
|
|
}
|
|
++CurValID;
|
|
Name = "";
|
|
}
|
|
|
|
if (!ArgTy->isFirstClassType())
|
|
return error(TypeLoc, "invalid type for function argument");
|
|
|
|
ArgList.emplace_back(TypeLoc, ArgTy,
|
|
AttributeSet::get(ArgTy->getContext(), Attrs),
|
|
std::move(Name));
|
|
}
|
|
}
|
|
|
|
return parseToken(lltok::rparen, "expected ')' at end of argument list");
|
|
}
|
|
|
|
/// parseFunctionType
|
|
/// ::= Type ArgumentList OptionalAttrs
|
|
bool LLParser::parseFunctionType(Type *&Result) {
|
|
assert(Lex.getKind() == lltok::lparen);
|
|
|
|
if (!FunctionType::isValidReturnType(Result))
|
|
return tokError("invalid function return type");
|
|
|
|
SmallVector<ArgInfo, 8> ArgList;
|
|
bool IsVarArg;
|
|
if (parseArgumentList(ArgList, IsVarArg))
|
|
return true;
|
|
|
|
// Reject names on the arguments lists.
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i) {
|
|
if (!ArgList[i].Name.empty())
|
|
return error(ArgList[i].Loc, "argument name invalid in function type");
|
|
if (ArgList[i].Attrs.hasAttributes())
|
|
return error(ArgList[i].Loc,
|
|
"argument attributes invalid in function type");
|
|
}
|
|
|
|
SmallVector<Type*, 16> ArgListTy;
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
|
|
ArgListTy.push_back(ArgList[i].Ty);
|
|
|
|
Result = FunctionType::get(Result, ArgListTy, IsVarArg);
|
|
return false;
|
|
}
|
|
|
|
/// parseAnonStructType - parse an anonymous struct type, which is inlined into
|
|
/// other structs.
|
|
bool LLParser::parseAnonStructType(Type *&Result, bool Packed) {
|
|
SmallVector<Type*, 8> Elts;
|
|
if (parseStructBody(Elts))
|
|
return true;
|
|
|
|
Result = StructType::get(Context, Elts, Packed);
|
|
return false;
|
|
}
|
|
|
|
/// parseStructDefinition - parse a struct in a 'type' definition.
|
|
bool LLParser::parseStructDefinition(SMLoc TypeLoc, StringRef Name,
|
|
std::pair<Type *, LocTy> &Entry,
|
|
Type *&ResultTy) {
|
|
// If the type was already defined, diagnose the redefinition.
|
|
if (Entry.first && !Entry.second.isValid())
|
|
return error(TypeLoc, "redefinition of type");
|
|
|
|
// If we have opaque, just return without filling in the definition for the
|
|
// struct. This counts as a definition as far as the .ll file goes.
|
|
if (EatIfPresent(lltok::kw_opaque)) {
|
|
// This type is being defined, so clear the location to indicate this.
|
|
Entry.second = SMLoc();
|
|
|
|
// If this type number has never been uttered, create it.
|
|
if (!Entry.first)
|
|
Entry.first = StructType::create(Context, Name);
|
|
ResultTy = Entry.first;
|
|
return false;
|
|
}
|
|
|
|
// If the type starts with '<', then it is either a packed struct or a vector.
|
|
bool isPacked = EatIfPresent(lltok::less);
|
|
|
|
// If we don't have a struct, then we have a random type alias, which we
|
|
// accept for compatibility with old files. These types are not allowed to be
|
|
// forward referenced and not allowed to be recursive.
|
|
if (Lex.getKind() != lltok::lbrace) {
|
|
if (Entry.first)
|
|
return error(TypeLoc, "forward references to non-struct type");
|
|
|
|
ResultTy = nullptr;
|
|
if (isPacked)
|
|
return parseArrayVectorType(ResultTy, true);
|
|
return parseType(ResultTy);
|
|
}
|
|
|
|
// This type is being defined, so clear the location to indicate this.
|
|
Entry.second = SMLoc();
|
|
|
|
// If this type number has never been uttered, create it.
|
|
if (!Entry.first)
|
|
Entry.first = StructType::create(Context, Name);
|
|
|
|
StructType *STy = cast<StructType>(Entry.first);
|
|
|
|
SmallVector<Type*, 8> Body;
|
|
if (parseStructBody(Body) ||
|
|
(isPacked && parseToken(lltok::greater, "expected '>' in packed struct")))
|
|
return true;
|
|
|
|
STy->setBody(Body, isPacked);
|
|
ResultTy = STy;
|
|
return false;
|
|
}
|
|
|
|
/// parseStructType: Handles packed and unpacked types. </> parsed elsewhere.
|
|
/// StructType
|
|
/// ::= '{' '}'
|
|
/// ::= '{' Type (',' Type)* '}'
|
|
/// ::= '<' '{' '}' '>'
|
|
/// ::= '<' '{' Type (',' Type)* '}' '>'
|
|
bool LLParser::parseStructBody(SmallVectorImpl<Type *> &Body) {
|
|
assert(Lex.getKind() == lltok::lbrace);
|
|
Lex.Lex(); // Consume the '{'
|
|
|
|
// Handle the empty struct.
|
|
if (EatIfPresent(lltok::rbrace))
|
|
return false;
|
|
|
|
LocTy EltTyLoc = Lex.getLoc();
|
|
Type *Ty = nullptr;
|
|
if (parseType(Ty))
|
|
return true;
|
|
Body.push_back(Ty);
|
|
|
|
if (!StructType::isValidElementType(Ty))
|
|
return error(EltTyLoc, "invalid element type for struct");
|
|
|
|
while (EatIfPresent(lltok::comma)) {
|
|
EltTyLoc = Lex.getLoc();
|
|
if (parseType(Ty))
|
|
return true;
|
|
|
|
if (!StructType::isValidElementType(Ty))
|
|
return error(EltTyLoc, "invalid element type for struct");
|
|
|
|
Body.push_back(Ty);
|
|
}
|
|
|
|
return parseToken(lltok::rbrace, "expected '}' at end of struct");
|
|
}
|
|
|
|
/// parseArrayVectorType - parse an array or vector type, assuming the first
|
|
/// token has already been consumed.
|
|
/// Type
|
|
/// ::= '[' APSINTVAL 'x' Types ']'
|
|
/// ::= '<' APSINTVAL 'x' Types '>'
|
|
/// ::= '<' 'vscale' 'x' APSINTVAL 'x' Types '>'
|
|
bool LLParser::parseArrayVectorType(Type *&Result, bool IsVector) {
|
|
bool Scalable = false;
|
|
|
|
if (IsVector && Lex.getKind() == lltok::kw_vscale) {
|
|
Lex.Lex(); // consume the 'vscale'
|
|
if (parseToken(lltok::kw_x, "expected 'x' after vscale"))
|
|
return true;
|
|
|
|
Scalable = true;
|
|
}
|
|
|
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned() ||
|
|
Lex.getAPSIntVal().getBitWidth() > 64)
|
|
return tokError("expected number in address space");
|
|
|
|
LocTy SizeLoc = Lex.getLoc();
|
|
uint64_t Size = Lex.getAPSIntVal().getZExtValue();
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::kw_x, "expected 'x' after element count"))
|
|
return true;
|
|
|
|
LocTy TypeLoc = Lex.getLoc();
|
|
Type *EltTy = nullptr;
|
|
if (parseType(EltTy))
|
|
return true;
|
|
|
|
if (parseToken(IsVector ? lltok::greater : lltok::rsquare,
|
|
"expected end of sequential type"))
|
|
return true;
|
|
|
|
if (IsVector) {
|
|
if (Size == 0)
|
|
return error(SizeLoc, "zero element vector is illegal");
|
|
if ((unsigned)Size != Size)
|
|
return error(SizeLoc, "size too large for vector");
|
|
if (!VectorType::isValidElementType(EltTy))
|
|
return error(TypeLoc, "invalid vector element type");
|
|
Result = VectorType::get(EltTy, unsigned(Size), Scalable);
|
|
} else {
|
|
if (!ArrayType::isValidElementType(EltTy))
|
|
return error(TypeLoc, "invalid array element type");
|
|
Result = ArrayType::get(EltTy, Size);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Function Semantic Analysis.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
LLParser::PerFunctionState::PerFunctionState(LLParser &p, Function &f,
|
|
int functionNumber)
|
|
: 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);
|
|
}
|
|
|
|
LLParser::PerFunctionState::~PerFunctionState() {
|
|
// If there were any forward referenced non-basicblock values, delete them.
|
|
|
|
for (const auto &P : ForwardRefVals) {
|
|
if (isa<BasicBlock>(P.second.first))
|
|
continue;
|
|
P.second.first->replaceAllUsesWith(
|
|
UndefValue::get(P.second.first->getType()));
|
|
P.second.first->deleteValue();
|
|
}
|
|
|
|
for (const auto &P : ForwardRefValIDs) {
|
|
if (isa<BasicBlock>(P.second.first))
|
|
continue;
|
|
P.second.first->replaceAllUsesWith(
|
|
UndefValue::get(P.second.first->getType()));
|
|
P.second.first->deleteValue();
|
|
}
|
|
}
|
|
|
|
bool LLParser::PerFunctionState::finishFunction() {
|
|
if (!ForwardRefVals.empty())
|
|
return P.error(ForwardRefVals.begin()->second.second,
|
|
"use of undefined value '%" + ForwardRefVals.begin()->first +
|
|
"'");
|
|
if (!ForwardRefValIDs.empty())
|
|
return P.error(ForwardRefValIDs.begin()->second.second,
|
|
"use of undefined value '%" +
|
|
Twine(ForwardRefValIDs.begin()->first) + "'");
|
|
return false;
|
|
}
|
|
|
|
/// getVal - Get a value with the specified name or ID, creating a
|
|
/// forward reference record if needed. This can return null if the value
|
|
/// exists but does not have the right type.
|
|
Value *LLParser::PerFunctionState::getVal(const std::string &Name, Type *Ty,
|
|
LocTy Loc, bool IsCall) {
|
|
// Look this name up in the normal function symbol table.
|
|
Value *Val = F.getValueSymbolTable()->lookup(Name);
|
|
|
|
// If this is a forward reference for the value, see if we already created a
|
|
// forward ref record.
|
|
if (!Val) {
|
|
auto I = ForwardRefVals.find(Name);
|
|
if (I != ForwardRefVals.end())
|
|
Val = I->second.first;
|
|
}
|
|
|
|
// If we have the value in the symbol table or fwd-ref table, return it.
|
|
if (Val)
|
|
return P.checkValidVariableType(Loc, "%" + Name, Ty, Val, IsCall);
|
|
|
|
// Don't make placeholders with invalid type.
|
|
if (!Ty->isFirstClassType()) {
|
|
P.error(Loc, "invalid use of a non-first-class type");
|
|
return nullptr;
|
|
}
|
|
|
|
// Otherwise, create a new forward reference for this value and remember it.
|
|
Value *FwdVal;
|
|
if (Ty->isLabelTy()) {
|
|
FwdVal = BasicBlock::Create(F.getContext(), Name, &F);
|
|
} else {
|
|
FwdVal = new Argument(Ty, Name);
|
|
}
|
|
|
|
ForwardRefVals[Name] = std::make_pair(FwdVal, Loc);
|
|
return FwdVal;
|
|
}
|
|
|
|
Value *LLParser::PerFunctionState::getVal(unsigned ID, Type *Ty, LocTy Loc,
|
|
bool IsCall) {
|
|
// Look this name up in the normal function symbol table.
|
|
Value *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr;
|
|
|
|
// If this is a forward reference for the value, see if we already created a
|
|
// forward ref record.
|
|
if (!Val) {
|
|
auto I = ForwardRefValIDs.find(ID);
|
|
if (I != ForwardRefValIDs.end())
|
|
Val = I->second.first;
|
|
}
|
|
|
|
// If we have the value in the symbol table or fwd-ref table, return it.
|
|
if (Val)
|
|
return P.checkValidVariableType(Loc, "%" + Twine(ID), Ty, Val, IsCall);
|
|
|
|
if (!Ty->isFirstClassType()) {
|
|
P.error(Loc, "invalid use of a non-first-class type");
|
|
return nullptr;
|
|
}
|
|
|
|
// Otherwise, create a new forward reference for this value and remember it.
|
|
Value *FwdVal;
|
|
if (Ty->isLabelTy()) {
|
|
FwdVal = BasicBlock::Create(F.getContext(), "", &F);
|
|
} else {
|
|
FwdVal = new Argument(Ty);
|
|
}
|
|
|
|
ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc);
|
|
return FwdVal;
|
|
}
|
|
|
|
/// setInstName - After an instruction is parsed and inserted into its
|
|
/// basic block, this installs its name.
|
|
bool LLParser::PerFunctionState::setInstName(int NameID,
|
|
const std::string &NameStr,
|
|
LocTy NameLoc, Instruction *Inst) {
|
|
// If this instruction has void type, it cannot have a name or ID specified.
|
|
if (Inst->getType()->isVoidTy()) {
|
|
if (NameID != -1 || !NameStr.empty())
|
|
return P.error(NameLoc, "instructions returning void cannot have a name");
|
|
return false;
|
|
}
|
|
|
|
// If this was a numbered instruction, verify that the instruction is the
|
|
// expected value and resolve any forward references.
|
|
if (NameStr.empty()) {
|
|
// If neither a name nor an ID was specified, just use the next ID.
|
|
if (NameID == -1)
|
|
NameID = NumberedVals.size();
|
|
|
|
if (unsigned(NameID) != NumberedVals.size())
|
|
return P.error(NameLoc, "instruction expected to be numbered '%" +
|
|
Twine(NumberedVals.size()) + "'");
|
|
|
|
auto FI = ForwardRefValIDs.find(NameID);
|
|
if (FI != ForwardRefValIDs.end()) {
|
|
Value *Sentinel = FI->second.first;
|
|
if (Sentinel->getType() != Inst->getType())
|
|
return P.error(NameLoc, "instruction forward referenced with type '" +
|
|
getTypeString(FI->second.first->getType()) +
|
|
"'");
|
|
|
|
Sentinel->replaceAllUsesWith(Inst);
|
|
Sentinel->deleteValue();
|
|
ForwardRefValIDs.erase(FI);
|
|
}
|
|
|
|
NumberedVals.push_back(Inst);
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, the instruction had a name. Resolve forward refs and set it.
|
|
auto FI = ForwardRefVals.find(NameStr);
|
|
if (FI != ForwardRefVals.end()) {
|
|
Value *Sentinel = FI->second.first;
|
|
if (Sentinel->getType() != Inst->getType())
|
|
return P.error(NameLoc, "instruction forward referenced with type '" +
|
|
getTypeString(FI->second.first->getType()) +
|
|
"'");
|
|
|
|
Sentinel->replaceAllUsesWith(Inst);
|
|
Sentinel->deleteValue();
|
|
ForwardRefVals.erase(FI);
|
|
}
|
|
|
|
// Set the name on the instruction.
|
|
Inst->setName(NameStr);
|
|
|
|
if (Inst->getName() != NameStr)
|
|
return P.error(NameLoc, "multiple definition of local value named '" +
|
|
NameStr + "'");
|
|
return false;
|
|
}
|
|
|
|
/// getBB - Get a basic block with the specified name or ID, creating a
|
|
/// forward reference record if needed.
|
|
BasicBlock *LLParser::PerFunctionState::getBB(const std::string &Name,
|
|
LocTy Loc) {
|
|
return dyn_cast_or_null<BasicBlock>(
|
|
getVal(Name, Type::getLabelTy(F.getContext()), Loc, /*IsCall=*/false));
|
|
}
|
|
|
|
BasicBlock *LLParser::PerFunctionState::getBB(unsigned ID, LocTy Loc) {
|
|
return dyn_cast_or_null<BasicBlock>(
|
|
getVal(ID, Type::getLabelTy(F.getContext()), Loc, /*IsCall=*/false));
|
|
}
|
|
|
|
/// defineBB - Define the specified basic block, which is either named or
|
|
/// unnamed. If there is an error, this returns null otherwise it returns
|
|
/// the block being defined.
|
|
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;
|
|
}
|
|
BB = getBB(NumberedVals.size(), Loc);
|
|
if (!BB) {
|
|
P.error(Loc, "unable to create block numbered '" +
|
|
Twine(NumberedVals.size()) + "'");
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
BB = getBB(Name, Loc);
|
|
if (!BB) {
|
|
P.error(Loc, "unable to create block named '" + Name + "'");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Move the block to the end of the function. Forward ref'd blocks are
|
|
// inserted wherever they happen to be referenced.
|
|
F.getBasicBlockList().splice(F.end(), F.getBasicBlockList(), BB);
|
|
|
|
// Remove the block from forward ref sets.
|
|
if (Name.empty()) {
|
|
ForwardRefValIDs.erase(NumberedVals.size());
|
|
NumberedVals.push_back(BB);
|
|
} else {
|
|
// BB forward references are already in the function symbol table.
|
|
ForwardRefVals.erase(Name);
|
|
}
|
|
|
|
return BB;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Constants.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseValID - parse an abstract value that doesn't necessarily have a
|
|
/// type implied. For example, if we parse "4" we don't know what integer type
|
|
/// it has. The value will later be combined with its type and checked for
|
|
/// sanity. PFS is used to convert function-local operands of metadata (since
|
|
/// metadata operands are not just parsed here but also converted to values).
|
|
/// PFS can be null when we are not parsing metadata values inside a function.
|
|
bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS) {
|
|
ID.Loc = Lex.getLoc();
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected value token");
|
|
case lltok::GlobalID: // @42
|
|
ID.UIntVal = Lex.getUIntVal();
|
|
ID.Kind = ValID::t_GlobalID;
|
|
break;
|
|
case lltok::GlobalVar: // @foo
|
|
ID.StrVal = Lex.getStrVal();
|
|
ID.Kind = ValID::t_GlobalName;
|
|
break;
|
|
case lltok::LocalVarID: // %42
|
|
ID.UIntVal = Lex.getUIntVal();
|
|
ID.Kind = ValID::t_LocalID;
|
|
break;
|
|
case lltok::LocalVar: // %foo
|
|
ID.StrVal = Lex.getStrVal();
|
|
ID.Kind = ValID::t_LocalName;
|
|
break;
|
|
case lltok::APSInt:
|
|
ID.APSIntVal = Lex.getAPSIntVal();
|
|
ID.Kind = ValID::t_APSInt;
|
|
break;
|
|
case lltok::APFloat:
|
|
ID.APFloatVal = Lex.getAPFloatVal();
|
|
ID.Kind = ValID::t_APFloat;
|
|
break;
|
|
case lltok::kw_true:
|
|
ID.ConstantVal = ConstantInt::getTrue(Context);
|
|
ID.Kind = ValID::t_Constant;
|
|
break;
|
|
case lltok::kw_false:
|
|
ID.ConstantVal = ConstantInt::getFalse(Context);
|
|
ID.Kind = ValID::t_Constant;
|
|
break;
|
|
case lltok::kw_null: ID.Kind = ValID::t_Null; break;
|
|
case lltok::kw_undef: ID.Kind = ValID::t_Undef; break;
|
|
case lltok::kw_zeroinitializer: ID.Kind = ValID::t_Zero; break;
|
|
case lltok::kw_none: ID.Kind = ValID::t_None; break;
|
|
|
|
case lltok::lbrace: {
|
|
// ValID ::= '{' ConstVector '}'
|
|
Lex.Lex();
|
|
SmallVector<Constant*, 16> Elts;
|
|
if (parseGlobalValueVector(Elts) ||
|
|
parseToken(lltok::rbrace, "expected end of struct constant"))
|
|
return true;
|
|
|
|
ID.ConstantStructElts = std::make_unique<Constant *[]>(Elts.size());
|
|
ID.UIntVal = Elts.size();
|
|
memcpy(ID.ConstantStructElts.get(), Elts.data(),
|
|
Elts.size() * sizeof(Elts[0]));
|
|
ID.Kind = ValID::t_ConstantStruct;
|
|
return false;
|
|
}
|
|
case lltok::less: {
|
|
// ValID ::= '<' ConstVector '>' --> Vector.
|
|
// ValID ::= '<' '{' ConstVector '}' '>' --> Packed Struct.
|
|
Lex.Lex();
|
|
bool isPackedStruct = EatIfPresent(lltok::lbrace);
|
|
|
|
SmallVector<Constant*, 16> Elts;
|
|
LocTy FirstEltLoc = Lex.getLoc();
|
|
if (parseGlobalValueVector(Elts) ||
|
|
(isPackedStruct &&
|
|
parseToken(lltok::rbrace, "expected end of packed struct")) ||
|
|
parseToken(lltok::greater, "expected end of constant"))
|
|
return true;
|
|
|
|
if (isPackedStruct) {
|
|
ID.ConstantStructElts = std::make_unique<Constant *[]>(Elts.size());
|
|
memcpy(ID.ConstantStructElts.get(), Elts.data(),
|
|
Elts.size() * sizeof(Elts[0]));
|
|
ID.UIntVal = Elts.size();
|
|
ID.Kind = ValID::t_PackedConstantStruct;
|
|
return false;
|
|
}
|
|
|
|
if (Elts.empty())
|
|
return error(ID.Loc, "constant vector must not be empty");
|
|
|
|
if (!Elts[0]->getType()->isIntegerTy() &&
|
|
!Elts[0]->getType()->isFloatingPointTy() &&
|
|
!Elts[0]->getType()->isPointerTy())
|
|
return error(
|
|
FirstEltLoc,
|
|
"vector elements must have integer, pointer or floating point type");
|
|
|
|
// Verify that all the vector elements have the same type.
|
|
for (unsigned i = 1, e = Elts.size(); i != e; ++i)
|
|
if (Elts[i]->getType() != Elts[0]->getType())
|
|
return error(FirstEltLoc, "vector element #" + Twine(i) +
|
|
" is not of type '" +
|
|
getTypeString(Elts[0]->getType()));
|
|
|
|
ID.ConstantVal = ConstantVector::get(Elts);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
case lltok::lsquare: { // Array Constant
|
|
Lex.Lex();
|
|
SmallVector<Constant*, 16> Elts;
|
|
LocTy FirstEltLoc = Lex.getLoc();
|
|
if (parseGlobalValueVector(Elts) ||
|
|
parseToken(lltok::rsquare, "expected end of array constant"))
|
|
return true;
|
|
|
|
// Handle empty element.
|
|
if (Elts.empty()) {
|
|
// Use undef instead of an array because it's inconvenient to determine
|
|
// the element type at this point, there being no elements to examine.
|
|
ID.Kind = ValID::t_EmptyArray;
|
|
return false;
|
|
}
|
|
|
|
if (!Elts[0]->getType()->isFirstClassType())
|
|
return error(FirstEltLoc, "invalid array element type: " +
|
|
getTypeString(Elts[0]->getType()));
|
|
|
|
ArrayType *ATy = ArrayType::get(Elts[0]->getType(), Elts.size());
|
|
|
|
// Verify all elements are correct type!
|
|
for (unsigned i = 0, e = Elts.size(); i != e; ++i) {
|
|
if (Elts[i]->getType() != Elts[0]->getType())
|
|
return error(FirstEltLoc, "array element #" + Twine(i) +
|
|
" is not of type '" +
|
|
getTypeString(Elts[0]->getType()));
|
|
}
|
|
|
|
ID.ConstantVal = ConstantArray::get(ATy, Elts);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
case lltok::kw_c: // c "foo"
|
|
Lex.Lex();
|
|
ID.ConstantVal = ConstantDataArray::getString(Context, Lex.getStrVal(),
|
|
false);
|
|
if (parseToken(lltok::StringConstant, "expected string"))
|
|
return true;
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
|
|
case lltok::kw_asm: {
|
|
// ValID ::= 'asm' SideEffect? AlignStack? IntelDialect? STRINGCONSTANT ','
|
|
// STRINGCONSTANT
|
|
bool HasSideEffect, AlignStack, AsmDialect;
|
|
Lex.Lex();
|
|
if (parseOptionalToken(lltok::kw_sideeffect, HasSideEffect) ||
|
|
parseOptionalToken(lltok::kw_alignstack, AlignStack) ||
|
|
parseOptionalToken(lltok::kw_inteldialect, AsmDialect) ||
|
|
parseStringConstant(ID.StrVal) ||
|
|
parseToken(lltok::comma, "expected comma in inline asm expression") ||
|
|
parseToken(lltok::StringConstant, "expected constraint string"))
|
|
return true;
|
|
ID.StrVal2 = Lex.getStrVal();
|
|
ID.UIntVal = unsigned(HasSideEffect) | (unsigned(AlignStack)<<1) |
|
|
(unsigned(AsmDialect)<<2);
|
|
ID.Kind = ValID::t_InlineAsm;
|
|
return false;
|
|
}
|
|
|
|
case lltok::kw_blockaddress: {
|
|
// ValID ::= 'blockaddress' '(' @foo ',' %bar ')'
|
|
Lex.Lex();
|
|
|
|
ValID Fn, Label;
|
|
|
|
if (parseToken(lltok::lparen, "expected '(' in block address expression") ||
|
|
parseValID(Fn) ||
|
|
parseToken(lltok::comma,
|
|
"expected comma in block address expression") ||
|
|
parseValID(Label) ||
|
|
parseToken(lltok::rparen, "expected ')' in block address expression"))
|
|
return true;
|
|
|
|
if (Fn.Kind != ValID::t_GlobalID && Fn.Kind != ValID::t_GlobalName)
|
|
return error(Fn.Loc, "expected function name in blockaddress");
|
|
if (Label.Kind != ValID::t_LocalID && Label.Kind != ValID::t_LocalName)
|
|
return error(Label.Loc, "expected basic block name in blockaddress");
|
|
|
|
// 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];
|
|
} else if (!ForwardRefVals.count(Fn.StrVal)) {
|
|
GV = M->getNamedValue(Fn.StrVal);
|
|
}
|
|
Function *F = nullptr;
|
|
if (GV) {
|
|
// Confirm that it's actually a function with a definition.
|
|
if (!isa<Function>(GV))
|
|
return error(Fn.Loc, "expected function name in blockaddress");
|
|
F = cast<Function>(GV);
|
|
if (F->isDeclaration())
|
|
return error(Fn.Loc, "cannot take blockaddress inside a declaration");
|
|
}
|
|
|
|
if (!F) {
|
|
// Make a global variable as a placeholder for this reference.
|
|
GlobalValue *&FwdRef =
|
|
ForwardRefBlockAddresses.insert(std::make_pair(
|
|
std::move(Fn),
|
|
std::map<ValID, GlobalValue *>()))
|
|
.first->second.insert(std::make_pair(std::move(Label), nullptr))
|
|
.first->second;
|
|
if (!FwdRef)
|
|
FwdRef = new GlobalVariable(*M, Type::getInt8Ty(Context), false,
|
|
GlobalValue::InternalLinkage, nullptr, "");
|
|
ID.ConstantVal = FwdRef;
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
|
|
// We found the function; now find the basic block. Don't use PFS, since we
|
|
// might be inside a constant expression.
|
|
BasicBlock *BB;
|
|
if (BlockAddressPFS && F == &BlockAddressPFS->getFunction()) {
|
|
if (Label.Kind == ValID::t_LocalID)
|
|
BB = BlockAddressPFS->getBB(Label.UIntVal, Label.Loc);
|
|
else
|
|
BB = BlockAddressPFS->getBB(Label.StrVal, Label.Loc);
|
|
if (!BB)
|
|
return error(Label.Loc, "referenced value is not a basic block");
|
|
} else {
|
|
if (Label.Kind == ValID::t_LocalID)
|
|
return error(Label.Loc, "cannot take address of numeric label after "
|
|
"the function is defined");
|
|
BB = dyn_cast_or_null<BasicBlock>(
|
|
F->getValueSymbolTable()->lookup(Label.StrVal));
|
|
if (!BB)
|
|
return error(Label.Loc, "referenced value is not a basic block");
|
|
}
|
|
|
|
ID.ConstantVal = BlockAddress::get(F, BB);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
|
|
case lltok::kw_trunc:
|
|
case lltok::kw_zext:
|
|
case lltok::kw_sext:
|
|
case lltok::kw_fptrunc:
|
|
case lltok::kw_fpext:
|
|
case lltok::kw_bitcast:
|
|
case lltok::kw_addrspacecast:
|
|
case lltok::kw_uitofp:
|
|
case lltok::kw_sitofp:
|
|
case lltok::kw_fptoui:
|
|
case lltok::kw_fptosi:
|
|
case lltok::kw_inttoptr:
|
|
case lltok::kw_ptrtoint: {
|
|
unsigned Opc = Lex.getUIntVal();
|
|
Type *DestTy = nullptr;
|
|
Constant *SrcVal;
|
|
Lex.Lex();
|
|
if (parseToken(lltok::lparen, "expected '(' after constantexpr cast") ||
|
|
parseGlobalTypeAndValue(SrcVal) ||
|
|
parseToken(lltok::kw_to, "expected 'to' in constantexpr cast") ||
|
|
parseType(DestTy) ||
|
|
parseToken(lltok::rparen, "expected ')' at end of constantexpr cast"))
|
|
return true;
|
|
if (!CastInst::castIsValid((Instruction::CastOps)Opc, SrcVal, DestTy))
|
|
return error(ID.Loc, "invalid cast opcode for cast from '" +
|
|
getTypeString(SrcVal->getType()) + "' to '" +
|
|
getTypeString(DestTy) + "'");
|
|
ID.ConstantVal = ConstantExpr::getCast((Instruction::CastOps)Opc,
|
|
SrcVal, DestTy);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
case lltok::kw_extractvalue: {
|
|
Lex.Lex();
|
|
Constant *Val;
|
|
SmallVector<unsigned, 4> Indices;
|
|
if (parseToken(lltok::lparen,
|
|
"expected '(' in extractvalue constantexpr") ||
|
|
parseGlobalTypeAndValue(Val) || parseIndexList(Indices) ||
|
|
parseToken(lltok::rparen, "expected ')' in extractvalue constantexpr"))
|
|
return true;
|
|
|
|
if (!Val->getType()->isAggregateType())
|
|
return error(ID.Loc, "extractvalue operand must be aggregate type");
|
|
if (!ExtractValueInst::getIndexedType(Val->getType(), Indices))
|
|
return error(ID.Loc, "invalid indices for extractvalue");
|
|
ID.ConstantVal = ConstantExpr::getExtractValue(Val, Indices);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
case lltok::kw_insertvalue: {
|
|
Lex.Lex();
|
|
Constant *Val0, *Val1;
|
|
SmallVector<unsigned, 4> Indices;
|
|
if (parseToken(lltok::lparen, "expected '(' in insertvalue constantexpr") ||
|
|
parseGlobalTypeAndValue(Val0) ||
|
|
parseToken(lltok::comma,
|
|
"expected comma in insertvalue constantexpr") ||
|
|
parseGlobalTypeAndValue(Val1) || parseIndexList(Indices) ||
|
|
parseToken(lltok::rparen, "expected ')' in insertvalue constantexpr"))
|
|
return true;
|
|
if (!Val0->getType()->isAggregateType())
|
|
return error(ID.Loc, "insertvalue operand must be aggregate type");
|
|
Type *IndexedType =
|
|
ExtractValueInst::getIndexedType(Val0->getType(), Indices);
|
|
if (!IndexedType)
|
|
return error(ID.Loc, "invalid indices for insertvalue");
|
|
if (IndexedType != Val1->getType())
|
|
return error(ID.Loc, "insertvalue operand and field disagree in type: '" +
|
|
getTypeString(Val1->getType()) +
|
|
"' instead of '" + getTypeString(IndexedType) +
|
|
"'");
|
|
ID.ConstantVal = ConstantExpr::getInsertValue(Val0, Val1, Indices);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
case lltok::kw_icmp:
|
|
case lltok::kw_fcmp: {
|
|
unsigned PredVal, Opc = Lex.getUIntVal();
|
|
Constant *Val0, *Val1;
|
|
Lex.Lex();
|
|
if (parseCmpPredicate(PredVal, Opc) ||
|
|
parseToken(lltok::lparen, "expected '(' in compare constantexpr") ||
|
|
parseGlobalTypeAndValue(Val0) ||
|
|
parseToken(lltok::comma, "expected comma in compare constantexpr") ||
|
|
parseGlobalTypeAndValue(Val1) ||
|
|
parseToken(lltok::rparen, "expected ')' in compare constantexpr"))
|
|
return true;
|
|
|
|
if (Val0->getType() != Val1->getType())
|
|
return error(ID.Loc, "compare operands must have the same type");
|
|
|
|
CmpInst::Predicate Pred = (CmpInst::Predicate)PredVal;
|
|
|
|
if (Opc == Instruction::FCmp) {
|
|
if (!Val0->getType()->isFPOrFPVectorTy())
|
|
return error(ID.Loc, "fcmp requires floating point operands");
|
|
ID.ConstantVal = ConstantExpr::getFCmp(Pred, Val0, Val1);
|
|
} else {
|
|
assert(Opc == Instruction::ICmp && "Unexpected opcode for CmpInst!");
|
|
if (!Val0->getType()->isIntOrIntVectorTy() &&
|
|
!Val0->getType()->isPtrOrPtrVectorTy())
|
|
return error(ID.Loc, "icmp requires pointer or integer operands");
|
|
ID.ConstantVal = ConstantExpr::getICmp(Pred, Val0, Val1);
|
|
}
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
|
|
// Unary Operators.
|
|
case lltok::kw_fneg: {
|
|
unsigned Opc = Lex.getUIntVal();
|
|
Constant *Val;
|
|
Lex.Lex();
|
|
if (parseToken(lltok::lparen, "expected '(' in unary constantexpr") ||
|
|
parseGlobalTypeAndValue(Val) ||
|
|
parseToken(lltok::rparen, "expected ')' in unary constantexpr"))
|
|
return true;
|
|
|
|
// Check that the type is valid for the operator.
|
|
switch (Opc) {
|
|
case Instruction::FNeg:
|
|
if (!Val->getType()->isFPOrFPVectorTy())
|
|
return error(ID.Loc, "constexpr requires fp operands");
|
|
break;
|
|
default: llvm_unreachable("Unknown unary operator!");
|
|
}
|
|
unsigned Flags = 0;
|
|
Constant *C = ConstantExpr::get(Opc, Val, Flags);
|
|
ID.ConstantVal = C;
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
// Binary Operators.
|
|
case lltok::kw_add:
|
|
case lltok::kw_fadd:
|
|
case lltok::kw_sub:
|
|
case lltok::kw_fsub:
|
|
case lltok::kw_mul:
|
|
case lltok::kw_fmul:
|
|
case lltok::kw_udiv:
|
|
case lltok::kw_sdiv:
|
|
case lltok::kw_fdiv:
|
|
case lltok::kw_urem:
|
|
case lltok::kw_srem:
|
|
case lltok::kw_frem:
|
|
case lltok::kw_shl:
|
|
case lltok::kw_lshr:
|
|
case lltok::kw_ashr: {
|
|
bool NUW = false;
|
|
bool NSW = false;
|
|
bool Exact = false;
|
|
unsigned Opc = Lex.getUIntVal();
|
|
Constant *Val0, *Val1;
|
|
Lex.Lex();
|
|
if (Opc == Instruction::Add || Opc == Instruction::Sub ||
|
|
Opc == Instruction::Mul || Opc == Instruction::Shl) {
|
|
if (EatIfPresent(lltok::kw_nuw))
|
|
NUW = true;
|
|
if (EatIfPresent(lltok::kw_nsw)) {
|
|
NSW = true;
|
|
if (EatIfPresent(lltok::kw_nuw))
|
|
NUW = true;
|
|
}
|
|
} else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv ||
|
|
Opc == Instruction::LShr || Opc == Instruction::AShr) {
|
|
if (EatIfPresent(lltok::kw_exact))
|
|
Exact = true;
|
|
}
|
|
if (parseToken(lltok::lparen, "expected '(' in binary constantexpr") ||
|
|
parseGlobalTypeAndValue(Val0) ||
|
|
parseToken(lltok::comma, "expected comma in binary constantexpr") ||
|
|
parseGlobalTypeAndValue(Val1) ||
|
|
parseToken(lltok::rparen, "expected ')' in binary constantexpr"))
|
|
return true;
|
|
if (Val0->getType() != Val1->getType())
|
|
return error(ID.Loc, "operands of constexpr must have same type");
|
|
// Check that the type is valid for the operator.
|
|
switch (Opc) {
|
|
case Instruction::Add:
|
|
case Instruction::Sub:
|
|
case Instruction::Mul:
|
|
case Instruction::UDiv:
|
|
case Instruction::SDiv:
|
|
case Instruction::URem:
|
|
case Instruction::SRem:
|
|
case Instruction::Shl:
|
|
case Instruction::AShr:
|
|
case Instruction::LShr:
|
|
if (!Val0->getType()->isIntOrIntVectorTy())
|
|
return error(ID.Loc, "constexpr requires integer operands");
|
|
break;
|
|
case Instruction::FAdd:
|
|
case Instruction::FSub:
|
|
case Instruction::FMul:
|
|
case Instruction::FDiv:
|
|
case Instruction::FRem:
|
|
if (!Val0->getType()->isFPOrFPVectorTy())
|
|
return error(ID.Loc, "constexpr requires fp operands");
|
|
break;
|
|
default: llvm_unreachable("Unknown binary operator!");
|
|
}
|
|
unsigned Flags = 0;
|
|
if (NUW) Flags |= OverflowingBinaryOperator::NoUnsignedWrap;
|
|
if (NSW) Flags |= OverflowingBinaryOperator::NoSignedWrap;
|
|
if (Exact) Flags |= PossiblyExactOperator::IsExact;
|
|
Constant *C = ConstantExpr::get(Opc, Val0, Val1, Flags);
|
|
ID.ConstantVal = C;
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
|
|
// Logical Operations
|
|
case lltok::kw_and:
|
|
case lltok::kw_or:
|
|
case lltok::kw_xor: {
|
|
unsigned Opc = Lex.getUIntVal();
|
|
Constant *Val0, *Val1;
|
|
Lex.Lex();
|
|
if (parseToken(lltok::lparen, "expected '(' in logical constantexpr") ||
|
|
parseGlobalTypeAndValue(Val0) ||
|
|
parseToken(lltok::comma, "expected comma in logical constantexpr") ||
|
|
parseGlobalTypeAndValue(Val1) ||
|
|
parseToken(lltok::rparen, "expected ')' in logical constantexpr"))
|
|
return true;
|
|
if (Val0->getType() != Val1->getType())
|
|
return error(ID.Loc, "operands of constexpr must have same type");
|
|
if (!Val0->getType()->isIntOrIntVectorTy())
|
|
return error(ID.Loc,
|
|
"constexpr requires integer or integer vector operands");
|
|
ID.ConstantVal = ConstantExpr::get(Opc, Val0, Val1);
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
|
|
case lltok::kw_getelementptr:
|
|
case lltok::kw_shufflevector:
|
|
case lltok::kw_insertelement:
|
|
case lltok::kw_extractelement:
|
|
case lltok::kw_select: {
|
|
unsigned Opc = Lex.getUIntVal();
|
|
SmallVector<Constant*, 16> Elts;
|
|
bool InBounds = false;
|
|
Type *Ty;
|
|
Lex.Lex();
|
|
|
|
if (Opc == Instruction::GetElementPtr)
|
|
InBounds = EatIfPresent(lltok::kw_inbounds);
|
|
|
|
if (parseToken(lltok::lparen, "expected '(' in constantexpr"))
|
|
return true;
|
|
|
|
LocTy ExplicitTypeLoc = Lex.getLoc();
|
|
if (Opc == Instruction::GetElementPtr) {
|
|
if (parseType(Ty) ||
|
|
parseToken(lltok::comma, "expected comma after getelementptr's type"))
|
|
return true;
|
|
}
|
|
|
|
Optional<unsigned> InRangeOp;
|
|
if (parseGlobalValueVector(
|
|
Elts, Opc == Instruction::GetElementPtr ? &InRangeOp : nullptr) ||
|
|
parseToken(lltok::rparen, "expected ')' in constantexpr"))
|
|
return true;
|
|
|
|
if (Opc == Instruction::GetElementPtr) {
|
|
if (Elts.size() == 0 ||
|
|
!Elts[0]->getType()->isPtrOrPtrVectorTy())
|
|
return error(ID.Loc, "base of getelementptr must be a pointer");
|
|
|
|
Type *BaseType = Elts[0]->getType();
|
|
auto *BasePointerType = cast<PointerType>(BaseType->getScalarType());
|
|
if (Ty != BasePointerType->getElementType())
|
|
return error(
|
|
ExplicitTypeLoc,
|
|
"explicit pointee type doesn't match operand's pointee type");
|
|
|
|
unsigned GEPWidth =
|
|
BaseType->isVectorTy()
|
|
? cast<FixedVectorType>(BaseType)->getNumElements()
|
|
: 0;
|
|
|
|
ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end());
|
|
for (Constant *Val : Indices) {
|
|
Type *ValTy = Val->getType();
|
|
if (!ValTy->isIntOrIntVectorTy())
|
|
return error(ID.Loc, "getelementptr index must be an integer");
|
|
if (auto *ValVTy = dyn_cast<VectorType>(ValTy)) {
|
|
unsigned ValNumEl = cast<FixedVectorType>(ValVTy)->getNumElements();
|
|
if (GEPWidth && (ValNumEl != GEPWidth))
|
|
return error(
|
|
ID.Loc,
|
|
"getelementptr vector index has a wrong number of elements");
|
|
// GEPWidth may have been unknown because the base is a scalar,
|
|
// but it is known now.
|
|
GEPWidth = ValNumEl;
|
|
}
|
|
}
|
|
|
|
SmallPtrSet<Type*, 4> Visited;
|
|
if (!Indices.empty() && !Ty->isSized(&Visited))
|
|
return error(ID.Loc, "base element of getelementptr must be sized");
|
|
|
|
if (!GetElementPtrInst::getIndexedType(Ty, Indices))
|
|
return error(ID.Loc, "invalid getelementptr indices");
|
|
|
|
if (InRangeOp) {
|
|
if (*InRangeOp == 0)
|
|
return error(ID.Loc,
|
|
"inrange keyword may not appear on pointer operand");
|
|
--*InRangeOp;
|
|
}
|
|
|
|
ID.ConstantVal = ConstantExpr::getGetElementPtr(Ty, Elts[0], Indices,
|
|
InBounds, InRangeOp);
|
|
} else if (Opc == Instruction::Select) {
|
|
if (Elts.size() != 3)
|
|
return error(ID.Loc, "expected three operands to select");
|
|
if (const char *Reason = SelectInst::areInvalidOperands(Elts[0], Elts[1],
|
|
Elts[2]))
|
|
return error(ID.Loc, Reason);
|
|
ID.ConstantVal = ConstantExpr::getSelect(Elts[0], Elts[1], Elts[2]);
|
|
} else if (Opc == Instruction::ShuffleVector) {
|
|
if (Elts.size() != 3)
|
|
return error(ID.Loc, "expected three operands to shufflevector");
|
|
if (!ShuffleVectorInst::isValidOperands(Elts[0], Elts[1], Elts[2]))
|
|
return error(ID.Loc, "invalid operands to shufflevector");
|
|
SmallVector<int, 16> Mask;
|
|
ShuffleVectorInst::getShuffleMask(cast<Constant>(Elts[2]), Mask);
|
|
ID.ConstantVal = ConstantExpr::getShuffleVector(Elts[0], Elts[1], Mask);
|
|
} else if (Opc == Instruction::ExtractElement) {
|
|
if (Elts.size() != 2)
|
|
return error(ID.Loc, "expected two operands to extractelement");
|
|
if (!ExtractElementInst::isValidOperands(Elts[0], Elts[1]))
|
|
return error(ID.Loc, "invalid extractelement operands");
|
|
ID.ConstantVal = ConstantExpr::getExtractElement(Elts[0], Elts[1]);
|
|
} else {
|
|
assert(Opc == Instruction::InsertElement && "Unknown opcode");
|
|
if (Elts.size() != 3)
|
|
return error(ID.Loc, "expected three operands to insertelement");
|
|
if (!InsertElementInst::isValidOperands(Elts[0], Elts[1], Elts[2]))
|
|
return error(ID.Loc, "invalid insertelement operands");
|
|
ID.ConstantVal =
|
|
ConstantExpr::getInsertElement(Elts[0], Elts[1],Elts[2]);
|
|
}
|
|
|
|
ID.Kind = ValID::t_Constant;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// parseGlobalValue - parse a global value with the specified type.
|
|
bool LLParser::parseGlobalValue(Type *Ty, Constant *&C) {
|
|
C = nullptr;
|
|
ValID ID;
|
|
Value *V = nullptr;
|
|
bool Parsed = parseValID(ID) ||
|
|
convertValIDToValue(Ty, ID, V, nullptr, /*IsCall=*/false);
|
|
if (V && !(C = dyn_cast<Constant>(V)))
|
|
return error(ID.Loc, "global values must be constants");
|
|
return Parsed;
|
|
}
|
|
|
|
bool LLParser::parseGlobalTypeAndValue(Constant *&V) {
|
|
Type *Ty = nullptr;
|
|
return parseType(Ty) || parseGlobalValue(Ty, V);
|
|
}
|
|
|
|
bool LLParser::parseOptionalComdat(StringRef GlobalName, Comdat *&C) {
|
|
C = nullptr;
|
|
|
|
LocTy KwLoc = Lex.getLoc();
|
|
if (!EatIfPresent(lltok::kw_comdat))
|
|
return false;
|
|
|
|
if (EatIfPresent(lltok::lparen)) {
|
|
if (Lex.getKind() != lltok::ComdatVar)
|
|
return tokError("expected comdat variable");
|
|
C = getComdat(Lex.getStrVal(), Lex.getLoc());
|
|
Lex.Lex();
|
|
if (parseToken(lltok::rparen, "expected ')' after comdat var"))
|
|
return true;
|
|
} else {
|
|
if (GlobalName.empty())
|
|
return tokError("comdat cannot be unnamed");
|
|
C = getComdat(std::string(GlobalName), KwLoc);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseGlobalValueVector
|
|
/// ::= /*empty*/
|
|
/// ::= [inrange] TypeAndValue (',' [inrange] TypeAndValue)*
|
|
bool LLParser::parseGlobalValueVector(SmallVectorImpl<Constant *> &Elts,
|
|
Optional<unsigned> *InRangeOp) {
|
|
// Empty list.
|
|
if (Lex.getKind() == lltok::rbrace ||
|
|
Lex.getKind() == lltok::rsquare ||
|
|
Lex.getKind() == lltok::greater ||
|
|
Lex.getKind() == lltok::rparen)
|
|
return false;
|
|
|
|
do {
|
|
if (InRangeOp && !*InRangeOp && EatIfPresent(lltok::kw_inrange))
|
|
*InRangeOp = Elts.size();
|
|
|
|
Constant *C;
|
|
if (parseGlobalTypeAndValue(C))
|
|
return true;
|
|
Elts.push_back(C);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseMDTuple(MDNode *&MD, bool IsDistinct) {
|
|
SmallVector<Metadata *, 16> Elts;
|
|
if (parseMDNodeVector(Elts))
|
|
return true;
|
|
|
|
MD = (IsDistinct ? MDTuple::getDistinct : MDTuple::get)(Context, Elts);
|
|
return false;
|
|
}
|
|
|
|
/// MDNode:
|
|
/// ::= !{ ... }
|
|
/// ::= !7
|
|
/// ::= !DILocation(...)
|
|
bool LLParser::parseMDNode(MDNode *&N) {
|
|
if (Lex.getKind() == lltok::MetadataVar)
|
|
return parseSpecializedMDNode(N);
|
|
|
|
return parseToken(lltok::exclaim, "expected '!' here") || parseMDNodeTail(N);
|
|
}
|
|
|
|
bool LLParser::parseMDNodeTail(MDNode *&N) {
|
|
// !{ ... }
|
|
if (Lex.getKind() == lltok::lbrace)
|
|
return parseMDTuple(N);
|
|
|
|
// !42
|
|
return parseMDNodeID(N);
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// Structure to represent an optional metadata field.
|
|
template <class FieldTy> struct MDFieldImpl {
|
|
typedef MDFieldImpl ImplTy;
|
|
FieldTy Val;
|
|
bool Seen;
|
|
|
|
void assign(FieldTy Val) {
|
|
Seen = true;
|
|
this->Val = std::move(Val);
|
|
}
|
|
|
|
explicit MDFieldImpl(FieldTy Default)
|
|
: Val(std::move(Default)), Seen(false) {}
|
|
};
|
|
|
|
/// Structure to represent an optional metadata field that
|
|
/// can be of either type (A or B) and encapsulates the
|
|
/// MD<typeofA>Field and MD<typeofB>Field structs, so not
|
|
/// to reimplement the specifics for representing each Field.
|
|
template <class FieldTypeA, class FieldTypeB> struct MDEitherFieldImpl {
|
|
typedef MDEitherFieldImpl<FieldTypeA, FieldTypeB> ImplTy;
|
|
FieldTypeA A;
|
|
FieldTypeB B;
|
|
bool Seen;
|
|
|
|
enum {
|
|
IsInvalid = 0,
|
|
IsTypeA = 1,
|
|
IsTypeB = 2
|
|
} WhatIs;
|
|
|
|
void assign(FieldTypeA A) {
|
|
Seen = true;
|
|
this->A = std::move(A);
|
|
WhatIs = IsTypeA;
|
|
}
|
|
|
|
void assign(FieldTypeB B) {
|
|
Seen = true;
|
|
this->B = std::move(B);
|
|
WhatIs = IsTypeB;
|
|
}
|
|
|
|
explicit MDEitherFieldImpl(FieldTypeA DefaultA, FieldTypeB DefaultB)
|
|
: A(std::move(DefaultA)), B(std::move(DefaultB)), Seen(false),
|
|
WhatIs(IsInvalid) {}
|
|
};
|
|
|
|
struct MDUnsignedField : public MDFieldImpl<uint64_t> {
|
|
uint64_t Max;
|
|
|
|
MDUnsignedField(uint64_t Default = 0, uint64_t Max = UINT64_MAX)
|
|
: ImplTy(Default), Max(Max) {}
|
|
};
|
|
|
|
struct LineField : public MDUnsignedField {
|
|
LineField() : MDUnsignedField(0, UINT32_MAX) {}
|
|
};
|
|
|
|
struct ColumnField : public MDUnsignedField {
|
|
ColumnField() : MDUnsignedField(0, UINT16_MAX) {}
|
|
};
|
|
|
|
struct DwarfTagField : public MDUnsignedField {
|
|
DwarfTagField() : MDUnsignedField(0, dwarf::DW_TAG_hi_user) {}
|
|
DwarfTagField(dwarf::Tag DefaultTag)
|
|
: MDUnsignedField(DefaultTag, dwarf::DW_TAG_hi_user) {}
|
|
};
|
|
|
|
struct DwarfMacinfoTypeField : public MDUnsignedField {
|
|
DwarfMacinfoTypeField() : MDUnsignedField(0, dwarf::DW_MACINFO_vendor_ext) {}
|
|
DwarfMacinfoTypeField(dwarf::MacinfoRecordType DefaultType)
|
|
: MDUnsignedField(DefaultType, dwarf::DW_MACINFO_vendor_ext) {}
|
|
};
|
|
|
|
struct DwarfAttEncodingField : public MDUnsignedField {
|
|
DwarfAttEncodingField() : MDUnsignedField(0, dwarf::DW_ATE_hi_user) {}
|
|
};
|
|
|
|
struct DwarfVirtualityField : public MDUnsignedField {
|
|
DwarfVirtualityField() : MDUnsignedField(0, dwarf::DW_VIRTUALITY_max) {}
|
|
};
|
|
|
|
struct DwarfLangField : public MDUnsignedField {
|
|
DwarfLangField() : MDUnsignedField(0, dwarf::DW_LANG_hi_user) {}
|
|
};
|
|
|
|
struct DwarfCCField : public MDUnsignedField {
|
|
DwarfCCField() : MDUnsignedField(0, dwarf::DW_CC_hi_user) {}
|
|
};
|
|
|
|
struct EmissionKindField : public MDUnsignedField {
|
|
EmissionKindField() : MDUnsignedField(0, DICompileUnit::LastEmissionKind) {}
|
|
};
|
|
|
|
struct NameTableKindField : public MDUnsignedField {
|
|
NameTableKindField()
|
|
: MDUnsignedField(
|
|
0, (unsigned)
|
|
DICompileUnit::DebugNameTableKind::LastDebugNameTableKind) {}
|
|
};
|
|
|
|
struct DIFlagField : public MDFieldImpl<DINode::DIFlags> {
|
|
DIFlagField() : MDFieldImpl(DINode::FlagZero) {}
|
|
};
|
|
|
|
struct DISPFlagField : public MDFieldImpl<DISubprogram::DISPFlags> {
|
|
DISPFlagField() : MDFieldImpl(DISubprogram::SPFlagZero) {}
|
|
};
|
|
|
|
struct MDAPSIntField : public MDFieldImpl<APSInt> {
|
|
MDAPSIntField() : ImplTy(APSInt()) {}
|
|
};
|
|
|
|
struct MDSignedField : public MDFieldImpl<int64_t> {
|
|
int64_t Min;
|
|
int64_t Max;
|
|
|
|
MDSignedField(int64_t Default = 0)
|
|
: ImplTy(Default), Min(INT64_MIN), Max(INT64_MAX) {}
|
|
MDSignedField(int64_t Default, int64_t Min, int64_t Max)
|
|
: ImplTy(Default), Min(Min), Max(Max) {}
|
|
};
|
|
|
|
struct MDBoolField : public MDFieldImpl<bool> {
|
|
MDBoolField(bool Default = false) : ImplTy(Default) {}
|
|
};
|
|
|
|
struct MDField : public MDFieldImpl<Metadata *> {
|
|
bool AllowNull;
|
|
|
|
MDField(bool AllowNull = true) : ImplTy(nullptr), AllowNull(AllowNull) {}
|
|
};
|
|
|
|
struct MDConstant : public MDFieldImpl<ConstantAsMetadata *> {
|
|
MDConstant() : ImplTy(nullptr) {}
|
|
};
|
|
|
|
struct MDStringField : public MDFieldImpl<MDString *> {
|
|
bool AllowEmpty;
|
|
MDStringField(bool AllowEmpty = true)
|
|
: ImplTy(nullptr), AllowEmpty(AllowEmpty) {}
|
|
};
|
|
|
|
struct MDFieldList : public MDFieldImpl<SmallVector<Metadata *, 4>> {
|
|
MDFieldList() : ImplTy(SmallVector<Metadata *, 4>()) {}
|
|
};
|
|
|
|
struct ChecksumKindField : public MDFieldImpl<DIFile::ChecksumKind> {
|
|
ChecksumKindField(DIFile::ChecksumKind CSKind) : ImplTy(CSKind) {}
|
|
};
|
|
|
|
struct MDSignedOrMDField : MDEitherFieldImpl<MDSignedField, MDField> {
|
|
MDSignedOrMDField(int64_t Default = 0, bool AllowNull = true)
|
|
: ImplTy(MDSignedField(Default), MDField(AllowNull)) {}
|
|
|
|
MDSignedOrMDField(int64_t Default, int64_t Min, int64_t Max,
|
|
bool AllowNull = true)
|
|
: ImplTy(MDSignedField(Default, Min, Max), MDField(AllowNull)) {}
|
|
|
|
bool isMDSignedField() const { return WhatIs == IsTypeA; }
|
|
bool isMDField() const { return WhatIs == IsTypeB; }
|
|
int64_t getMDSignedValue() const {
|
|
assert(isMDSignedField() && "Wrong field type");
|
|
return A.Val;
|
|
}
|
|
Metadata *getMDFieldValue() const {
|
|
assert(isMDField() && "Wrong field type");
|
|
return B.Val;
|
|
}
|
|
};
|
|
|
|
struct MDSignedOrUnsignedField
|
|
: MDEitherFieldImpl<MDSignedField, MDUnsignedField> {
|
|
MDSignedOrUnsignedField() : ImplTy(MDSignedField(0), MDUnsignedField(0)) {}
|
|
|
|
bool isMDSignedField() const { return WhatIs == IsTypeA; }
|
|
bool isMDUnsignedField() const { return WhatIs == IsTypeB; }
|
|
int64_t getMDSignedValue() const {
|
|
assert(isMDSignedField() && "Wrong field type");
|
|
return A.Val;
|
|
}
|
|
uint64_t getMDUnsignedValue() const {
|
|
assert(isMDUnsignedField() && "Wrong field type");
|
|
return B.Val;
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
namespace llvm {
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDAPSIntField &Result) {
|
|
if (Lex.getKind() != lltok::APSInt)
|
|
return tokError("expected integer");
|
|
|
|
Result.assign(Lex.getAPSIntVal());
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
MDUnsignedField &Result) {
|
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
|
|
return tokError("expected unsigned integer");
|
|
|
|
auto &U = Lex.getAPSIntVal();
|
|
if (U.ugt(Result.Max))
|
|
return tokError("value for '" + Name + "' too large, limit is " +
|
|
Twine(Result.Max));
|
|
Result.assign(U.getZExtValue());
|
|
assert(Result.Val <= Result.Max && "Expected value in range");
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, LineField &Result) {
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
}
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, ColumnField &Result) {
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, DwarfTagField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::DwarfTag)
|
|
return tokError("expected DWARF tag");
|
|
|
|
unsigned Tag = dwarf::getTag(Lex.getStrVal());
|
|
if (Tag == dwarf::DW_TAG_invalid)
|
|
return tokError("invalid DWARF tag" + Twine(" '") + Lex.getStrVal() + "'");
|
|
assert(Tag <= Result.Max && "Expected valid DWARF tag");
|
|
|
|
Result.assign(Tag);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
DwarfMacinfoTypeField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::DwarfMacinfo)
|
|
return tokError("expected DWARF macinfo type");
|
|
|
|
unsigned Macinfo = dwarf::getMacinfo(Lex.getStrVal());
|
|
if (Macinfo == dwarf::DW_MACINFO_invalid)
|
|
return tokError("invalid DWARF macinfo type" + Twine(" '") +
|
|
Lex.getStrVal() + "'");
|
|
assert(Macinfo <= Result.Max && "Expected valid DWARF macinfo type");
|
|
|
|
Result.assign(Macinfo);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
DwarfVirtualityField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::DwarfVirtuality)
|
|
return tokError("expected DWARF virtuality code");
|
|
|
|
unsigned Virtuality = dwarf::getVirtuality(Lex.getStrVal());
|
|
if (Virtuality == dwarf::DW_VIRTUALITY_invalid)
|
|
return tokError("invalid DWARF virtuality code" + Twine(" '") +
|
|
Lex.getStrVal() + "'");
|
|
assert(Virtuality <= Result.Max && "Expected valid DWARF virtuality code");
|
|
Result.assign(Virtuality);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, DwarfLangField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::DwarfLang)
|
|
return tokError("expected DWARF language");
|
|
|
|
unsigned Lang = dwarf::getLanguage(Lex.getStrVal());
|
|
if (!Lang)
|
|
return tokError("invalid DWARF language" + Twine(" '") + Lex.getStrVal() +
|
|
"'");
|
|
assert(Lang <= Result.Max && "Expected valid DWARF language");
|
|
Result.assign(Lang);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, DwarfCCField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::DwarfCC)
|
|
return tokError("expected DWARF calling convention");
|
|
|
|
unsigned CC = dwarf::getCallingConvention(Lex.getStrVal());
|
|
if (!CC)
|
|
return tokError("invalid DWARF calling convention" + Twine(" '") +
|
|
Lex.getStrVal() + "'");
|
|
assert(CC <= Result.Max && "Expected valid DWARF calling convention");
|
|
Result.assign(CC);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
EmissionKindField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::EmissionKind)
|
|
return tokError("expected emission kind");
|
|
|
|
auto Kind = DICompileUnit::getEmissionKind(Lex.getStrVal());
|
|
if (!Kind)
|
|
return tokError("invalid emission kind" + Twine(" '") + Lex.getStrVal() +
|
|
"'");
|
|
assert(*Kind <= Result.Max && "Expected valid emission kind");
|
|
Result.assign(*Kind);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
NameTableKindField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::NameTableKind)
|
|
return tokError("expected nameTable kind");
|
|
|
|
auto Kind = DICompileUnit::getNameTableKind(Lex.getStrVal());
|
|
if (!Kind)
|
|
return tokError("invalid nameTable kind" + Twine(" '") + Lex.getStrVal() +
|
|
"'");
|
|
assert(((unsigned)*Kind) <= Result.Max && "Expected valid nameTable kind");
|
|
Result.assign((unsigned)*Kind);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
DwarfAttEncodingField &Result) {
|
|
if (Lex.getKind() == lltok::APSInt)
|
|
return parseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
|
|
|
|
if (Lex.getKind() != lltok::DwarfAttEncoding)
|
|
return tokError("expected DWARF type attribute encoding");
|
|
|
|
unsigned Encoding = dwarf::getAttributeEncoding(Lex.getStrVal());
|
|
if (!Encoding)
|
|
return tokError("invalid DWARF type attribute encoding" + Twine(" '") +
|
|
Lex.getStrVal() + "'");
|
|
assert(Encoding <= Result.Max && "Expected valid DWARF language");
|
|
Result.assign(Encoding);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// DIFlagField
|
|
/// ::= uint32
|
|
/// ::= DIFlagVector
|
|
/// ::= DIFlagVector '|' DIFlagFwdDecl '|' uint32 '|' DIFlagPublic
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, DIFlagField &Result) {
|
|
|
|
// parser for a single flag.
|
|
auto parseFlag = [&](DINode::DIFlags &Val) {
|
|
if (Lex.getKind() == lltok::APSInt && !Lex.getAPSIntVal().isSigned()) {
|
|
uint32_t TempVal = static_cast<uint32_t>(Val);
|
|
bool Res = parseUInt32(TempVal);
|
|
Val = static_cast<DINode::DIFlags>(TempVal);
|
|
return Res;
|
|
}
|
|
|
|
if (Lex.getKind() != lltok::DIFlag)
|
|
return tokError("expected debug info flag");
|
|
|
|
Val = DINode::getFlag(Lex.getStrVal());
|
|
if (!Val)
|
|
return tokError(Twine("invalid debug info flag flag '") +
|
|
Lex.getStrVal() + "'");
|
|
Lex.Lex();
|
|
return false;
|
|
};
|
|
|
|
// parse the flags and combine them together.
|
|
DINode::DIFlags Combined = DINode::FlagZero;
|
|
do {
|
|
DINode::DIFlags Val;
|
|
if (parseFlag(Val))
|
|
return true;
|
|
Combined |= Val;
|
|
} while (EatIfPresent(lltok::bar));
|
|
|
|
Result.assign(Combined);
|
|
return false;
|
|
}
|
|
|
|
/// DISPFlagField
|
|
/// ::= uint32
|
|
/// ::= DISPFlagVector
|
|
/// ::= DISPFlagVector '|' DISPFlag* '|' uint32
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, DISPFlagField &Result) {
|
|
|
|
// parser for a single flag.
|
|
auto parseFlag = [&](DISubprogram::DISPFlags &Val) {
|
|
if (Lex.getKind() == lltok::APSInt && !Lex.getAPSIntVal().isSigned()) {
|
|
uint32_t TempVal = static_cast<uint32_t>(Val);
|
|
bool Res = parseUInt32(TempVal);
|
|
Val = static_cast<DISubprogram::DISPFlags>(TempVal);
|
|
return Res;
|
|
}
|
|
|
|
if (Lex.getKind() != lltok::DISPFlag)
|
|
return tokError("expected debug info flag");
|
|
|
|
Val = DISubprogram::getFlag(Lex.getStrVal());
|
|
if (!Val)
|
|
return tokError(Twine("invalid subprogram debug info flag '") +
|
|
Lex.getStrVal() + "'");
|
|
Lex.Lex();
|
|
return false;
|
|
};
|
|
|
|
// parse the flags and combine them together.
|
|
DISubprogram::DISPFlags Combined = DISubprogram::SPFlagZero;
|
|
do {
|
|
DISubprogram::DISPFlags Val;
|
|
if (parseFlag(Val))
|
|
return true;
|
|
Combined |= Val;
|
|
} while (EatIfPresent(lltok::bar));
|
|
|
|
Result.assign(Combined);
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDSignedField &Result) {
|
|
if (Lex.getKind() != lltok::APSInt)
|
|
return tokError("expected signed integer");
|
|
|
|
auto &S = Lex.getAPSIntVal();
|
|
if (S < Result.Min)
|
|
return tokError("value for '" + Name + "' too small, limit is " +
|
|
Twine(Result.Min));
|
|
if (S > Result.Max)
|
|
return tokError("value for '" + Name + "' too large, limit is " +
|
|
Twine(Result.Max));
|
|
Result.assign(S.getExtValue());
|
|
assert(Result.Val >= Result.Min && "Expected value in range");
|
|
assert(Result.Val <= Result.Max && "Expected value in range");
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDBoolField &Result) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected 'true' or 'false'");
|
|
case lltok::kw_true:
|
|
Result.assign(true);
|
|
break;
|
|
case lltok::kw_false:
|
|
Result.assign(false);
|
|
break;
|
|
}
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDField &Result) {
|
|
if (Lex.getKind() == lltok::kw_null) {
|
|
if (!Result.AllowNull)
|
|
return tokError("'" + Name + "' cannot be null");
|
|
Lex.Lex();
|
|
Result.assign(nullptr);
|
|
return false;
|
|
}
|
|
|
|
Metadata *MD;
|
|
if (parseMetadata(MD, nullptr))
|
|
return true;
|
|
|
|
Result.assign(MD);
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
MDSignedOrMDField &Result) {
|
|
// Try to parse a signed int.
|
|
if (Lex.getKind() == lltok::APSInt) {
|
|
MDSignedField Res = Result.A;
|
|
if (!parseMDField(Loc, Name, Res)) {
|
|
Result.assign(Res);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Otherwise, try to parse as an MDField.
|
|
MDField Res = Result.B;
|
|
if (!parseMDField(Loc, Name, Res)) {
|
|
Result.assign(Res);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDStringField &Result) {
|
|
LocTy ValueLoc = Lex.getLoc();
|
|
std::string S;
|
|
if (parseStringConstant(S))
|
|
return true;
|
|
|
|
if (!Result.AllowEmpty && S.empty())
|
|
return error(ValueLoc, "'" + Name + "' cannot be empty");
|
|
|
|
Result.assign(S.empty() ? nullptr : MDString::get(Context, S));
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name, MDFieldList &Result) {
|
|
SmallVector<Metadata *, 4> MDs;
|
|
if (parseMDNodeVector(MDs))
|
|
return true;
|
|
|
|
Result.assign(std::move(MDs));
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool LLParser::parseMDField(LocTy Loc, StringRef Name,
|
|
ChecksumKindField &Result) {
|
|
Optional<DIFile::ChecksumKind> CSKind =
|
|
DIFile::getChecksumKind(Lex.getStrVal());
|
|
|
|
if (Lex.getKind() != lltok::ChecksumKind || !CSKind)
|
|
return tokError("invalid checksum kind" + Twine(" '") + Lex.getStrVal() +
|
|
"'");
|
|
|
|
Result.assign(*CSKind);
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
} // end namespace llvm
|
|
|
|
template <class ParserTy>
|
|
bool LLParser::parseMDFieldsImplBody(ParserTy ParseField) {
|
|
do {
|
|
if (Lex.getKind() != lltok::LabelStr)
|
|
return tokError("expected field label here");
|
|
|
|
if (ParseField())
|
|
return true;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
return false;
|
|
}
|
|
|
|
template <class ParserTy>
|
|
bool LLParser::parseMDFieldsImpl(ParserTy ParseField, LocTy &ClosingLoc) {
|
|
assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
if (Lex.getKind() != lltok::rparen)
|
|
if (parseMDFieldsImplBody(ParseField))
|
|
return true;
|
|
|
|
ClosingLoc = Lex.getLoc();
|
|
return parseToken(lltok::rparen, "expected ')' here");
|
|
}
|
|
|
|
template <class FieldTy>
|
|
bool LLParser::parseMDField(StringRef Name, FieldTy &Result) {
|
|
if (Result.Seen)
|
|
return tokError("field '" + Name + "' cannot be specified more than once");
|
|
|
|
LocTy Loc = Lex.getLoc();
|
|
Lex.Lex();
|
|
return parseMDField(Loc, Name, Result);
|
|
}
|
|
|
|
bool LLParser::parseSpecializedMDNode(MDNode *&N, bool IsDistinct) {
|
|
assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
|
|
|
|
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) \
|
|
if (Lex.getStrVal() == #CLASS) \
|
|
return parse##CLASS(N, IsDistinct);
|
|
#include "llvm/IR/Metadata.def"
|
|
|
|
return tokError("expected metadata type");
|
|
}
|
|
|
|
#define DECLARE_FIELD(NAME, TYPE, INIT) TYPE NAME INIT
|
|
#define NOP_FIELD(NAME, TYPE, INIT)
|
|
#define REQUIRE_FIELD(NAME, TYPE, INIT) \
|
|
if (!NAME.Seen) \
|
|
return error(ClosingLoc, "missing required field '" #NAME "'");
|
|
#define PARSE_MD_FIELD(NAME, TYPE, DEFAULT) \
|
|
if (Lex.getStrVal() == #NAME) \
|
|
return parseMDField(#NAME, NAME);
|
|
#define PARSE_MD_FIELDS() \
|
|
VISIT_MD_FIELDS(DECLARE_FIELD, DECLARE_FIELD) \
|
|
do { \
|
|
LocTy ClosingLoc; \
|
|
if (parseMDFieldsImpl( \
|
|
[&]() -> bool { \
|
|
VISIT_MD_FIELDS(PARSE_MD_FIELD, PARSE_MD_FIELD) \
|
|
return tokError(Twine("invalid field '") + Lex.getStrVal() + \
|
|
"'"); \
|
|
}, \
|
|
ClosingLoc)) \
|
|
return true; \
|
|
VISIT_MD_FIELDS(NOP_FIELD, REQUIRE_FIELD) \
|
|
} while (false)
|
|
#define GET_OR_DISTINCT(CLASS, ARGS) \
|
|
(IsDistinct ? CLASS::getDistinct ARGS : CLASS::get ARGS)
|
|
|
|
/// parseDILocationFields:
|
|
/// ::= !DILocation(line: 43, column: 8, scope: !5, inlinedAt: !6,
|
|
/// isImplicitCode: true)
|
|
bool LLParser::parseDILocation(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(column, ColumnField, ); \
|
|
REQUIRED(scope, MDField, (/* AllowNull */ false)); \
|
|
OPTIONAL(inlinedAt, MDField, ); \
|
|
OPTIONAL(isImplicitCode, MDBoolField, (false));
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result =
|
|
GET_OR_DISTINCT(DILocation, (Context, line.Val, column.Val, scope.Val,
|
|
inlinedAt.Val, isImplicitCode.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseGenericDINode:
|
|
/// ::= !GenericDINode(tag: 15, header: "...", operands: {...})
|
|
bool LLParser::parseGenericDINode(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(tag, DwarfTagField, ); \
|
|
OPTIONAL(header, MDStringField, ); \
|
|
OPTIONAL(operands, MDFieldList, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(GenericDINode,
|
|
(Context, tag.Val, header.Val, operands.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDISubrange:
|
|
/// ::= !DISubrange(count: 30, lowerBound: 2)
|
|
/// ::= !DISubrange(count: !node, lowerBound: 2)
|
|
/// ::= !DISubrange(lowerBound: !node1, upperBound: !node2, stride: !node3)
|
|
bool LLParser::parseDISubrange(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(count, MDSignedOrMDField, (-1, -1, INT64_MAX, false)); \
|
|
OPTIONAL(lowerBound, MDSignedOrMDField, ); \
|
|
OPTIONAL(upperBound, MDSignedOrMDField, ); \
|
|
OPTIONAL(stride, MDSignedOrMDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Metadata *Count = nullptr;
|
|
Metadata *LowerBound = nullptr;
|
|
Metadata *UpperBound = nullptr;
|
|
Metadata *Stride = nullptr;
|
|
if (count.isMDSignedField())
|
|
Count = ConstantAsMetadata::get(ConstantInt::getSigned(
|
|
Type::getInt64Ty(Context), count.getMDSignedValue()));
|
|
else if (count.isMDField())
|
|
Count = count.getMDFieldValue();
|
|
|
|
auto convToMetadata = [&](MDSignedOrMDField Bound) -> Metadata * {
|
|
if (Bound.isMDSignedField())
|
|
return ConstantAsMetadata::get(ConstantInt::getSigned(
|
|
Type::getInt64Ty(Context), Bound.getMDSignedValue()));
|
|
if (Bound.isMDField())
|
|
return Bound.getMDFieldValue();
|
|
return nullptr;
|
|
};
|
|
|
|
LowerBound = convToMetadata(lowerBound);
|
|
UpperBound = convToMetadata(upperBound);
|
|
Stride = convToMetadata(stride);
|
|
|
|
Result = GET_OR_DISTINCT(DISubrange,
|
|
(Context, Count, LowerBound, UpperBound, Stride));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseDIGenericSubrange:
|
|
/// ::= !DIGenericSubrange(lowerBound: !node1, upperBound: !node2, stride:
|
|
/// !node3)
|
|
bool LLParser::parseDIGenericSubrange(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(count, MDSignedOrMDField, ); \
|
|
OPTIONAL(lowerBound, MDSignedOrMDField, ); \
|
|
OPTIONAL(upperBound, MDSignedOrMDField, ); \
|
|
OPTIONAL(stride, MDSignedOrMDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
auto ConvToMetadata = [&](MDSignedOrMDField Bound) -> Metadata * {
|
|
if (Bound.isMDSignedField())
|
|
return DIExpression::get(
|
|
Context, {dwarf::DW_OP_consts,
|
|
static_cast<uint64_t>(Bound.getMDSignedValue())});
|
|
if (Bound.isMDField())
|
|
return Bound.getMDFieldValue();
|
|
return nullptr;
|
|
};
|
|
|
|
Metadata *Count = ConvToMetadata(count);
|
|
Metadata *LowerBound = ConvToMetadata(lowerBound);
|
|
Metadata *UpperBound = ConvToMetadata(upperBound);
|
|
Metadata *Stride = ConvToMetadata(stride);
|
|
|
|
Result = GET_OR_DISTINCT(DIGenericSubrange,
|
|
(Context, Count, LowerBound, UpperBound, Stride));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseDIEnumerator:
|
|
/// ::= !DIEnumerator(value: 30, isUnsigned: true, name: "SomeKind")
|
|
bool LLParser::parseDIEnumerator(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(name, MDStringField, ); \
|
|
REQUIRED(value, MDAPSIntField, ); \
|
|
OPTIONAL(isUnsigned, MDBoolField, (false));
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
if (isUnsigned.Val && value.Val.isNegative())
|
|
return tokError("unsigned enumerator with negative value");
|
|
|
|
APSInt Value(value.Val);
|
|
// Add a leading zero so that unsigned values with the msb set are not
|
|
// mistaken for negative values when used for signed enumerators.
|
|
if (!isUnsigned.Val && value.Val.isUnsigned() && value.Val.isSignBitSet())
|
|
Value = Value.zext(Value.getBitWidth() + 1);
|
|
|
|
Result =
|
|
GET_OR_DISTINCT(DIEnumerator, (Context, Value, isUnsigned.Val, name.Val));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseDIBasicType:
|
|
/// ::= !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32,
|
|
/// encoding: DW_ATE_encoding, flags: 0)
|
|
bool LLParser::parseDIBasicType(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_base_type)); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \
|
|
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(encoding, DwarfAttEncodingField, ); \
|
|
OPTIONAL(flags, DIFlagField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DIBasicType, (Context, tag.Val, name.Val, size.Val,
|
|
align.Val, encoding.Val, flags.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIStringType:
|
|
/// ::= !DIStringType(name: "character(4)", size: 32, align: 32)
|
|
bool LLParser::parseDIStringType(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_string_type)); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(stringLength, MDField, ); \
|
|
OPTIONAL(stringLengthExpression, MDField, ); \
|
|
OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \
|
|
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(encoding, DwarfAttEncodingField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DIStringType,
|
|
(Context, tag.Val, name.Val, stringLength.Val,
|
|
stringLengthExpression.Val, size.Val, align.Val,
|
|
encoding.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIDerivedType:
|
|
/// ::= !DIDerivedType(tag: DW_TAG_pointer_type, name: "int", file: !0,
|
|
/// line: 7, scope: !1, baseType: !2, size: 32,
|
|
/// align: 32, offset: 0, flags: 0, extraData: !3,
|
|
/// dwarfAddressSpace: 3)
|
|
bool LLParser::parseDIDerivedType(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(tag, DwarfTagField, ); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(scope, MDField, ); \
|
|
REQUIRED(baseType, MDField, ); \
|
|
OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \
|
|
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(offset, MDUnsignedField, (0, UINT64_MAX)); \
|
|
OPTIONAL(flags, DIFlagField, ); \
|
|
OPTIONAL(extraData, MDField, ); \
|
|
OPTIONAL(dwarfAddressSpace, MDUnsignedField, (UINT32_MAX, UINT32_MAX));
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Optional<unsigned> DWARFAddressSpace;
|
|
if (dwarfAddressSpace.Val != UINT32_MAX)
|
|
DWARFAddressSpace = dwarfAddressSpace.Val;
|
|
|
|
Result = GET_OR_DISTINCT(DIDerivedType,
|
|
(Context, tag.Val, name.Val, file.Val, line.Val,
|
|
scope.Val, baseType.Val, size.Val, align.Val,
|
|
offset.Val, DWARFAddressSpace, flags.Val,
|
|
extraData.Val));
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseDICompositeType(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(tag, DwarfTagField, ); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(scope, MDField, ); \
|
|
OPTIONAL(baseType, MDField, ); \
|
|
OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \
|
|
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(offset, MDUnsignedField, (0, UINT64_MAX)); \
|
|
OPTIONAL(flags, DIFlagField, ); \
|
|
OPTIONAL(elements, MDField, ); \
|
|
OPTIONAL(runtimeLang, DwarfLangField, ); \
|
|
OPTIONAL(vtableHolder, MDField, ); \
|
|
OPTIONAL(templateParams, MDField, ); \
|
|
OPTIONAL(identifier, MDStringField, ); \
|
|
OPTIONAL(discriminator, MDField, ); \
|
|
OPTIONAL(dataLocation, MDField, ); \
|
|
OPTIONAL(associated, MDField, ); \
|
|
OPTIONAL(allocated, MDField, ); \
|
|
OPTIONAL(rank, MDSignedOrMDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Metadata *Rank = nullptr;
|
|
if (rank.isMDSignedField())
|
|
Rank = ConstantAsMetadata::get(ConstantInt::getSigned(
|
|
Type::getInt64Ty(Context), rank.getMDSignedValue()));
|
|
else if (rank.isMDField())
|
|
Rank = rank.getMDFieldValue();
|
|
|
|
// If this has an identifier try to build an ODR type.
|
|
if (identifier.Val)
|
|
if (auto *CT = DICompositeType::buildODRType(
|
|
Context, *identifier.Val, tag.Val, name.Val, file.Val, line.Val,
|
|
scope.Val, baseType.Val, size.Val, align.Val, offset.Val, flags.Val,
|
|
elements.Val, runtimeLang.Val, vtableHolder.Val, templateParams.Val,
|
|
discriminator.Val, dataLocation.Val, associated.Val, allocated.Val,
|
|
Rank)) {
|
|
Result = CT;
|
|
return false;
|
|
}
|
|
|
|
// Create a new node, and save it in the context if it belongs in the type
|
|
// map.
|
|
Result = GET_OR_DISTINCT(
|
|
DICompositeType,
|
|
(Context, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val,
|
|
size.Val, align.Val, offset.Val, flags.Val, elements.Val,
|
|
runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val,
|
|
discriminator.Val, dataLocation.Val, associated.Val, allocated.Val,
|
|
Rank));
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseDISubroutineType(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(flags, DIFlagField, ); \
|
|
OPTIONAL(cc, DwarfCCField, ); \
|
|
REQUIRED(types, MDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DISubroutineType,
|
|
(Context, flags.Val, cc.Val, types.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIFileType:
|
|
/// ::= !DIFileType(filename: "path/to/file", directory: "/path/to/dir",
|
|
/// checksumkind: CSK_MD5,
|
|
/// checksum: "000102030405060708090a0b0c0d0e0f",
|
|
/// source: "source file contents")
|
|
bool LLParser::parseDIFile(MDNode *&Result, bool IsDistinct) {
|
|
// The default constructed value for checksumkind is required, but will never
|
|
// be used, as the parser checks if the field was actually Seen before using
|
|
// the Val.
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(filename, MDStringField, ); \
|
|
REQUIRED(directory, MDStringField, ); \
|
|
OPTIONAL(checksumkind, ChecksumKindField, (DIFile::CSK_MD5)); \
|
|
OPTIONAL(checksum, MDStringField, ); \
|
|
OPTIONAL(source, MDStringField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Optional<DIFile::ChecksumInfo<MDString *>> OptChecksum;
|
|
if (checksumkind.Seen && checksum.Seen)
|
|
OptChecksum.emplace(checksumkind.Val, checksum.Val);
|
|
else if (checksumkind.Seen || checksum.Seen)
|
|
return Lex.Error("'checksumkind' and 'checksum' must be provided together");
|
|
|
|
Optional<MDString *> OptSource;
|
|
if (source.Seen)
|
|
OptSource = source.Val;
|
|
Result = GET_OR_DISTINCT(DIFile, (Context, filename.Val, directory.Val,
|
|
OptChecksum, OptSource));
|
|
return false;
|
|
}
|
|
|
|
/// parseDICompileUnit:
|
|
/// ::= !DICompileUnit(language: DW_LANG_C99, file: !0, producer: "clang",
|
|
/// isOptimized: true, flags: "-O2", runtimeVersion: 1,
|
|
/// splitDebugFilename: "abc.debug",
|
|
/// emissionKind: FullDebug, enums: !1, retainedTypes: !2,
|
|
/// globals: !4, imports: !5, macros: !6, dwoId: 0x0abcd,
|
|
/// sysroot: "/", sdk: "MacOSX.sdk")
|
|
bool LLParser::parseDICompileUnit(MDNode *&Result, bool IsDistinct) {
|
|
if (!IsDistinct)
|
|
return Lex.Error("missing 'distinct', required for !DICompileUnit");
|
|
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(language, DwarfLangField, ); \
|
|
REQUIRED(file, MDField, (/* AllowNull */ false)); \
|
|
OPTIONAL(producer, MDStringField, ); \
|
|
OPTIONAL(isOptimized, MDBoolField, ); \
|
|
OPTIONAL(flags, MDStringField, ); \
|
|
OPTIONAL(runtimeVersion, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(splitDebugFilename, MDStringField, ); \
|
|
OPTIONAL(emissionKind, EmissionKindField, ); \
|
|
OPTIONAL(enums, MDField, ); \
|
|
OPTIONAL(retainedTypes, MDField, ); \
|
|
OPTIONAL(globals, MDField, ); \
|
|
OPTIONAL(imports, MDField, ); \
|
|
OPTIONAL(macros, MDField, ); \
|
|
OPTIONAL(dwoId, MDUnsignedField, ); \
|
|
OPTIONAL(splitDebugInlining, MDBoolField, = true); \
|
|
OPTIONAL(debugInfoForProfiling, MDBoolField, = false); \
|
|
OPTIONAL(nameTableKind, NameTableKindField, ); \
|
|
OPTIONAL(rangesBaseAddress, MDBoolField, = false); \
|
|
OPTIONAL(sysroot, MDStringField, ); \
|
|
OPTIONAL(sdk, MDStringField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = DICompileUnit::getDistinct(
|
|
Context, language.Val, file.Val, producer.Val, isOptimized.Val, flags.Val,
|
|
runtimeVersion.Val, splitDebugFilename.Val, emissionKind.Val, enums.Val,
|
|
retainedTypes.Val, globals.Val, imports.Val, macros.Val, dwoId.Val,
|
|
splitDebugInlining.Val, debugInfoForProfiling.Val, nameTableKind.Val,
|
|
rangesBaseAddress.Val, sysroot.Val, sdk.Val);
|
|
return false;
|
|
}
|
|
|
|
/// parseDISubprogram:
|
|
/// ::= !DISubprogram(scope: !0, name: "foo", linkageName: "_Zfoo",
|
|
/// file: !1, line: 7, type: !2, isLocal: false,
|
|
/// isDefinition: true, scopeLine: 8, containingType: !3,
|
|
/// virtuality: DW_VIRTUALTIY_pure_virtual,
|
|
/// virtualIndex: 10, thisAdjustment: 4, flags: 11,
|
|
/// spFlags: 10, isOptimized: false, templateParams: !4,
|
|
/// declaration: !5, retainedNodes: !6, thrownTypes: !7)
|
|
bool LLParser::parseDISubprogram(MDNode *&Result, bool IsDistinct) {
|
|
auto Loc = Lex.getLoc();
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(scope, MDField, ); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(linkageName, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(type, MDField, ); \
|
|
OPTIONAL(isLocal, MDBoolField, ); \
|
|
OPTIONAL(isDefinition, MDBoolField, (true)); \
|
|
OPTIONAL(scopeLine, LineField, ); \
|
|
OPTIONAL(containingType, MDField, ); \
|
|
OPTIONAL(virtuality, DwarfVirtualityField, ); \
|
|
OPTIONAL(virtualIndex, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(thisAdjustment, MDSignedField, (0, INT32_MIN, INT32_MAX)); \
|
|
OPTIONAL(flags, DIFlagField, ); \
|
|
OPTIONAL(spFlags, DISPFlagField, ); \
|
|
OPTIONAL(isOptimized, MDBoolField, ); \
|
|
OPTIONAL(unit, MDField, ); \
|
|
OPTIONAL(templateParams, MDField, ); \
|
|
OPTIONAL(declaration, MDField, ); \
|
|
OPTIONAL(retainedNodes, MDField, ); \
|
|
OPTIONAL(thrownTypes, MDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
// An explicit spFlags field takes precedence over individual fields in
|
|
// older IR versions.
|
|
DISubprogram::DISPFlags SPFlags =
|
|
spFlags.Seen ? spFlags.Val
|
|
: DISubprogram::toSPFlags(isLocal.Val, isDefinition.Val,
|
|
isOptimized.Val, virtuality.Val);
|
|
if ((SPFlags & DISubprogram::SPFlagDefinition) && !IsDistinct)
|
|
return Lex.Error(
|
|
Loc,
|
|
"missing 'distinct', required for !DISubprogram that is a Definition");
|
|
Result = GET_OR_DISTINCT(
|
|
DISubprogram,
|
|
(Context, scope.Val, name.Val, linkageName.Val, file.Val, line.Val,
|
|
type.Val, scopeLine.Val, containingType.Val, virtualIndex.Val,
|
|
thisAdjustment.Val, flags.Val, SPFlags, unit.Val, templateParams.Val,
|
|
declaration.Val, retainedNodes.Val, thrownTypes.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDILexicalBlock:
|
|
/// ::= !DILexicalBlock(scope: !0, file: !2, line: 7, column: 9)
|
|
bool LLParser::parseDILexicalBlock(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, (/* AllowNull */ false)); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(column, ColumnField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(
|
|
DILexicalBlock, (Context, scope.Val, file.Val, line.Val, column.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDILexicalBlockFile:
|
|
/// ::= !DILexicalBlockFile(scope: !0, file: !2, discriminator: 9)
|
|
bool LLParser::parseDILexicalBlockFile(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, (/* AllowNull */ false)); \
|
|
OPTIONAL(file, MDField, ); \
|
|
REQUIRED(discriminator, MDUnsignedField, (0, UINT32_MAX));
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DILexicalBlockFile,
|
|
(Context, scope.Val, file.Val, discriminator.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDICommonBlock:
|
|
/// ::= !DICommonBlock(scope: !0, file: !2, name: "COMMON name", line: 9)
|
|
bool LLParser::parseDICommonBlock(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, ); \
|
|
OPTIONAL(declaration, MDField, ); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DICommonBlock,
|
|
(Context, scope.Val, declaration.Val, name.Val,
|
|
file.Val, line.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDINamespace:
|
|
/// ::= !DINamespace(scope: !0, file: !2, name: "SomeNamespace", line: 9)
|
|
bool LLParser::parseDINamespace(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, ); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(exportSymbols, MDBoolField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DINamespace,
|
|
(Context, scope.Val, name.Val, exportSymbols.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIMacro:
|
|
/// ::= !DIMacro(macinfo: type, line: 9, name: "SomeMacro", value:
|
|
/// "SomeValue")
|
|
bool LLParser::parseDIMacro(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(type, DwarfMacinfoTypeField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
REQUIRED(name, MDStringField, ); \
|
|
OPTIONAL(value, MDStringField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DIMacro,
|
|
(Context, type.Val, line.Val, name.Val, value.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIMacroFile:
|
|
/// ::= !DIMacroFile(line: 9, file: !2, nodes: !3)
|
|
bool LLParser::parseDIMacroFile(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(type, DwarfMacinfoTypeField, (dwarf::DW_MACINFO_start_file)); \
|
|
OPTIONAL(line, LineField, ); \
|
|
REQUIRED(file, MDField, ); \
|
|
OPTIONAL(nodes, MDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DIMacroFile,
|
|
(Context, type.Val, line.Val, file.Val, nodes.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIModule:
|
|
/// ::= !DIModule(scope: !0, name: "SomeModule", configMacros:
|
|
/// "-DNDEBUG", includePath: "/usr/include", apinotes: "module.apinotes",
|
|
/// file: !1, line: 4)
|
|
bool LLParser::parseDIModule(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, ); \
|
|
REQUIRED(name, MDStringField, ); \
|
|
OPTIONAL(configMacros, MDStringField, ); \
|
|
OPTIONAL(includePath, MDStringField, ); \
|
|
OPTIONAL(apinotes, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DIModule, (Context, file.Val, scope.Val, name.Val,
|
|
configMacros.Val, includePath.Val,
|
|
apinotes.Val, line.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDITemplateTypeParameter:
|
|
/// ::= !DITemplateTypeParameter(name: "Ty", type: !1, defaulted: false)
|
|
bool LLParser::parseDITemplateTypeParameter(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
REQUIRED(type, MDField, ); \
|
|
OPTIONAL(defaulted, MDBoolField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DITemplateTypeParameter,
|
|
(Context, name.Val, type.Val, defaulted.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDITemplateValueParameter:
|
|
/// ::= !DITemplateValueParameter(tag: DW_TAG_template_value_parameter,
|
|
/// name: "V", type: !1, defaulted: false,
|
|
/// value: i32 7)
|
|
bool LLParser::parseDITemplateValueParameter(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_template_value_parameter)); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(type, MDField, ); \
|
|
OPTIONAL(defaulted, MDBoolField, ); \
|
|
REQUIRED(value, MDField, );
|
|
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(
|
|
DITemplateValueParameter,
|
|
(Context, tag.Val, name.Val, type.Val, defaulted.Val, value.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIGlobalVariable:
|
|
/// ::= !DIGlobalVariable(scope: !0, name: "foo", linkageName: "foo",
|
|
/// file: !1, line: 7, type: !2, isLocal: false,
|
|
/// isDefinition: true, templateParams: !3,
|
|
/// declaration: !4, align: 8)
|
|
bool LLParser::parseDIGlobalVariable(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(name, MDStringField, (/* AllowEmpty */ false)); \
|
|
OPTIONAL(scope, MDField, ); \
|
|
OPTIONAL(linkageName, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(type, MDField, ); \
|
|
OPTIONAL(isLocal, MDBoolField, ); \
|
|
OPTIONAL(isDefinition, MDBoolField, (true)); \
|
|
OPTIONAL(templateParams, MDField, ); \
|
|
OPTIONAL(declaration, MDField, ); \
|
|
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result =
|
|
GET_OR_DISTINCT(DIGlobalVariable,
|
|
(Context, scope.Val, name.Val, linkageName.Val, file.Val,
|
|
line.Val, type.Val, isLocal.Val, isDefinition.Val,
|
|
declaration.Val, templateParams.Val, align.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDILocalVariable:
|
|
/// ::= !DILocalVariable(arg: 7, scope: !0, name: "foo",
|
|
/// file: !1, line: 7, type: !2, arg: 2, flags: 7,
|
|
/// align: 8)
|
|
/// ::= !DILocalVariable(scope: !0, name: "foo",
|
|
/// file: !1, line: 7, type: !2, arg: 2, flags: 7,
|
|
/// align: 8)
|
|
bool LLParser::parseDILocalVariable(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, (/* AllowNull */ false)); \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(arg, MDUnsignedField, (0, UINT16_MAX)); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(type, MDField, ); \
|
|
OPTIONAL(flags, DIFlagField, ); \
|
|
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DILocalVariable,
|
|
(Context, scope.Val, name.Val, file.Val, line.Val,
|
|
type.Val, arg.Val, flags.Val, align.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDILabel:
|
|
/// ::= !DILabel(scope: !0, name: "foo", file: !1, line: 7)
|
|
bool LLParser::parseDILabel(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(scope, MDField, (/* AllowNull */ false)); \
|
|
REQUIRED(name, MDStringField, ); \
|
|
REQUIRED(file, MDField, ); \
|
|
REQUIRED(line, LineField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DILabel,
|
|
(Context, scope.Val, name.Val, file.Val, line.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIExpression:
|
|
/// ::= !DIExpression(0, 7, -1)
|
|
bool LLParser::parseDIExpression(MDNode *&Result, bool IsDistinct) {
|
|
assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
SmallVector<uint64_t, 8> Elements;
|
|
if (Lex.getKind() != lltok::rparen)
|
|
do {
|
|
if (Lex.getKind() == lltok::DwarfOp) {
|
|
if (unsigned Op = dwarf::getOperationEncoding(Lex.getStrVal())) {
|
|
Lex.Lex();
|
|
Elements.push_back(Op);
|
|
continue;
|
|
}
|
|
return tokError(Twine("invalid DWARF op '") + Lex.getStrVal() + "'");
|
|
}
|
|
|
|
if (Lex.getKind() == lltok::DwarfAttEncoding) {
|
|
if (unsigned Op = dwarf::getAttributeEncoding(Lex.getStrVal())) {
|
|
Lex.Lex();
|
|
Elements.push_back(Op);
|
|
continue;
|
|
}
|
|
return tokError(Twine("invalid DWARF attribute encoding '") +
|
|
Lex.getStrVal() + "'");
|
|
}
|
|
|
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
|
|
return tokError("expected unsigned integer");
|
|
|
|
auto &U = Lex.getAPSIntVal();
|
|
if (U.ugt(UINT64_MAX))
|
|
return tokError("element too large, limit is " + Twine(UINT64_MAX));
|
|
Elements.push_back(U.getZExtValue());
|
|
Lex.Lex();
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
Result = GET_OR_DISTINCT(DIExpression, (Context, Elements));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIGlobalVariableExpression:
|
|
/// ::= !DIGlobalVariableExpression(var: !0, expr: !1)
|
|
bool LLParser::parseDIGlobalVariableExpression(MDNode *&Result,
|
|
bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(var, MDField, ); \
|
|
REQUIRED(expr, MDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result =
|
|
GET_OR_DISTINCT(DIGlobalVariableExpression, (Context, var.Val, expr.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIObjCProperty:
|
|
/// ::= !DIObjCProperty(name: "foo", file: !1, line: 7, setter: "setFoo",
|
|
/// getter: "getFoo", attributes: 7, type: !2)
|
|
bool LLParser::parseDIObjCProperty(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
OPTIONAL(name, MDStringField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(setter, MDStringField, ); \
|
|
OPTIONAL(getter, MDStringField, ); \
|
|
OPTIONAL(attributes, MDUnsignedField, (0, UINT32_MAX)); \
|
|
OPTIONAL(type, MDField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(DIObjCProperty,
|
|
(Context, name.Val, file.Val, line.Val, setter.Val,
|
|
getter.Val, attributes.Val, type.Val));
|
|
return false;
|
|
}
|
|
|
|
/// parseDIImportedEntity:
|
|
/// ::= !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0, entity: !1,
|
|
/// line: 7, name: "foo")
|
|
bool LLParser::parseDIImportedEntity(MDNode *&Result, bool IsDistinct) {
|
|
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
|
REQUIRED(tag, DwarfTagField, ); \
|
|
REQUIRED(scope, MDField, ); \
|
|
OPTIONAL(entity, MDField, ); \
|
|
OPTIONAL(file, MDField, ); \
|
|
OPTIONAL(line, LineField, ); \
|
|
OPTIONAL(name, MDStringField, );
|
|
PARSE_MD_FIELDS();
|
|
#undef VISIT_MD_FIELDS
|
|
|
|
Result = GET_OR_DISTINCT(
|
|
DIImportedEntity,
|
|
(Context, tag.Val, scope.Val, entity.Val, file.Val, line.Val, name.Val));
|
|
return false;
|
|
}
|
|
|
|
#undef PARSE_MD_FIELD
|
|
#undef NOP_FIELD
|
|
#undef REQUIRE_FIELD
|
|
#undef DECLARE_FIELD
|
|
|
|
/// parseMetadataAsValue
|
|
/// ::= metadata i32 %local
|
|
/// ::= metadata i32 @global
|
|
/// ::= metadata i32 7
|
|
/// ::= metadata !0
|
|
/// ::= metadata !{...}
|
|
/// ::= metadata !"string"
|
|
bool LLParser::parseMetadataAsValue(Value *&V, PerFunctionState &PFS) {
|
|
// Note: the type 'metadata' has already been parsed.
|
|
Metadata *MD;
|
|
if (parseMetadata(MD, &PFS))
|
|
return true;
|
|
|
|
V = MetadataAsValue::get(Context, MD);
|
|
return false;
|
|
}
|
|
|
|
/// parseValueAsMetadata
|
|
/// ::= i32 %local
|
|
/// ::= i32 @global
|
|
/// ::= i32 7
|
|
bool LLParser::parseValueAsMetadata(Metadata *&MD, const Twine &TypeMsg,
|
|
PerFunctionState *PFS) {
|
|
Type *Ty;
|
|
LocTy Loc;
|
|
if (parseType(Ty, TypeMsg, Loc))
|
|
return true;
|
|
if (Ty->isMetadataTy())
|
|
return error(Loc, "invalid metadata-value-metadata roundtrip");
|
|
|
|
Value *V;
|
|
if (parseValue(Ty, V, PFS))
|
|
return true;
|
|
|
|
MD = ValueAsMetadata::get(V);
|
|
return false;
|
|
}
|
|
|
|
/// parseMetadata
|
|
/// ::= i32 %local
|
|
/// ::= i32 @global
|
|
/// ::= i32 7
|
|
/// ::= !42
|
|
/// ::= !{...}
|
|
/// ::= !"string"
|
|
/// ::= !DILocation(...)
|
|
bool LLParser::parseMetadata(Metadata *&MD, PerFunctionState *PFS) {
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
MDNode *N;
|
|
if (parseSpecializedMDNode(N))
|
|
return true;
|
|
MD = N;
|
|
return false;
|
|
}
|
|
|
|
// ValueAsMetadata:
|
|
// <type> <value>
|
|
if (Lex.getKind() != lltok::exclaim)
|
|
return parseValueAsMetadata(MD, "expected metadata operand", PFS);
|
|
|
|
// '!'.
|
|
assert(Lex.getKind() == lltok::exclaim && "Expected '!' here");
|
|
Lex.Lex();
|
|
|
|
// MDString:
|
|
// ::= '!' STRINGCONSTANT
|
|
if (Lex.getKind() == lltok::StringConstant) {
|
|
MDString *S;
|
|
if (parseMDString(S))
|
|
return true;
|
|
MD = S;
|
|
return false;
|
|
}
|
|
|
|
// MDNode:
|
|
// !{ ... }
|
|
// !7
|
|
MDNode *N;
|
|
if (parseMDNodeTail(N))
|
|
return true;
|
|
MD = N;
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Function Parsing.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
|
|
PerFunctionState *PFS, bool IsCall) {
|
|
if (Ty->isFunctionTy())
|
|
return error(ID.Loc, "functions are not values, refer to them as pointers");
|
|
|
|
switch (ID.Kind) {
|
|
case ValID::t_LocalID:
|
|
if (!PFS)
|
|
return error(ID.Loc, "invalid use of function-local name");
|
|
V = PFS->getVal(ID.UIntVal, Ty, ID.Loc, IsCall);
|
|
return V == nullptr;
|
|
case ValID::t_LocalName:
|
|
if (!PFS)
|
|
return error(ID.Loc, "invalid use of function-local name");
|
|
V = PFS->getVal(ID.StrVal, Ty, ID.Loc, IsCall);
|
|
return V == nullptr;
|
|
case ValID::t_InlineAsm: {
|
|
if (!ID.FTy || !InlineAsm::Verify(ID.FTy, ID.StrVal2))
|
|
return error(ID.Loc, "invalid type for inline asm constraint string");
|
|
V = InlineAsm::get(ID.FTy, ID.StrVal, ID.StrVal2, ID.UIntVal & 1,
|
|
(ID.UIntVal >> 1) & 1,
|
|
(InlineAsm::AsmDialect(ID.UIntVal >> 2)));
|
|
return false;
|
|
}
|
|
case ValID::t_GlobalName:
|
|
V = getGlobalVal(ID.StrVal, Ty, ID.Loc, IsCall);
|
|
return V == nullptr;
|
|
case ValID::t_GlobalID:
|
|
V = getGlobalVal(ID.UIntVal, Ty, ID.Loc, IsCall);
|
|
return V == nullptr;
|
|
case ValID::t_APSInt:
|
|
if (!Ty->isIntegerTy())
|
|
return error(ID.Loc, "integer constant must have integer type");
|
|
ID.APSIntVal = ID.APSIntVal.extOrTrunc(Ty->getPrimitiveSizeInBits());
|
|
V = ConstantInt::get(Context, ID.APSIntVal);
|
|
return false;
|
|
case ValID::t_APFloat:
|
|
if (!Ty->isFloatingPointTy() ||
|
|
!ConstantFP::isValueValidForType(Ty, ID.APFloatVal))
|
|
return error(ID.Loc, "floating point constant invalid for type");
|
|
|
|
// The lexer has no type info, so builds all half, bfloat, float, and double
|
|
// FP constants as double. Fix this here. Long double does not need this.
|
|
if (&ID.APFloatVal.getSemantics() == &APFloat::IEEEdouble()) {
|
|
// Check for signaling before potentially converting and losing that info.
|
|
bool IsSNAN = ID.APFloatVal.isSignaling();
|
|
bool Ignored;
|
|
if (Ty->isHalfTy())
|
|
ID.APFloatVal.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven,
|
|
&Ignored);
|
|
else if (Ty->isBFloatTy())
|
|
ID.APFloatVal.convert(APFloat::BFloat(), APFloat::rmNearestTiesToEven,
|
|
&Ignored);
|
|
else if (Ty->isFloatTy())
|
|
ID.APFloatVal.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,
|
|
&Ignored);
|
|
if (IsSNAN) {
|
|
// The convert call above may quiet an SNaN, so manufacture another
|
|
// SNaN. The bitcast works because the payload (significand) parameter
|
|
// is truncated to fit.
|
|
APInt Payload = ID.APFloatVal.bitcastToAPInt();
|
|
ID.APFloatVal = APFloat::getSNaN(ID.APFloatVal.getSemantics(),
|
|
ID.APFloatVal.isNegative(), &Payload);
|
|
}
|
|
}
|
|
V = ConstantFP::get(Context, ID.APFloatVal);
|
|
|
|
if (V->getType() != Ty)
|
|
return error(ID.Loc, "floating point constant does not have type '" +
|
|
getTypeString(Ty) + "'");
|
|
|
|
return false;
|
|
case ValID::t_Null:
|
|
if (!Ty->isPointerTy())
|
|
return error(ID.Loc, "null must be a pointer type");
|
|
V = ConstantPointerNull::get(cast<PointerType>(Ty));
|
|
return false;
|
|
case ValID::t_Undef:
|
|
// FIXME: LabelTy should not be a first-class type.
|
|
if (!Ty->isFirstClassType() || Ty->isLabelTy())
|
|
return error(ID.Loc, "invalid type for undef constant");
|
|
V = UndefValue::get(Ty);
|
|
return false;
|
|
case ValID::t_EmptyArray:
|
|
if (!Ty->isArrayTy() || cast<ArrayType>(Ty)->getNumElements() != 0)
|
|
return error(ID.Loc, "invalid empty array initializer");
|
|
V = UndefValue::get(Ty);
|
|
return false;
|
|
case ValID::t_Zero:
|
|
// FIXME: LabelTy should not be a first-class type.
|
|
if (!Ty->isFirstClassType() || Ty->isLabelTy())
|
|
return error(ID.Loc, "invalid type for null constant");
|
|
V = Constant::getNullValue(Ty);
|
|
return false;
|
|
case ValID::t_None:
|
|
if (!Ty->isTokenTy())
|
|
return error(ID.Loc, "invalid type for none constant");
|
|
V = Constant::getNullValue(Ty);
|
|
return false;
|
|
case ValID::t_Constant:
|
|
if (ID.ConstantVal->getType() != Ty)
|
|
return error(ID.Loc, "constant expression type mismatch");
|
|
|
|
V = ID.ConstantVal;
|
|
return false;
|
|
case ValID::t_ConstantStruct:
|
|
case ValID::t_PackedConstantStruct:
|
|
if (StructType *ST = dyn_cast<StructType>(Ty)) {
|
|
if (ST->getNumElements() != ID.UIntVal)
|
|
return error(ID.Loc,
|
|
"initializer with struct type has wrong # elements");
|
|
if (ST->isPacked() != (ID.Kind == ValID::t_PackedConstantStruct))
|
|
return error(ID.Loc, "packed'ness of initializer and type don't match");
|
|
|
|
// Verify that the elements are compatible with the structtype.
|
|
for (unsigned i = 0, e = ID.UIntVal; i != e; ++i)
|
|
if (ID.ConstantStructElts[i]->getType() != ST->getElementType(i))
|
|
return error(
|
|
ID.Loc,
|
|
"element " + Twine(i) +
|
|
" of struct initializer doesn't match struct element type");
|
|
|
|
V = ConstantStruct::get(
|
|
ST, makeArrayRef(ID.ConstantStructElts.get(), ID.UIntVal));
|
|
} else
|
|
return error(ID.Loc, "constant expression type mismatch");
|
|
return false;
|
|
}
|
|
llvm_unreachable("Invalid ValID");
|
|
}
|
|
|
|
bool LLParser::parseConstantValue(Type *Ty, Constant *&C) {
|
|
C = nullptr;
|
|
ValID ID;
|
|
auto Loc = Lex.getLoc();
|
|
if (parseValID(ID, /*PFS=*/nullptr))
|
|
return true;
|
|
switch (ID.Kind) {
|
|
case ValID::t_APSInt:
|
|
case ValID::t_APFloat:
|
|
case ValID::t_Undef:
|
|
case ValID::t_Constant:
|
|
case ValID::t_ConstantStruct:
|
|
case ValID::t_PackedConstantStruct: {
|
|
Value *V;
|
|
if (convertValIDToValue(Ty, ID, V, /*PFS=*/nullptr, /*IsCall=*/false))
|
|
return true;
|
|
assert(isa<Constant>(V) && "Expected a constant value");
|
|
C = cast<Constant>(V);
|
|
return false;
|
|
}
|
|
case ValID::t_Null:
|
|
C = Constant::getNullValue(Ty);
|
|
return false;
|
|
default:
|
|
return error(Loc, "expected a constant value");
|
|
}
|
|
}
|
|
|
|
bool LLParser::parseValue(Type *Ty, Value *&V, PerFunctionState *PFS) {
|
|
V = nullptr;
|
|
ValID ID;
|
|
return parseValID(ID, PFS) ||
|
|
convertValIDToValue(Ty, ID, V, PFS, /*IsCall=*/false);
|
|
}
|
|
|
|
bool LLParser::parseTypeAndValue(Value *&V, PerFunctionState *PFS) {
|
|
Type *Ty = nullptr;
|
|
return parseType(Ty) || parseValue(Ty, V, PFS);
|
|
}
|
|
|
|
bool LLParser::parseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
|
|
PerFunctionState &PFS) {
|
|
Value *V;
|
|
Loc = Lex.getLoc();
|
|
if (parseTypeAndValue(V, PFS))
|
|
return true;
|
|
if (!isa<BasicBlock>(V))
|
|
return error(Loc, "expected a basic block");
|
|
BB = cast<BasicBlock>(V);
|
|
return false;
|
|
}
|
|
|
|
/// FunctionHeader
|
|
/// ::= OptionalLinkage OptionalPreemptionSpecifier OptionalVisibility
|
|
/// OptionalCallingConv OptRetAttrs OptUnnamedAddr Type GlobalName
|
|
/// '(' ArgList ')' OptAddrSpace OptFuncAttrs OptSection OptionalAlign
|
|
/// OptGC OptionalPrefix OptionalPrologue OptPersonalityFn
|
|
bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine) {
|
|
// parse the linkage.
|
|
LocTy LinkageLoc = Lex.getLoc();
|
|
unsigned Linkage;
|
|
unsigned Visibility;
|
|
unsigned DLLStorageClass;
|
|
bool DSOLocal;
|
|
AttrBuilder RetAttrs;
|
|
unsigned CC;
|
|
bool HasLinkage;
|
|
Type *RetType = nullptr;
|
|
LocTy RetTypeLoc = Lex.getLoc();
|
|
if (parseOptionalLinkage(Linkage, HasLinkage, Visibility, DLLStorageClass,
|
|
DSOLocal) ||
|
|
parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
|
|
parseType(RetType, RetTypeLoc, true /*void allowed*/))
|
|
return true;
|
|
|
|
// Verify that the linkage is ok.
|
|
switch ((GlobalValue::LinkageTypes)Linkage) {
|
|
case GlobalValue::ExternalLinkage:
|
|
break; // always ok.
|
|
case GlobalValue::ExternalWeakLinkage:
|
|
if (IsDefine)
|
|
return error(LinkageLoc, "invalid linkage for function definition");
|
|
break;
|
|
case GlobalValue::PrivateLinkage:
|
|
case GlobalValue::InternalLinkage:
|
|
case GlobalValue::AvailableExternallyLinkage:
|
|
case GlobalValue::LinkOnceAnyLinkage:
|
|
case GlobalValue::LinkOnceODRLinkage:
|
|
case GlobalValue::WeakAnyLinkage:
|
|
case GlobalValue::WeakODRLinkage:
|
|
if (!IsDefine)
|
|
return error(LinkageLoc, "invalid linkage for function declaration");
|
|
break;
|
|
case GlobalValue::AppendingLinkage:
|
|
case GlobalValue::CommonLinkage:
|
|
return error(LinkageLoc, "invalid function linkage type");
|
|
}
|
|
|
|
if (!isValidVisibilityForLinkage(Visibility, Linkage))
|
|
return error(LinkageLoc,
|
|
"symbol with local linkage must have default visibility");
|
|
|
|
if (!FunctionType::isValidReturnType(RetType))
|
|
return error(RetTypeLoc, "invalid function return type");
|
|
|
|
LocTy NameLoc = Lex.getLoc();
|
|
|
|
std::string FunctionName;
|
|
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()) + "'");
|
|
} else {
|
|
return tokError("expected function name");
|
|
}
|
|
|
|
Lex.Lex();
|
|
|
|
if (Lex.getKind() != lltok::lparen)
|
|
return tokError("expected '(' in function argument list");
|
|
|
|
SmallVector<ArgInfo, 8> ArgList;
|
|
bool IsVarArg;
|
|
AttrBuilder FuncAttrs;
|
|
std::vector<unsigned> FwdRefAttrGrps;
|
|
LocTy BuiltinLoc;
|
|
std::string Section;
|
|
std::string Partition;
|
|
MaybeAlign Alignment;
|
|
std::string GC;
|
|
GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
|
|
unsigned AddrSpace = 0;
|
|
Constant *Prefix = nullptr;
|
|
Constant *Prologue = nullptr;
|
|
Constant *PersonalityFn = nullptr;
|
|
Comdat *C;
|
|
|
|
if (parseArgumentList(ArgList, IsVarArg) ||
|
|
parseOptionalUnnamedAddr(UnnamedAddr) ||
|
|
parseOptionalProgramAddrSpace(AddrSpace) ||
|
|
parseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false,
|
|
BuiltinLoc) ||
|
|
(EatIfPresent(lltok::kw_section) && parseStringConstant(Section)) ||
|
|
(EatIfPresent(lltok::kw_partition) && parseStringConstant(Partition)) ||
|
|
parseOptionalComdat(FunctionName, C) ||
|
|
parseOptionalAlignment(Alignment) ||
|
|
(EatIfPresent(lltok::kw_gc) && parseStringConstant(GC)) ||
|
|
(EatIfPresent(lltok::kw_prefix) && parseGlobalTypeAndValue(Prefix)) ||
|
|
(EatIfPresent(lltok::kw_prologue) && parseGlobalTypeAndValue(Prologue)) ||
|
|
(EatIfPresent(lltok::kw_personality) &&
|
|
parseGlobalTypeAndValue(PersonalityFn)))
|
|
return true;
|
|
|
|
if (FuncAttrs.contains(Attribute::Builtin))
|
|
return error(BuiltinLoc, "'builtin' attribute not valid on function");
|
|
|
|
// If the alignment was parsed as an attribute, move to the alignment field.
|
|
if (FuncAttrs.hasAlignmentAttr()) {
|
|
Alignment = FuncAttrs.getAlignment();
|
|
FuncAttrs.removeAttribute(Attribute::Alignment);
|
|
}
|
|
|
|
// Okay, if we got here, the function is syntactically valid. Convert types
|
|
// and do semantic checks.
|
|
std::vector<Type*> ParamTypeList;
|
|
SmallVector<AttributeSet, 8> Attrs;
|
|
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i) {
|
|
ParamTypeList.push_back(ArgList[i].Ty);
|
|
Attrs.push_back(ArgList[i].Attrs);
|
|
}
|
|
|
|
AttributeList PAL =
|
|
AttributeList::get(Context, AttributeSet::get(Context, FuncAttrs),
|
|
AttributeSet::get(Context, RetAttrs), Attrs);
|
|
|
|
if (PAL.hasAttribute(1, Attribute::StructRet) && !RetType->isVoidTy())
|
|
return error(RetTypeLoc, "functions with 'sret' argument must return void");
|
|
|
|
FunctionType *FT = FunctionType::get(RetType, ParamTypeList, IsVarArg);
|
|
PointerType *PFT = PointerType::get(FT, AddrSpace);
|
|
|
|
Fn = nullptr;
|
|
if (!FunctionName.empty()) {
|
|
// If this was a definition of a forward reference, remove the definition
|
|
// from the forward reference table and fill in the forward ref.
|
|
auto FRVI = ForwardRefVals.find(FunctionName);
|
|
if (FRVI != ForwardRefVals.end()) {
|
|
Fn = M->getFunction(FunctionName);
|
|
if (!Fn)
|
|
return error(FRVI->second.second, "invalid forward reference to "
|
|
"function as global value!");
|
|
if (Fn->getType() != PFT)
|
|
return error(FRVI->second.second,
|
|
"invalid forward reference to "
|
|
"function '" +
|
|
FunctionName +
|
|
"' with wrong type: "
|
|
"expected '" +
|
|
getTypeString(PFT) + "' but was '" +
|
|
getTypeString(Fn->getType()) + "'");
|
|
ForwardRefVals.erase(FRVI);
|
|
} else if ((Fn = M->getFunction(FunctionName))) {
|
|
// Reject redefinitions.
|
|
return error(NameLoc,
|
|
"invalid redefinition of function '" + FunctionName + "'");
|
|
} else if (M->getNamedValue(FunctionName)) {
|
|
return error(NameLoc, "redefinition of function '@" + FunctionName + "'");
|
|
}
|
|
|
|
} else {
|
|
// If this is a definition of a forward referenced function, make sure the
|
|
// types agree.
|
|
auto I = ForwardRefValIDs.find(NumberedVals.size());
|
|
if (I != ForwardRefValIDs.end()) {
|
|
Fn = cast<Function>(I->second.first);
|
|
if (Fn->getType() != PFT)
|
|
return error(NameLoc, "type of definition and forward reference of '@" +
|
|
Twine(NumberedVals.size()) +
|
|
"' disagree: "
|
|
"expected '" +
|
|
getTypeString(PFT) + "' but was '" +
|
|
getTypeString(Fn->getType()) + "'");
|
|
ForwardRefValIDs.erase(I);
|
|
}
|
|
}
|
|
|
|
if (!Fn)
|
|
Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace,
|
|
FunctionName, M);
|
|
else // Move the forward-reference to the correct spot in the module.
|
|
M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn);
|
|
|
|
assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS");
|
|
|
|
if (FunctionName.empty())
|
|
NumberedVals.push_back(Fn);
|
|
|
|
Fn->setLinkage((GlobalValue::LinkageTypes)Linkage);
|
|
maybeSetDSOLocal(DSOLocal, *Fn);
|
|
Fn->setVisibility((GlobalValue::VisibilityTypes)Visibility);
|
|
Fn->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
|
|
Fn->setCallingConv(CC);
|
|
Fn->setAttributes(PAL);
|
|
Fn->setUnnamedAddr(UnnamedAddr);
|
|
Fn->setAlignment(MaybeAlign(Alignment));
|
|
Fn->setSection(Section);
|
|
Fn->setPartition(Partition);
|
|
Fn->setComdat(C);
|
|
Fn->setPersonalityFn(PersonalityFn);
|
|
if (!GC.empty()) Fn->setGC(GC);
|
|
Fn->setPrefixData(Prefix);
|
|
Fn->setPrologueData(Prologue);
|
|
ForwardRefAttrGroups[Fn] = FwdRefAttrGrps;
|
|
|
|
// Add all of the arguments we parsed to the function.
|
|
Function::arg_iterator ArgIt = Fn->arg_begin();
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i, ++ArgIt) {
|
|
// If the argument has a name, insert it into the argument symbol table.
|
|
if (ArgList[i].Name.empty()) continue;
|
|
|
|
// Set the name, if it conflicted, it will be auto-renamed.
|
|
ArgIt->setName(ArgList[i].Name);
|
|
|
|
if (ArgIt->getName() != ArgList[i].Name)
|
|
return error(ArgList[i].Loc,
|
|
"redefinition of argument '%" + ArgList[i].Name + "'");
|
|
}
|
|
|
|
if (IsDefine)
|
|
return false;
|
|
|
|
// Check the declaration has no block address forward references.
|
|
ValID ID;
|
|
if (FunctionName.empty()) {
|
|
ID.Kind = ValID::t_GlobalID;
|
|
ID.UIntVal = NumberedVals.size() - 1;
|
|
} else {
|
|
ID.Kind = ValID::t_GlobalName;
|
|
ID.StrVal = FunctionName;
|
|
}
|
|
auto Blocks = ForwardRefBlockAddresses.find(ID);
|
|
if (Blocks != ForwardRefBlockAddresses.end())
|
|
return error(Blocks->first.Loc,
|
|
"cannot take blockaddress inside a declaration");
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::PerFunctionState::resolveForwardRefBlockAddresses() {
|
|
ValID ID;
|
|
if (FunctionNumber == -1) {
|
|
ID.Kind = ValID::t_GlobalName;
|
|
ID.StrVal = std::string(F.getName());
|
|
} else {
|
|
ID.Kind = ValID::t_GlobalID;
|
|
ID.UIntVal = FunctionNumber;
|
|
}
|
|
|
|
auto Blocks = P.ForwardRefBlockAddresses.find(ID);
|
|
if (Blocks == P.ForwardRefBlockAddresses.end())
|
|
return false;
|
|
|
|
for (const auto &I : Blocks->second) {
|
|
const ValID &BBID = I.first;
|
|
GlobalValue *GV = I.second;
|
|
|
|
assert((BBID.Kind == ValID::t_LocalID || BBID.Kind == ValID::t_LocalName) &&
|
|
"Expected local id or name");
|
|
BasicBlock *BB;
|
|
if (BBID.Kind == ValID::t_LocalName)
|
|
BB = getBB(BBID.StrVal, BBID.Loc);
|
|
else
|
|
BB = getBB(BBID.UIntVal, BBID.Loc);
|
|
if (!BB)
|
|
return P.error(BBID.Loc, "referenced value is not a basic block");
|
|
|
|
GV->replaceAllUsesWith(BlockAddress::get(&F, BB));
|
|
GV->eraseFromParent();
|
|
}
|
|
|
|
P.ForwardRefBlockAddresses.erase(Blocks);
|
|
return false;
|
|
}
|
|
|
|
/// parseFunctionBody
|
|
/// ::= '{' BasicBlock+ UseListOrderDirective* '}'
|
|
bool LLParser::parseFunctionBody(Function &Fn) {
|
|
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);
|
|
|
|
// Resolve block addresses and allow basic blocks to be forward-declared
|
|
// within this function.
|
|
if (PFS.resolveForwardRefBlockAddresses())
|
|
return true;
|
|
SaveAndRestore<PerFunctionState *> ScopeExit(BlockAddressPFS, &PFS);
|
|
|
|
// We need at least one basic block.
|
|
if (Lex.getKind() == lltok::rbrace || Lex.getKind() == lltok::kw_uselistorder)
|
|
return tokError("function body requires at least one basic block");
|
|
|
|
while (Lex.getKind() != lltok::rbrace &&
|
|
Lex.getKind() != lltok::kw_uselistorder)
|
|
if (parseBasicBlock(PFS))
|
|
return true;
|
|
|
|
while (Lex.getKind() != lltok::rbrace)
|
|
if (parseUseListOrder(&PFS))
|
|
return true;
|
|
|
|
// Eat the }.
|
|
Lex.Lex();
|
|
|
|
// Verify function is ok.
|
|
return PFS.finishFunction();
|
|
}
|
|
|
|
/// parseBasicBlock
|
|
/// ::= (LabelStr|LabelID)? Instruction*
|
|
bool LLParser::parseBasicBlock(PerFunctionState &PFS) {
|
|
// If this basic block starts out with a name, remember it.
|
|
std::string Name;
|
|
int NameID = -1;
|
|
LocTy NameLoc = Lex.getLoc();
|
|
if (Lex.getKind() == lltok::LabelStr) {
|
|
Name = Lex.getStrVal();
|
|
Lex.Lex();
|
|
} else if (Lex.getKind() == lltok::LabelID) {
|
|
NameID = Lex.getUIntVal();
|
|
Lex.Lex();
|
|
}
|
|
|
|
BasicBlock *BB = PFS.defineBB(Name, NameID, NameLoc);
|
|
if (!BB)
|
|
return true;
|
|
|
|
std::string NameStr;
|
|
|
|
// parse the instructions in this block until we get a terminator.
|
|
Instruction *Inst;
|
|
do {
|
|
// This instruction may have three possibilities for a name: a) none
|
|
// specified, b) name specified "%foo =", c) number specified: "%4 =".
|
|
LocTy NameLoc = Lex.getLoc();
|
|
int NameID = -1;
|
|
NameStr = "";
|
|
|
|
if (Lex.getKind() == lltok::LocalVarID) {
|
|
NameID = Lex.getUIntVal();
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' after instruction id"))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::LocalVar) {
|
|
NameStr = Lex.getStrVal();
|
|
Lex.Lex();
|
|
if (parseToken(lltok::equal, "expected '=' after instruction name"))
|
|
return true;
|
|
}
|
|
|
|
switch (parseInstruction(Inst, BB, PFS)) {
|
|
default:
|
|
llvm_unreachable("Unknown parseInstruction result!");
|
|
case InstError: return true;
|
|
case InstNormal:
|
|
BB->getInstList().push_back(Inst);
|
|
|
|
// With a normal result, we check to see if the instruction is followed by
|
|
// a comma and metadata.
|
|
if (EatIfPresent(lltok::comma))
|
|
if (parseInstructionMetadata(*Inst))
|
|
return true;
|
|
break;
|
|
case InstExtraComma:
|
|
BB->getInstList().push_back(Inst);
|
|
|
|
// If the instruction parser ate an extra comma at the end of it, it
|
|
// *must* be followed by metadata.
|
|
if (parseInstructionMetadata(*Inst))
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
// Set the name on the instruction.
|
|
if (PFS.setInstName(NameID, NameStr, NameLoc, Inst))
|
|
return true;
|
|
} while (!Inst->isTerminator());
|
|
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Parsing.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseInstruction - parse one of the many different instructions.
|
|
///
|
|
int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
|
|
PerFunctionState &PFS) {
|
|
lltok::Kind Token = Lex.getKind();
|
|
if (Token == lltok::Eof)
|
|
return tokError("found end of file when expecting more instructions");
|
|
LocTy Loc = Lex.getLoc();
|
|
unsigned KeywordVal = Lex.getUIntVal();
|
|
Lex.Lex(); // Eat the keyword.
|
|
|
|
switch (Token) {
|
|
default:
|
|
return error(Loc, "expected instruction opcode");
|
|
// Terminator Instructions.
|
|
case lltok::kw_unreachable: Inst = new UnreachableInst(Context); return false;
|
|
case lltok::kw_ret:
|
|
return parseRet(Inst, BB, PFS);
|
|
case lltok::kw_br:
|
|
return parseBr(Inst, PFS);
|
|
case lltok::kw_switch:
|
|
return parseSwitch(Inst, PFS);
|
|
case lltok::kw_indirectbr:
|
|
return parseIndirectBr(Inst, PFS);
|
|
case lltok::kw_invoke:
|
|
return parseInvoke(Inst, PFS);
|
|
case lltok::kw_resume:
|
|
return parseResume(Inst, PFS);
|
|
case lltok::kw_cleanupret:
|
|
return parseCleanupRet(Inst, PFS);
|
|
case lltok::kw_catchret:
|
|
return parseCatchRet(Inst, PFS);
|
|
case lltok::kw_catchswitch:
|
|
return parseCatchSwitch(Inst, PFS);
|
|
case lltok::kw_catchpad:
|
|
return parseCatchPad(Inst, PFS);
|
|
case lltok::kw_cleanuppad:
|
|
return parseCleanupPad(Inst, PFS);
|
|
case lltok::kw_callbr:
|
|
return parseCallBr(Inst, PFS);
|
|
// Unary Operators.
|
|
case lltok::kw_fneg: {
|
|
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
|
int Res = parseUnaryOp(Inst, PFS, KeywordVal, /*IsFP*/ true);
|
|
if (Res != 0)
|
|
return Res;
|
|
if (FMF.any())
|
|
Inst->setFastMathFlags(FMF);
|
|
return false;
|
|
}
|
|
// Binary Operators.
|
|
case lltok::kw_add:
|
|
case lltok::kw_sub:
|
|
case lltok::kw_mul:
|
|
case lltok::kw_shl: {
|
|
bool NUW = EatIfPresent(lltok::kw_nuw);
|
|
bool NSW = EatIfPresent(lltok::kw_nsw);
|
|
if (!NUW) NUW = EatIfPresent(lltok::kw_nuw);
|
|
|
|
if (parseArithmetic(Inst, PFS, KeywordVal, /*IsFP*/ false))
|
|
return true;
|
|
|
|
if (NUW) cast<BinaryOperator>(Inst)->setHasNoUnsignedWrap(true);
|
|
if (NSW) cast<BinaryOperator>(Inst)->setHasNoSignedWrap(true);
|
|
return false;
|
|
}
|
|
case lltok::kw_fadd:
|
|
case lltok::kw_fsub:
|
|
case lltok::kw_fmul:
|
|
case lltok::kw_fdiv:
|
|
case lltok::kw_frem: {
|
|
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
|
int Res = parseArithmetic(Inst, PFS, KeywordVal, /*IsFP*/ true);
|
|
if (Res != 0)
|
|
return Res;
|
|
if (FMF.any())
|
|
Inst->setFastMathFlags(FMF);
|
|
return 0;
|
|
}
|
|
|
|
case lltok::kw_sdiv:
|
|
case lltok::kw_udiv:
|
|
case lltok::kw_lshr:
|
|
case lltok::kw_ashr: {
|
|
bool Exact = EatIfPresent(lltok::kw_exact);
|
|
|
|
if (parseArithmetic(Inst, PFS, KeywordVal, /*IsFP*/ false))
|
|
return true;
|
|
if (Exact) cast<BinaryOperator>(Inst)->setIsExact(true);
|
|
return false;
|
|
}
|
|
|
|
case lltok::kw_urem:
|
|
case lltok::kw_srem:
|
|
return parseArithmetic(Inst, PFS, KeywordVal,
|
|
/*IsFP*/ false);
|
|
case lltok::kw_and:
|
|
case lltok::kw_or:
|
|
case lltok::kw_xor:
|
|
return parseLogical(Inst, PFS, KeywordVal);
|
|
case lltok::kw_icmp:
|
|
return parseCompare(Inst, PFS, KeywordVal);
|
|
case lltok::kw_fcmp: {
|
|
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
|
int Res = parseCompare(Inst, PFS, KeywordVal);
|
|
if (Res != 0)
|
|
return Res;
|
|
if (FMF.any())
|
|
Inst->setFastMathFlags(FMF);
|
|
return 0;
|
|
}
|
|
|
|
// Casts.
|
|
case lltok::kw_trunc:
|
|
case lltok::kw_zext:
|
|
case lltok::kw_sext:
|
|
case lltok::kw_fptrunc:
|
|
case lltok::kw_fpext:
|
|
case lltok::kw_bitcast:
|
|
case lltok::kw_addrspacecast:
|
|
case lltok::kw_uitofp:
|
|
case lltok::kw_sitofp:
|
|
case lltok::kw_fptoui:
|
|
case lltok::kw_fptosi:
|
|
case lltok::kw_inttoptr:
|
|
case lltok::kw_ptrtoint:
|
|
return parseCast(Inst, PFS, KeywordVal);
|
|
// Other.
|
|
case lltok::kw_select: {
|
|
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
|
int Res = parseSelect(Inst, PFS);
|
|
if (Res != 0)
|
|
return Res;
|
|
if (FMF.any()) {
|
|
if (!isa<FPMathOperator>(Inst))
|
|
return error(Loc, "fast-math-flags specified for select without "
|
|
"floating-point scalar or vector return type");
|
|
Inst->setFastMathFlags(FMF);
|
|
}
|
|
return 0;
|
|
}
|
|
case lltok::kw_va_arg:
|
|
return parseVAArg(Inst, PFS);
|
|
case lltok::kw_extractelement:
|
|
return parseExtractElement(Inst, PFS);
|
|
case lltok::kw_insertelement:
|
|
return parseInsertElement(Inst, PFS);
|
|
case lltok::kw_shufflevector:
|
|
return parseShuffleVector(Inst, PFS);
|
|
case lltok::kw_phi: {
|
|
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
|
int Res = parsePHI(Inst, PFS);
|
|
if (Res != 0)
|
|
return Res;
|
|
if (FMF.any()) {
|
|
if (!isa<FPMathOperator>(Inst))
|
|
return error(Loc, "fast-math-flags specified for phi without "
|
|
"floating-point scalar or vector return type");
|
|
Inst->setFastMathFlags(FMF);
|
|
}
|
|
return 0;
|
|
}
|
|
case lltok::kw_landingpad:
|
|
return parseLandingPad(Inst, PFS);
|
|
case lltok::kw_freeze:
|
|
return parseFreeze(Inst, PFS);
|
|
// Call.
|
|
case lltok::kw_call:
|
|
return parseCall(Inst, PFS, CallInst::TCK_None);
|
|
case lltok::kw_tail:
|
|
return parseCall(Inst, PFS, CallInst::TCK_Tail);
|
|
case lltok::kw_musttail:
|
|
return parseCall(Inst, PFS, CallInst::TCK_MustTail);
|
|
case lltok::kw_notail:
|
|
return parseCall(Inst, PFS, CallInst::TCK_NoTail);
|
|
// Memory.
|
|
case lltok::kw_alloca:
|
|
return parseAlloc(Inst, PFS);
|
|
case lltok::kw_load:
|
|
return parseLoad(Inst, PFS);
|
|
case lltok::kw_store:
|
|
return parseStore(Inst, PFS);
|
|
case lltok::kw_cmpxchg:
|
|
return parseCmpXchg(Inst, PFS);
|
|
case lltok::kw_atomicrmw:
|
|
return parseAtomicRMW(Inst, PFS);
|
|
case lltok::kw_fence:
|
|
return parseFence(Inst, PFS);
|
|
case lltok::kw_getelementptr:
|
|
return parseGetElementPtr(Inst, PFS);
|
|
case lltok::kw_extractvalue:
|
|
return parseExtractValue(Inst, PFS);
|
|
case lltok::kw_insertvalue:
|
|
return parseInsertValue(Inst, PFS);
|
|
}
|
|
}
|
|
|
|
/// parseCmpPredicate - parse an integer or fp predicate, based on Kind.
|
|
bool LLParser::parseCmpPredicate(unsigned &P, unsigned Opc) {
|
|
if (Opc == Instruction::FCmp) {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected fcmp predicate (e.g. 'oeq')");
|
|
case lltok::kw_oeq: P = CmpInst::FCMP_OEQ; break;
|
|
case lltok::kw_one: P = CmpInst::FCMP_ONE; break;
|
|
case lltok::kw_olt: P = CmpInst::FCMP_OLT; break;
|
|
case lltok::kw_ogt: P = CmpInst::FCMP_OGT; break;
|
|
case lltok::kw_ole: P = CmpInst::FCMP_OLE; break;
|
|
case lltok::kw_oge: P = CmpInst::FCMP_OGE; break;
|
|
case lltok::kw_ord: P = CmpInst::FCMP_ORD; break;
|
|
case lltok::kw_uno: P = CmpInst::FCMP_UNO; break;
|
|
case lltok::kw_ueq: P = CmpInst::FCMP_UEQ; break;
|
|
case lltok::kw_une: P = CmpInst::FCMP_UNE; break;
|
|
case lltok::kw_ult: P = CmpInst::FCMP_ULT; break;
|
|
case lltok::kw_ugt: P = CmpInst::FCMP_UGT; break;
|
|
case lltok::kw_ule: P = CmpInst::FCMP_ULE; break;
|
|
case lltok::kw_uge: P = CmpInst::FCMP_UGE; break;
|
|
case lltok::kw_true: P = CmpInst::FCMP_TRUE; break;
|
|
case lltok::kw_false: P = CmpInst::FCMP_FALSE; break;
|
|
}
|
|
} else {
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected icmp predicate (e.g. 'eq')");
|
|
case lltok::kw_eq: P = CmpInst::ICMP_EQ; break;
|
|
case lltok::kw_ne: P = CmpInst::ICMP_NE; break;
|
|
case lltok::kw_slt: P = CmpInst::ICMP_SLT; break;
|
|
case lltok::kw_sgt: P = CmpInst::ICMP_SGT; break;
|
|
case lltok::kw_sle: P = CmpInst::ICMP_SLE; break;
|
|
case lltok::kw_sge: P = CmpInst::ICMP_SGE; break;
|
|
case lltok::kw_ult: P = CmpInst::ICMP_ULT; break;
|
|
case lltok::kw_ugt: P = CmpInst::ICMP_UGT; break;
|
|
case lltok::kw_ule: P = CmpInst::ICMP_ULE; break;
|
|
case lltok::kw_uge: P = CmpInst::ICMP_UGE; break;
|
|
}
|
|
}
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Terminator Instructions.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseRet - parse a return instruction.
|
|
/// ::= 'ret' void (',' !dbg, !1)*
|
|
/// ::= 'ret' TypeAndValue (',' !dbg, !1)*
|
|
bool LLParser::parseRet(Instruction *&Inst, BasicBlock *BB,
|
|
PerFunctionState &PFS) {
|
|
SMLoc TypeLoc = Lex.getLoc();
|
|
Type *Ty = nullptr;
|
|
if (parseType(Ty, true /*void allowed*/))
|
|
return true;
|
|
|
|
Type *ResType = PFS.getFunction().getReturnType();
|
|
|
|
if (Ty->isVoidTy()) {
|
|
if (!ResType->isVoidTy())
|
|
return error(TypeLoc, "value doesn't match function result type '" +
|
|
getTypeString(ResType) + "'");
|
|
|
|
Inst = ReturnInst::Create(Context);
|
|
return false;
|
|
}
|
|
|
|
Value *RV;
|
|
if (parseValue(Ty, RV, PFS))
|
|
return true;
|
|
|
|
if (ResType != RV->getType())
|
|
return error(TypeLoc, "value doesn't match function result type '" +
|
|
getTypeString(ResType) + "'");
|
|
|
|
Inst = ReturnInst::Create(Context, RV);
|
|
return false;
|
|
}
|
|
|
|
/// parseBr
|
|
/// ::= 'br' TypeAndValue
|
|
/// ::= 'br' TypeAndValue ',' TypeAndValue ',' TypeAndValue
|
|
bool LLParser::parseBr(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy Loc, Loc2;
|
|
Value *Op0;
|
|
BasicBlock *Op1, *Op2;
|
|
if (parseTypeAndValue(Op0, Loc, PFS))
|
|
return true;
|
|
|
|
if (BasicBlock *BB = dyn_cast<BasicBlock>(Op0)) {
|
|
Inst = BranchInst::Create(BB);
|
|
return false;
|
|
}
|
|
|
|
if (Op0->getType() != Type::getInt1Ty(Context))
|
|
return error(Loc, "branch condition must have 'i1' type");
|
|
|
|
if (parseToken(lltok::comma, "expected ',' after branch condition") ||
|
|
parseTypeAndBasicBlock(Op1, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after true destination") ||
|
|
parseTypeAndBasicBlock(Op2, Loc2, PFS))
|
|
return true;
|
|
|
|
Inst = BranchInst::Create(Op1, Op2, Op0);
|
|
return false;
|
|
}
|
|
|
|
/// parseSwitch
|
|
/// Instruction
|
|
/// ::= 'switch' TypeAndValue ',' TypeAndValue '[' JumpTable ']'
|
|
/// JumpTable
|
|
/// ::= (TypeAndValue ',' TypeAndValue)*
|
|
bool LLParser::parseSwitch(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy CondLoc, BBLoc;
|
|
Value *Cond;
|
|
BasicBlock *DefaultBB;
|
|
if (parseTypeAndValue(Cond, CondLoc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after switch condition") ||
|
|
parseTypeAndBasicBlock(DefaultBB, BBLoc, PFS) ||
|
|
parseToken(lltok::lsquare, "expected '[' with switch table"))
|
|
return true;
|
|
|
|
if (!Cond->getType()->isIntegerTy())
|
|
return error(CondLoc, "switch condition must have integer type");
|
|
|
|
// parse the jump table pairs.
|
|
SmallPtrSet<Value*, 32> SeenCases;
|
|
SmallVector<std::pair<ConstantInt*, BasicBlock*>, 32> Table;
|
|
while (Lex.getKind() != lltok::rsquare) {
|
|
Value *Constant;
|
|
BasicBlock *DestBB;
|
|
|
|
if (parseTypeAndValue(Constant, CondLoc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after case value") ||
|
|
parseTypeAndBasicBlock(DestBB, PFS))
|
|
return true;
|
|
|
|
if (!SeenCases.insert(Constant).second)
|
|
return error(CondLoc, "duplicate case value in switch");
|
|
if (!isa<ConstantInt>(Constant))
|
|
return error(CondLoc, "case value is not a constant integer");
|
|
|
|
Table.push_back(std::make_pair(cast<ConstantInt>(Constant), DestBB));
|
|
}
|
|
|
|
Lex.Lex(); // Eat the ']'.
|
|
|
|
SwitchInst *SI = SwitchInst::Create(Cond, DefaultBB, Table.size());
|
|
for (unsigned i = 0, e = Table.size(); i != e; ++i)
|
|
SI->addCase(Table[i].first, Table[i].second);
|
|
Inst = SI;
|
|
return false;
|
|
}
|
|
|
|
/// parseIndirectBr
|
|
/// Instruction
|
|
/// ::= 'indirectbr' TypeAndValue ',' '[' LabelList ']'
|
|
bool LLParser::parseIndirectBr(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy AddrLoc;
|
|
Value *Address;
|
|
if (parseTypeAndValue(Address, AddrLoc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after indirectbr address") ||
|
|
parseToken(lltok::lsquare, "expected '[' with indirectbr"))
|
|
return true;
|
|
|
|
if (!Address->getType()->isPointerTy())
|
|
return error(AddrLoc, "indirectbr address must have pointer type");
|
|
|
|
// parse the destination list.
|
|
SmallVector<BasicBlock*, 16> DestList;
|
|
|
|
if (Lex.getKind() != lltok::rsquare) {
|
|
BasicBlock *DestBB;
|
|
if (parseTypeAndBasicBlock(DestBB, PFS))
|
|
return true;
|
|
DestList.push_back(DestBB);
|
|
|
|
while (EatIfPresent(lltok::comma)) {
|
|
if (parseTypeAndBasicBlock(DestBB, PFS))
|
|
return true;
|
|
DestList.push_back(DestBB);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rsquare, "expected ']' at end of block list"))
|
|
return true;
|
|
|
|
IndirectBrInst *IBI = IndirectBrInst::Create(Address, DestList.size());
|
|
for (unsigned i = 0, e = DestList.size(); i != e; ++i)
|
|
IBI->addDestination(DestList[i]);
|
|
Inst = IBI;
|
|
return false;
|
|
}
|
|
|
|
/// parseInvoke
|
|
/// ::= 'invoke' OptionalCallingConv OptionalAttrs Type Value ParamList
|
|
/// OptionalAttrs 'to' TypeAndValue 'unwind' TypeAndValue
|
|
bool LLParser::parseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy CallLoc = Lex.getLoc();
|
|
AttrBuilder RetAttrs, FnAttrs;
|
|
std::vector<unsigned> FwdRefAttrGrps;
|
|
LocTy NoBuiltinLoc;
|
|
unsigned CC;
|
|
unsigned InvokeAddrSpace;
|
|
Type *RetType = nullptr;
|
|
LocTy RetTypeLoc;
|
|
ValID CalleeID;
|
|
SmallVector<ParamInfo, 16> ArgList;
|
|
SmallVector<OperandBundleDef, 2> BundleList;
|
|
|
|
BasicBlock *NormalBB, *UnwindBB;
|
|
if (parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
|
|
parseOptionalProgramAddrSpace(InvokeAddrSpace) ||
|
|
parseType(RetType, RetTypeLoc, true /*void allowed*/) ||
|
|
parseValID(CalleeID) || parseParameterList(ArgList, PFS) ||
|
|
parseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
|
|
NoBuiltinLoc) ||
|
|
parseOptionalOperandBundles(BundleList, PFS) ||
|
|
parseToken(lltok::kw_to, "expected 'to' in invoke") ||
|
|
parseTypeAndBasicBlock(NormalBB, PFS) ||
|
|
parseToken(lltok::kw_unwind, "expected 'unwind' in invoke") ||
|
|
parseTypeAndBasicBlock(UnwindBB, PFS))
|
|
return true;
|
|
|
|
// If RetType is a non-function pointer type, then this is the short syntax
|
|
// for the call, which means that RetType is just the return type. Infer the
|
|
// rest of the function argument types from the arguments that are present.
|
|
FunctionType *Ty = dyn_cast<FunctionType>(RetType);
|
|
if (!Ty) {
|
|
// Pull out the types of all of the arguments...
|
|
std::vector<Type*> ParamTypes;
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
|
|
ParamTypes.push_back(ArgList[i].V->getType());
|
|
|
|
if (!FunctionType::isValidReturnType(RetType))
|
|
return error(RetTypeLoc, "Invalid result type for LLVM function");
|
|
|
|
Ty = FunctionType::get(RetType, ParamTypes, false);
|
|
}
|
|
|
|
CalleeID.FTy = Ty;
|
|
|
|
// Look up the callee.
|
|
Value *Callee;
|
|
if (convertValIDToValue(PointerType::get(Ty, InvokeAddrSpace), CalleeID,
|
|
Callee, &PFS, /*IsCall=*/true))
|
|
return true;
|
|
|
|
// Set up the Attribute for the function.
|
|
SmallVector<Value *, 8> Args;
|
|
SmallVector<AttributeSet, 8> ArgAttrs;
|
|
|
|
// Loop through FunctionType's arguments and ensure they are specified
|
|
// correctly. Also, gather any parameter attributes.
|
|
FunctionType::param_iterator I = Ty->param_begin();
|
|
FunctionType::param_iterator E = Ty->param_end();
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i) {
|
|
Type *ExpectedTy = nullptr;
|
|
if (I != E) {
|
|
ExpectedTy = *I++;
|
|
} else if (!Ty->isVarArg()) {
|
|
return error(ArgList[i].Loc, "too many arguments specified");
|
|
}
|
|
|
|
if (ExpectedTy && ExpectedTy != ArgList[i].V->getType())
|
|
return error(ArgList[i].Loc, "argument is not of expected type '" +
|
|
getTypeString(ExpectedTy) + "'");
|
|
Args.push_back(ArgList[i].V);
|
|
ArgAttrs.push_back(ArgList[i].Attrs);
|
|
}
|
|
|
|
if (I != E)
|
|
return error(CallLoc, "not enough parameters specified for call");
|
|
|
|
if (FnAttrs.hasAlignmentAttr())
|
|
return error(CallLoc, "invoke instructions may not have an alignment");
|
|
|
|
// Finish off the Attribute and check them
|
|
AttributeList PAL =
|
|
AttributeList::get(Context, AttributeSet::get(Context, FnAttrs),
|
|
AttributeSet::get(Context, RetAttrs), ArgAttrs);
|
|
|
|
InvokeInst *II =
|
|
InvokeInst::Create(Ty, Callee, NormalBB, UnwindBB, Args, BundleList);
|
|
II->setCallingConv(CC);
|
|
II->setAttributes(PAL);
|
|
ForwardRefAttrGroups[II] = FwdRefAttrGrps;
|
|
Inst = II;
|
|
return false;
|
|
}
|
|
|
|
/// parseResume
|
|
/// ::= 'resume' TypeAndValue
|
|
bool LLParser::parseResume(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Exn; LocTy ExnLoc;
|
|
if (parseTypeAndValue(Exn, ExnLoc, PFS))
|
|
return true;
|
|
|
|
ResumeInst *RI = ResumeInst::Create(Exn);
|
|
Inst = RI;
|
|
return false;
|
|
}
|
|
|
|
bool LLParser::parseExceptionArgs(SmallVectorImpl<Value *> &Args,
|
|
PerFunctionState &PFS) {
|
|
if (parseToken(lltok::lsquare, "expected '[' in catchpad/cleanuppad"))
|
|
return true;
|
|
|
|
while (Lex.getKind() != lltok::rsquare) {
|
|
// If this isn't the first argument, we need a comma.
|
|
if (!Args.empty() &&
|
|
parseToken(lltok::comma, "expected ',' in argument list"))
|
|
return true;
|
|
|
|
// parse the argument.
|
|
LocTy ArgLoc;
|
|
Type *ArgTy = nullptr;
|
|
if (parseType(ArgTy, ArgLoc))
|
|
return true;
|
|
|
|
Value *V;
|
|
if (ArgTy->isMetadataTy()) {
|
|
if (parseMetadataAsValue(V, PFS))
|
|
return true;
|
|
} else {
|
|
if (parseValue(ArgTy, V, PFS))
|
|
return true;
|
|
}
|
|
Args.push_back(V);
|
|
}
|
|
|
|
Lex.Lex(); // Lex the ']'.
|
|
return false;
|
|
}
|
|
|
|
/// parseCleanupRet
|
|
/// ::= 'cleanupret' from Value unwind ('to' 'caller' | TypeAndValue)
|
|
bool LLParser::parseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *CleanupPad = nullptr;
|
|
|
|
if (parseToken(lltok::kw_from, "expected 'from' after cleanupret"))
|
|
return true;
|
|
|
|
if (parseValue(Type::getTokenTy(Context), CleanupPad, PFS))
|
|
return true;
|
|
|
|
if (parseToken(lltok::kw_unwind, "expected 'unwind' in cleanupret"))
|
|
return true;
|
|
|
|
BasicBlock *UnwindBB = nullptr;
|
|
if (Lex.getKind() == lltok::kw_to) {
|
|
Lex.Lex();
|
|
if (parseToken(lltok::kw_caller, "expected 'caller' in cleanupret"))
|
|
return true;
|
|
} else {
|
|
if (parseTypeAndBasicBlock(UnwindBB, PFS)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Inst = CleanupReturnInst::Create(CleanupPad, UnwindBB);
|
|
return false;
|
|
}
|
|
|
|
/// parseCatchRet
|
|
/// ::= 'catchret' from Parent Value 'to' TypeAndValue
|
|
bool LLParser::parseCatchRet(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *CatchPad = nullptr;
|
|
|
|
if (parseToken(lltok::kw_from, "expected 'from' after catchret"))
|
|
return true;
|
|
|
|
if (parseValue(Type::getTokenTy(Context), CatchPad, PFS))
|
|
return true;
|
|
|
|
BasicBlock *BB;
|
|
if (parseToken(lltok::kw_to, "expected 'to' in catchret") ||
|
|
parseTypeAndBasicBlock(BB, PFS))
|
|
return true;
|
|
|
|
Inst = CatchReturnInst::Create(CatchPad, BB);
|
|
return false;
|
|
}
|
|
|
|
/// parseCatchSwitch
|
|
/// ::= 'catchswitch' within Parent
|
|
bool LLParser::parseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *ParentPad;
|
|
|
|
if (parseToken(lltok::kw_within, "expected 'within' after catchswitch"))
|
|
return true;
|
|
|
|
if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar &&
|
|
Lex.getKind() != lltok::LocalVarID)
|
|
return tokError("expected scope value for catchswitch");
|
|
|
|
if (parseValue(Type::getTokenTy(Context), ParentPad, PFS))
|
|
return true;
|
|
|
|
if (parseToken(lltok::lsquare, "expected '[' with catchswitch labels"))
|
|
return true;
|
|
|
|
SmallVector<BasicBlock *, 32> Table;
|
|
do {
|
|
BasicBlock *DestBB;
|
|
if (parseTypeAndBasicBlock(DestBB, PFS))
|
|
return true;
|
|
Table.push_back(DestBB);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rsquare, "expected ']' after catchswitch labels"))
|
|
return true;
|
|
|
|
if (parseToken(lltok::kw_unwind, "expected 'unwind' after catchswitch scope"))
|
|
return true;
|
|
|
|
BasicBlock *UnwindBB = nullptr;
|
|
if (EatIfPresent(lltok::kw_to)) {
|
|
if (parseToken(lltok::kw_caller, "expected 'caller' in catchswitch"))
|
|
return true;
|
|
} else {
|
|
if (parseTypeAndBasicBlock(UnwindBB, PFS))
|
|
return true;
|
|
}
|
|
|
|
auto *CatchSwitch =
|
|
CatchSwitchInst::Create(ParentPad, UnwindBB, Table.size());
|
|
for (BasicBlock *DestBB : Table)
|
|
CatchSwitch->addHandler(DestBB);
|
|
Inst = CatchSwitch;
|
|
return false;
|
|
}
|
|
|
|
/// parseCatchPad
|
|
/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue
|
|
bool LLParser::parseCatchPad(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *CatchSwitch = nullptr;
|
|
|
|
if (parseToken(lltok::kw_within, "expected 'within' after catchpad"))
|
|
return true;
|
|
|
|
if (Lex.getKind() != lltok::LocalVar && Lex.getKind() != lltok::LocalVarID)
|
|
return tokError("expected scope value for catchpad");
|
|
|
|
if (parseValue(Type::getTokenTy(Context), CatchSwitch, PFS))
|
|
return true;
|
|
|
|
SmallVector<Value *, 8> Args;
|
|
if (parseExceptionArgs(Args, PFS))
|
|
return true;
|
|
|
|
Inst = CatchPadInst::Create(CatchSwitch, Args);
|
|
return false;
|
|
}
|
|
|
|
/// parseCleanupPad
|
|
/// ::= 'cleanuppad' within Parent ParamList
|
|
bool LLParser::parseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *ParentPad = nullptr;
|
|
|
|
if (parseToken(lltok::kw_within, "expected 'within' after cleanuppad"))
|
|
return true;
|
|
|
|
if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar &&
|
|
Lex.getKind() != lltok::LocalVarID)
|
|
return tokError("expected scope value for cleanuppad");
|
|
|
|
if (parseValue(Type::getTokenTy(Context), ParentPad, PFS))
|
|
return true;
|
|
|
|
SmallVector<Value *, 8> Args;
|
|
if (parseExceptionArgs(Args, PFS))
|
|
return true;
|
|
|
|
Inst = CleanupPadInst::Create(ParentPad, Args);
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Unary Operators.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseUnaryOp
|
|
/// ::= UnaryOp TypeAndValue ',' Value
|
|
///
|
|
/// If IsFP is false, then any integer operand is allowed, if it is true, any fp
|
|
/// operand is allowed.
|
|
bool LLParser::parseUnaryOp(Instruction *&Inst, PerFunctionState &PFS,
|
|
unsigned Opc, bool IsFP) {
|
|
LocTy Loc; Value *LHS;
|
|
if (parseTypeAndValue(LHS, Loc, PFS))
|
|
return true;
|
|
|
|
bool Valid = IsFP ? LHS->getType()->isFPOrFPVectorTy()
|
|
: LHS->getType()->isIntOrIntVectorTy();
|
|
|
|
if (!Valid)
|
|
return error(Loc, "invalid operand type for instruction");
|
|
|
|
Inst = UnaryOperator::Create((Instruction::UnaryOps)Opc, LHS);
|
|
return false;
|
|
}
|
|
|
|
/// parseCallBr
|
|
/// ::= 'callbr' OptionalCallingConv OptionalAttrs Type Value ParamList
|
|
/// OptionalAttrs OptionalOperandBundles 'to' TypeAndValue
|
|
/// '[' LabelList ']'
|
|
bool LLParser::parseCallBr(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy CallLoc = Lex.getLoc();
|
|
AttrBuilder RetAttrs, FnAttrs;
|
|
std::vector<unsigned> FwdRefAttrGrps;
|
|
LocTy NoBuiltinLoc;
|
|
unsigned CC;
|
|
Type *RetType = nullptr;
|
|
LocTy RetTypeLoc;
|
|
ValID CalleeID;
|
|
SmallVector<ParamInfo, 16> ArgList;
|
|
SmallVector<OperandBundleDef, 2> BundleList;
|
|
|
|
BasicBlock *DefaultDest;
|
|
if (parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
|
|
parseType(RetType, RetTypeLoc, true /*void allowed*/) ||
|
|
parseValID(CalleeID) || parseParameterList(ArgList, PFS) ||
|
|
parseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
|
|
NoBuiltinLoc) ||
|
|
parseOptionalOperandBundles(BundleList, PFS) ||
|
|
parseToken(lltok::kw_to, "expected 'to' in callbr") ||
|
|
parseTypeAndBasicBlock(DefaultDest, PFS) ||
|
|
parseToken(lltok::lsquare, "expected '[' in callbr"))
|
|
return true;
|
|
|
|
// parse the destination list.
|
|
SmallVector<BasicBlock *, 16> IndirectDests;
|
|
|
|
if (Lex.getKind() != lltok::rsquare) {
|
|
BasicBlock *DestBB;
|
|
if (parseTypeAndBasicBlock(DestBB, PFS))
|
|
return true;
|
|
IndirectDests.push_back(DestBB);
|
|
|
|
while (EatIfPresent(lltok::comma)) {
|
|
if (parseTypeAndBasicBlock(DestBB, PFS))
|
|
return true;
|
|
IndirectDests.push_back(DestBB);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rsquare, "expected ']' at end of block list"))
|
|
return true;
|
|
|
|
// If RetType is a non-function pointer type, then this is the short syntax
|
|
// for the call, which means that RetType is just the return type. Infer the
|
|
// rest of the function argument types from the arguments that are present.
|
|
FunctionType *Ty = dyn_cast<FunctionType>(RetType);
|
|
if (!Ty) {
|
|
// Pull out the types of all of the arguments...
|
|
std::vector<Type *> ParamTypes;
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
|
|
ParamTypes.push_back(ArgList[i].V->getType());
|
|
|
|
if (!FunctionType::isValidReturnType(RetType))
|
|
return error(RetTypeLoc, "Invalid result type for LLVM function");
|
|
|
|
Ty = FunctionType::get(RetType, ParamTypes, false);
|
|
}
|
|
|
|
CalleeID.FTy = Ty;
|
|
|
|
// Look up the callee.
|
|
Value *Callee;
|
|
if (convertValIDToValue(PointerType::getUnqual(Ty), CalleeID, Callee, &PFS,
|
|
/*IsCall=*/true))
|
|
return true;
|
|
|
|
// Set up the Attribute for the function.
|
|
SmallVector<Value *, 8> Args;
|
|
SmallVector<AttributeSet, 8> ArgAttrs;
|
|
|
|
// Loop through FunctionType's arguments and ensure they are specified
|
|
// correctly. Also, gather any parameter attributes.
|
|
FunctionType::param_iterator I = Ty->param_begin();
|
|
FunctionType::param_iterator E = Ty->param_end();
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i) {
|
|
Type *ExpectedTy = nullptr;
|
|
if (I != E) {
|
|
ExpectedTy = *I++;
|
|
} else if (!Ty->isVarArg()) {
|
|
return error(ArgList[i].Loc, "too many arguments specified");
|
|
}
|
|
|
|
if (ExpectedTy && ExpectedTy != ArgList[i].V->getType())
|
|
return error(ArgList[i].Loc, "argument is not of expected type '" +
|
|
getTypeString(ExpectedTy) + "'");
|
|
Args.push_back(ArgList[i].V);
|
|
ArgAttrs.push_back(ArgList[i].Attrs);
|
|
}
|
|
|
|
if (I != E)
|
|
return error(CallLoc, "not enough parameters specified for call");
|
|
|
|
if (FnAttrs.hasAlignmentAttr())
|
|
return error(CallLoc, "callbr instructions may not have an alignment");
|
|
|
|
// Finish off the Attribute and check them
|
|
AttributeList PAL =
|
|
AttributeList::get(Context, AttributeSet::get(Context, FnAttrs),
|
|
AttributeSet::get(Context, RetAttrs), ArgAttrs);
|
|
|
|
CallBrInst *CBI =
|
|
CallBrInst::Create(Ty, Callee, DefaultDest, IndirectDests, Args,
|
|
BundleList);
|
|
CBI->setCallingConv(CC);
|
|
CBI->setAttributes(PAL);
|
|
ForwardRefAttrGroups[CBI] = FwdRefAttrGrps;
|
|
Inst = CBI;
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Binary Operators.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseArithmetic
|
|
/// ::= ArithmeticOps TypeAndValue ',' Value
|
|
///
|
|
/// If IsFP is false, then any integer operand is allowed, if it is true, any fp
|
|
/// operand is allowed.
|
|
bool LLParser::parseArithmetic(Instruction *&Inst, PerFunctionState &PFS,
|
|
unsigned Opc, bool IsFP) {
|
|
LocTy Loc; Value *LHS, *RHS;
|
|
if (parseTypeAndValue(LHS, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' in arithmetic operation") ||
|
|
parseValue(LHS->getType(), RHS, PFS))
|
|
return true;
|
|
|
|
bool Valid = IsFP ? LHS->getType()->isFPOrFPVectorTy()
|
|
: LHS->getType()->isIntOrIntVectorTy();
|
|
|
|
if (!Valid)
|
|
return error(Loc, "invalid operand type for instruction");
|
|
|
|
Inst = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS);
|
|
return false;
|
|
}
|
|
|
|
/// parseLogical
|
|
/// ::= ArithmeticOps TypeAndValue ',' Value {
|
|
bool LLParser::parseLogical(Instruction *&Inst, PerFunctionState &PFS,
|
|
unsigned Opc) {
|
|
LocTy Loc; Value *LHS, *RHS;
|
|
if (parseTypeAndValue(LHS, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' in logical operation") ||
|
|
parseValue(LHS->getType(), RHS, PFS))
|
|
return true;
|
|
|
|
if (!LHS->getType()->isIntOrIntVectorTy())
|
|
return error(Loc,
|
|
"instruction requires integer or integer vector operands");
|
|
|
|
Inst = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS);
|
|
return false;
|
|
}
|
|
|
|
/// parseCompare
|
|
/// ::= 'icmp' IPredicates TypeAndValue ',' Value
|
|
/// ::= 'fcmp' FPredicates TypeAndValue ',' Value
|
|
bool LLParser::parseCompare(Instruction *&Inst, PerFunctionState &PFS,
|
|
unsigned Opc) {
|
|
// parse the integer/fp comparison predicate.
|
|
LocTy Loc;
|
|
unsigned Pred;
|
|
Value *LHS, *RHS;
|
|
if (parseCmpPredicate(Pred, Opc) || parseTypeAndValue(LHS, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after compare value") ||
|
|
parseValue(LHS->getType(), RHS, PFS))
|
|
return true;
|
|
|
|
if (Opc == Instruction::FCmp) {
|
|
if (!LHS->getType()->isFPOrFPVectorTy())
|
|
return error(Loc, "fcmp requires floating point operands");
|
|
Inst = new FCmpInst(CmpInst::Predicate(Pred), LHS, RHS);
|
|
} else {
|
|
assert(Opc == Instruction::ICmp && "Unknown opcode for CmpInst!");
|
|
if (!LHS->getType()->isIntOrIntVectorTy() &&
|
|
!LHS->getType()->isPtrOrPtrVectorTy())
|
|
return error(Loc, "icmp requires integer operands");
|
|
Inst = new ICmpInst(CmpInst::Predicate(Pred), LHS, RHS);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Other Instructions.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseCast
|
|
/// ::= CastOpc TypeAndValue 'to' Type
|
|
bool LLParser::parseCast(Instruction *&Inst, PerFunctionState &PFS,
|
|
unsigned Opc) {
|
|
LocTy Loc;
|
|
Value *Op;
|
|
Type *DestTy = nullptr;
|
|
if (parseTypeAndValue(Op, Loc, PFS) ||
|
|
parseToken(lltok::kw_to, "expected 'to' after cast value") ||
|
|
parseType(DestTy))
|
|
return true;
|
|
|
|
if (!CastInst::castIsValid((Instruction::CastOps)Opc, Op, DestTy)) {
|
|
CastInst::castIsValid((Instruction::CastOps)Opc, Op, DestTy);
|
|
return error(Loc, "invalid cast opcode for cast from '" +
|
|
getTypeString(Op->getType()) + "' to '" +
|
|
getTypeString(DestTy) + "'");
|
|
}
|
|
Inst = CastInst::Create((Instruction::CastOps)Opc, Op, DestTy);
|
|
return false;
|
|
}
|
|
|
|
/// parseSelect
|
|
/// ::= 'select' TypeAndValue ',' TypeAndValue ',' TypeAndValue
|
|
bool LLParser::parseSelect(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy Loc;
|
|
Value *Op0, *Op1, *Op2;
|
|
if (parseTypeAndValue(Op0, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after select condition") ||
|
|
parseTypeAndValue(Op1, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after select value") ||
|
|
parseTypeAndValue(Op2, PFS))
|
|
return true;
|
|
|
|
if (const char *Reason = SelectInst::areInvalidOperands(Op0, Op1, Op2))
|
|
return error(Loc, Reason);
|
|
|
|
Inst = SelectInst::Create(Op0, Op1, Op2);
|
|
return false;
|
|
}
|
|
|
|
/// parseVAArg
|
|
/// ::= 'va_arg' TypeAndValue ',' Type
|
|
bool LLParser::parseVAArg(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Op;
|
|
Type *EltTy = nullptr;
|
|
LocTy TypeLoc;
|
|
if (parseTypeAndValue(Op, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after vaarg operand") ||
|
|
parseType(EltTy, TypeLoc))
|
|
return true;
|
|
|
|
if (!EltTy->isFirstClassType())
|
|
return error(TypeLoc, "va_arg requires operand with first class type");
|
|
|
|
Inst = new VAArgInst(Op, EltTy);
|
|
return false;
|
|
}
|
|
|
|
/// parseExtractElement
|
|
/// ::= 'extractelement' TypeAndValue ',' TypeAndValue
|
|
bool LLParser::parseExtractElement(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy Loc;
|
|
Value *Op0, *Op1;
|
|
if (parseTypeAndValue(Op0, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after extract value") ||
|
|
parseTypeAndValue(Op1, PFS))
|
|
return true;
|
|
|
|
if (!ExtractElementInst::isValidOperands(Op0, Op1))
|
|
return error(Loc, "invalid extractelement operands");
|
|
|
|
Inst = ExtractElementInst::Create(Op0, Op1);
|
|
return false;
|
|
}
|
|
|
|
/// parseInsertElement
|
|
/// ::= 'insertelement' TypeAndValue ',' TypeAndValue ',' TypeAndValue
|
|
bool LLParser::parseInsertElement(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy Loc;
|
|
Value *Op0, *Op1, *Op2;
|
|
if (parseTypeAndValue(Op0, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after insertelement value") ||
|
|
parseTypeAndValue(Op1, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after insertelement value") ||
|
|
parseTypeAndValue(Op2, PFS))
|
|
return true;
|
|
|
|
if (!InsertElementInst::isValidOperands(Op0, Op1, Op2))
|
|
return error(Loc, "invalid insertelement operands");
|
|
|
|
Inst = InsertElementInst::Create(Op0, Op1, Op2);
|
|
return false;
|
|
}
|
|
|
|
/// parseShuffleVector
|
|
/// ::= 'shufflevector' TypeAndValue ',' TypeAndValue ',' TypeAndValue
|
|
bool LLParser::parseShuffleVector(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy Loc;
|
|
Value *Op0, *Op1, *Op2;
|
|
if (parseTypeAndValue(Op0, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after shuffle mask") ||
|
|
parseTypeAndValue(Op1, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after shuffle value") ||
|
|
parseTypeAndValue(Op2, PFS))
|
|
return true;
|
|
|
|
if (!ShuffleVectorInst::isValidOperands(Op0, Op1, Op2))
|
|
return error(Loc, "invalid shufflevector operands");
|
|
|
|
Inst = new ShuffleVectorInst(Op0, Op1, Op2);
|
|
return false;
|
|
}
|
|
|
|
/// parsePHI
|
|
/// ::= 'phi' Type '[' Value ',' Value ']' (',' '[' Value ',' Value ']')*
|
|
int LLParser::parsePHI(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Type *Ty = nullptr; LocTy TypeLoc;
|
|
Value *Op0, *Op1;
|
|
|
|
if (parseType(Ty, TypeLoc) ||
|
|
parseToken(lltok::lsquare, "expected '[' in phi value list") ||
|
|
parseValue(Ty, Op0, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after insertelement value") ||
|
|
parseValue(Type::getLabelTy(Context), Op1, PFS) ||
|
|
parseToken(lltok::rsquare, "expected ']' in phi value list"))
|
|
return true;
|
|
|
|
bool AteExtraComma = false;
|
|
SmallVector<std::pair<Value*, BasicBlock*>, 16> PHIVals;
|
|
|
|
while (true) {
|
|
PHIVals.push_back(std::make_pair(Op0, cast<BasicBlock>(Op1)));
|
|
|
|
if (!EatIfPresent(lltok::comma))
|
|
break;
|
|
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
AteExtraComma = true;
|
|
break;
|
|
}
|
|
|
|
if (parseToken(lltok::lsquare, "expected '[' in phi value list") ||
|
|
parseValue(Ty, Op0, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after insertelement value") ||
|
|
parseValue(Type::getLabelTy(Context), Op1, PFS) ||
|
|
parseToken(lltok::rsquare, "expected ']' in phi value list"))
|
|
return true;
|
|
}
|
|
|
|
if (!Ty->isFirstClassType())
|
|
return error(TypeLoc, "phi node must have first class type");
|
|
|
|
PHINode *PN = PHINode::Create(Ty, PHIVals.size());
|
|
for (unsigned i = 0, e = PHIVals.size(); i != e; ++i)
|
|
PN->addIncoming(PHIVals[i].first, PHIVals[i].second);
|
|
Inst = PN;
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseLandingPad
|
|
/// ::= 'landingpad' Type 'personality' TypeAndValue 'cleanup'? Clause+
|
|
/// Clause
|
|
/// ::= 'catch' TypeAndValue
|
|
/// ::= 'filter'
|
|
/// ::= 'filter' TypeAndValue ( ',' TypeAndValue )*
|
|
bool LLParser::parseLandingPad(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Type *Ty = nullptr; LocTy TyLoc;
|
|
|
|
if (parseType(Ty, TyLoc))
|
|
return true;
|
|
|
|
std::unique_ptr<LandingPadInst> LP(LandingPadInst::Create(Ty, 0));
|
|
LP->setCleanup(EatIfPresent(lltok::kw_cleanup));
|
|
|
|
while (Lex.getKind() == lltok::kw_catch || Lex.getKind() == lltok::kw_filter){
|
|
LandingPadInst::ClauseType CT;
|
|
if (EatIfPresent(lltok::kw_catch))
|
|
CT = LandingPadInst::Catch;
|
|
else if (EatIfPresent(lltok::kw_filter))
|
|
CT = LandingPadInst::Filter;
|
|
else
|
|
return tokError("expected 'catch' or 'filter' clause type");
|
|
|
|
Value *V;
|
|
LocTy VLoc;
|
|
if (parseTypeAndValue(V, VLoc, PFS))
|
|
return true;
|
|
|
|
// A 'catch' type expects a non-array constant. A filter clause expects an
|
|
// array constant.
|
|
if (CT == LandingPadInst::Catch) {
|
|
if (isa<ArrayType>(V->getType()))
|
|
error(VLoc, "'catch' clause has an invalid type");
|
|
} else {
|
|
if (!isa<ArrayType>(V->getType()))
|
|
error(VLoc, "'filter' clause has an invalid type");
|
|
}
|
|
|
|
Constant *CV = dyn_cast<Constant>(V);
|
|
if (!CV)
|
|
return error(VLoc, "clause argument must be a constant");
|
|
LP->addClause(CV);
|
|
}
|
|
|
|
Inst = LP.release();
|
|
return false;
|
|
}
|
|
|
|
/// parseFreeze
|
|
/// ::= 'freeze' Type Value
|
|
bool LLParser::parseFreeze(Instruction *&Inst, PerFunctionState &PFS) {
|
|
LocTy Loc;
|
|
Value *Op;
|
|
if (parseTypeAndValue(Op, Loc, PFS))
|
|
return true;
|
|
|
|
Inst = new FreezeInst(Op);
|
|
return false;
|
|
}
|
|
|
|
/// parseCall
|
|
/// ::= 'call' OptionalFastMathFlags OptionalCallingConv
|
|
/// OptionalAttrs Type Value ParameterList OptionalAttrs
|
|
/// ::= 'tail' 'call' OptionalFastMathFlags OptionalCallingConv
|
|
/// OptionalAttrs Type Value ParameterList OptionalAttrs
|
|
/// ::= 'musttail' 'call' OptionalFastMathFlags OptionalCallingConv
|
|
/// OptionalAttrs Type Value ParameterList OptionalAttrs
|
|
/// ::= 'notail' 'call' OptionalFastMathFlags OptionalCallingConv
|
|
/// OptionalAttrs Type Value ParameterList OptionalAttrs
|
|
bool LLParser::parseCall(Instruction *&Inst, PerFunctionState &PFS,
|
|
CallInst::TailCallKind TCK) {
|
|
AttrBuilder RetAttrs, FnAttrs;
|
|
std::vector<unsigned> FwdRefAttrGrps;
|
|
LocTy BuiltinLoc;
|
|
unsigned CallAddrSpace;
|
|
unsigned CC;
|
|
Type *RetType = nullptr;
|
|
LocTy RetTypeLoc;
|
|
ValID CalleeID;
|
|
SmallVector<ParamInfo, 16> ArgList;
|
|
SmallVector<OperandBundleDef, 2> BundleList;
|
|
LocTy CallLoc = Lex.getLoc();
|
|
|
|
if (TCK != CallInst::TCK_None &&
|
|
parseToken(lltok::kw_call,
|
|
"expected 'tail call', 'musttail call', or 'notail call'"))
|
|
return true;
|
|
|
|
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
|
|
|
if (parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
|
|
parseOptionalProgramAddrSpace(CallAddrSpace) ||
|
|
parseType(RetType, RetTypeLoc, true /*void allowed*/) ||
|
|
parseValID(CalleeID) ||
|
|
parseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail,
|
|
PFS.getFunction().isVarArg()) ||
|
|
parseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, BuiltinLoc) ||
|
|
parseOptionalOperandBundles(BundleList, PFS))
|
|
return true;
|
|
|
|
// If RetType is a non-function pointer type, then this is the short syntax
|
|
// for the call, which means that RetType is just the return type. Infer the
|
|
// rest of the function argument types from the arguments that are present.
|
|
FunctionType *Ty = dyn_cast<FunctionType>(RetType);
|
|
if (!Ty) {
|
|
// Pull out the types of all of the arguments...
|
|
std::vector<Type*> ParamTypes;
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
|
|
ParamTypes.push_back(ArgList[i].V->getType());
|
|
|
|
if (!FunctionType::isValidReturnType(RetType))
|
|
return error(RetTypeLoc, "Invalid result type for LLVM function");
|
|
|
|
Ty = FunctionType::get(RetType, ParamTypes, false);
|
|
}
|
|
|
|
CalleeID.FTy = Ty;
|
|
|
|
// Look up the callee.
|
|
Value *Callee;
|
|
if (convertValIDToValue(PointerType::get(Ty, CallAddrSpace), CalleeID, Callee,
|
|
&PFS, /*IsCall=*/true))
|
|
return true;
|
|
|
|
// Set up the Attribute for the function.
|
|
SmallVector<AttributeSet, 8> Attrs;
|
|
|
|
SmallVector<Value*, 8> Args;
|
|
|
|
// Loop through FunctionType's arguments and ensure they are specified
|
|
// correctly. Also, gather any parameter attributes.
|
|
FunctionType::param_iterator I = Ty->param_begin();
|
|
FunctionType::param_iterator E = Ty->param_end();
|
|
for (unsigned i = 0, e = ArgList.size(); i != e; ++i) {
|
|
Type *ExpectedTy = nullptr;
|
|
if (I != E) {
|
|
ExpectedTy = *I++;
|
|
} else if (!Ty->isVarArg()) {
|
|
return error(ArgList[i].Loc, "too many arguments specified");
|
|
}
|
|
|
|
if (ExpectedTy && ExpectedTy != ArgList[i].V->getType())
|
|
return error(ArgList[i].Loc, "argument is not of expected type '" +
|
|
getTypeString(ExpectedTy) + "'");
|
|
Args.push_back(ArgList[i].V);
|
|
Attrs.push_back(ArgList[i].Attrs);
|
|
}
|
|
|
|
if (I != E)
|
|
return error(CallLoc, "not enough parameters specified for call");
|
|
|
|
if (FnAttrs.hasAlignmentAttr())
|
|
return error(CallLoc, "call instructions may not have an alignment");
|
|
|
|
// Finish off the Attribute and check them
|
|
AttributeList PAL =
|
|
AttributeList::get(Context, AttributeSet::get(Context, FnAttrs),
|
|
AttributeSet::get(Context, RetAttrs), Attrs);
|
|
|
|
CallInst *CI = CallInst::Create(Ty, Callee, Args, BundleList);
|
|
CI->setTailCallKind(TCK);
|
|
CI->setCallingConv(CC);
|
|
if (FMF.any()) {
|
|
if (!isa<FPMathOperator>(CI)) {
|
|
CI->deleteValue();
|
|
return error(CallLoc, "fast-math-flags specified for call without "
|
|
"floating-point scalar or vector return type");
|
|
}
|
|
CI->setFastMathFlags(FMF);
|
|
}
|
|
CI->setAttributes(PAL);
|
|
ForwardRefAttrGroups[CI] = FwdRefAttrGrps;
|
|
Inst = CI;
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Memory Instructions.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseAlloc
|
|
/// ::= 'alloca' 'inalloca'? 'swifterror'? Type (',' TypeAndValue)?
|
|
/// (',' 'align' i32)? (',', 'addrspace(n))?
|
|
int LLParser::parseAlloc(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Size = nullptr;
|
|
LocTy SizeLoc, TyLoc, ASLoc;
|
|
MaybeAlign Alignment;
|
|
unsigned AddrSpace = 0;
|
|
Type *Ty = nullptr;
|
|
|
|
bool IsInAlloca = EatIfPresent(lltok::kw_inalloca);
|
|
bool IsSwiftError = EatIfPresent(lltok::kw_swifterror);
|
|
|
|
if (parseType(Ty, TyLoc))
|
|
return true;
|
|
|
|
if (Ty->isFunctionTy() || !PointerType::isValidElementType(Ty))
|
|
return error(TyLoc, "invalid type for alloca");
|
|
|
|
bool AteExtraComma = false;
|
|
if (EatIfPresent(lltok::comma)) {
|
|
if (Lex.getKind() == lltok::kw_align) {
|
|
if (parseOptionalAlignment(Alignment))
|
|
return true;
|
|
if (parseOptionalCommaAddrSpace(AddrSpace, ASLoc, AteExtraComma))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::kw_addrspace) {
|
|
ASLoc = Lex.getLoc();
|
|
if (parseOptionalAddrSpace(AddrSpace))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::MetadataVar) {
|
|
AteExtraComma = true;
|
|
} else {
|
|
if (parseTypeAndValue(Size, SizeLoc, PFS))
|
|
return true;
|
|
if (EatIfPresent(lltok::comma)) {
|
|
if (Lex.getKind() == lltok::kw_align) {
|
|
if (parseOptionalAlignment(Alignment))
|
|
return true;
|
|
if (parseOptionalCommaAddrSpace(AddrSpace, ASLoc, AteExtraComma))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::kw_addrspace) {
|
|
ASLoc = Lex.getLoc();
|
|
if (parseOptionalAddrSpace(AddrSpace))
|
|
return true;
|
|
} else if (Lex.getKind() == lltok::MetadataVar) {
|
|
AteExtraComma = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Size && !Size->getType()->isIntegerTy())
|
|
return error(SizeLoc, "element count must have integer type");
|
|
|
|
SmallPtrSet<Type *, 4> Visited;
|
|
if (!Alignment && !Ty->isSized(&Visited))
|
|
return error(TyLoc, "Cannot allocate unsized type");
|
|
if (!Alignment)
|
|
Alignment = M->getDataLayout().getPrefTypeAlign(Ty);
|
|
AllocaInst *AI = new AllocaInst(Ty, AddrSpace, Size, *Alignment);
|
|
AI->setUsedWithInAlloca(IsInAlloca);
|
|
AI->setSwiftError(IsSwiftError);
|
|
Inst = AI;
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseLoad
|
|
/// ::= 'load' 'volatile'? TypeAndValue (',' 'align' i32)?
|
|
/// ::= 'load' 'atomic' 'volatile'? TypeAndValue
|
|
/// 'singlethread'? AtomicOrdering (',' 'align' i32)?
|
|
int LLParser::parseLoad(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Val; LocTy Loc;
|
|
MaybeAlign Alignment;
|
|
bool AteExtraComma = false;
|
|
bool isAtomic = false;
|
|
AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
|
|
SyncScope::ID SSID = SyncScope::System;
|
|
|
|
if (Lex.getKind() == lltok::kw_atomic) {
|
|
isAtomic = true;
|
|
Lex.Lex();
|
|
}
|
|
|
|
bool isVolatile = false;
|
|
if (Lex.getKind() == lltok::kw_volatile) {
|
|
isVolatile = true;
|
|
Lex.Lex();
|
|
}
|
|
|
|
Type *Ty;
|
|
LocTy ExplicitTypeLoc = Lex.getLoc();
|
|
if (parseType(Ty) ||
|
|
parseToken(lltok::comma, "expected comma after load's type") ||
|
|
parseTypeAndValue(Val, Loc, PFS) ||
|
|
parseScopeAndOrdering(isAtomic, SSID, Ordering) ||
|
|
parseOptionalCommaAlign(Alignment, AteExtraComma))
|
|
return true;
|
|
|
|
if (!Val->getType()->isPointerTy() || !Ty->isFirstClassType())
|
|
return error(Loc, "load operand must be a pointer to a first class type");
|
|
if (isAtomic && !Alignment)
|
|
return error(Loc, "atomic load must have explicit non-zero alignment");
|
|
if (Ordering == AtomicOrdering::Release ||
|
|
Ordering == AtomicOrdering::AcquireRelease)
|
|
return error(Loc, "atomic load cannot use Release ordering");
|
|
|
|
if (Ty != cast<PointerType>(Val->getType())->getElementType())
|
|
return error(ExplicitTypeLoc,
|
|
"explicit pointee type doesn't match operand's pointee type");
|
|
SmallPtrSet<Type *, 4> Visited;
|
|
if (!Alignment && !Ty->isSized(&Visited))
|
|
return error(ExplicitTypeLoc, "loading unsized types is not allowed");
|
|
if (!Alignment)
|
|
Alignment = M->getDataLayout().getABITypeAlign(Ty);
|
|
Inst = new LoadInst(Ty, Val, "", isVolatile, *Alignment, Ordering, SSID);
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseStore
|
|
|
|
/// ::= 'store' 'volatile'? TypeAndValue ',' TypeAndValue (',' 'align' i32)?
|
|
/// ::= 'store' 'atomic' 'volatile'? TypeAndValue ',' TypeAndValue
|
|
/// 'singlethread'? AtomicOrdering (',' 'align' i32)?
|
|
int LLParser::parseStore(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Val, *Ptr; LocTy Loc, PtrLoc;
|
|
MaybeAlign Alignment;
|
|
bool AteExtraComma = false;
|
|
bool isAtomic = false;
|
|
AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
|
|
SyncScope::ID SSID = SyncScope::System;
|
|
|
|
if (Lex.getKind() == lltok::kw_atomic) {
|
|
isAtomic = true;
|
|
Lex.Lex();
|
|
}
|
|
|
|
bool isVolatile = false;
|
|
if (Lex.getKind() == lltok::kw_volatile) {
|
|
isVolatile = true;
|
|
Lex.Lex();
|
|
}
|
|
|
|
if (parseTypeAndValue(Val, Loc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after store operand") ||
|
|
parseTypeAndValue(Ptr, PtrLoc, PFS) ||
|
|
parseScopeAndOrdering(isAtomic, SSID, Ordering) ||
|
|
parseOptionalCommaAlign(Alignment, AteExtraComma))
|
|
return true;
|
|
|
|
if (!Ptr->getType()->isPointerTy())
|
|
return error(PtrLoc, "store operand must be a pointer");
|
|
if (!Val->getType()->isFirstClassType())
|
|
return error(Loc, "store operand must be a first class value");
|
|
if (cast<PointerType>(Ptr->getType())->getElementType() != Val->getType())
|
|
return error(Loc, "stored value and pointer type do not match");
|
|
if (isAtomic && !Alignment)
|
|
return error(Loc, "atomic store must have explicit non-zero alignment");
|
|
if (Ordering == AtomicOrdering::Acquire ||
|
|
Ordering == AtomicOrdering::AcquireRelease)
|
|
return error(Loc, "atomic store cannot use Acquire ordering");
|
|
SmallPtrSet<Type *, 4> Visited;
|
|
if (!Alignment && !Val->getType()->isSized(&Visited))
|
|
return error(Loc, "storing unsized types is not allowed");
|
|
if (!Alignment)
|
|
Alignment = M->getDataLayout().getABITypeAlign(Val->getType());
|
|
|
|
Inst = new StoreInst(Val, Ptr, isVolatile, *Alignment, Ordering, SSID);
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseCmpXchg
|
|
/// ::= 'cmpxchg' 'weak'? 'volatile'? TypeAndValue ',' TypeAndValue ','
|
|
/// TypeAndValue 'singlethread'? AtomicOrdering AtomicOrdering
|
|
int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Ptr, *Cmp, *New; LocTy PtrLoc, CmpLoc, NewLoc;
|
|
bool AteExtraComma = false;
|
|
AtomicOrdering SuccessOrdering = AtomicOrdering::NotAtomic;
|
|
AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
|
|
SyncScope::ID SSID = SyncScope::System;
|
|
bool isVolatile = false;
|
|
bool isWeak = false;
|
|
|
|
if (EatIfPresent(lltok::kw_weak))
|
|
isWeak = true;
|
|
|
|
if (EatIfPresent(lltok::kw_volatile))
|
|
isVolatile = true;
|
|
|
|
if (parseTypeAndValue(Ptr, PtrLoc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after cmpxchg address") ||
|
|
parseTypeAndValue(Cmp, CmpLoc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after cmpxchg cmp operand") ||
|
|
parseTypeAndValue(New, NewLoc, PFS) ||
|
|
parseScopeAndOrdering(true /*Always atomic*/, SSID, SuccessOrdering) ||
|
|
parseOrdering(FailureOrdering))
|
|
return true;
|
|
|
|
if (SuccessOrdering == AtomicOrdering::Unordered ||
|
|
FailureOrdering == AtomicOrdering::Unordered)
|
|
return tokError("cmpxchg cannot be unordered");
|
|
if (isStrongerThan(FailureOrdering, SuccessOrdering))
|
|
return tokError("cmpxchg failure argument shall be no stronger than the "
|
|
"success argument");
|
|
if (FailureOrdering == AtomicOrdering::Release ||
|
|
FailureOrdering == AtomicOrdering::AcquireRelease)
|
|
return tokError(
|
|
"cmpxchg failure ordering cannot include release semantics");
|
|
if (!Ptr->getType()->isPointerTy())
|
|
return error(PtrLoc, "cmpxchg operand must be a pointer");
|
|
if (cast<PointerType>(Ptr->getType())->getElementType() != Cmp->getType())
|
|
return error(CmpLoc, "compare value and pointer type do not match");
|
|
if (cast<PointerType>(Ptr->getType())->getElementType() != New->getType())
|
|
return error(NewLoc, "new value and pointer type do not match");
|
|
if (!New->getType()->isFirstClassType())
|
|
return error(NewLoc, "cmpxchg operand must be a first class value");
|
|
|
|
Align Alignment(
|
|
PFS.getFunction().getParent()->getDataLayout().getTypeStoreSize(
|
|
Cmp->getType()));
|
|
|
|
AtomicCmpXchgInst *CXI = new AtomicCmpXchgInst(
|
|
Ptr, Cmp, New, Alignment, SuccessOrdering, FailureOrdering, SSID);
|
|
CXI->setVolatile(isVolatile);
|
|
CXI->setWeak(isWeak);
|
|
Inst = CXI;
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseAtomicRMW
|
|
/// ::= 'atomicrmw' 'volatile'? BinOp TypeAndValue ',' TypeAndValue
|
|
/// 'singlethread'? AtomicOrdering
|
|
int LLParser::parseAtomicRMW(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Ptr, *Val; LocTy PtrLoc, ValLoc;
|
|
bool AteExtraComma = false;
|
|
AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
|
|
SyncScope::ID SSID = SyncScope::System;
|
|
bool isVolatile = false;
|
|
bool IsFP = false;
|
|
AtomicRMWInst::BinOp Operation;
|
|
|
|
if (EatIfPresent(lltok::kw_volatile))
|
|
isVolatile = true;
|
|
|
|
switch (Lex.getKind()) {
|
|
default:
|
|
return tokError("expected binary operation in atomicrmw");
|
|
case lltok::kw_xchg: Operation = AtomicRMWInst::Xchg; break;
|
|
case lltok::kw_add: Operation = AtomicRMWInst::Add; break;
|
|
case lltok::kw_sub: Operation = AtomicRMWInst::Sub; break;
|
|
case lltok::kw_and: Operation = AtomicRMWInst::And; break;
|
|
case lltok::kw_nand: Operation = AtomicRMWInst::Nand; break;
|
|
case lltok::kw_or: Operation = AtomicRMWInst::Or; break;
|
|
case lltok::kw_xor: Operation = AtomicRMWInst::Xor; break;
|
|
case lltok::kw_max: Operation = AtomicRMWInst::Max; break;
|
|
case lltok::kw_min: Operation = AtomicRMWInst::Min; break;
|
|
case lltok::kw_umax: Operation = AtomicRMWInst::UMax; break;
|
|
case lltok::kw_umin: Operation = AtomicRMWInst::UMin; break;
|
|
case lltok::kw_fadd:
|
|
Operation = AtomicRMWInst::FAdd;
|
|
IsFP = true;
|
|
break;
|
|
case lltok::kw_fsub:
|
|
Operation = AtomicRMWInst::FSub;
|
|
IsFP = true;
|
|
break;
|
|
}
|
|
Lex.Lex(); // Eat the operation.
|
|
|
|
if (parseTypeAndValue(Ptr, PtrLoc, PFS) ||
|
|
parseToken(lltok::comma, "expected ',' after atomicrmw address") ||
|
|
parseTypeAndValue(Val, ValLoc, PFS) ||
|
|
parseScopeAndOrdering(true /*Always atomic*/, SSID, Ordering))
|
|
return true;
|
|
|
|
if (Ordering == AtomicOrdering::Unordered)
|
|
return tokError("atomicrmw cannot be unordered");
|
|
if (!Ptr->getType()->isPointerTy())
|
|
return error(PtrLoc, "atomicrmw operand must be a pointer");
|
|
if (cast<PointerType>(Ptr->getType())->getElementType() != Val->getType())
|
|
return error(ValLoc, "atomicrmw value and pointer type do not match");
|
|
|
|
if (Operation == AtomicRMWInst::Xchg) {
|
|
if (!Val->getType()->isIntegerTy() &&
|
|
!Val->getType()->isFloatingPointTy()) {
|
|
return error(ValLoc,
|
|
"atomicrmw " + AtomicRMWInst::getOperationName(Operation) +
|
|
" operand must be an integer or floating point type");
|
|
}
|
|
} else if (IsFP) {
|
|
if (!Val->getType()->isFloatingPointTy()) {
|
|
return error(ValLoc, "atomicrmw " +
|
|
AtomicRMWInst::getOperationName(Operation) +
|
|
" operand must be a floating point type");
|
|
}
|
|
} else {
|
|
if (!Val->getType()->isIntegerTy()) {
|
|
return error(ValLoc, "atomicrmw " +
|
|
AtomicRMWInst::getOperationName(Operation) +
|
|
" operand must be an integer");
|
|
}
|
|
}
|
|
|
|
unsigned Size = Val->getType()->getPrimitiveSizeInBits();
|
|
if (Size < 8 || (Size & (Size - 1)))
|
|
return error(ValLoc, "atomicrmw operand must be power-of-two byte-sized"
|
|
" integer");
|
|
Align Alignment(
|
|
PFS.getFunction().getParent()->getDataLayout().getTypeStoreSize(
|
|
Val->getType()));
|
|
AtomicRMWInst *RMWI =
|
|
new AtomicRMWInst(Operation, Ptr, Val, Alignment, Ordering, SSID);
|
|
RMWI->setVolatile(isVolatile);
|
|
Inst = RMWI;
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseFence
|
|
/// ::= 'fence' 'singlethread'? AtomicOrdering
|
|
int LLParser::parseFence(Instruction *&Inst, PerFunctionState &PFS) {
|
|
AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
|
|
SyncScope::ID SSID = SyncScope::System;
|
|
if (parseScopeAndOrdering(true /*Always atomic*/, SSID, Ordering))
|
|
return true;
|
|
|
|
if (Ordering == AtomicOrdering::Unordered)
|
|
return tokError("fence cannot be unordered");
|
|
if (Ordering == AtomicOrdering::Monotonic)
|
|
return tokError("fence cannot be monotonic");
|
|
|
|
Inst = new FenceInst(Context, Ordering, SSID);
|
|
return InstNormal;
|
|
}
|
|
|
|
/// parseGetElementPtr
|
|
/// ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)*
|
|
int LLParser::parseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Ptr = nullptr;
|
|
Value *Val = nullptr;
|
|
LocTy Loc, EltLoc;
|
|
|
|
bool InBounds = EatIfPresent(lltok::kw_inbounds);
|
|
|
|
Type *Ty = nullptr;
|
|
LocTy ExplicitTypeLoc = Lex.getLoc();
|
|
if (parseType(Ty) ||
|
|
parseToken(lltok::comma, "expected comma after getelementptr's type") ||
|
|
parseTypeAndValue(Ptr, Loc, PFS))
|
|
return true;
|
|
|
|
Type *BaseType = Ptr->getType();
|
|
PointerType *BasePointerType = dyn_cast<PointerType>(BaseType->getScalarType());
|
|
if (!BasePointerType)
|
|
return error(Loc, "base of getelementptr must be a pointer");
|
|
|
|
if (Ty != BasePointerType->getElementType())
|
|
return error(ExplicitTypeLoc,
|
|
"explicit pointee type doesn't match operand's pointee type");
|
|
|
|
SmallVector<Value*, 16> Indices;
|
|
bool AteExtraComma = false;
|
|
// GEP returns a vector of pointers if at least one of parameters is a vector.
|
|
// All vector parameters should have the same vector width.
|
|
ElementCount GEPWidth = BaseType->isVectorTy()
|
|
? cast<VectorType>(BaseType)->getElementCount()
|
|
: ElementCount::getFixed(0);
|
|
|
|
while (EatIfPresent(lltok::comma)) {
|
|
if (Lex.getKind() == lltok::MetadataVar) {
|
|
AteExtraComma = true;
|
|
break;
|
|
}
|
|
if (parseTypeAndValue(Val, EltLoc, PFS))
|
|
return true;
|
|
if (!Val->getType()->isIntOrIntVectorTy())
|
|
return error(EltLoc, "getelementptr index must be an integer");
|
|
|
|
if (auto *ValVTy = dyn_cast<VectorType>(Val->getType())) {
|
|
ElementCount ValNumEl = ValVTy->getElementCount();
|
|
if (GEPWidth != ElementCount::getFixed(0) && GEPWidth != ValNumEl)
|
|
return error(
|
|
EltLoc,
|
|
"getelementptr vector index has a wrong number of elements");
|
|
GEPWidth = ValNumEl;
|
|
}
|
|
Indices.push_back(Val);
|
|
}
|
|
|
|
SmallPtrSet<Type*, 4> Visited;
|
|
if (!Indices.empty() && !Ty->isSized(&Visited))
|
|
return error(Loc, "base element of getelementptr must be sized");
|
|
|
|
if (!GetElementPtrInst::getIndexedType(Ty, Indices))
|
|
return error(Loc, "invalid getelementptr indices");
|
|
Inst = GetElementPtrInst::Create(Ty, Ptr, Indices);
|
|
if (InBounds)
|
|
cast<GetElementPtrInst>(Inst)->setIsInBounds(true);
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseExtractValue
|
|
/// ::= 'extractvalue' TypeAndValue (',' uint32)+
|
|
int LLParser::parseExtractValue(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Val; LocTy Loc;
|
|
SmallVector<unsigned, 4> Indices;
|
|
bool AteExtraComma;
|
|
if (parseTypeAndValue(Val, Loc, PFS) ||
|
|
parseIndexList(Indices, AteExtraComma))
|
|
return true;
|
|
|
|
if (!Val->getType()->isAggregateType())
|
|
return error(Loc, "extractvalue operand must be aggregate type");
|
|
|
|
if (!ExtractValueInst::getIndexedType(Val->getType(), Indices))
|
|
return error(Loc, "invalid indices for extractvalue");
|
|
Inst = ExtractValueInst::Create(Val, Indices);
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
/// parseInsertValue
|
|
/// ::= 'insertvalue' TypeAndValue ',' TypeAndValue (',' uint32)+
|
|
int LLParser::parseInsertValue(Instruction *&Inst, PerFunctionState &PFS) {
|
|
Value *Val0, *Val1; LocTy Loc0, Loc1;
|
|
SmallVector<unsigned, 4> Indices;
|
|
bool AteExtraComma;
|
|
if (parseTypeAndValue(Val0, Loc0, PFS) ||
|
|
parseToken(lltok::comma, "expected comma after insertvalue operand") ||
|
|
parseTypeAndValue(Val1, Loc1, PFS) ||
|
|
parseIndexList(Indices, AteExtraComma))
|
|
return true;
|
|
|
|
if (!Val0->getType()->isAggregateType())
|
|
return error(Loc0, "insertvalue operand must be aggregate type");
|
|
|
|
Type *IndexedType = ExtractValueInst::getIndexedType(Val0->getType(), Indices);
|
|
if (!IndexedType)
|
|
return error(Loc0, "invalid indices for insertvalue");
|
|
if (IndexedType != Val1->getType())
|
|
return error(Loc1, "insertvalue operand and field disagree in type: '" +
|
|
getTypeString(Val1->getType()) + "' instead of '" +
|
|
getTypeString(IndexedType) + "'");
|
|
Inst = InsertValueInst::Create(Val0, Val1, Indices);
|
|
return AteExtraComma ? InstExtraComma : InstNormal;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Embedded metadata.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseMDNodeVector
|
|
/// ::= { Element (',' Element)* }
|
|
/// Element
|
|
/// ::= 'null' | TypeAndValue
|
|
bool LLParser::parseMDNodeVector(SmallVectorImpl<Metadata *> &Elts) {
|
|
if (parseToken(lltok::lbrace, "expected '{' here"))
|
|
return true;
|
|
|
|
// Check for an empty list.
|
|
if (EatIfPresent(lltok::rbrace))
|
|
return false;
|
|
|
|
do {
|
|
// Null is a special case since it is typeless.
|
|
if (EatIfPresent(lltok::kw_null)) {
|
|
Elts.push_back(nullptr);
|
|
continue;
|
|
}
|
|
|
|
Metadata *MD;
|
|
if (parseMetadata(MD, nullptr))
|
|
return true;
|
|
Elts.push_back(MD);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
return parseToken(lltok::rbrace, "expected end of metadata node");
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Use-list order directives.
|
|
//===----------------------------------------------------------------------===//
|
|
bool LLParser::sortUseListOrder(Value *V, ArrayRef<unsigned> Indexes,
|
|
SMLoc Loc) {
|
|
if (V->use_empty())
|
|
return error(Loc, "value has no uses");
|
|
|
|
unsigned NumUses = 0;
|
|
SmallDenseMap<const Use *, unsigned, 16> Order;
|
|
for (const Use &U : V->uses()) {
|
|
if (++NumUses > Indexes.size())
|
|
break;
|
|
Order[&U] = Indexes[NumUses - 1];
|
|
}
|
|
if (NumUses < 2)
|
|
return error(Loc, "value only has one use");
|
|
if (Order.size() != Indexes.size() || NumUses > Indexes.size())
|
|
return error(Loc,
|
|
"wrong number of indexes, expected " + Twine(V->getNumUses()));
|
|
|
|
V->sortUseList([&](const Use &L, const Use &R) {
|
|
return Order.lookup(&L) < Order.lookup(&R);
|
|
});
|
|
return false;
|
|
}
|
|
|
|
/// parseUseListOrderIndexes
|
|
/// ::= '{' uint32 (',' uint32)+ '}'
|
|
bool LLParser::parseUseListOrderIndexes(SmallVectorImpl<unsigned> &Indexes) {
|
|
SMLoc Loc = Lex.getLoc();
|
|
if (parseToken(lltok::lbrace, "expected '{' here"))
|
|
return true;
|
|
if (Lex.getKind() == lltok::rbrace)
|
|
return Lex.Error("expected non-empty list of uselistorder indexes");
|
|
|
|
// Use Offset, Max, and IsOrdered to check consistency of indexes. The
|
|
// indexes should be distinct numbers in the range [0, size-1], and should
|
|
// not be in order.
|
|
unsigned Offset = 0;
|
|
unsigned Max = 0;
|
|
bool IsOrdered = true;
|
|
assert(Indexes.empty() && "Expected empty order vector");
|
|
do {
|
|
unsigned Index;
|
|
if (parseUInt32(Index))
|
|
return true;
|
|
|
|
// Update consistency checks.
|
|
Offset += Index - Indexes.size();
|
|
Max = std::max(Max, Index);
|
|
IsOrdered &= Index == Indexes.size();
|
|
|
|
Indexes.push_back(Index);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rbrace, "expected '}' here"))
|
|
return true;
|
|
|
|
if (Indexes.size() < 2)
|
|
return error(Loc, "expected >= 2 uselistorder indexes");
|
|
if (Offset != 0 || Max >= Indexes.size())
|
|
return error(Loc,
|
|
"expected distinct uselistorder indexes in range [0, size)");
|
|
if (IsOrdered)
|
|
return error(Loc, "expected uselistorder indexes to change the order");
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseUseListOrder
|
|
/// ::= 'uselistorder' Type Value ',' UseListOrderIndexes
|
|
bool LLParser::parseUseListOrder(PerFunctionState *PFS) {
|
|
SMLoc Loc = Lex.getLoc();
|
|
if (parseToken(lltok::kw_uselistorder, "expected uselistorder directive"))
|
|
return true;
|
|
|
|
Value *V;
|
|
SmallVector<unsigned, 16> Indexes;
|
|
if (parseTypeAndValue(V, PFS) ||
|
|
parseToken(lltok::comma, "expected comma in uselistorder directive") ||
|
|
parseUseListOrderIndexes(Indexes))
|
|
return true;
|
|
|
|
return sortUseListOrder(V, Indexes, Loc);
|
|
}
|
|
|
|
/// parseUseListOrderBB
|
|
/// ::= 'uselistorder_bb' @foo ',' %bar ',' UseListOrderIndexes
|
|
bool LLParser::parseUseListOrderBB() {
|
|
assert(Lex.getKind() == lltok::kw_uselistorder_bb);
|
|
SMLoc Loc = Lex.getLoc();
|
|
Lex.Lex();
|
|
|
|
ValID Fn, Label;
|
|
SmallVector<unsigned, 16> Indexes;
|
|
if (parseValID(Fn) ||
|
|
parseToken(lltok::comma, "expected comma in uselistorder_bb directive") ||
|
|
parseValID(Label) ||
|
|
parseToken(lltok::comma, "expected comma in uselistorder_bb directive") ||
|
|
parseUseListOrderIndexes(Indexes))
|
|
return true;
|
|
|
|
// Check the function.
|
|
GlobalValue *GV;
|
|
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;
|
|
else
|
|
return error(Fn.Loc, "expected function name in uselistorder_bb");
|
|
if (!GV)
|
|
return error(Fn.Loc,
|
|
"invalid function forward reference in uselistorder_bb");
|
|
auto *F = dyn_cast<Function>(GV);
|
|
if (!F)
|
|
return error(Fn.Loc, "expected function name in uselistorder_bb");
|
|
if (F->isDeclaration())
|
|
return error(Fn.Loc, "invalid declaration in uselistorder_bb");
|
|
|
|
// Check the basic block.
|
|
if (Label.Kind == ValID::t_LocalID)
|
|
return error(Label.Loc, "invalid numeric label in uselistorder_bb");
|
|
if (Label.Kind != ValID::t_LocalName)
|
|
return error(Label.Loc, "expected basic block name in uselistorder_bb");
|
|
Value *V = F->getValueSymbolTable()->lookup(Label.StrVal);
|
|
if (!V)
|
|
return error(Label.Loc, "invalid basic block in uselistorder_bb");
|
|
if (!isa<BasicBlock>(V))
|
|
return error(Label.Loc, "expected basic block in uselistorder_bb");
|
|
|
|
return sortUseListOrder(V, Indexes, Loc);
|
|
}
|
|
|
|
/// ModuleEntry
|
|
/// ::= 'module' ':' '(' 'path' ':' STRINGCONSTANT ',' 'hash' ':' Hash ')'
|
|
/// Hash ::= '(' UInt32 ',' UInt32 ',' UInt32 ',' UInt32 ',' UInt32 ')'
|
|
bool LLParser::parseModuleEntry(unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_module);
|
|
Lex.Lex();
|
|
|
|
std::string Path;
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_path, "expected 'path' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseStringConstant(Path) ||
|
|
parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_hash, "expected 'hash' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
ModuleHash Hash;
|
|
if (parseUInt32(Hash[0]) || parseToken(lltok::comma, "expected ',' here") ||
|
|
parseUInt32(Hash[1]) || parseToken(lltok::comma, "expected ',' here") ||
|
|
parseUInt32(Hash[2]) || parseToken(lltok::comma, "expected ',' here") ||
|
|
parseUInt32(Hash[3]) || parseToken(lltok::comma, "expected ',' here") ||
|
|
parseUInt32(Hash[4]))
|
|
return true;
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here") ||
|
|
parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
auto ModuleEntry = Index->addModule(Path, ID, Hash);
|
|
ModuleIdMap[ID] = ModuleEntry->first();
|
|
|
|
return false;
|
|
}
|
|
|
|
/// TypeIdEntry
|
|
/// ::= 'typeid' ':' '(' 'name' ':' STRINGCONSTANT ',' TypeIdSummary ')'
|
|
bool LLParser::parseTypeIdEntry(unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_typeid);
|
|
Lex.Lex();
|
|
|
|
std::string Name;
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_name, "expected 'name' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseStringConstant(Name))
|
|
return true;
|
|
|
|
TypeIdSummary &TIS = Index->getOrInsertTypeIdSummary(Name);
|
|
if (parseToken(lltok::comma, "expected ',' here") ||
|
|
parseTypeIdSummary(TIS) || parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
// Check if this ID was forward referenced, and if so, update the
|
|
// corresponding GUIDs.
|
|
auto FwdRefTIDs = ForwardRefTypeIds.find(ID);
|
|
if (FwdRefTIDs != ForwardRefTypeIds.end()) {
|
|
for (auto TIDRef : FwdRefTIDs->second) {
|
|
assert(!*TIDRef.first &&
|
|
"Forward referenced type id GUID expected to be 0");
|
|
*TIDRef.first = GlobalValue::getGUID(Name);
|
|
}
|
|
ForwardRefTypeIds.erase(FwdRefTIDs);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// TypeIdSummary
|
|
/// ::= 'summary' ':' '(' TypeTestResolution [',' OptionalWpdResolutions]? ')'
|
|
bool LLParser::parseTypeIdSummary(TypeIdSummary &TIS) {
|
|
if (parseToken(lltok::kw_summary, "expected 'summary' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseTypeTestResolution(TIS.TTRes))
|
|
return true;
|
|
|
|
if (EatIfPresent(lltok::comma)) {
|
|
// Expect optional wpdResolutions field
|
|
if (parseOptionalWpdResolutions(TIS.WPDRes))
|
|
return true;
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static ValueInfo EmptyVI =
|
|
ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
|
|
|
|
/// TypeIdCompatibleVtableEntry
|
|
/// ::= 'typeidCompatibleVTable' ':' '(' 'name' ':' STRINGCONSTANT ','
|
|
/// TypeIdCompatibleVtableInfo
|
|
/// ')'
|
|
bool LLParser::parseTypeIdCompatibleVtableEntry(unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_typeidCompatibleVTable);
|
|
Lex.Lex();
|
|
|
|
std::string Name;
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_name, "expected 'name' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseStringConstant(Name))
|
|
return true;
|
|
|
|
TypeIdCompatibleVtableInfo &TI =
|
|
Index->getOrInsertTypeIdCompatibleVtableSummary(Name);
|
|
if (parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_summary, "expected 'summary' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
// parse each call edge
|
|
do {
|
|
uint64_t Offset;
|
|
if (parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_offset, "expected 'offset' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") || parseUInt64(Offset) ||
|
|
parseToken(lltok::comma, "expected ',' here"))
|
|
return true;
|
|
|
|
LocTy Loc = Lex.getLoc();
|
|
unsigned GVId;
|
|
ValueInfo VI;
|
|
if (parseGVReference(VI, GVId))
|
|
return true;
|
|
|
|
// Keep track of the TypeIdCompatibleVtableInfo array index needing a
|
|
// forward reference. We will save the location of the ValueInfo needing an
|
|
// update, but can only do so once the std::vector is finalized.
|
|
if (VI == EmptyVI)
|
|
IdToIndexMap[GVId].push_back(std::make_pair(TI.size(), Loc));
|
|
TI.push_back({Offset, VI});
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in call"))
|
|
return true;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
// Now that the TI vector is finalized, it is safe to save the locations
|
|
// of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Infos = ForwardRefValueInfos[I.first];
|
|
for (auto P : I.second) {
|
|
assert(TI[P.first].VTableVI == EmptyVI &&
|
|
"Forward referenced ValueInfo expected to be empty");
|
|
Infos.emplace_back(&TI[P.first].VTableVI, P.second);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here") ||
|
|
parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
// Check if this ID was forward referenced, and if so, update the
|
|
// corresponding GUIDs.
|
|
auto FwdRefTIDs = ForwardRefTypeIds.find(ID);
|
|
if (FwdRefTIDs != ForwardRefTypeIds.end()) {
|
|
for (auto TIDRef : FwdRefTIDs->second) {
|
|
assert(!*TIDRef.first &&
|
|
"Forward referenced type id GUID expected to be 0");
|
|
*TIDRef.first = GlobalValue::getGUID(Name);
|
|
}
|
|
ForwardRefTypeIds.erase(FwdRefTIDs);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// TypeTestResolution
|
|
/// ::= 'typeTestRes' ':' '(' 'kind' ':'
|
|
/// ( 'unsat' | 'byteArray' | 'inline' | 'single' | 'allOnes' ) ','
|
|
/// 'sizeM1BitWidth' ':' SizeM1BitWidth [',' 'alignLog2' ':' UInt64]?
|
|
/// [',' 'sizeM1' ':' UInt64]? [',' 'bitMask' ':' UInt8]?
|
|
/// [',' 'inlinesBits' ':' UInt64]? ')'
|
|
bool LLParser::parseTypeTestResolution(TypeTestResolution &TTRes) {
|
|
if (parseToken(lltok::kw_typeTestRes, "expected 'typeTestRes' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_kind, "expected 'kind' here") ||
|
|
parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_unknown:
|
|
TTRes.TheKind = TypeTestResolution::Unknown;
|
|
break;
|
|
case lltok::kw_unsat:
|
|
TTRes.TheKind = TypeTestResolution::Unsat;
|
|
break;
|
|
case lltok::kw_byteArray:
|
|
TTRes.TheKind = TypeTestResolution::ByteArray;
|
|
break;
|
|
case lltok::kw_inline:
|
|
TTRes.TheKind = TypeTestResolution::Inline;
|
|
break;
|
|
case lltok::kw_single:
|
|
TTRes.TheKind = TypeTestResolution::Single;
|
|
break;
|
|
case lltok::kw_allOnes:
|
|
TTRes.TheKind = TypeTestResolution::AllOnes;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "unexpected TypeTestResolution kind");
|
|
}
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_sizeM1BitWidth, "expected 'sizeM1BitWidth' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseUInt32(TTRes.SizeM1BitWidth))
|
|
return true;
|
|
|
|
// parse optional fields
|
|
while (EatIfPresent(lltok::comma)) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_alignLog2:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") ||
|
|
parseUInt64(TTRes.AlignLog2))
|
|
return true;
|
|
break;
|
|
case lltok::kw_sizeM1:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseUInt64(TTRes.SizeM1))
|
|
return true;
|
|
break;
|
|
case lltok::kw_bitMask: {
|
|
unsigned Val;
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseUInt32(Val))
|
|
return true;
|
|
assert(Val <= 0xff);
|
|
TTRes.BitMask = (uint8_t)Val;
|
|
break;
|
|
}
|
|
case lltok::kw_inlineBits:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") ||
|
|
parseUInt64(TTRes.InlineBits))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected optional TypeTestResolution field");
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalWpdResolutions
|
|
/// ::= 'wpsResolutions' ':' '(' WpdResolution [',' WpdResolution]* ')'
|
|
/// WpdResolution ::= '(' 'offset' ':' UInt64 ',' WpdRes ')'
|
|
bool LLParser::parseOptionalWpdResolutions(
|
|
std::map<uint64_t, WholeProgramDevirtResolution> &WPDResMap) {
|
|
if (parseToken(lltok::kw_wpdResolutions, "expected 'wpdResolutions' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
do {
|
|
uint64_t Offset;
|
|
WholeProgramDevirtResolution WPDRes;
|
|
if (parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_offset, "expected 'offset' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") || parseUInt64(Offset) ||
|
|
parseToken(lltok::comma, "expected ',' here") || parseWpdRes(WPDRes) ||
|
|
parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
WPDResMap[Offset] = WPDRes;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// WpdRes
|
|
/// ::= 'wpdRes' ':' '(' 'kind' ':' 'indir'
|
|
/// [',' OptionalResByArg]? ')'
|
|
/// ::= 'wpdRes' ':' '(' 'kind' ':' 'singleImpl'
|
|
/// ',' 'singleImplName' ':' STRINGCONSTANT ','
|
|
/// [',' OptionalResByArg]? ')'
|
|
/// ::= 'wpdRes' ':' '(' 'kind' ':' 'branchFunnel'
|
|
/// [',' OptionalResByArg]? ')'
|
|
bool LLParser::parseWpdRes(WholeProgramDevirtResolution &WPDRes) {
|
|
if (parseToken(lltok::kw_wpdRes, "expected 'wpdRes' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_kind, "expected 'kind' here") ||
|
|
parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_indir:
|
|
WPDRes.TheKind = WholeProgramDevirtResolution::Indir;
|
|
break;
|
|
case lltok::kw_singleImpl:
|
|
WPDRes.TheKind = WholeProgramDevirtResolution::SingleImpl;
|
|
break;
|
|
case lltok::kw_branchFunnel:
|
|
WPDRes.TheKind = WholeProgramDevirtResolution::BranchFunnel;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "unexpected WholeProgramDevirtResolution kind");
|
|
}
|
|
Lex.Lex();
|
|
|
|
// parse optional fields
|
|
while (EatIfPresent(lltok::comma)) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_singleImplName:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseStringConstant(WPDRes.SingleImplName))
|
|
return true;
|
|
break;
|
|
case lltok::kw_resByArg:
|
|
if (parseOptionalResByArg(WPDRes.ResByArg))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(),
|
|
"expected optional WholeProgramDevirtResolution field");
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalResByArg
|
|
/// ::= 'wpdRes' ':' '(' ResByArg[, ResByArg]* ')'
|
|
/// ResByArg ::= Args ',' 'byArg' ':' '(' 'kind' ':'
|
|
/// ( 'indir' | 'uniformRetVal' | 'UniqueRetVal' |
|
|
/// 'virtualConstProp' )
|
|
/// [',' 'info' ':' UInt64]? [',' 'byte' ':' UInt32]?
|
|
/// [',' 'bit' ':' UInt32]? ')'
|
|
bool LLParser::parseOptionalResByArg(
|
|
std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>
|
|
&ResByArg) {
|
|
if (parseToken(lltok::kw_resByArg, "expected 'resByArg' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
do {
|
|
std::vector<uint64_t> Args;
|
|
if (parseArgs(Args) || parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_byArg, "expected 'byArg here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_kind, "expected 'kind' here") ||
|
|
parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
|
|
WholeProgramDevirtResolution::ByArg ByArg;
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_indir:
|
|
ByArg.TheKind = WholeProgramDevirtResolution::ByArg::Indir;
|
|
break;
|
|
case lltok::kw_uniformRetVal:
|
|
ByArg.TheKind = WholeProgramDevirtResolution::ByArg::UniformRetVal;
|
|
break;
|
|
case lltok::kw_uniqueRetVal:
|
|
ByArg.TheKind = WholeProgramDevirtResolution::ByArg::UniqueRetVal;
|
|
break;
|
|
case lltok::kw_virtualConstProp:
|
|
ByArg.TheKind = WholeProgramDevirtResolution::ByArg::VirtualConstProp;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(),
|
|
"unexpected WholeProgramDevirtResolution::ByArg kind");
|
|
}
|
|
Lex.Lex();
|
|
|
|
// parse optional fields
|
|
while (EatIfPresent(lltok::comma)) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_info:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseUInt64(ByArg.Info))
|
|
return true;
|
|
break;
|
|
case lltok::kw_byte:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseUInt32(ByArg.Byte))
|
|
return true;
|
|
break;
|
|
case lltok::kw_bit:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseUInt32(ByArg.Bit))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(),
|
|
"expected optional whole program devirt field");
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
ResByArg[Args] = ByArg;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalResByArg
|
|
/// ::= 'args' ':' '(' UInt64[, UInt64]* ')'
|
|
bool LLParser::parseArgs(std::vector<uint64_t> &Args) {
|
|
if (parseToken(lltok::kw_args, "expected 'args' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
do {
|
|
uint64_t Val;
|
|
if (parseUInt64(Val))
|
|
return true;
|
|
Args.push_back(Val);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static const auto FwdVIRef = (GlobalValueSummaryMapTy::value_type *)-8;
|
|
|
|
static void resolveFwdRef(ValueInfo *Fwd, ValueInfo &Resolved) {
|
|
bool ReadOnly = Fwd->isReadOnly();
|
|
bool WriteOnly = Fwd->isWriteOnly();
|
|
assert(!(ReadOnly && WriteOnly));
|
|
*Fwd = Resolved;
|
|
if (ReadOnly)
|
|
Fwd->setReadOnly();
|
|
if (WriteOnly)
|
|
Fwd->setWriteOnly();
|
|
}
|
|
|
|
/// Stores the given Name/GUID and associated summary into the Index.
|
|
/// Also updates any forward references to the associated entry ID.
|
|
void LLParser::addGlobalValueToIndex(
|
|
std::string Name, GlobalValue::GUID GUID, GlobalValue::LinkageTypes Linkage,
|
|
unsigned ID, std::unique_ptr<GlobalValueSummary> Summary) {
|
|
// First create the ValueInfo utilizing the Name or GUID.
|
|
ValueInfo VI;
|
|
if (GUID != 0) {
|
|
assert(Name.empty());
|
|
VI = Index->getOrInsertValueInfo(GUID);
|
|
} else {
|
|
assert(!Name.empty());
|
|
if (M) {
|
|
auto *GV = M->getNamedValue(Name);
|
|
assert(GV);
|
|
VI = Index->getOrInsertValueInfo(GV);
|
|
} else {
|
|
assert(
|
|
(!GlobalValue::isLocalLinkage(Linkage) || !SourceFileName.empty()) &&
|
|
"Need a source_filename to compute GUID for local");
|
|
GUID = GlobalValue::getGUID(
|
|
GlobalValue::getGlobalIdentifier(Name, Linkage, SourceFileName));
|
|
VI = Index->getOrInsertValueInfo(GUID, Index->saveString(Name));
|
|
}
|
|
}
|
|
|
|
// Resolve forward references from calls/refs
|
|
auto FwdRefVIs = ForwardRefValueInfos.find(ID);
|
|
if (FwdRefVIs != ForwardRefValueInfos.end()) {
|
|
for (auto VIRef : FwdRefVIs->second) {
|
|
assert(VIRef.first->getRef() == FwdVIRef &&
|
|
"Forward referenced ValueInfo expected to be empty");
|
|
resolveFwdRef(VIRef.first, VI);
|
|
}
|
|
ForwardRefValueInfos.erase(FwdRefVIs);
|
|
}
|
|
|
|
// Resolve forward references from aliases
|
|
auto FwdRefAliasees = ForwardRefAliasees.find(ID);
|
|
if (FwdRefAliasees != ForwardRefAliasees.end()) {
|
|
for (auto AliaseeRef : FwdRefAliasees->second) {
|
|
assert(!AliaseeRef.first->hasAliasee() &&
|
|
"Forward referencing alias already has aliasee");
|
|
assert(Summary && "Aliasee must be a definition");
|
|
AliaseeRef.first->setAliasee(VI, Summary.get());
|
|
}
|
|
ForwardRefAliasees.erase(FwdRefAliasees);
|
|
}
|
|
|
|
// Add the summary if one was provided.
|
|
if (Summary)
|
|
Index->addGlobalValueSummary(VI, std::move(Summary));
|
|
|
|
// Save the associated ValueInfo for use in later references by ID.
|
|
if (ID == NumberedValueInfos.size())
|
|
NumberedValueInfos.push_back(VI);
|
|
else {
|
|
// Handle non-continuous numbers (to make test simplification easier).
|
|
if (ID > NumberedValueInfos.size())
|
|
NumberedValueInfos.resize(ID + 1);
|
|
NumberedValueInfos[ID] = VI;
|
|
}
|
|
}
|
|
|
|
/// parseSummaryIndexFlags
|
|
/// ::= 'flags' ':' UInt64
|
|
bool LLParser::parseSummaryIndexFlags() {
|
|
assert(Lex.getKind() == lltok::kw_flags);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
uint64_t Flags;
|
|
if (parseUInt64(Flags))
|
|
return true;
|
|
if (Index)
|
|
Index->setFlags(Flags);
|
|
return false;
|
|
}
|
|
|
|
/// parseBlockCount
|
|
/// ::= 'blockcount' ':' UInt64
|
|
bool LLParser::parseBlockCount() {
|
|
assert(Lex.getKind() == lltok::kw_blockcount);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
uint64_t BlockCount;
|
|
if (parseUInt64(BlockCount))
|
|
return true;
|
|
if (Index)
|
|
Index->setBlockCount(BlockCount);
|
|
return false;
|
|
}
|
|
|
|
/// parseGVEntry
|
|
/// ::= 'gv' ':' '(' ('name' ':' STRINGCONSTANT | 'guid' ':' UInt64)
|
|
/// [',' 'summaries' ':' Summary[',' Summary]* ]? ')'
|
|
/// Summary ::= '(' (FunctionSummary | VariableSummary | AliasSummary) ')'
|
|
bool LLParser::parseGVEntry(unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_gv);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
std::string Name;
|
|
GlobalValue::GUID GUID = 0;
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_name:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseStringConstant(Name))
|
|
return true;
|
|
// Can't create GUID/ValueInfo until we have the linkage.
|
|
break;
|
|
case lltok::kw_guid:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':' here") || parseUInt64(GUID))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected name or guid tag");
|
|
}
|
|
|
|
if (!EatIfPresent(lltok::comma)) {
|
|
// No summaries. Wrap up.
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
// This was created for a call to an external or indirect target.
|
|
// A GUID with no summary came from a VALUE_GUID record, dummy GUID
|
|
// created for indirect calls with VP. A Name with no GUID came from
|
|
// an external definition. We pass ExternalLinkage since that is only
|
|
// used when the GUID must be computed from Name, and in that case
|
|
// the symbol must have external linkage.
|
|
addGlobalValueToIndex(Name, GUID, GlobalValue::ExternalLinkage, ID,
|
|
nullptr);
|
|
return false;
|
|
}
|
|
|
|
// Have a list of summaries
|
|
if (parseToken(lltok::kw_summaries, "expected 'summaries' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
do {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_function:
|
|
if (parseFunctionSummary(Name, GUID, ID))
|
|
return true;
|
|
break;
|
|
case lltok::kw_variable:
|
|
if (parseVariableSummary(Name, GUID, ID))
|
|
return true;
|
|
break;
|
|
case lltok::kw_alias:
|
|
if (parseAliasSummary(Name, GUID, ID))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected summary type");
|
|
}
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here") ||
|
|
parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// FunctionSummary
|
|
/// ::= 'function' ':' '(' 'module' ':' ModuleReference ',' GVFlags
|
|
/// ',' 'insts' ':' UInt32 [',' OptionalFFlags]? [',' OptionalCalls]?
|
|
/// [',' OptionalTypeIdInfo]? [',' OptionalParamAccesses]?
|
|
/// [',' OptionalRefs]? ')'
|
|
bool LLParser::parseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
|
|
unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_function);
|
|
Lex.Lex();
|
|
|
|
StringRef ModulePath;
|
|
GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
|
|
/*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
|
|
/*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false);
|
|
unsigned InstCount;
|
|
std::vector<FunctionSummary::EdgeTy> Calls;
|
|
FunctionSummary::TypeIdInfo TypeIdInfo;
|
|
std::vector<FunctionSummary::ParamAccess> ParamAccesses;
|
|
std::vector<ValueInfo> Refs;
|
|
// Default is all-zeros (conservative values).
|
|
FunctionSummary::FFlags FFlags = {};
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseModuleReference(ModulePath) ||
|
|
parseToken(lltok::comma, "expected ',' here") || parseGVFlags(GVFlags) ||
|
|
parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_insts, "expected 'insts' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") || parseUInt32(InstCount))
|
|
return true;
|
|
|
|
// parse optional fields
|
|
while (EatIfPresent(lltok::comma)) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_funcFlags:
|
|
if (parseOptionalFFlags(FFlags))
|
|
return true;
|
|
break;
|
|
case lltok::kw_calls:
|
|
if (parseOptionalCalls(Calls))
|
|
return true;
|
|
break;
|
|
case lltok::kw_typeIdInfo:
|
|
if (parseOptionalTypeIdInfo(TypeIdInfo))
|
|
return true;
|
|
break;
|
|
case lltok::kw_refs:
|
|
if (parseOptionalRefs(Refs))
|
|
return true;
|
|
break;
|
|
case lltok::kw_params:
|
|
if (parseOptionalParamAccesses(ParamAccesses))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected optional function summary field");
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
auto FS = std::make_unique<FunctionSummary>(
|
|
GVFlags, InstCount, FFlags, /*EntryCount=*/0, std::move(Refs),
|
|
std::move(Calls), std::move(TypeIdInfo.TypeTests),
|
|
std::move(TypeIdInfo.TypeTestAssumeVCalls),
|
|
std::move(TypeIdInfo.TypeCheckedLoadVCalls),
|
|
std::move(TypeIdInfo.TypeTestAssumeConstVCalls),
|
|
std::move(TypeIdInfo.TypeCheckedLoadConstVCalls),
|
|
std::move(ParamAccesses));
|
|
|
|
FS->setModulePath(ModulePath);
|
|
|
|
addGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
|
|
ID, std::move(FS));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// VariableSummary
|
|
/// ::= 'variable' ':' '(' 'module' ':' ModuleReference ',' GVFlags
|
|
/// [',' OptionalRefs]? ')'
|
|
bool LLParser::parseVariableSummary(std::string Name, GlobalValue::GUID GUID,
|
|
unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_variable);
|
|
Lex.Lex();
|
|
|
|
StringRef ModulePath;
|
|
GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
|
|
/*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
|
|
/*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false);
|
|
GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false,
|
|
/* WriteOnly */ false,
|
|
/* Constant */ false,
|
|
GlobalObject::VCallVisibilityPublic);
|
|
std::vector<ValueInfo> Refs;
|
|
VTableFuncList VTableFuncs;
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseModuleReference(ModulePath) ||
|
|
parseToken(lltok::comma, "expected ',' here") || parseGVFlags(GVFlags) ||
|
|
parseToken(lltok::comma, "expected ',' here") ||
|
|
parseGVarFlags(GVarFlags))
|
|
return true;
|
|
|
|
// parse optional fields
|
|
while (EatIfPresent(lltok::comma)) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_vTableFuncs:
|
|
if (parseOptionalVTableFuncs(VTableFuncs))
|
|
return true;
|
|
break;
|
|
case lltok::kw_refs:
|
|
if (parseOptionalRefs(Refs))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected optional variable summary field");
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
auto GS =
|
|
std::make_unique<GlobalVarSummary>(GVFlags, GVarFlags, std::move(Refs));
|
|
|
|
GS->setModulePath(ModulePath);
|
|
GS->setVTableFuncs(std::move(VTableFuncs));
|
|
|
|
addGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
|
|
ID, std::move(GS));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// AliasSummary
|
|
/// ::= 'alias' ':' '(' 'module' ':' ModuleReference ',' GVFlags ','
|
|
/// 'aliasee' ':' GVReference ')'
|
|
bool LLParser::parseAliasSummary(std::string Name, GlobalValue::GUID GUID,
|
|
unsigned ID) {
|
|
assert(Lex.getKind() == lltok::kw_alias);
|
|
LocTy Loc = Lex.getLoc();
|
|
Lex.Lex();
|
|
|
|
StringRef ModulePath;
|
|
GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
|
|
/*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
|
|
/*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false);
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseModuleReference(ModulePath) ||
|
|
parseToken(lltok::comma, "expected ',' here") || parseGVFlags(GVFlags) ||
|
|
parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_aliasee, "expected 'aliasee' here") ||
|
|
parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
|
|
ValueInfo AliaseeVI;
|
|
unsigned GVId;
|
|
if (parseGVReference(AliaseeVI, GVId))
|
|
return true;
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
auto AS = std::make_unique<AliasSummary>(GVFlags);
|
|
|
|
AS->setModulePath(ModulePath);
|
|
|
|
// Record forward reference if the aliasee is not parsed yet.
|
|
if (AliaseeVI.getRef() == FwdVIRef) {
|
|
ForwardRefAliasees[GVId].emplace_back(AS.get(), Loc);
|
|
} else {
|
|
auto Summary = Index->findSummaryInModule(AliaseeVI, ModulePath);
|
|
assert(Summary && "Aliasee must be a definition");
|
|
AS->setAliasee(AliaseeVI, Summary);
|
|
}
|
|
|
|
addGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
|
|
ID, std::move(AS));
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Flag
|
|
/// ::= [0|1]
|
|
bool LLParser::parseFlag(unsigned &Val) {
|
|
if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
|
|
return tokError("expected integer");
|
|
Val = (unsigned)Lex.getAPSIntVal().getBoolValue();
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// OptionalFFlags
|
|
/// := 'funcFlags' ':' '(' ['readNone' ':' Flag]?
|
|
/// [',' 'readOnly' ':' Flag]? [',' 'noRecurse' ':' Flag]?
|
|
/// [',' 'returnDoesNotAlias' ':' Flag]? ')'
|
|
/// [',' 'noInline' ':' Flag]? ')'
|
|
/// [',' 'alwaysInline' ':' Flag]? ')'
|
|
|
|
bool LLParser::parseOptionalFFlags(FunctionSummary::FFlags &FFlags) {
|
|
assert(Lex.getKind() == lltok::kw_funcFlags);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' in funcFlags") |
|
|
parseToken(lltok::lparen, "expected '(' in funcFlags"))
|
|
return true;
|
|
|
|
do {
|
|
unsigned Val = 0;
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_readNone:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val))
|
|
return true;
|
|
FFlags.ReadNone = Val;
|
|
break;
|
|
case lltok::kw_readOnly:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val))
|
|
return true;
|
|
FFlags.ReadOnly = Val;
|
|
break;
|
|
case lltok::kw_noRecurse:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val))
|
|
return true;
|
|
FFlags.NoRecurse = Val;
|
|
break;
|
|
case lltok::kw_returnDoesNotAlias:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val))
|
|
return true;
|
|
FFlags.ReturnDoesNotAlias = Val;
|
|
break;
|
|
case lltok::kw_noInline:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val))
|
|
return true;
|
|
FFlags.NoInline = Val;
|
|
break;
|
|
case lltok::kw_alwaysInline:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Val))
|
|
return true;
|
|
FFlags.AlwaysInline = Val;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected function flag type");
|
|
}
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in funcFlags"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalCalls
|
|
/// := 'calls' ':' '(' Call [',' Call]* ')'
|
|
/// Call ::= '(' 'callee' ':' GVReference
|
|
/// [( ',' 'hotness' ':' Hotness | ',' 'relbf' ':' UInt32 )]? ')'
|
|
bool LLParser::parseOptionalCalls(std::vector<FunctionSummary::EdgeTy> &Calls) {
|
|
assert(Lex.getKind() == lltok::kw_calls);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' in calls") |
|
|
parseToken(lltok::lparen, "expected '(' in calls"))
|
|
return true;
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
// parse each call edge
|
|
do {
|
|
ValueInfo VI;
|
|
if (parseToken(lltok::lparen, "expected '(' in call") ||
|
|
parseToken(lltok::kw_callee, "expected 'callee' in call") ||
|
|
parseToken(lltok::colon, "expected ':'"))
|
|
return true;
|
|
|
|
LocTy Loc = Lex.getLoc();
|
|
unsigned GVId;
|
|
if (parseGVReference(VI, GVId))
|
|
return true;
|
|
|
|
CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown;
|
|
unsigned RelBF = 0;
|
|
if (EatIfPresent(lltok::comma)) {
|
|
// Expect either hotness or relbf
|
|
if (EatIfPresent(lltok::kw_hotness)) {
|
|
if (parseToken(lltok::colon, "expected ':'") || parseHotness(Hotness))
|
|
return true;
|
|
} else {
|
|
if (parseToken(lltok::kw_relbf, "expected relbf") ||
|
|
parseToken(lltok::colon, "expected ':'") || parseUInt32(RelBF))
|
|
return true;
|
|
}
|
|
}
|
|
// Keep track of the Call array index needing a forward reference.
|
|
// We will save the location of the ValueInfo needing an update, but
|
|
// can only do so once the std::vector is finalized.
|
|
if (VI.getRef() == FwdVIRef)
|
|
IdToIndexMap[GVId].push_back(std::make_pair(Calls.size(), Loc));
|
|
Calls.push_back(FunctionSummary::EdgeTy{VI, CalleeInfo(Hotness, RelBF)});
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in call"))
|
|
return true;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
// Now that the Calls vector is finalized, it is safe to save the locations
|
|
// of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Infos = ForwardRefValueInfos[I.first];
|
|
for (auto P : I.second) {
|
|
assert(Calls[P.first].first.getRef() == FwdVIRef &&
|
|
"Forward referenced ValueInfo expected to be empty");
|
|
Infos.emplace_back(&Calls[P.first].first, P.second);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in calls"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Hotness
|
|
/// := ('unknown'|'cold'|'none'|'hot'|'critical')
|
|
bool LLParser::parseHotness(CalleeInfo::HotnessType &Hotness) {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_unknown:
|
|
Hotness = CalleeInfo::HotnessType::Unknown;
|
|
break;
|
|
case lltok::kw_cold:
|
|
Hotness = CalleeInfo::HotnessType::Cold;
|
|
break;
|
|
case lltok::kw_none:
|
|
Hotness = CalleeInfo::HotnessType::None;
|
|
break;
|
|
case lltok::kw_hot:
|
|
Hotness = CalleeInfo::HotnessType::Hot;
|
|
break;
|
|
case lltok::kw_critical:
|
|
Hotness = CalleeInfo::HotnessType::Critical;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "invalid call edge hotness");
|
|
}
|
|
Lex.Lex();
|
|
return false;
|
|
}
|
|
|
|
/// OptionalVTableFuncs
|
|
/// := 'vTableFuncs' ':' '(' VTableFunc [',' VTableFunc]* ')'
|
|
/// VTableFunc ::= '(' 'virtFunc' ':' GVReference ',' 'offset' ':' UInt64 ')'
|
|
bool LLParser::parseOptionalVTableFuncs(VTableFuncList &VTableFuncs) {
|
|
assert(Lex.getKind() == lltok::kw_vTableFuncs);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' in vTableFuncs") |
|
|
parseToken(lltok::lparen, "expected '(' in vTableFuncs"))
|
|
return true;
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
// parse each virtual function pair
|
|
do {
|
|
ValueInfo VI;
|
|
if (parseToken(lltok::lparen, "expected '(' in vTableFunc") ||
|
|
parseToken(lltok::kw_virtFunc, "expected 'callee' in vTableFunc") ||
|
|
parseToken(lltok::colon, "expected ':'"))
|
|
return true;
|
|
|
|
LocTy Loc = Lex.getLoc();
|
|
unsigned GVId;
|
|
if (parseGVReference(VI, GVId))
|
|
return true;
|
|
|
|
uint64_t Offset;
|
|
if (parseToken(lltok::comma, "expected comma") ||
|
|
parseToken(lltok::kw_offset, "expected offset") ||
|
|
parseToken(lltok::colon, "expected ':'") || parseUInt64(Offset))
|
|
return true;
|
|
|
|
// Keep track of the VTableFuncs array index needing a forward reference.
|
|
// We will save the location of the ValueInfo needing an update, but
|
|
// can only do so once the std::vector is finalized.
|
|
if (VI == EmptyVI)
|
|
IdToIndexMap[GVId].push_back(std::make_pair(VTableFuncs.size(), Loc));
|
|
VTableFuncs.push_back({VI, Offset});
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in vTableFunc"))
|
|
return true;
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
// Now that the VTableFuncs vector is finalized, it is safe to save the
|
|
// locations of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Infos = ForwardRefValueInfos[I.first];
|
|
for (auto P : I.second) {
|
|
assert(VTableFuncs[P.first].FuncVI == EmptyVI &&
|
|
"Forward referenced ValueInfo expected to be empty");
|
|
Infos.emplace_back(&VTableFuncs[P.first].FuncVI, P.second);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in vTableFuncs"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// ParamNo := 'param' ':' UInt64
|
|
bool LLParser::parseParamNo(uint64_t &ParamNo) {
|
|
if (parseToken(lltok::kw_param, "expected 'param' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") || parseUInt64(ParamNo))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// ParamAccessOffset := 'offset' ':' '[' APSINTVAL ',' APSINTVAL ']'
|
|
bool LLParser::parseParamAccessOffset(ConstantRange &Range) {
|
|
APSInt Lower;
|
|
APSInt Upper;
|
|
auto ParseAPSInt = [&](APSInt &Val) {
|
|
if (Lex.getKind() != lltok::APSInt)
|
|
return tokError("expected integer");
|
|
Val = Lex.getAPSIntVal();
|
|
Val = Val.extOrTrunc(FunctionSummary::ParamAccess::RangeWidth);
|
|
Val.setIsSigned(true);
|
|
Lex.Lex();
|
|
return false;
|
|
};
|
|
if (parseToken(lltok::kw_offset, "expected 'offset' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lsquare, "expected '[' here") || ParseAPSInt(Lower) ||
|
|
parseToken(lltok::comma, "expected ',' here") || ParseAPSInt(Upper) ||
|
|
parseToken(lltok::rsquare, "expected ']' here"))
|
|
return true;
|
|
|
|
++Upper;
|
|
Range =
|
|
(Lower == Upper && !Lower.isMaxValue())
|
|
? ConstantRange::getEmpty(FunctionSummary::ParamAccess::RangeWidth)
|
|
: ConstantRange(Lower, Upper);
|
|
|
|
return false;
|
|
}
|
|
|
|
/// ParamAccessCall
|
|
/// := '(' 'callee' ':' GVReference ',' ParamNo ',' ParamAccessOffset ')'
|
|
bool LLParser::parseParamAccessCall(FunctionSummary::ParamAccess::Call &Call,
|
|
IdLocListType &IdLocList) {
|
|
if (parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseToken(lltok::kw_callee, "expected 'callee' here") ||
|
|
parseToken(lltok::colon, "expected ':' here"))
|
|
return true;
|
|
|
|
unsigned GVId;
|
|
ValueInfo VI;
|
|
LocTy Loc = Lex.getLoc();
|
|
if (parseGVReference(VI, GVId))
|
|
return true;
|
|
|
|
Call.Callee = VI;
|
|
IdLocList.emplace_back(GVId, Loc);
|
|
|
|
if (parseToken(lltok::comma, "expected ',' here") ||
|
|
parseParamNo(Call.ParamNo) ||
|
|
parseToken(lltok::comma, "expected ',' here") ||
|
|
parseParamAccessOffset(Call.Offsets))
|
|
return true;
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// ParamAccess
|
|
/// := '(' ParamNo ',' ParamAccessOffset [',' OptionalParamAccessCalls]? ')'
|
|
/// OptionalParamAccessCalls := '(' Call [',' Call]* ')'
|
|
bool LLParser::parseParamAccess(FunctionSummary::ParamAccess &Param,
|
|
IdLocListType &IdLocList) {
|
|
if (parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseParamNo(Param.ParamNo) ||
|
|
parseToken(lltok::comma, "expected ',' here") ||
|
|
parseParamAccessOffset(Param.Use))
|
|
return true;
|
|
|
|
if (EatIfPresent(lltok::comma)) {
|
|
if (parseToken(lltok::kw_calls, "expected 'calls' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
do {
|
|
FunctionSummary::ParamAccess::Call Call;
|
|
if (parseParamAccessCall(Call, IdLocList))
|
|
return true;
|
|
Param.Calls.push_back(Call);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalParamAccesses
|
|
/// := 'params' ':' '(' ParamAccess [',' ParamAccess]* ')'
|
|
bool LLParser::parseOptionalParamAccesses(
|
|
std::vector<FunctionSummary::ParamAccess> &Params) {
|
|
assert(Lex.getKind() == lltok::kw_params);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
IdLocListType VContexts;
|
|
size_t CallsNum = 0;
|
|
do {
|
|
FunctionSummary::ParamAccess ParamAccess;
|
|
if (parseParamAccess(ParamAccess, VContexts))
|
|
return true;
|
|
CallsNum += ParamAccess.Calls.size();
|
|
assert(VContexts.size() == CallsNum);
|
|
Params.emplace_back(std::move(ParamAccess));
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
// Now that the Params is finalized, it is safe to save the locations
|
|
// of any forward GV references that need updating later.
|
|
IdLocListType::const_iterator ItContext = VContexts.begin();
|
|
for (auto &PA : Params) {
|
|
for (auto &C : PA.Calls) {
|
|
if (C.Callee.getRef() == FwdVIRef)
|
|
ForwardRefValueInfos[ItContext->first].emplace_back(&C.Callee,
|
|
ItContext->second);
|
|
++ItContext;
|
|
}
|
|
}
|
|
assert(ItContext == VContexts.end());
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalRefs
|
|
/// := 'refs' ':' '(' GVReference [',' GVReference]* ')'
|
|
bool LLParser::parseOptionalRefs(std::vector<ValueInfo> &Refs) {
|
|
assert(Lex.getKind() == lltok::kw_refs);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' in refs") ||
|
|
parseToken(lltok::lparen, "expected '(' in refs"))
|
|
return true;
|
|
|
|
struct ValueContext {
|
|
ValueInfo VI;
|
|
unsigned GVId;
|
|
LocTy Loc;
|
|
};
|
|
std::vector<ValueContext> VContexts;
|
|
// parse each ref edge
|
|
do {
|
|
ValueContext VC;
|
|
VC.Loc = Lex.getLoc();
|
|
if (parseGVReference(VC.VI, VC.GVId))
|
|
return true;
|
|
VContexts.push_back(VC);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
// Sort value contexts so that ones with writeonly
|
|
// and readonly ValueInfo are at the end of VContexts vector.
|
|
// See FunctionSummary::specialRefCounts()
|
|
llvm::sort(VContexts, [](const ValueContext &VC1, const ValueContext &VC2) {
|
|
return VC1.VI.getAccessSpecifier() < VC2.VI.getAccessSpecifier();
|
|
});
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
for (auto &VC : VContexts) {
|
|
// Keep track of the Refs array index needing a forward reference.
|
|
// We will save the location of the ValueInfo needing an update, but
|
|
// can only do so once the std::vector is finalized.
|
|
if (VC.VI.getRef() == FwdVIRef)
|
|
IdToIndexMap[VC.GVId].push_back(std::make_pair(Refs.size(), VC.Loc));
|
|
Refs.push_back(VC.VI);
|
|
}
|
|
|
|
// Now that the Refs vector is finalized, it is safe to save the locations
|
|
// of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Infos = ForwardRefValueInfos[I.first];
|
|
for (auto P : I.second) {
|
|
assert(Refs[P.first].getRef() == FwdVIRef &&
|
|
"Forward referenced ValueInfo expected to be empty");
|
|
Infos.emplace_back(&Refs[P.first], P.second);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in refs"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// OptionalTypeIdInfo
|
|
/// := 'typeidinfo' ':' '(' [',' TypeTests]? [',' TypeTestAssumeVCalls]?
|
|
/// [',' TypeCheckedLoadVCalls]? [',' TypeTestAssumeConstVCalls]?
|
|
/// [',' TypeCheckedLoadConstVCalls]? ')'
|
|
bool LLParser::parseOptionalTypeIdInfo(
|
|
FunctionSummary::TypeIdInfo &TypeIdInfo) {
|
|
assert(Lex.getKind() == lltok::kw_typeIdInfo);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' in typeIdInfo"))
|
|
return true;
|
|
|
|
do {
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_typeTests:
|
|
if (parseTypeTests(TypeIdInfo.TypeTests))
|
|
return true;
|
|
break;
|
|
case lltok::kw_typeTestAssumeVCalls:
|
|
if (parseVFuncIdList(lltok::kw_typeTestAssumeVCalls,
|
|
TypeIdInfo.TypeTestAssumeVCalls))
|
|
return true;
|
|
break;
|
|
case lltok::kw_typeCheckedLoadVCalls:
|
|
if (parseVFuncIdList(lltok::kw_typeCheckedLoadVCalls,
|
|
TypeIdInfo.TypeCheckedLoadVCalls))
|
|
return true;
|
|
break;
|
|
case lltok::kw_typeTestAssumeConstVCalls:
|
|
if (parseConstVCallList(lltok::kw_typeTestAssumeConstVCalls,
|
|
TypeIdInfo.TypeTestAssumeConstVCalls))
|
|
return true;
|
|
break;
|
|
case lltok::kw_typeCheckedLoadConstVCalls:
|
|
if (parseConstVCallList(lltok::kw_typeCheckedLoadConstVCalls,
|
|
TypeIdInfo.TypeCheckedLoadConstVCalls))
|
|
return true;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "invalid typeIdInfo list type");
|
|
}
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in typeIdInfo"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// TypeTests
|
|
/// ::= 'typeTests' ':' '(' (SummaryID | UInt64)
|
|
/// [',' (SummaryID | UInt64)]* ')'
|
|
bool LLParser::parseTypeTests(std::vector<GlobalValue::GUID> &TypeTests) {
|
|
assert(Lex.getKind() == lltok::kw_typeTests);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' in typeIdInfo"))
|
|
return true;
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
do {
|
|
GlobalValue::GUID GUID = 0;
|
|
if (Lex.getKind() == lltok::SummaryID) {
|
|
unsigned ID = Lex.getUIntVal();
|
|
LocTy Loc = Lex.getLoc();
|
|
// Keep track of the TypeTests array index needing a forward reference.
|
|
// We will save the location of the GUID needing an update, but
|
|
// can only do so once the std::vector is finalized.
|
|
IdToIndexMap[ID].push_back(std::make_pair(TypeTests.size(), Loc));
|
|
Lex.Lex();
|
|
} else if (parseUInt64(GUID))
|
|
return true;
|
|
TypeTests.push_back(GUID);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
// Now that the TypeTests vector is finalized, it is safe to save the
|
|
// locations of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Ids = ForwardRefTypeIds[I.first];
|
|
for (auto P : I.second) {
|
|
assert(TypeTests[P.first] == 0 &&
|
|
"Forward referenced type id GUID expected to be 0");
|
|
Ids.emplace_back(&TypeTests[P.first], P.second);
|
|
}
|
|
}
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' in typeIdInfo"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// VFuncIdList
|
|
/// ::= Kind ':' '(' VFuncId [',' VFuncId]* ')'
|
|
bool LLParser::parseVFuncIdList(
|
|
lltok::Kind Kind, std::vector<FunctionSummary::VFuncId> &VFuncIdList) {
|
|
assert(Lex.getKind() == Kind);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
do {
|
|
FunctionSummary::VFuncId VFuncId;
|
|
if (parseVFuncId(VFuncId, IdToIndexMap, VFuncIdList.size()))
|
|
return true;
|
|
VFuncIdList.push_back(VFuncId);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
// Now that the VFuncIdList vector is finalized, it is safe to save the
|
|
// locations of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Ids = ForwardRefTypeIds[I.first];
|
|
for (auto P : I.second) {
|
|
assert(VFuncIdList[P.first].GUID == 0 &&
|
|
"Forward referenced type id GUID expected to be 0");
|
|
Ids.emplace_back(&VFuncIdList[P.first].GUID, P.second);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// ConstVCallList
|
|
/// ::= Kind ':' '(' ConstVCall [',' ConstVCall]* ')'
|
|
bool LLParser::parseConstVCallList(
|
|
lltok::Kind Kind,
|
|
std::vector<FunctionSummary::ConstVCall> &ConstVCallList) {
|
|
assert(Lex.getKind() == Kind);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
IdToIndexMapType IdToIndexMap;
|
|
do {
|
|
FunctionSummary::ConstVCall ConstVCall;
|
|
if (parseConstVCall(ConstVCall, IdToIndexMap, ConstVCallList.size()))
|
|
return true;
|
|
ConstVCallList.push_back(ConstVCall);
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
// Now that the ConstVCallList vector is finalized, it is safe to save the
|
|
// locations of any forward GV references that need updating later.
|
|
for (auto I : IdToIndexMap) {
|
|
auto &Ids = ForwardRefTypeIds[I.first];
|
|
for (auto P : I.second) {
|
|
assert(ConstVCallList[P.first].VFunc.GUID == 0 &&
|
|
"Forward referenced type id GUID expected to be 0");
|
|
Ids.emplace_back(&ConstVCallList[P.first].VFunc.GUID, P.second);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// ConstVCall
|
|
/// ::= '(' VFuncId ',' Args ')'
|
|
bool LLParser::parseConstVCall(FunctionSummary::ConstVCall &ConstVCall,
|
|
IdToIndexMapType &IdToIndexMap, unsigned Index) {
|
|
if (parseToken(lltok::lparen, "expected '(' here") ||
|
|
parseVFuncId(ConstVCall.VFunc, IdToIndexMap, Index))
|
|
return true;
|
|
|
|
if (EatIfPresent(lltok::comma))
|
|
if (parseArgs(ConstVCall.Args))
|
|
return true;
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// VFuncId
|
|
/// ::= 'vFuncId' ':' '(' (SummaryID | 'guid' ':' UInt64) ','
|
|
/// 'offset' ':' UInt64 ')'
|
|
bool LLParser::parseVFuncId(FunctionSummary::VFuncId &VFuncId,
|
|
IdToIndexMapType &IdToIndexMap, unsigned Index) {
|
|
assert(Lex.getKind() == lltok::kw_vFuncId);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
if (Lex.getKind() == lltok::SummaryID) {
|
|
VFuncId.GUID = 0;
|
|
unsigned ID = Lex.getUIntVal();
|
|
LocTy Loc = Lex.getLoc();
|
|
// Keep track of the array index needing a forward reference.
|
|
// We will save the location of the GUID needing an update, but
|
|
// can only do so once the caller's std::vector is finalized.
|
|
IdToIndexMap[ID].push_back(std::make_pair(Index, Loc));
|
|
Lex.Lex();
|
|
} else if (parseToken(lltok::kw_guid, "expected 'guid' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseUInt64(VFuncId.GUID))
|
|
return true;
|
|
|
|
if (parseToken(lltok::comma, "expected ',' here") ||
|
|
parseToken(lltok::kw_offset, "expected 'offset' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseUInt64(VFuncId.Offset) ||
|
|
parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// GVFlags
|
|
/// ::= 'flags' ':' '(' 'linkage' ':' OptionalLinkageAux ','
|
|
/// 'notEligibleToImport' ':' Flag ',' 'live' ':' Flag ','
|
|
/// 'dsoLocal' ':' Flag ',' 'canAutoHide' ':' Flag ')'
|
|
bool LLParser::parseGVFlags(GlobalValueSummary::GVFlags &GVFlags) {
|
|
assert(Lex.getKind() == lltok::kw_flags);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
do {
|
|
unsigned Flag = 0;
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_linkage:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'"))
|
|
return true;
|
|
bool HasLinkage;
|
|
GVFlags.Linkage = parseOptionalLinkageAux(Lex.getKind(), HasLinkage);
|
|
assert(HasLinkage && "Linkage not optional in summary entry");
|
|
Lex.Lex();
|
|
break;
|
|
case lltok::kw_notEligibleToImport:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Flag))
|
|
return true;
|
|
GVFlags.NotEligibleToImport = Flag;
|
|
break;
|
|
case lltok::kw_live:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Flag))
|
|
return true;
|
|
GVFlags.Live = Flag;
|
|
break;
|
|
case lltok::kw_dsoLocal:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Flag))
|
|
return true;
|
|
GVFlags.DSOLocal = Flag;
|
|
break;
|
|
case lltok::kw_canAutoHide:
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'") || parseFlag(Flag))
|
|
return true;
|
|
GVFlags.CanAutoHide = Flag;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected gv flag type");
|
|
}
|
|
} while (EatIfPresent(lltok::comma));
|
|
|
|
if (parseToken(lltok::rparen, "expected ')' here"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// GVarFlags
|
|
/// ::= 'varFlags' ':' '(' 'readonly' ':' Flag
|
|
/// ',' 'writeonly' ':' Flag
|
|
/// ',' 'constant' ':' Flag ')'
|
|
bool LLParser::parseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags) {
|
|
assert(Lex.getKind() == lltok::kw_varFlags);
|
|
Lex.Lex();
|
|
|
|
if (parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::lparen, "expected '(' here"))
|
|
return true;
|
|
|
|
auto ParseRest = [this](unsigned int &Val) {
|
|
Lex.Lex();
|
|
if (parseToken(lltok::colon, "expected ':'"))
|
|
return true;
|
|
return parseFlag(Val);
|
|
};
|
|
|
|
do {
|
|
unsigned Flag = 0;
|
|
switch (Lex.getKind()) {
|
|
case lltok::kw_readonly:
|
|
if (ParseRest(Flag))
|
|
return true;
|
|
GVarFlags.MaybeReadOnly = Flag;
|
|
break;
|
|
case lltok::kw_writeonly:
|
|
if (ParseRest(Flag))
|
|
return true;
|
|
GVarFlags.MaybeWriteOnly = Flag;
|
|
break;
|
|
case lltok::kw_constant:
|
|
if (ParseRest(Flag))
|
|
return true;
|
|
GVarFlags.Constant = Flag;
|
|
break;
|
|
case lltok::kw_vcall_visibility:
|
|
if (ParseRest(Flag))
|
|
return true;
|
|
GVarFlags.VCallVisibility = Flag;
|
|
break;
|
|
default:
|
|
return error(Lex.getLoc(), "expected gvar flag type");
|
|
}
|
|
} while (EatIfPresent(lltok::comma));
|
|
return parseToken(lltok::rparen, "expected ')' here");
|
|
}
|
|
|
|
/// ModuleReference
|
|
/// ::= 'module' ':' UInt
|
|
bool LLParser::parseModuleReference(StringRef &ModulePath) {
|
|
// parse module id.
|
|
if (parseToken(lltok::kw_module, "expected 'module' here") ||
|
|
parseToken(lltok::colon, "expected ':' here") ||
|
|
parseToken(lltok::SummaryID, "expected module ID"))
|
|
return true;
|
|
|
|
unsigned ModuleID = Lex.getUIntVal();
|
|
auto I = ModuleIdMap.find(ModuleID);
|
|
// We should have already parsed all module IDs
|
|
assert(I != ModuleIdMap.end());
|
|
ModulePath = I->second;
|
|
return false;
|
|
}
|
|
|
|
/// GVReference
|
|
/// ::= SummaryID
|
|
bool LLParser::parseGVReference(ValueInfo &VI, unsigned &GVId) {
|
|
bool WriteOnly = false, ReadOnly = EatIfPresent(lltok::kw_readonly);
|
|
if (!ReadOnly)
|
|
WriteOnly = EatIfPresent(lltok::kw_writeonly);
|
|
if (parseToken(lltok::SummaryID, "expected GV ID"))
|
|
return true;
|
|
|
|
GVId = Lex.getUIntVal();
|
|
// Check if we already have a VI for this GV
|
|
if (GVId < NumberedValueInfos.size()) {
|
|
assert(NumberedValueInfos[GVId].getRef() != FwdVIRef);
|
|
VI = NumberedValueInfos[GVId];
|
|
} else
|
|
// We will create a forward reference to the stored location.
|
|
VI = ValueInfo(false, FwdVIRef);
|
|
|
|
if (ReadOnly)
|
|
VI.setReadOnly();
|
|
if (WriteOnly)
|
|
VI.setWriteOnly();
|
|
return false;
|
|
}
|