Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to Tapir intrinsics #265

Open
wants to merge 4 commits into
base: dev/18.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -1800,6 +1800,8 @@ LANGBUILTIN(__arithmetic_fence, "v.", "tE", ALL_LANGUAGES)
// and needs a builtin to carry the information to codegen.
BUILTIN(__hyper_lookup, "v*vC*z.", "nU")

BUILTIN(__tapir_frame, "v*", "n")

#undef BUILTIN
#undef LIBBUILTIN
#undef LANGBUILTIN
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5990,6 +5990,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Str.getPointer(), Zeros);
return RValue::get(Ptr);
}
case Builtin::BI__tapir_frame: {
Function *FF = CGM.getIntrinsic(Intrinsic::tapir_frame);
return RValue::get(Builder.CreateCall(FF, {}));
}
case Builtin::BI__hyper_lookup: {
llvm::Value *Size = EmitScalarExpr(E->getArg(1));
Function *F = CGM.getIntrinsic(Intrinsic::hyper_lookup, Size->getType());
Expand Down
29 changes: 29 additions & 0 deletions clang/test/Cilk/tapir-frame.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %clang_cc1 %s -x c -O1 -fopencilk -mllvm -use-opencilk-runtime-bc=false -mllvm -debug-abi-calls=true -verify -S -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics

// CHECK-LABEL: zero
int zero()
{
return __tapir_frame() != 0;
// CHECK: ret i32 0
}

// CHECK-LABEL: one
int one()
{
extern void f(int);
_Cilk_spawn f(0);
_Cilk_spawn f(1);
// CHECK: ret i32 1
return __tapir_frame() != 0;
}

// CHECK-LABEL: function3
int function3()
{
extern void f(int);
extern int g(void *);
_Cilk_spawn f(0);
// CHECK: call i32 @g(ptr noundef nonnull %__cilkrts_sf)
return g(__tapir_frame());
}
15 changes: 11 additions & 4 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ def IntrArgMemOnly : IntrinsicProperty;
// accessible by the module being compiled. This is a weaker form of IntrNoMem.
def IntrInaccessibleMemOnly : IntrinsicProperty;

def IntrReadInaccessibleMemOnly : IntrinsicProperty;

// IntrInaccessibleMemOrArgMemOnly -- This intrinsic only accesses memory that
// its pointer-typed arguments point to or memory that is not accessible
// by the module being compiled. This is a weaker form of IntrArgMemOnly.
Expand Down Expand Up @@ -1719,10 +1721,10 @@ def int_syncregion_start
: Intrinsic<[llvm_token_ty], [], [IntrArgMemOnly, IntrWillReturn]>;

def int_tapir_runtime_start
: Intrinsic<[llvm_token_ty], [], [IntrArgMemOnly, IntrWillReturn]>;
: Intrinsic<[llvm_token_ty], [], [IntrInaccessibleMemOnly, IntrWillReturn]>;

def int_tapir_runtime_end
: Intrinsic<[], [llvm_token_ty], [IntrArgMemOnly, IntrWillReturn]>;
: Intrinsic<[], [llvm_token_ty], [IntrInaccessibleMemOnly, IntrWillReturn]>;

// Intrinsics for taskframes.

Expand Down Expand Up @@ -1765,18 +1767,23 @@ def int_tapir_loop_grainsize
: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>],
[IntrNoMem, IntrWillReturn, IntrSpeculatable]>;

// Return the stack_frame in an OpenCilk function, otherwise null.
def int_tapir_frame
: Intrinsic<[llvm_ptr_ty], [], [IntrWillReturn,IntrReadInaccessibleMemOnly]>;

// Intrinsic to get the frame address of a spawned task. Tapir
// lowering transforms this intrinsic into ordinary frameaddress
// intrinsics.
def int_task_frameaddress
: Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrWillReturn]>;
: Intrinsic<[llvm_ptr_ty], [llvm_i32_ty],
[IntrReadInaccessibleMemOnly,IntrWillReturn]>;

