Skip to content

Commit a032dc1

Browse files
committed
[MLIR][OpenMP] Refactoring createTargetData in OMPIRBuilder
Key changes: - Refactor the createTargetData function to make use of the emitOffloadingArrays and emitOffloadingArraysArgument functions to generate code. - Added a new emitIfClause helper function to allow handling if clauses in a similar fashion to Clang. - Updated the MLIR side of code to account for changes to createTargetData. Depends on D149872 Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D146557
1 parent 7e22921 commit a032dc1

File tree

5 files changed

+419
-336
lines changed

5 files changed

+419
-336
lines changed

llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,25 @@ class OpenMPIRBuilder {
14781478
/// Computes the size of type in bytes.
14791479
Value *getSizeInBytes(Value *BasePtr);
14801480

1481+
// Emit a branch from the current block to the Target block only if
1482+
// the current block has a terminator.
1483+
void emitBranch(BasicBlock *Target);
1484+
1485+
// If BB has no use then delete it and return. Else place BB after the current
1486+
// block, if possible, or else at the end of the function. Also add a branch
1487+
// from current block to BB if current block does not have a terminator.
1488+
void emitBlock(BasicBlock *BB, Function *CurFn, bool IsFinished = false);
1489+
1490+
/// Emits code for OpenMP 'if' clause using specified \a BodyGenCallbackTy
1491+
/// Here is the logic:
1492+
/// if (Cond) {
1493+
/// ThenGen();
1494+
/// } else {
1495+
/// ElseGen();
1496+
/// }
1497+
void emitIfClause(Value *Cond, BodyGenCallbackTy ThenGen,
1498+
BodyGenCallbackTy ElseGen, InsertPointTy AllocaIP = {});
1499+
14811500
/// Create the global variable holding the offload mappings information.
14821501
GlobalVariable *createOffloadMaptypes(SmallVectorImpl<uint64_t> &Mappings,
14831502
std::string VarName);
@@ -1987,29 +2006,41 @@ class OpenMPIRBuilder {
19872006
StringRef EntryFnName,
19882007
StringRef EntryFnIDName,
19892008
int32_t NumTeams, int32_t NumThreads);
2009+
/// Type of BodyGen to use for region codegen
2010+
///
2011+
/// Priv: If device pointer privatization is required, emit the body of the
2012+
/// region here. It will have to be duplicated: with and without
2013+
/// privatization.
2014+
/// DupNoPriv: If we need device pointer privatization, we need
2015+
/// to emit the body of the region with no privatization in the 'else' branch
2016+
/// of the conditional.
2017+
/// NoPriv: If we don't require privatization of device
2018+
/// pointers, we emit the body in between the runtime calls. This avoids
2019+
/// duplicating the body code.
2020+
enum BodyGenTy { Priv, DupNoPriv, NoPriv };
19902021

19912022
/// Generator for '#omp target data'
19922023
///
19932024
/// \param Loc The location where the target data construct was encountered.
2025+
/// \param AllocaIP The insertion points to be used for alloca instructions.
19942026
/// \param CodeGenIP The insertion point at which the target directive code
19952027
/// should be placed.
1996-
/// \param MapTypeFlags BitVector storing the mapType flags for the
1997-
/// mapOperands.
1998-
/// \param MapNames Names for the mapOperands.
1999-
/// \param MapperAllocas Pointers to the AllocInsts for the map clause.
20002028
/// \param IsBegin If true then emits begin mapper call otherwise emits
20012029
/// end mapper call.
20022030
/// \param DeviceID Stores the DeviceID from the device clause.
20032031
/// \param IfCond Value which corresponds to the if clause condition.
2004-
/// \param ProcessMapOpCB Callback that generates code for the map clause.
2005-
/// \param BodyGenCB Callback that will generate the region code.
2032+
/// \param Info Stores all information realted to the Target Data directive.
2033+
/// \param GenMapInfoCB Callback that populates the MapInfos and returns.
2034+
/// \param BodyGenCB Optional Callback to generate the region code.
20062035
OpenMPIRBuilder::InsertPointTy createTargetData(
2007-
const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy CodeGenIP,
2008-
SmallVectorImpl<uint64_t> &MapTypeFlags,
2009-
SmallVectorImpl<Constant *> &MapNames,
2010-
struct MapperAllocas &MapperAllocas, bool IsBegin, int64_t DeviceID,
2011-
Value *IfCond, BodyGenCallbackTy ProcessMapOpCB,
2012-
BodyGenCallbackTy BodyGenCB = {});
2036+
const LocationDescription &Loc, InsertPointTy AllocaIP,
2037+
InsertPointTy CodeGenIP, Value *DeviceID, Value *IfCond,
2038+
TargetDataInfo &Info,
2039+
function_ref<MapInfosTy &(InsertPointTy CodeGenIP)> GenMapInfoCB,
2040+
omp::RuntimeFunction *MapperFunc = nullptr,
2041+
function_ref<InsertPointTy(InsertPointTy CodeGenIP,
2042+
BodyGenTy BodyGenType)>
2043+
BodyGenCB = nullptr);
20132044

