llvm/lib/Transforms/Coroutines/CoroCleanup.cpp
Gor Nishanov 6ff9c199ca [Coroutines] Part13: Handle single edge PHINodes across suspends
Summary:
If one of the uses of the value is a single edge PHINode, handle it.

Original:

    %val = something
    <suspend>
    %p = PHINode [%val]

After Spill + Part13:

    %val = something
    %slot = gep val.spill.slot
    store %val, %slot
    <suspend>
    %p = load %slot

Plus tiny fixes/changes:
   * use correct index for coro.free in CoroCleanup
   * fixup id parameter in coro.free to allow authoring coroutine in plain C with __builtins

Reviewers: majnemer

Subscribers: mehdi_amini, llvm-commits

Differential Revision: https://reviews.llvm.org/D24242

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281020 91177308-0d34-0410-b5e6-96231b3b80d8
2016-09-09 05:39:00 +00:00

112 lines
3.2 KiB
C++

//===- CoroCleanup.cpp - Coroutine Cleanup Pass ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This pass lowers all remaining coroutine intrinsics.
//===----------------------------------------------------------------------===//
#include "CoroInternal.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Scalar.h"
using namespace llvm;
#define DEBUG_TYPE "coro-cleanup"
namespace {
// Created on demand if CoroCleanup pass has work to do.
struct Lowerer : coro::LowererBase {
Lowerer(Module &M) : LowererBase(M) {}
bool lowerRemainingCoroIntrinsics(Function &F);
};
}
static void simplifyCFG(Function &F) {
llvm::legacy::FunctionPassManager FPM(F.getParent());
FPM.add(createCFGSimplificationPass());
FPM.doInitialization();
FPM.run(F);
FPM.doFinalization();
}
bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) {
bool Changed = false;
for (auto IB = inst_begin(F), E = inst_end(F); IB != E;) {
Instruction &I = *IB++;
if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
switch (II->getIntrinsicID()) {
default:
continue;
case Intrinsic::coro_begin:
II->replaceAllUsesWith(II->getArgOperand(1));
break;
case Intrinsic::coro_free:
II->replaceAllUsesWith(II->getArgOperand(1));
break;
case Intrinsic::coro_alloc:
II->replaceAllUsesWith(ConstantInt::getTrue(Context));
break;
case Intrinsic::coro_id:
II->replaceAllUsesWith(ConstantTokenNone::get(Context));
break;
}
II->eraseFromParent();
Changed = true;
}
}
if (Changed) {
// After replacement were made we can cleanup the function body a little.
simplifyCFG(F);
}
return Changed;
}
//===----------------------------------------------------------------------===//
// Top Level Driver
//===----------------------------------------------------------------------===//
namespace {
struct CoroCleanup : FunctionPass {
static char ID; // Pass identification, replacement for typeid
CoroCleanup() : FunctionPass(ID) {}
std::unique_ptr<Lowerer> L;
// This pass has work to do only if we find intrinsics we are going to lower
// in the module.
bool doInitialization(Module &M) override {
if (coro::declaresIntrinsics(M, {"llvm.coro.alloc", "llvm.coro.begin",
"llvm.coro.free", "llvm.coro.id"}))
L = llvm::make_unique<Lowerer>(M);
return false;
}
bool runOnFunction(Function &F) override {
if (L)
return L->lowerRemainingCoroIntrinsics(F);
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
if (!L)
AU.setPreservesAll();
}
};
}
char CoroCleanup::ID = 0;
INITIALIZE_PASS(CoroCleanup, "coro-cleanup",
"Lower all coroutine related intrinsics", false, false)
Pass *llvm::createCoroCleanupPass() { return new CoroCleanup(); }