[llvm-commits] [dragonegg] r86682 - in /dragonegg/trunk: llvm-convert.cpp llvm-internal.h

Duncan Sands baldrick at free.fr
Tue Nov 10 02:25:00 PST 2009


Author: baldrick
Date: Tue Nov 10 04:24:57 2009
New Revision: 86682

URL: http://llvm.org/viewvc/llvm-project?rev=86682&view=rev
Log:
It is important for Ada to get rid of trampolines wherever possible.
Unfortunately the optimizers have a hard time doing this.  Help them
out by using llvm.invariant.start to mark the trampoline storage as
being constant after the initial write.

The llvm.invariant.start/end intrinsics are annoyingly hard to use.
There needs to be an llvm.invariant.end call because otherwise the
llvm.invariant.start call will be deleted being readonly.  The call
to llvm.invariant.start needs to dominate the end call, which is
hard to achieve cheaply unless the start call is in the entry block.
This is the reason this patch pushes the trampoline initialization
into the entry block.  The region lasts until the end of the function,
which means calling llvm.invariant.end at every possible exit point
of the program.  This is impossible in general, since potentially the
optimizers may discover that some call in the program does not return,
at which point they may discard vast amounts of unreachable code which
might include any llvm.invariant.end calls, at which point the start
calls will be deleted too being readonly with no uses.

Modified:
    dragonegg/trunk/llvm-convert.cpp
    dragonegg/trunk/llvm-internal.h

Modified: dragonegg/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-convert.cpp?rev=86682&r1=86681&r2=86682&view=diff

==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Tue Nov 10 04:24:57 2009
@@ -763,6 +763,26 @@
 typedef SmallVector<std::pair<BasicBlock*, tree>, 8> TreeVector;
 typedef SmallVector<std::pair<BasicBlock*, Value*>, 8> ValueVector;
 
+/// EndInvariantRegions - Output a call to llvm.invariant.end for each call
+/// to llvm.invariant.start recorded in InvariantRegions.
+void TreeToLLVM::EndInvariantRegions() {
+  if (InvariantRegions.empty())
+    return;
+
+  Value *Ops[3];
+  Value *IEnd = Intrinsic::getDeclaration(TheModule,Intrinsic::invariant_end);
+  for (unsigned i = 0, e = InvariantRegions.size(); i < e; ++i) {
+    CallInst *CI = InvariantRegions[i];
+    Ops[0] = CI;
+    Ops[1] = CI->getOperand(1);
+    Ops[2] = CI->getOperand(2);
+    Builder.CreateCall(IEnd, Ops, Ops + 3);
+  }
+
+  // Do not clear out InvariantRegions in case the function has multiple exits:
+  // we need to output calls to llvm.invariant.end before each one.
+}
+
 /// PopulatePhiNodes - Populate generated phi nodes with their operands.
 void TreeToLLVM::PopulatePhiNodes() {
   PredVector Predecessors;
@@ -929,6 +949,9 @@
     TheDebugInfo->EmitStopPoint(Fn, Builder.GetInsertBlock(), Builder);
     TheDebugInfo->EmitFunctionEnd(Builder.GetInsertBlock(), true);
   }