// Ideally the types would be [llvm_anyptr_ty], [LLVMMatchType<0>]
// but that does not work, so rely on the front end to insert bitcasts.
def int_hyper_lookup
: Intrinsic<[llvm_ptr_ty],
[llvm_ptr_ty, llvm_anyint_ty, llvm_ptr_ty, llvm_ptr_ty], [
IntrWillReturn, IntrReadMem, IntrInaccessibleMemOnly,
IntrWillReturn, IntrReadInaccessibleMemOnly,
IntrStrandPure, IntrHyperView, IntrInjective
]>;

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Transforms/Tapir/LoweringUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ class TapirTarget {
/// Lower a Tapir sync instruction \p SI.
virtual void lowerSync(SyncInst &SI) = 0;

virtual void lowerFrameCall(CallBase *Call, DominatorTree &DT) {}

virtual void lowerReducerOperation(CallBase *Call) {}

/// Lower calls to the tapir.runtime.{start,end} intrinsics. Only
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Transforms/Tapir/OpenCilkABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ class OpenCilkABI final : public TapirTarget {

BasicBlock *GetDefaultSyncLandingpad(Function &F, Value *SF, DebugLoc Loc);

Value *getValidFrame(CallBase *FrameCall, DominatorTree &DT);

public:
OpenCilkABI(Module &M);
~OpenCilkABI() { DetachCtxToStackFrame.clear(); }
Expand All @@ -167,6 +169,7 @@ class OpenCilkABI final : public TapirTarget {
Value *lowerGrainsizeCall(CallInst *GrainsizeCall) override final;
void lowerSync(SyncInst &SI) override final;
void lowerReducerOperation(CallBase *CI) override;
void lowerFrameCall(CallBase *CI, DominatorTree &DT) override;

ArgStructMode getArgStructMode() const override final {
return ArgStructMode::None;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/IntrinsicLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
report_fatal_error("Code generator does not support intrinsic function '"+
Callee->getName()+"'!");

case Intrinsic::tapir_frame:
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
break;

case Intrinsic::expect: {
// Just replace __builtin_expect(exp, c) with EXP.
Value *V = CI->getArgOperand(0);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7816,6 +7816,11 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
TLI.getFrameIndexTy(DAG.getDataLayout()),
getValue(I.getArgOperand(0))));
return;
case Intrinsic::tapir_frame: {
EVT VT = TLI.getValueType(DAG.getDataLayout(), I.getType());
setValue(&I, DAG.getConstant(0, sdl, VT));
return;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Tapir/LoweringUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@ bool TapirTarget::shouldProcessFunction(const Function &F) const {
case Intrinsic::reducer_unregister:
case Intrinsic::tapir_loop_grainsize:
case Intrinsic::task_frameaddress:
case Intrinsic::tapir_frame:
case Intrinsic::tapir_runtime_start:
case Intrinsic::tapir_runtime_end:
return true;
Expand Down
101 changes: 101 additions & 0 deletions llvm/lib/Transforms/Tapir/OpenCilkABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/TapirTaskInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
Expand Down Expand Up @@ -1178,6 +1179,106 @@ OpenCilkABI::getLoopOutlineProcessor(const TapirLoopInfo *TL) {
return nullptr;
}

// Return the stack frame for this function if it is definitely
// initialized. Otherwise return null.
// The lookup call must be dominated by a call to enter frame.
// The lookup call must not be reachable by any call to leave
// frame unless there is an intervening enter frame.
// This function will conservatively return null in some cases
// it does not understand. Most likely to matter, if a basic
// block contains a leave frame call followed by an enter frame
// call it will be treated as leaving the frame invalid.

Value *OpenCilkABI::getValidFrame(CallBase *FrameCall, DominatorTree &DT) {
BasicBlock *FrameBlock = FrameCall->getParent();
Function *F = FrameBlock->getParent();
Value *Frame = DetachCtxToStackFrame.lookup(F);
if (!Frame)
return nullptr;

// Blocks with enter frame calls.
SmallPtrSet<BasicBlock *, 8> EnterBlocks;
// The last enter or leave frame call before FrameCall
// in the same basic block.
CallBase *SameBlockCall = nullptr;
// True if the call is enter, false if leave or not yet set.
bool SameBlockEnter = false;
// Leave frame calls other than those before FrameCall
// in the same basic block.
SmallPtrSet<CallBase *, 8> Leaves;

// Use pointer identity to check call target. Enter and leave
// are always called with a known getCalledFunction().
// This function runs before inlining of runtime calls.
Value *Enter1 = CILKRTS_FUNC(enter_frame_helper).getCallee();
Value *Enter2 = CILKRTS_FUNC(enter_frame).getCallee();
Value *Leave1 = CILKRTS_FUNC(leave_frame_helper).getCallee();
Value *Leave2 = CILKRTS_FUNC(leave_frame).getCallee();
Value *Leave3 = CilkHelperEpilogue.getCallee();
Value *Leave4 = CilkParentEpilogue.getCallee();

// Collect all enter_frame and leave_frame calls.
bool Initialized = false;
for (User *U : Frame->users()) {
if (CallBase *C = dyn_cast<CallBase>(U)) {
Function *Fn = C->getCalledFunction();
BasicBlock *Block = C->getParent();
if (Fn == Enter1 || Fn == Enter2) {
if (FrameBlock == Block && C->comesBefore(FrameCall)) {
if (!SameBlockCall || SameBlockCall->comesBefore(C)) {
SameBlockCall = C;
SameBlockEnter = true;
}
Initialized = true;
} else {
EnterBlocks.insert(Block);
if (!Initialized && DT.dominates(C, FrameCall))
Initialized = true;
}
} else if (Fn == Leave1 || Fn == Leave2 || Fn == Leave3 || Fn == Leave4) {
if (Block == FrameBlock && C->comesBefore(FrameCall)) {
if (!SameBlockCall || SameBlockCall->comesBefore(C)) {
SameBlockCall = C;
SameBlockEnter = false;
}
} else {
Leaves.insert(C);
}
}
}
}
if (!Initialized)
return nullptr;

// Is the answer found in the same basic block?
if (SameBlockCall)
return SameBlockEnter ? Frame : nullptr;

// Ignore any enter frame call in a block that also contains
// a leave frame call.
for (CallBase *L : Leaves) {
EnterBlocks.erase(L->getParent());
}

// Look for leave frame calls that might reach the use without
// an intervening enter frame call.
for (CallBase *L : Leaves) {
if (isPotentiallyReachable(L, FrameCall, &EnterBlocks, &DT, nullptr))
return nullptr;
}
return Frame;
}

void OpenCilkABI::lowerFrameCall(CallBase *FrameCall, DominatorTree &DT) {
assert(FrameCall->data_operands_size() == 0);
Value *Frame = getValidFrame(FrameCall, DT);
if (Frame == nullptr)
Frame = Constant::getNullValue(FrameCall->getType());
FrameCall->replaceAllUsesWith(Frame);
FrameCall->eraseFromParent();
}


void OpenCilkABI::lowerReducerOperation(CallBase *CI) {
FunctionCallee Fn = nullptr;
const Function *Called = CI->getCalledFunction();
Expand Down
59 changes: 38 additions & 21 deletions llvm/lib/Transforms/Tapir/TapirToTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,42 +180,59 @@ bool TapirToTargetImpl::processSimpleABI(Function &F, BasicBlock *TFEntry) {
SmallVector<CallInst *, 8> TaskFrameAddrCalls;
SmallVector<CallInst *, 8> TapirRTCalls;
SmallVector<CallBase *, 8> ReducerOperations;
SmallVector<CallInst *, 8> TapirFrameCalls;

for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
// Record calls to get Tapir-loop grainsizes.
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
if (Intrinsic::tapir_loop_grainsize == II->getIntrinsicID())

// Record sync instructions in this function.
if (SyncInst *SI = dyn_cast<SyncInst>(&I)) {
Syncs.push_back(SI);
continue;
}

if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I)) {
switch (II->getIntrinsicID()) {
case Intrinsic::tapir_loop_grainsize:
GrainsizeCalls.push_back(II);
break;

// Record calls to task_frameaddr intrinsics.
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
if (Intrinsic::task_frameaddress == II->getIntrinsicID())
case Intrinsic::task_frameaddress:
TaskFrameAddrCalls.push_back(II);
break;

// Record calls to tapir_runtime_start intrinsics. We rely on analyzing
// uses of these intrinsic calls to find calls to tapir_runtime_end.
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
if (Intrinsic::tapir_runtime_start == II->getIntrinsicID())
// Record calls to tapir_runtime_start intrinsics.
// We rely on analyzing uses of these intrinsic calls
// to find calls to tapir_runtime_end.
case Intrinsic::tapir_runtime_start:
TapirRTCalls.push_back(II);

// Record sync instructions in this function.
if (SyncInst *SI = dyn_cast<SyncInst>(&I))
Syncs.push_back(SI);

if (!dyn_cast<CallBase>(&I))
break;

case Intrinsic::tapir_frame:
TapirFrameCalls.push_back(II);
break;

case Intrinsic::hyper_lookup:
case Intrinsic::reducer_register:
case Intrinsic::reducer_unregister:
ReducerOperations.push_back(cast<CallInst>(&I));
break;
}
continue;

if (isTapirIntrinsic(Intrinsic::hyper_lookup, &I, nullptr) ||
isTapirIntrinsic(Intrinsic::reducer_register, &I, nullptr) ||
isTapirIntrinsic(Intrinsic::reducer_unregister, &I, nullptr))
ReducerOperations.push_back(cast<CallInst>(&I));
}
}
}

// Lower simple Tapir instructions in this function. Collect the set of
// helper functions generated by this process.
bool Changed = false;

while (!TapirFrameCalls.empty()) {
CallInst *CI = TapirFrameCalls.pop_back_val();
Target->lowerFrameCall(CI, GetDT(F));
Changed = true;
}

// Lower calls to get Tapir-loop grainsizes.
while (!GrainsizeCalls.empty()) {
CallInst *GrainsizeCall = GrainsizeCalls.pop_back_val();
Expand Down
2 changes: 2 additions & 0 deletions llvm/utils/TableGen/CodeGenIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ void CodeGenIntrinsic::setProperty(Record *R) {
ME &= MemoryEffects::argMemOnly();
else if (R->getName() == "IntrInaccessibleMemOnly")
ME &= MemoryEffects::inaccessibleMemOnly();
else if (R->getName() == "IntrReadInaccessibleMemOnly")
ME &= MemoryEffects::inaccessibleMemOnly(ModRefInfo::Ref);
else if (R->getName() == "IntrInaccessibleMemOrArgMemOnly")
ME &= MemoryEffects::inaccessibleOrArgMemOnly();
else if (R->getName() == "Commutative")
Expand Down
Loading