Commit 07590e89 authored by Stelle, George Widgery's avatar Stelle, George Widgery
Browse files

Updated for opencilk v1.0

parent 4eb5119b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -253,6 +253,8 @@ public:
  /// Returns true if Function F should be processed.
  virtual bool shouldProcessFunction(const Function &F) const;

  virtual void prepareModule() {}

  /// Returns true if tasks in Function F should be outlined into their own
  /// functions.  Such outlining is a common step for many Tapir backends.
  virtual bool shouldDoOutlining(const Function &F) const { return true; }
+9 −13
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ class TapirLoopInfo;
class OpenCilkABI : public TapirTarget {
  ValueToValueMapTy DetachCtxToStackFrame;
  SmallPtrSet<CallBase *, 8> CallsToInline;
  LoopOutlineProcessor *LOP = nullptr;

  // Cilk RTS data types
  StructType *StackFrameTy = nullptr;
@@ -66,6 +65,7 @@ class OpenCilkABI : public TapirTarget {
  Function *Get__cilkrts_enter_frame();
  Function *Get__cilkrts_enter_frame_fast();
  Function *Get__cilkrts_detach();
  Function *Get__cilkrts_save_fp_ctrl_state();
  Function *Get__cilkrts_pop_frame();

  // Helper functions for implementing the Cilk ABI protocol
@@ -73,7 +73,6 @@ class OpenCilkABI : public TapirTarget {
  Function *GetCilkSyncNoThrowFn();
  Function *GetCilkPauseFrameFn();
  Function *GetCilkParentEpilogueFn();
  void EmitSaveFloatingPointState(IRBuilder<> &B, Value *SF);

  AllocaInst *CreateStackFrame(Function &F);
  Value *GetOrCreateCilkStackFrame(Function &F);
@@ -92,11 +91,8 @@ class OpenCilkABI : public TapirTarget {

public:
  OpenCilkABI(Module &M);
  ~OpenCilkABI() {
    DetachCtxToStackFrame.clear();
    if (LOP)
      delete LOP;
  }
  ~OpenCilkABI() { DetachCtxToStackFrame.clear(); }
  void prepareModule() override final;
  Value *lowerGrainsizeCall(CallInst *GrainsizeCall) override final;
  void lowerSync(SyncInst &SI) override final;

@@ -106,9 +102,9 @@ public:
  void addHelperAttributes(Function &F) override final;

  void preProcessFunction(Function &F, TaskInfo &TI,
                          bool OutliningTapirLoops) override final;
  void postProcessFunction(Function &F, bool OutliningTapirLoops)
    override final;
                          bool ProcessingTapirLoops) override final;
  void postProcessFunction(Function &F,
                           bool ProcessingTapirLoops) override final;
  void postProcessHelper(Function &F) override final;

  void preProcessOutlinedTask(Function &F, Instruction *DetachPt,
@@ -119,12 +115,12 @@ public:
                               bool IsSpawner) override final;
  void preProcessRootSpawner(Function &F) override final;
  void postProcessRootSpawner(Function &F) override final;
  void processSubTaskCall(TaskOutlineInfo &TOI, DominatorTree &DT)
    override final;
  void processSubTaskCall(TaskOutlineInfo &TOI,
                          DominatorTree &DT) override final;

  LoopOutlineProcessor *
  getLoopOutlineProcessor(const TapirLoopInfo *TL) override final;
};
}  // end of llvm namespace
} // namespace llvm

#endif
+166 −67
Original line number Diff line number Diff line
@@ -12,21 +12,26 @@
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Tapir/OpenCilkABI.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Transforms/Tapir/CilkRTSCilkFor.h"
#include "llvm/Transforms/Tapir/Outline.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/EscapeEnumerator.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/TapirUtils.h"
#include "llvm/Support/Process.h"

using namespace llvm;

@@ -35,6 +40,14 @@ using namespace llvm;
extern cl::opt<bool> DebugABICalls;
extern cl::opt<bool> UseExternalABIFunctions;

static cl::opt<bool> UseOpenCilkRuntimeBC(
    "use-opencilk-runtime-bc", cl::init(true),
    cl::desc("Use a bitcode file for the OpenCilk runtime ABI"), cl::Hidden);
static cl::opt<std::string> OpenCilkRuntimeBCPath(
    "opencilk-runtime-bc-path", cl::init(""),
    cl::desc("Path to the bitcode file for the OpenCilk runtime ABI"),
    cl::Hidden);

