# HG changeset patch # User Frits van Bommel # Date 1241259583 -7200 # Node ID 6c8af78364f5a12bbdbfaf58013ea124bc6daaca # Parent 23b23b74e3264b784fa0456d2d4ec8fc7530fd05 There's an issue with LLVM metadata support; it triggers an assert when trying to generate asm for code with metadata globals. This new pass is used as a workaround: it strips metadata from the module before it reaches the code generator. Obviously, this is disabled if LLVM doesn't support metadata. diff -r 23b23b74e326 -r 6c8af78364f5 gen/optimizer.cpp --- a/gen/optimizer.cpp Sat May 02 11:58:50 2009 +0200 +++ b/gen/optimizer.cpp Sat May 02 12:19:43 2009 +0200 @@ -50,6 +50,12 @@ cl::desc("Disable promotion of GC allocations to stack memory in -O"), cl::ZeroOrMore); +// Not recommended; metadata currently triggers an assert in the backend... +static cl::opt +disableStripMetaData("disable-strip-metadata", + cl::desc("Disable default metadata stripping (not recommended)"), + cl::ZeroOrMore); + static cl::opt enableInlining("inlining", cl::desc("(*) Enable function inlining in -O"), @@ -137,6 +143,13 @@ pm.add(createCFGSimplificationPass()); } } +#ifdef USE_METADATA + if (!disableStripMetaData) { + // This one is purposely not disabled by disableLangSpecificPasses + // because the code generator will assert if it's not used. + pm.add(createStripMetaData()); + } +#endif // -O3 if (optimizeLevel >= 3) @@ -181,8 +194,18 @@ // Returns true if any optimization passes were invoked. bool ldc_optimize_module(llvm::Module* m) { - if (!optimize()) + if (!optimize()) { +#ifdef USE_METADATA + if (!disableStripMetaData) { + // This one always needs to run if metadata is generated, because + // the code generator will assert if it's not used. + ModulePass* stripMD = createStripMetaData(); + stripMD->runOnModule(*m); + delete stripMD; + } +#endif return false; + } PassManager pm; pm.add(new TargetData(m)); diff -r 23b23b74e326 -r 6c8af78364f5 gen/passes/Passes.h --- a/gen/passes/Passes.h Sat May 02 11:58:50 2009 +0200 +++ b/gen/passes/Passes.h Sat May 02 12:19:43 2009 +0200 @@ -1,13 +1,19 @@ #ifndef LDC_PASSES_H #define LDC_PASSES_H +#include "gen/metadata.h" namespace llvm { class FunctionPass; + class ModulePass; } // Performs simplifications on runtime calls. llvm::FunctionPass* createSimplifyDRuntimeCalls(); llvm::FunctionPass* createGarbageCollect2Stack(); +#ifdef USE_METADATA +llvm::ModulePass *createStripMetaData(); +#endif + #endif diff -r 23b23b74e326 -r 6c8af78364f5 gen/passes/StripMetaData.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/passes/StripMetaData.cpp Sat May 02 12:19:43 2009 +0200 @@ -0,0 +1,85 @@ +//===- StripMetaData - Strips D-specific metadata -------------------------===// +// +// The LLVM D Compiler +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// There's an issue with the new LLVM metadata support; an assertion fires when +// trying to generate asm for metadata globals. +// +// This pass is a workaround; it deletes the metadata LDC generates so the code +// generator doesn't see it. +// Obviously, this should only run after all passes that make use of that +// metadata or they won't work. +// +//===----------------------------------------------------------------------===// + +#include "gen/metadata.h" + +// This pass isn't needed without metadata, so #ifdef it out entirely if the +// LLVM version in use doesn't support it. +#ifdef USE_METADATA + + +#define DEBUG_TYPE "strip-metadata" + +#include "Passes.h" + +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Constants.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +using namespace llvm; + +STATISTIC(NumDeleted, "Number of metadata globals deleted"); + +//===----------------------------------------------------------------------===// +// StripMetaData Pass Implementation +//===----------------------------------------------------------------------===// + +namespace { + /// This pass optimizes library functions from the D runtime as used by LDC. + /// + class VISIBILITY_HIDDEN StripMetaData : public ModulePass { + public: + static char ID; // Pass identification + StripMetaData() : ModulePass(&ID) {} + + bool runOnModule(Module &M); + }; + char StripMetaData::ID = 0; +} // end anonymous namespace. + +static RegisterPass +X("strip-metadata", "Delete D-specific metadata"); + +// Public interface to the pass. +ModulePass *createStripMetaData() { + return new StripMetaData(); +} + +/// runOnFunction - Top level algorithm. +/// +bool StripMetaData::runOnModule(Module &M) { + bool Changed = false; + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E;) { + GlobalVariable* G = I++; + if (G->getNameLen() >= 9 && !strncmp(G->getNameStart(), "llvm.ldc.", 9)) { + assert(G->hasInitializer() && isa(G->getInitializer()) + && "Not a metadata global?"); + Changed = true; + NumDeleted++; + DEBUG(DOUT << "Deleting " << *G << '\n'); + G->eraseFromParent(); + } + } + return Changed; +} + + +#endif //USE_METADATA