20142045
using TargetBodyGenCallbackTy = function_ref<InsertPointTy(
20152046
InsertPointTy AllocaIP, InsertPointTy CodeGenIP)>;

llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp

Lines changed: 169 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4078,73 +4078,121 @@ Constant *OpenMPIRBuilder::registerTargetRegionFunction(
40784078
}
40794079

40804080
OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createTargetData(
4081-
const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy CodeGenIP,
4082-
SmallVectorImpl<uint64_t> &MapTypeFlags,
4083-
SmallVectorImpl<Constant *> &MapNames, struct MapperAllocas &MapperAllocas,
4084-
bool IsBegin, int64_t DeviceID, Value *IfCond,
4085-
BodyGenCallbackTy ProcessMapOpCB, BodyGenCallbackTy BodyGenCB) {
4081+
const LocationDescription &Loc, InsertPointTy AllocaIP,
4082+
InsertPointTy CodeGenIP, Value *DeviceID, Value *IfCond,
4083+
TargetDataInfo &Info,
4084+
function_ref<MapInfosTy &(InsertPointTy CodeGenIP)> GenMapInfoCB,
4085+
omp::RuntimeFunction *MapperFunc,
4086+
function_ref<InsertPointTy(InsertPointTy CodeGenIP, BodyGenTy BodyGenType)>
4087+
BodyGenCB) {
40864088
if (!updateToLocation(Loc))
40874089
return InsertPointTy();
40884090

40894091
Builder.restoreIP(CodeGenIP);
4092+
bool IsStandAlone = !BodyGenCB;
40904093

4091-
// LLVM utilities like blocks with terminators.
4092-
// The UI acts as a resume point for code insertion after the BodyGen
4093-
auto *UI = Builder.CreateUnreachable();
4094-
if (IfCond) {
4095-
auto *ThenTI =
4096-
SplitBlockAndInsertIfThen(IfCond, UI, /* Unreachable */ false);
4097-
ThenTI->getParent()->setName("omp_if.then");
4098-
Builder.SetInsertPoint(ThenTI);
4099-
} else {
4100-
Builder.SetInsertPoint(UI);
4101-
}
4094+
// Generate the code for the opening of the data environment. Capture all the
4095+
// arguments of the runtime call by reference because they are used in the
4096+
// closing of the region.
4097+
auto BeginThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {
4098+
emitOffloadingArrays(AllocaIP, Builder.saveIP(),
4099+
GenMapInfoCB(Builder.saveIP()), Info,
4100+
/*IsNonContiguous=*/true);
41024101

4103-
ProcessMapOpCB(Builder.saveIP(), Builder.saveIP());
4102+
TargetDataRTArgs RTArgs;
4103+
emitOffloadingArraysArgument(Builder, RTArgs, Info);
41044104

4105-
uint32_t SrcLocStrSize;
4106-
Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize);
4107-
Value *srcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize);
4105+
// Emit the number of elements in the offloading arrays.
4106+
Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs);
41084107