+
+  EndInvariantRegions();
+
   if (RetVals.empty())
     Builder.CreateRetVoid();
   else if (RetVals.size() == 1 && RetVals[0]->getType() == Fn->getReturnType()){
@@ -2105,6 +2128,7 @@
   if (UnwindBB) {
     CreateExceptionValues();
     EmitBlock(UnwindBB);
+    EndInvariantRegions();
 abort();//FIXME
 //FIXME    // Fetch and store exception handler.
 //FIXME    Value *Arg = Builder.CreateLoad(ExceptionValue, "eh_ptr");
@@ -2543,6 +2567,7 @@
   // after the function to prevent LLVM from thinking that control flow will
   // fall into the subsequent block.
   if (gimple_call_flags(stmt) & ECF_NORETURN) {
+    EndInvariantRegions();
     Builder.CreateUnreachable();
     EmitBlock(BasicBlock::Create(Context));
   }
@@ -4613,6 +4638,7 @@
   case BUILT_IN_TRAP:
     Builder.CreateCall(Intrinsic::getDeclaration(TheModule, Intrinsic::trap));
     // Emit an explicit unreachable instruction.
+    EndInvariantRegions();
     Builder.CreateUnreachable();
     EmitBlock(BasicBlock::Create(Context));
     return true;
@@ -5459,6 +5485,7 @@
   Args.push_back(Handler);
   Builder.CreateCall(Intrinsic::getDeclaration(TheModule, IID),
 		     Args.begin(), Args.end());
+  EndInvariantRegions();
   Result = Builder.CreateUnreachable();
   EmitBlock(BasicBlock::Create(Context));
 
@@ -5672,6 +5699,26 @@
   // is called.
   static const Type *VPTy = Type::getInt8PtrTy(Context);
 
+  // In order to simplify the use of llvm.invariant.start/end, generate the
+  // trampoline initialization code in the entry block.
+  BasicBlock *EntryBlock = Fn->begin();
+
+  // Note the current builder position.
+  BasicBlock *SavedInsertBB = Builder.GetInsertBlock();
+  BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint();
+
+  // Pop the entry block terminator.  There may not be a terminator if the entry
+  // block was not yet finished.
+  Instruction *Terminator = EntryBlock->getTerminator();
+  assert(((SavedInsertBB != EntryBlock && Terminator) ||
+          (SavedInsertPoint == EntryBlock->end() && !Terminator)) &&
+         "Insertion point doesn't make sense!");
+  if (Terminator)
+    Terminator->removeFromParent();
+
+  // Point the builder at the end of the entry block.
+  Builder.SetInsertPoint(EntryBlock);
+
   // Create a stack temporary to hold the trampoline machine code.
   const Type *TrampType = ArrayType::get(Type::getInt8Ty(Context),
                                          TRAMPOLINE_SIZE);
@@ -5703,6 +5750,22 @@
   unsigned Align = TYPE_ALIGN(TREE_TYPE(TREE_TYPE(gimple_call_arg(stmt, 0))))/8;
   Store->setAlignment(Align);
 
+  // The GCC trampoline storage is constant from this point on.   Tell this to
+  // the optimizers.
+  Intr = Intrinsic::getDeclaration(TheModule, Intrinsic::invariant_start);
+  Ops[0] = ConstantInt::get(Type::getInt64Ty(Context), TRAMPOLINE_SIZE);
+  Ops[1] = Builder.CreateBitCast(Tramp, VPTy);
+  CallInst *InvStart = Builder.CreateCall(Intr, Ops, Ops + 2);
+  InvariantRegions.push_back(InvStart);
+
+  // Restore the entry block terminator.
+  if (Terminator)
+    EntryBlock->getInstList().push_back(Terminator);
+
+  // Restore the builder insertion point.
+  if (SavedInsertBB != EntryBlock)
+    Builder.SetInsertPoint(SavedInsertBB, SavedInsertPoint);
+
   return true;
 }
 

Modified: dragonegg/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-internal.h?rev=86682&r1=86681&r2=86682&view=diff

==============================================================================
--- dragonegg/trunk/llvm-internal.h (original)
+++ dragonegg/trunk/llvm-internal.h Tue Nov 10 04:24:57 2009
@@ -357,6 +357,10 @@
   /// LocalDecls - Map from local declarations to their associated LLVM values.
   DenseMap<tree, AssertingVH<> > LocalDecls;
 
+  /// InvariantRegions - Calls to llvm.invariant.start for which a corresponding
+  /// call to llvm.invariant.end needs to be generated at function exit points.
+  SmallVector<CallInst*, 8> InvariantRegions;
+
   /// PendingPhis - Phi nodes which have not yet been populated with operands.
   SmallVector<PhiRecord, 16> PendingPhis;
 
@@ -469,11 +473,15 @@
   /// StartFunctionBody - Start the emission of 'fndecl', outputing all
   /// declarations for parameters and setting things up.
   void StartFunctionBody();
-  
+
   /// FinishFunctionBody - Once the body of the function has been emitted, this
   /// cleans up and returns the result function.
   Function *FinishFunctionBody();
 
+  /// EndInvariantRegions - Output a call to llvm.invariant.end for each call
+  /// of llvm.invariant.start recorded in InvariantRegions.
+  void EndInvariantRegions();
+
   /// PopulatePhiNodes - Populate generated phi nodes with their operands.
   void PopulatePhiNodes();
 





More information about the llvm-commits mailing list