enum {
  __CILKRTS_ABI_VERSION_OPENCILK = 3
};
@@ -66,13 +79,56 @@ enum {

#define CILKRTS_FUNC(name) Get__cilkrts_##name()

OpenCilkABI::OpenCilkABI(Module &M)
  : TapirTarget(M)
{
OpenCilkABI::OpenCilkABI(Module &M) : TapirTarget(M) {}

void OpenCilkABI::prepareModule() {
  LLVMContext &C = M.getContext();
  Type *VoidPtrTy = Type::getInt8PtrTy(C);
  Type *Int32Ty = Type::getInt32Ty(C);

  if (UseOpenCilkRuntimeBC) {
    Optional<std::string> path; 
    if("" == OpenCilkRuntimeBCPath){
      path = sys::Process::FindInEnvPath("LD_LIBRARY_PATH", "libopencilk-abi.bc");
      assert(path.hasValue() &&
             "Couldn't find OpenCilk runtime bitcode file in LD_LIBRARY_PATH.");
    } else {
      path = OpenCilkRuntimeBCPath.getValue();
    }
    LLVM_DEBUG(dbgs() << "Using external bitcode file for OpenCilk ABI: "
                      << OpenCilkRuntimeBCPath << "\n");
    SMDiagnostic SMD;

    // Parse the bitcode file.  This call imports structure definitions, but not
    // function definitions.
    std::unique_ptr<Module> ExternalModule =
        parseIRFile(*path, SMD, C);

    // Strip any debug info from the external module.  For convenience, this
    // Tapir target synthesizes some helper functions, like
    // __cilk_parent_epilogue, that contain calls to these functions, but don't
    // necessarily have debug info.  As a result, debug info in the external
    // module causes failures during subsequent inlining.
    StripDebugInfo(*ExternalModule);

    // Link the external module into the current module, copying over global
    // values.
    //
    // TODO: Consider restructuring the import process to use
    // Linker::Flags::LinkOnlyNeeded to copy over only the necessary contents
    // from the external module.
    bool Fail =
        Linker::linkModules(M, std::move(ExternalModule), Linker::Flags::None,
                            [](Module &M, const StringSet<> &GVS) {
                              LLVM_DEBUG({
                                for (StringRef GVName : GVS.keys())
                                  dbgs() << "Linking global value " << GVName
                                         << "\n";
                              });
                            });
    assert(!Fail && "Failed to link OpenCilk runtime bitcode module.\n");
  }

  // Get or create local definitions of Cilk RTS structure types.
  const char *StackFrameName = "struct.__cilkrts_stack_frame";
  StackFrameTy = StructType::lookupOrCreate(C, StackFrameName);
@@ -359,22 +415,6 @@ static Value *LoadSTyField(
  return L;
}

/// Emit inline assembly code to save the floating point state, for x86 Only.
void OpenCilkABI::EmitSaveFloatingPointState(IRBuilder<> &B, Value *SF) {
  LLVMContext &C = B.getContext();
  if (StackFrameFieldMXCSR >= 0) {
    FunctionType *FTy =
      FunctionType::get(Type::getVoidTy(C),
			{PointerType::getUnqual(Type::getInt32Ty(C))},
			false);
    Value *Asm = InlineAsm::get(FTy, "stmxcsr $0", "*m", /*sideeffects*/ true);
    Value *Args[1] = {
      GEP(B, SF, StackFrameFieldMXCSR),
    };
    B.CreateCall(Asm, Args);
  }
}

/// Helper to find a function with the given name, creating it if it doesn't
/// already exist. Returns false if the function was inserted, indicating that
/// the body of the function has yet to be defined.
@@ -397,9 +437,7 @@ CallInst *OpenCilkABI::EmitCilkSetJmp(IRBuilder<> &B, Value *SF) {
  LLVMContext &Ctx = M.getContext();

  // We always want to save the floating point state too
  Triple T(M.getTargetTriple());
  if (T.getArch() == Triple::x86 || T.getArch() == Triple::x86_64)
    EmitSaveFloatingPointState(B, SF);
  B.CreateCall(CILKRTS_FUNC(save_fp_ctrl_state), SF);

  Type *Int32Ty = Type::getInt32Ty(Ctx);
  Type *Int8PtrTy = Type::getInt8PtrTy(Ctx);
@@ -449,8 +487,13 @@ Function *OpenCilkABI::Get__cilkrts_pop_frame() {
  Function *Fn = nullptr;
  if (GetOrCreateFunction(M, "__cilkrts_pop_frame",
                          FunctionType::get(VoidTy, {StackFramePtrTy}, false),
                          Fn))
                          Fn)) {
    Fn->setLinkage(Function::AvailableExternallyLinkage);
    Fn->setDoesNotThrow();
    if (!DebugABICalls && !UseExternalABIFunctions)
      Fn->addFnAttr(Attribute::AlwaysInline);
    return Fn;
  }

  // Create the body of __cilkrts_pop_frame.
  const DataLayout &DL = M.getDataLayout();
@@ -520,8 +563,13 @@ Function *OpenCilkABI::Get__cilkrts_detach() {
  Function *Fn = nullptr;
  if (GetOrCreateFunction(M, "__cilkrts_detach",
                          FunctionType::get(VoidTy, {StackFramePtrTy}, false),
                          Fn))
                          Fn)) {
    Fn->setLinkage(Function::AvailableExternallyLinkage);
    Fn->setDoesNotThrow();
    if (!DebugABICalls && !UseExternalABIFunctions)
      Fn->addFnAttr(Attribute::AlwaysInline);
    return Fn;
  }

  // Create the body of __cilkrts_detach.
  const DataLayout &DL = M.getDataLayout();
@@ -581,6 +629,43 @@ Function *OpenCilkABI::Get__cilkrts_detach() {
  return Fn;
}

// Call system-dependent function to save floating-point state
Function *OpenCilkABI::Get__cilkrts_save_fp_ctrl_state() {
  LLVMContext &Ctx = M.getContext();
  Type *VoidTy = Type::getVoidTy(Ctx);
  PointerType *StackFramePtrTy = PointerType::getUnqual(StackFrameTy);
  Function *Fn = nullptr;
  if (GetOrCreateFunction(M, "__cilkrts_save_fp_ctrl_state",
                          FunctionType::get(VoidTy, {StackFramePtrTy}, false),
                          Fn)) {
    Fn->setLinkage(Function::AvailableExternallyLinkage);
    Fn->setDoesNotThrow();
    if (!DebugABICalls && !UseExternalABIFunctions)
      Fn->addFnAttr(Attribute::AlwaysInline);
    return Fn;
  }

  Function::arg_iterator Args = Fn->arg_begin();
  Value *SF = &*Args;

  BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", Fn);
  IRBuilder<> B(Entry);

  if (StackFrameFieldMXCSR >= 0) {
    FunctionType *FTy = FunctionType::get(
        VoidTy, {PointerType::getUnqual(Type::getInt32Ty(Ctx))}, false);
    Value *Asm = InlineAsm::get(FTy, "stmxcsr $0", "*m", /*sideeffects*/ true);
    Value *Args[1] = {
        GEP(B, SF, StackFrameFieldMXCSR),
    };
    B.CreateCall(Asm, Args);
  }

  B.CreateRetVoid();

  return Fn;
}

/// Get or create a LLVM function for __cilk_sync.  Calls to this function are
/// always inlined, as it saves the current stack/frame pointer values. This
/// function must be marked as returns_twice to allow it to be inlined, since
@@ -888,10 +973,19 @@ Function *OpenCilkABI::Get__cilkrts_enter_frame() {
  Type *VoidTy = Type::getVoidTy(Ctx);
  PointerType *StackFramePtrTy = PointerType::getUnqual(StackFrameTy);
  Function *Fn = nullptr;
  // NOTE(TFK): If the function was imported from the opencilk bitcode file
  //            then it will not have the requisite attributes. It is perhaps
  //            better to set these attributes when creating the opencilk bitcode
  //            file... for now I set them here.
  if (GetOrCreateFunction(M, "__cilkrts_enter_frame",
                          FunctionType::get(VoidTy, {StackFramePtrTy}, false),
                          Fn))
                          Fn)) {
    Fn->setLinkage(Function::AvailableExternallyLinkage);
    Fn->setDoesNotThrow();
    if (!DebugABICalls && !UseExternalABIFunctions)
      Fn->addFnAttr(Attribute::AlwaysInline);
    return Fn;
  }

  // Create the body of __cilkrts_enter_frame.
  const DataLayout &DL = M.getDataLayout();
@@ -1005,10 +1099,19 @@ Function *OpenCilkABI::Get__cilkrts_enter_frame_fast() {
  Type *VoidTy = Type::getVoidTy(Ctx);
  PointerType *StackFramePtrTy = PointerType::getUnqual(StackFrameTy);
  Function *Fn = nullptr;
  // NOTE(TFK): If the function was imported from the opencilk bitcode file
  //            then it will not have the requisite attributes. It is perhaps
  //            better to set these attributes when creating the opencilk bitcode
  //            file... for now I set them here.
  if (GetOrCreateFunction(M, "__cilkrts_enter_frame_fast",
                          FunctionType::get(VoidTy, {StackFramePtrTy}, false),
                          Fn))
                          Fn)) {
    Fn->setLinkage(Function::AvailableExternallyLinkage);
    Fn->setDoesNotThrow();
    if (!DebugABICalls && !UseExternalABIFunctions)
      Fn->addFnAttr(Attribute::AlwaysInline);
    return Fn;
  }

  // Create the body of __cilkrts_enter_frame_fast.
  const DataLayout &DL = M.getDataLayout();