4109-
GlobalVariable *MapTypesGV =
4110-
createOffloadMaptypes(MapTypeFlags, ".offload_maptypes");
4111-
Value *MapTypesArg = Builder.CreateConstInBoundsGEP2_32(
4112-
ArrayType::get(Builder.getInt64Ty(), MapTypeFlags.size()), MapTypesGV,
4113-
/*Idx0=*/0, /*Idx1=*/0);
4108+
// Source location for the ident struct
4109+
uint32_t SrcLocStrSize;
4110+
Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize);
4111+
Value *SrcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize);
4112+
4113+
Value *OffloadingArgs[] = {SrcLocInfo, DeviceID,
4114+
PointerNum, RTArgs.BasePointersArray,
4115+
RTArgs.PointersArray, RTArgs.SizesArray,
4116+
RTArgs.MapTypesArray, RTArgs.MapNamesArray,
4117+
RTArgs.MappersArray};
4118+
4119+
if (IsStandAlone) {
4120+
assert(MapperFunc && "MapperFunc missing for standalone target data");
4121+
Builder.CreateCall(getOrCreateRuntimeFunctionPtr(*MapperFunc),
4122+
OffloadingArgs);
4123+
} else {
4124+
Function *BeginMapperFunc = getOrCreateRuntimeFunctionPtr(
4125+
omp::OMPRTL___tgt_target_data_begin_mapper);
41144126

4115-
GlobalVariable *MapNamesGV =
4116-
createOffloadMapnames(MapNames, ".offload_mapnames");
4117-
Value *MapNamesArg = Builder.CreateConstInBoundsGEP2_32(
4118-
ArrayType::get(Builder.getInt8PtrTy(), MapNames.size()), MapNamesGV,
4119-
/*Idx0=*/0, /*Idx1=*/0);
4127+
Builder.CreateCall(BeginMapperFunc, OffloadingArgs);
4128+
4129+
// If device pointer privatization is required, emit the body of the
4130+
// region here. It will have to be duplicated: with and without
4131+
// privatization.
4132+
Builder.restoreIP(BodyGenCB(Builder.saveIP(), BodyGenTy::Priv));
4133+
}
4134+
};
4135+
4136+
// If we need device pointer privatization, we need to emit the body of the
4137+
// region with no privatization in the 'else' branch of the conditional.
4138+
// Otherwise, we don't have to do anything.
4139+
auto BeginElseGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {
4140+
Builder.restoreIP(BodyGenCB(Builder.saveIP(), BodyGenTy::DupNoPriv));
4141+
};
4142+
4143+
// Generate code for the closing of the data region.
4144+
auto EndThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {
4145+
TargetDataRTArgs RTArgs;
4146+
emitOffloadingArraysArgument(Builder, RTArgs, Info, /*EmitDebug=*/false,
4147+
/*ForEndCall=*/true);
4148+
4149+
// Emit the number of elements in the offloading arrays.
4150+
Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs);
4151+
4152+
// Source location for the ident struct
4153+
uint32_t SrcLocStrSize;
4154+
Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize);
4155+
Value *SrcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize);
4156+
4157+
Value *OffloadingArgs[] = {SrcLocInfo, DeviceID,
4158+
PointerNum, RTArgs.BasePointersArray,
4159+
RTArgs.PointersArray, RTArgs.SizesArray,
4160+
RTArgs.MapTypesArray, RTArgs.MapNamesArray,
4161+
RTArgs.MappersArray};
4162+
Function *EndMapperFunc =
4163+
getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_end_mapper);
4164+
4165+
Builder.CreateCall(EndMapperFunc, OffloadingArgs);
4166+
};
41204167

4121-
Function *beginMapperFunc =
4122-
getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_begin_mapper);
4123-
Function *endMapperFunc =
4124-
getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_end_mapper);
4168+
// We don't have to do anything to close the region if the if clause evaluates
4169+
// to false.
4170+
auto EndElseGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {};
41254171

41264172
if (BodyGenCB) {
4127-
// Create call to start the data region.
4128-
emitMapperCall(Builder.saveIP(), beginMapperFunc, srcLocInfo, MapTypesArg,
4129-
MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size());
4173+
if (IfCond) {
4174+
emitIfClause(IfCond, BeginThenGen, BeginElseGen, AllocaIP);
4175+
} else {
4176+
BeginThenGen(AllocaIP, Builder.saveIP());
4177+
}
41304178

4131-
BodyGenCB(Builder.saveIP(), Builder.saveIP());
4179+
// If we don't require privatization of device pointers, we emit the body in
4180+
// between the runtime calls. This avoids duplicating the body code.
4181+
Builder.restoreIP(BodyGenCB(Builder.saveIP(), BodyGenTy::NoPriv));
41324182

4133-
Builder.SetInsertPoint(UI->getParent());
4134-
// Create call to end the data region.
4135-
emitMapperCall(Builder.saveIP(), endMapperFunc, srcLocInfo, MapTypesArg,
4136-
MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size());
4183+
if (IfCond) {
4184+
emitIfClause(IfCond, EndThenGen, EndElseGen, AllocaIP);
4185+
} else {
4186+
EndThenGen(AllocaIP, Builder.saveIP());
4187+
}
41374188
} else {
4138-
emitMapperCall(Builder.saveIP(), IsBegin ? beginMapperFunc : endMapperFunc,
4139-
srcLocInfo, MapTypesArg, MapNamesArg, MapperAllocas,
4140-
DeviceID, MapTypeFlags.size());
4189+
if (IfCond) {
4190+
emitIfClause(IfCond, BeginThenGen, EndElseGen, AllocaIP);
4191+
} else {
4192+
BeginThenGen(AllocaIP, Builder.saveIP());
4193+
}
41414194
}
41424195

