#include "llvm/IR/TypeFinder.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/Support/CFG.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
#include <cctype>
using namespace llvm;
+static cl::opt<bool>
+OldStyleAttrSyntax("enable-old-style-attr-syntax",
+ cl::desc("Output attributes on functions rather than in attribute groups"),
+ cl::Hidden,
+ cl::init(false));
+
// Make virtual table appear in this compilation unit.
AssemblyAnnotationWriter::~AssemblyAnnotationWriter() {}
return 0;
}
-static void PrintCallingConv(unsigned cc, raw_ostream &Out)
-{
+static void PrintCallingConv(unsigned cc, raw_ostream &Out) {
switch (cc) {
- case CallingConv::Fast: Out << "fastcc"; break;
- case CallingConv::Cold: Out << "coldcc"; break;
- case CallingConv::X86_StdCall: Out << "x86_stdcallcc"; break;
- case CallingConv::X86_FastCall: Out << "x86_fastcallcc"; break;
- case CallingConv::X86_ThisCall: Out << "x86_thiscallcc"; break;
- case CallingConv::Intel_OCL_BI: Out << "intel_ocl_bicc"; break;
- case CallingConv::ARM_APCS: Out << "arm_apcscc"; break;
- case CallingConv::ARM_AAPCS: Out << "arm_aapcscc"; break;
- case CallingConv::ARM_AAPCS_VFP:Out << "arm_aapcs_vfpcc"; break;
- case CallingConv::MSP430_INTR: Out << "msp430_intrcc"; break;
- case CallingConv::PTX_Kernel: Out << "ptx_kernel"; break;
- case CallingConv::PTX_Device: Out << "ptx_device"; break;
- default: Out << "cc" << cc; break;
+ default: Out << "cc" << cc; break;
+ case CallingConv::Fast: Out << "fastcc"; break;
+ case CallingConv::Cold: Out << "coldcc"; break;
+ case CallingConv::X86_StdCall: Out << "x86_stdcallcc"; break;
+ case CallingConv::X86_FastCall: Out << "x86_fastcallcc"; break;
+ case CallingConv::X86_ThisCall: Out << "x86_thiscallcc"; break;
+ case CallingConv::Intel_OCL_BI: Out << "intel_ocl_bicc"; break;
+ case CallingConv::ARM_APCS: Out << "arm_apcscc"; break;
+ case CallingConv::ARM_AAPCS: Out << "arm_aapcscc"; break;
+ case CallingConv::ARM_AAPCS_VFP: Out << "arm_aapcs_vfpcc"; break;
+ case CallingConv::MSP430_INTR: Out << "msp430_intrcc"; break;
+ case CallingConv::PTX_Kernel: Out << "ptx_kernel"; break;
+ case CallingConv::PTX_Device: Out << "ptx_device"; break;
}
}
}
// Scan the name to see if it needs quotes first.
- bool NeedsQuotes = isdigit(Name[0]);
+ bool NeedsQuotes = isdigit(static_cast<unsigned char>(Name[0]));
if (!NeedsQuotes) {
for (unsigned i = 0, e = Name.size(); i != e; ++i) {
// By making this unsigned, the value passed in to isalnum will always be
// its implementation will assert. This situation can arise when dealing
// with UTF-8 multibyte characters.
unsigned char C = Name[i];
- if (!isalnum(C) && C != '-' && C != '.' && C != '_') {
+ if (!isalnum(static_cast<unsigned char>(C)) && C != '-' && C != '.' &&
+ C != '_') {
NeedsQuotes = true;
break;
}
/// mdnMap - Map for MDNodes.
DenseMap<const MDNode*, unsigned> mdnMap;
unsigned mdnNext;
+
+ /// asMap - The slot map for attribute sets.
+ DenseMap<AttributeSet, unsigned> asMap;
+ unsigned asNext;
public:
/// Construct from a module
explicit SlotTracker(const Module *M);
int getLocalSlot(const Value *V);
int getGlobalSlot(const GlobalValue *V);
int getMetadataSlot(const MDNode *N);
+ int getAttributeGroupSlot(AttributeSet AS);
/// If you'd like to deal with a function instead of just a module, use
/// this method to get its data into the SlotTracker.
unsigned mdn_size() const { return mdnMap.size(); }
bool mdn_empty() const { return mdnMap.empty(); }
+ /// AttributeSet map iterators.
+ typedef DenseMap<AttributeSet, unsigned>::iterator as_iterator;
+ as_iterator as_begin() { return asMap.begin(); }
+ as_iterator as_end() { return asMap.end(); }
+ unsigned as_size() const { return asMap.size(); }
+ bool as_empty() const { return asMap.empty(); }
+
/// This function does the actual initialization.
inline void initialize();
/// CreateFunctionSlot - Insert the specified Value* into the slot table.
void CreateFunctionSlot(const Value *V);
+ /// \brief Insert the specified AttributeSet into the slot table.
+ void CreateAttributeSetSlot(AttributeSet AS);
+
/// Add all of the module level global variables (and their initializers)
/// and function declarations, but not the contents of those functions.
void processModule();
// to be added to the slot table.
SlotTracker::SlotTracker(const Module *M)
: TheModule(M), TheFunction(0), FunctionProcessed(false),
- mNext(0), fNext(0), mdnNext(0) {
+ mNext(0), fNext(0), mdnNext(0), asNext(0) {
}
// Function level constructor. Causes the contents of the Module and the one
// function provided to be added to the slot table.
SlotTracker::SlotTracker(const Function *F)
: TheModule(F ? F->getParent() : 0), TheFunction(F), FunctionProcessed(false),
- mNext(0), fNext(0), mdnNext(0) {
+ mNext(0), fNext(0), mdnNext(0), asNext(0) {
}
inline void SlotTracker::initialize() {
CreateMetadataSlot(NMD->getOperand(i));
}
- // Add all the unnamed functions to the table.
for (Module::const_iterator I = TheModule->begin(), E = TheModule->end();
- I != E; ++I)
+ I != E; ++I) {
if (!I->hasName())
+ // Add all the unnamed functions to the table.
CreateModuleSlot(I);
+ // Add all the function attributes to the table.
+ // FIXME: Add attributes of other objects?
+ AttributeSet FnAttrs = I->getAttributes().getFnAttributes();
+ if (FnAttrs.hasAttributes(AttributeSet::FunctionIndex))
+ CreateAttributeSetSlot(FnAttrs);
+ }
+
ST_DEBUG("end processModule!\n");
}
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
if (MDNode *N = dyn_cast_or_null<MDNode>(I->getOperand(i)))
CreateMetadataSlot(N);
+
+ // Add all the call attributes to the table.
+ AttributeSet Attrs = CI->getAttributes().getFnAttributes();
+ if (Attrs.hasAttributes(AttributeSet::FunctionIndex))
+ CreateAttributeSetSlot(Attrs);
+ } else if (const InvokeInst *II = dyn_cast<InvokeInst>(I)) {
+ // Add all the call attributes to the table.
+ AttributeSet Attrs = II->getAttributes().getFnAttributes();
+ if (Attrs.hasAttributes(AttributeSet::FunctionIndex))
+ CreateAttributeSetSlot(Attrs);
}
// Process metadata attached with this instruction.
return FI == fMap.end() ? -1 : (int)FI->second;
}
+int SlotTracker::getAttributeGroupSlot(AttributeSet AS) {
+ // Check for uninitialized state and do lazy initialization.
+ initialize();
+
+ // Find the AttributeSet in the module map.
+ as_iterator AI = asMap.find(AS);
+ return AI == asMap.end() ? -1 : (int)AI->second;
+}
/// CreateModuleSlot - Insert the specified GlobalValue* into the slot table.
void SlotTracker::CreateModuleSlot(const GlobalValue *V) {
CreateMetadataSlot(Op);
}
+void SlotTracker::CreateAttributeSetSlot(AttributeSet AS) {
+ assert(AS.hasAttributes(AttributeSet::FunctionIndex) &&
+ "Doesn't need a slot!");
+
+ as_iterator I = asMap.find(AS);
+ if (I != asMap.end())
+ return;
+
+ unsigned DestSlot = asNext++;
+ asMap[AS] = DestSlot;
+}
+
//===----------------------------------------------------------------------===//
// AsmWriter Implementation
//===----------------------------------------------------------------------===//
void writeAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope);
void writeAllMDNodes();
+ void writeAllAttributeGroups();
void printTypeIdentities();
void printGlobal(const GlobalVariable *GV);
}
void AssemblyWriter::printModule(const Module *M) {
+ Machine.initialize();
+
if (!M->getModuleIdentifier().empty() &&
// Don't print the ID if it will start a new line (which would
// require a comment char before it).
for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
printFunction(I);
+ // Output all attribute groups.
+ if (!OldStyleAttrSyntax && !Machine.as_empty()) {
+ Out << '\n';
+ writeAllAttributeGroups();
+ }
+
// Output named metadata.
if (!M->named_metadata_empty()) Out << '\n';
if (Name.empty()) {
Out << "<empty name> ";
} else {
- if (isalpha(Name[0]) || Name[0] == '-' || Name[0] == '$' ||
+ if (isalpha(static_cast<unsigned char>(Name[0])) ||
+ Name[0] == '-' || Name[0] == '$' ||
Name[0] == '.' || Name[0] == '_')
Out << Name[0];
else
Out << '\\' << hexdigit(Name[0] >> 4) << hexdigit(Name[0] & 0x0F);
for (unsigned i = 1, e = Name.size(); i != e; ++i) {
unsigned char C = Name[i];
- if (isalnum(C) || C == '-' || C == '$' || C == '.' || C == '_')
+ if (isalnum(static_cast<unsigned char>(C)) || C == '-' || C == '$' ||
+ C == '.' || C == '_')
Out << C;
else
Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
if (F->isMaterializable())
Out << "; Materializable\n";
+ const AttributeSet &Attrs = F->getAttributes();
+ if (!OldStyleAttrSyntax && Attrs.hasAttributes(AttributeSet::FunctionIndex)) {
+ AttributeSet AS = Attrs.getFnAttributes();
+ std::string AttrStr = AS.getAsString(AttributeSet::FunctionIndex, true);
+ if (!AttrStr.empty())
+ Out << "; Function Attrs: " << AttrStr << '\n';
+ }
+
if (F->isDeclaration())
Out << "declare ";
else
}
FunctionType *FT = F->getFunctionType();
- const AttributeSet &Attrs = F->getAttributes();
if (Attrs.hasAttributes(AttributeSet::ReturnIndex))
Out << Attrs.getAsString(AttributeSet::ReturnIndex) << ' ';
TypePrinter.print(F->getReturnType(), Out);
Out << ')';
if (F->hasUnnamedAddr())
Out << " unnamed_addr";
- if (Attrs.hasAttributes(AttributeSet::FunctionIndex))
- Out << ' ' << Attrs.getAsString(AttributeSet::FunctionIndex);
+ if (!OldStyleAttrSyntax) {
+ if (Attrs.hasAttributes(AttributeSet::FunctionIndex))
+ Out << " #" << Machine.getAttributeGroupSlot(Attrs.getFnAttributes());
+ } else {
+ AttributeSet AS = Attrs.getFnAttributes();
+ std::string AttrStr = AS.getAsString(AttributeSet::FunctionIndex, true);
+ if (!AttrStr.empty())
+ Out << ' ' << AttrStr;
+ }
if (F->hasSection()) {
Out << " section \"";
PrintEscapedString(F->getSection(), Out);
/// which slot it occupies.
///
void AssemblyWriter::printInfoComment(const Value &V) {
- if (AnnotationWriter) {
+ if (AnnotationWriter)
AnnotationWriter->printInfoComment(V, Out);
- return;
- }
}
// This member is called for each Instruction in a function..
}
Out << ')';
if (PAL.hasAttributes(AttributeSet::FunctionIndex))
- Out << ' ' << PAL.getAsString(AttributeSet::FunctionIndex);
+ Out << " #" << Machine.getAttributeGroupSlot(PAL.getFnAttributes());
} else if (const InvokeInst *II = dyn_cast<InvokeInst>(&I)) {
Operand = II->getCalledValue();
PointerType *PTy = cast<PointerType>(Operand->getType());
Out << ')';
if (PAL.hasAttributes(AttributeSet::FunctionIndex))
- Out << ' ' << PAL.getAsString(AttributeSet::FunctionIndex);
+ Out << " #" << Machine.getAttributeGroupSlot(PAL.getFnAttributes());
Out << "\n to ";
writeOperand(II->getNormalDest(), true);
return;
DIDescriptor Desc(Node);
- if (Desc.getVersion() < LLVMDebugVersion11)
+ if (!Desc.Verify())
return;
unsigned Tag = Desc.getTag();
Out << "\n";
}
+void AssemblyWriter::writeAllAttributeGroups() {
+ std::vector<std::pair<AttributeSet, unsigned> > asVec;
+ asVec.resize(Machine.as_size());
+
+ for (SlotTracker::as_iterator I = Machine.as_begin(), E = Machine.as_end();
+ I != E; ++I)
+ asVec[I->second] = *I;
+
+ for (std::vector<std::pair<AttributeSet, unsigned> >::iterator
+ I = asVec.begin(), E = asVec.end(); I != E; ++I)
+ Out << "attributes #" << I->second << " = { "
+ << I->first.getAsString(AttributeSet::FunctionIndex, false, true)
+ << " }\n";
+}
+
//===----------------------------------------------------------------------===//
// External Interface declarations
//===----------------------------------------------------------------------===//