@@ -1195,15 +1298,15 @@ CallInst *OpenCilkABI::InsertStackFramePush(Function &F,
  AllocaInst *SF = cast<AllocaInst>(GetOrCreateCilkStackFrame(F));

  BasicBlock::iterator InsertPt = ++SF->getIterator();
  IRBuilder<> IRB(&(F.getEntryBlock()), InsertPt);
  IRBuilder<> B(&(F.getEntryBlock()), InsertPt);
  if (TaskFrameCreate)
    IRB.SetInsertPoint(TaskFrameCreate);
    B.SetInsertPoint(TaskFrameCreate);

  Value *Args[1] = {SF};
  if (Helper)
    return IRB.CreateCall(CILKRTS_FUNC(enter_frame_fast), Args);
    return B.CreateCall(CILKRTS_FUNC(enter_frame_fast), Args);
  else
    return IRB.CreateCall(CILKRTS_FUNC(enter_frame), Args);
    return B.CreateCall(CILKRTS_FUNC(enter_frame), Args);
}

void OpenCilkABI::InsertStackFramePop(Function &F, bool PromoteCallsToInvokes,
@@ -1215,12 +1318,11 @@ void OpenCilkABI::InsertStackFramePop(Function &F, bool PromoteCallsToInvokes,
  // Add eh cleanup that returns control to the runtime
  EscapeEnumerator EE(F, "cilkrabi_cleanup", PromoteCallsToInvokes);
  while (IRBuilder<> *Builder = EE.Next()) {
    if (ResumeInst *RI = dyn_cast<ResumeInst>(Builder->GetInsertPoint())) {
    if (ResumeInst *RI = dyn_cast<ResumeInst>(Builder->GetInsertPoint()))
      Resumes.insert(RI);
    } else if (ReturnInst *RI = dyn_cast<ReturnInst>(Builder->GetInsertPoint())) {
    else if (ReturnInst *RI = dyn_cast<ReturnInst>(Builder->GetInsertPoint()))
      Returns.insert(RI);
  }
  }

  for (ReturnInst *RI : Returns) {
    if (Helper) {
@@ -1358,7 +1460,7 @@ void OpenCilkABI::preProcessOutlinedTask(Function &F, Instruction *DetachPt,
    MarkSpawner(F);

  CallInst *EnterFrame =
      InsertStackFramePush(F, TaskFrameCreate, /*Helper*/false);
      InsertStackFramePush(F, TaskFrameCreate, /*Helper*/ true);
  InsertDetach(F, (DetachPt ? DetachPt : &*(++EnterFrame->getIterator())));
}

@@ -1459,17 +1561,14 @@ static inline void inlineCilkFunctions(
}

void OpenCilkABI::preProcessFunction(Function &F, TaskInfo &TI,
                                  bool OutliningTapirLoops) {
  if (OutliningTapirLoops)
                                     bool ProcessingTapirLoops) {
  if (ProcessingTapirLoops)
    // Don't do any preprocessing when outlining Tapir loops.
    return;

  if (F.getName() == "main")
    F.setName("cilk_main");
}

void OpenCilkABI::postProcessFunction(Function &F, bool OutliningTapirLoops) {
  if (OutliningTapirLoops)
void OpenCilkABI::postProcessFunction(Function &F, bool ProcessingTapirLoops) {
  if (ProcessingTapirLoops)
    // Don't do any postprocessing when outlining Tapir loops.
    return;

@@ -1479,9 +1578,9 @@ void OpenCilkABI::postProcessFunction(Function &F, bool OutliningTapirLoops) {

void OpenCilkABI::postProcessHelper(Function &F) {}

LoopOutlineProcessor *
OpenCilkABI::getLoopOutlineProcessor(const TapirLoopInfo *TL) {
  if (UseRuntimeCilkFor && !LOP)
    LOP = new RuntimeCilkFor(M);
  return LOP;
LoopOutlineProcessor *OpenCilkABI::getLoopOutlineProcessor(
    const TapirLoopInfo *TL) {
  if (UseRuntimeCilkFor)
    return new RuntimeCilkFor(M);
  return nullptr;
}
+2 −0
Original line number Diff line number Diff line
@@ -475,6 +475,8 @@ bool TapirToTargetImpl::run() {
  if (WorkList.empty())
    return false;

  Target->prepareModule();

  bool Changed = false;
  while (!WorkList.empty()) {
    // Process the next function.