4143-
// Update the insertion point and remove the terminator we introduced.
4144-
Builder.SetInsertPoint(UI->getParent());
4145-
if (IfCond)
4146-
UI->getParent()->setName("omp_if.end");
4147-
UI->eraseFromParent();
41484196
return Builder.saveIP();
41494197
}
41504198

@@ -4668,6 +4716,77 @@ void OpenMPIRBuilder::emitOffloadingArrays(
46684716
emitNonContiguousDescriptor(AllocaIP, CodeGenIP, CombinedInfo, Info);
46694717
}
46704718

4719+
void OpenMPIRBuilder::emitBranch(BasicBlock *Target) {
4720+
BasicBlock *CurBB = Builder.GetInsertBlock();
4721+
4722+
if (!CurBB || CurBB->getTerminator()) {
4723+
// If there is no insert point or the previous block is already
4724+
// terminated, don't touch it.
4725+
} else {
4726+
// Otherwise, create a fall-through branch.
4727+
Builder.CreateBr(Target);
4728+
}
4729+
4730+
Builder.ClearInsertionPoint();
4731+
}
4732+
4733+
void OpenMPIRBuilder::emitBlock(BasicBlock *BB, Function *CurFn,
4734+
bool IsFinished) {
4735+
BasicBlock *CurBB = Builder.GetInsertBlock();
4736+
4737+
// Fall out of the current block (if necessary).
4738+
emitBranch(BB);
4739+
4740+
if (IsFinished && BB->use_empty()) {
4741+
BB->eraseFromParent();
4742+
return;
4743+
}
4744+
4745+
// Place the block after the current block, if possible, or else at
4746+
// the end of the function.
4747+
if (CurBB && CurBB->getParent())
4748+
CurFn->insert(std::next(CurBB->getIterator()), BB);
4749+
else
4750+
CurFn->insert(CurFn->end(), BB);
4751+
Builder.SetInsertPoint(BB);
4752+
}
4753+
4754+
void OpenMPIRBuilder::emitIfClause(Value *Cond, BodyGenCallbackTy ThenGen,
4755+
BodyGenCallbackTy ElseGen,
4756+
InsertPointTy AllocaIP) {
4757+
// If the condition constant folds and can be elided, try to avoid emitting
4758+
// the condition and the dead arm of the if/else.
4759+
if (auto *CI = dyn_cast<ConstantInt>(Cond)) {
4760+
auto CondConstant = CI->getSExtValue();
4761+
if (CondConstant)
4762+
ThenGen(AllocaIP, Builder.saveIP());
4763+
else
4764+
ElseGen(AllocaIP, Builder.saveIP());
4765+
return;
4766+
}
4767+
4768+
Function *CurFn = Builder.GetInsertBlock()->getParent();
4769+
4770+
// Otherwise, the condition did not fold, or we couldn't elide it. Just
4771+
// emit the conditional branch.
4772+
BasicBlock *ThenBlock = BasicBlock::Create(M.getContext(), "omp_if.then");
4773+
BasicBlock *ElseBlock = BasicBlock::Create(M.getContext(), "omp_if.else");
4774+
BasicBlock *ContBlock = BasicBlock::Create(M.getContext(), "omp_if.end");
4775+
Builder.CreateCondBr(Cond, ThenBlock, ElseBlock);
4776+
// Emit the 'then' code.
4777+
emitBlock(ThenBlock, CurFn);
4778+
ThenGen(AllocaIP, Builder.saveIP());
4779+
emitBranch(ContBlock);
4780+
// Emit the 'else' code if present.
4781+
// There is no need to emit line number for unconditional branch.
4782+
emitBlock(ElseBlock, CurFn);
4783+
ElseGen(AllocaIP, Builder.saveIP());
4784+
// There is no need to emit line number for unconditional branch.
4785+
emitBranch(ContBlock);
4786+
// Emit the continuation block for code after the if.
4787+
emitBlock(ContBlock, CurFn, /*IsFinished=*/true);
4788+
}
4789+
46714790
bool OpenMPIRBuilder::checkAndEmitFlushAfterAtomic(
46724791
const LocationDescription &Loc, llvm::AtomicOrdering AO, AtomicKind AK) {
46734792
assert(!(AO == AtomicOrdering::NotAtomic ||

0 commit comments

Comments
 (0)