mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-27 11:55:49 +00:00
[OpenMP][OMPIRBuilder] Add Directives (master and critical) to OMPBuilder.
Add support for Master and Critical directive in the OMPIRBuilder. Both make use of a new common interface for emitting inlined OMP regions called `emitInlinedRegion` which was added in this patch as well. Also this patch modifies clang to use the new directives when `-fopenmp-enable-irbuilder` commandline option is passed. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D72304
This commit is contained in:
parent
e565db49c6
commit
e8a436c5ea
@ -3143,11 +3143,147 @@ static void emitMaster(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
|
||||
if (llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder()) {
|
||||
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
|
||||
|
||||
const CapturedStmt *CS = S.getInnermostCapturedStmt();
|
||||
const Stmt *MasterRegionBodyStmt = CS->getCapturedStmt();
|
||||
|
||||
// TODO: Replace with a generic helper function for finalization
|
||||
auto FiniCB = [this](InsertPointTy IP) {
|
||||
CGBuilderTy::InsertPointGuard IPG(Builder);
|
||||
assert(IP.getBlock()->end() != IP.getPoint() &&
|
||||
"OpenMP IR Builder should cause terminated block!");
|
||||
|
||||
llvm::BasicBlock *IPBB = IP.getBlock();
|
||||
llvm::BasicBlock *DestBB = IPBB->getUniqueSuccessor();
|
||||
assert(DestBB && "Finalization block should have one successor!");
|
||||
|
||||
// erase and replace with cleanup branch.
|
||||
IPBB->getTerminator()->eraseFromParent();
|
||||
Builder.SetInsertPoint(IPBB);
|
||||
CodeGenFunction::JumpDest Dest = getJumpDestInCurrentScope(DestBB);
|
||||
EmitBranchThroughCleanup(Dest);
|
||||
};
|
||||
|
||||
// TODO: Replace with a generic helper function for emitting body
|
||||
auto BodyGenCB = [MasterRegionBodyStmt, this](InsertPointTy AllocaIP,
|
||||
InsertPointTy CodeGenIP,
|
||||
llvm::BasicBlock &FiniBB) {
|
||||
// Alloca insertion block should be in the entry block of the containing
|
||||
// function So it expects an empty AllocaIP in which case will reuse the
|
||||
// old alloca insertion point, or a new AllocaIP in the same block as the
|
||||
// old one
|
||||
assert((!AllocaIP.isSet() ||
|
||||
AllocaInsertPt->getParent() == AllocaIP.getBlock()) &&
|
||||
"Insertion point should be in the entry block of containing "
|
||||
"function!");
|
||||
auto OldAllocaIP = AllocaInsertPt;
|
||||
if (AllocaIP.isSet())
|
||||
AllocaInsertPt = &*AllocaIP.getPoint();
|
||||
auto OldReturnBlock = ReturnBlock;
|
||||
ReturnBlock = getJumpDestInCurrentScope(&FiniBB);
|
||||
|
||||
llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
|
||||
if (llvm::Instruction *CodeGenIPBBTI = CodeGenIPBB->getTerminator())
|
||||
CodeGenIPBBTI->eraseFromParent();
|
||||
|
||||
Builder.SetInsertPoint(CodeGenIPBB);
|
||||
|
||||
EmitStmt(MasterRegionBodyStmt);
|
||||
|
||||
if (Builder.saveIP().isSet())
|
||||
Builder.CreateBr(&FiniBB);
|
||||
|
||||
AllocaInsertPt = OldAllocaIP;
|
||||
ReturnBlock = OldReturnBlock;
|
||||
};
|
||||
CGCapturedStmtInfo CGSI(*CS, CR_OpenMP);
|
||||
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
|
||||
Builder.restoreIP(OMPBuilder->CreateMaster(Builder, BodyGenCB, FiniCB));
|
||||
|
||||
return;
|
||||
}
|
||||
OMPLexicalScope Scope(*this, S, OMPD_unknown);
|
||||
emitMaster(*this, S);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) {
|
||||
if (llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder()) {
|
||||
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
|
||||
|
||||
const CapturedStmt *CS = S.getInnermostCapturedStmt();
|
||||
const Stmt *CriticalRegionBodyStmt = CS->getCapturedStmt();
|
||||
const Expr *Hint = nullptr;
|
||||
if (const auto *HintClause = S.getSingleClause<OMPHintClause>())
|
||||
Hint = HintClause->getHint();
|
||||
|
||||
// TODO: This is slightly different from what's currently being done in
|
||||
// clang. Fix the Int32Ty to IntPtrTy (pointer width size) when everything
|
||||
// about typing is final.
|
||||
llvm::Value *HintInst = nullptr;
|
||||
if (Hint)
|
||||
HintInst =
|
||||
Builder.CreateIntCast(EmitScalarExpr(Hint), CGM.Int32Ty, false);
|
||||
|
||||
// TODO: Replace with a generic helper function for finalization
|
||||
auto FiniCB = [this](InsertPointTy IP) {
|
||||
CGBuilderTy::InsertPointGuard IPG(Builder);
|
||||
assert(IP.getBlock()->end() != IP.getPoint() &&
|
||||
"OpenMP IR Builder should cause terminated block!");
|
||||
llvm::BasicBlock *IPBB = IP.getBlock();
|
||||
llvm::BasicBlock *DestBB = IPBB->getUniqueSuccessor();
|
||||
assert(DestBB && "Finalization block should have one successor!");
|
||||
|
||||
// erase and replace with cleanup branch.
|
||||
IPBB->getTerminator()->eraseFromParent();
|
||||
Builder.SetInsertPoint(IPBB);
|
||||
CodeGenFunction::JumpDest Dest = getJumpDestInCurrentScope(DestBB);
|
||||
EmitBranchThroughCleanup(Dest);
|
||||
};
|
||||
|
||||
// TODO: Replace with a generic helper function for emitting body
|
||||
auto BodyGenCB = [CriticalRegionBodyStmt, this](InsertPointTy AllocaIP,
|
||||
InsertPointTy CodeGenIP,
|
||||
llvm::BasicBlock &FiniBB) {
|
||||
// Alloca insertion block should be in the entry block of the containing
|
||||
// function So it expects an empty AllocaIP in which case will reuse the
|
||||
// old alloca insertion point, or a new AllocaIP in the same block as the
|
||||
// old one
|
||||
assert((!AllocaIP.isSet() ||
|
||||
AllocaInsertPt->getParent() == AllocaIP.getBlock()) &&
|
||||
"Insertion point should be in the entry block of containing "
|
||||
"function!");
|
||||
auto OldAllocaIP = AllocaInsertPt;
|
||||
if (AllocaIP.isSet())
|
||||
AllocaInsertPt = &*AllocaIP.getPoint();
|
||||
auto OldReturnBlock = ReturnBlock;
|
||||
ReturnBlock = getJumpDestInCurrentScope(&FiniBB);
|
||||
|
||||
llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
|
||||
if (llvm::Instruction *CodeGenIPBBTI = CodeGenIPBB->getTerminator())
|
||||
CodeGenIPBBTI->eraseFromParent();
|
||||
|
||||
Builder.SetInsertPoint(CodeGenIPBB);
|
||||
|
||||
EmitStmt(CriticalRegionBodyStmt);
|
||||
|
||||
if (Builder.saveIP().isSet())
|
||||
Builder.CreateBr(&FiniBB);
|
||||
|
||||
AllocaInsertPt = OldAllocaIP;
|
||||
ReturnBlock = OldReturnBlock;
|
||||
};
|
||||
|
||||
CGCapturedStmtInfo CGSI(*CS, CR_OpenMP);
|
||||
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI);
|
||||
Builder.restoreIP(OMPBuilder->CreateCritical(
|
||||
Builder, BodyGenCB, FiniCB, S.getDirectiveName().getAsString(),
|
||||
HintInst));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
|
||||
Action.Enter(CGF);
|
||||
CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt());
|
||||
|
@ -1,7 +1,10 @@
|
||||
// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --check-prefixes=ALL,NORMAL
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefixes=ALL,NORMAL
|
||||
// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
|
||||
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-enable-irbuilder -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --check-prefixes=ALL,IRBUILDER
|
||||
// RUN: %clang_cc1 -fopenmp -fopenmp-enable-irbuilder -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp -fopenmp-enable-irbuilder -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefixes=ALL,IRBUILDER
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck --check-prefix SIMD-ONLY0 %s
|
||||
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||
@ -12,74 +15,79 @@
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
|
||||
// CHECK: [[UNNAMED_LOCK:@.+]] = common global [8 x i32] zeroinitializer
|
||||
// CHECK: [[THE_NAME_LOCK:@.+]] = common global [8 x i32] zeroinitializer
|
||||
// CHECK: [[THE_NAME_LOCK1:@.+]] = common global [8 x i32] zeroinitializer
|
||||
// ALL: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
|
||||
// ALL: [[UNNAMED_LOCK:@.+]] = common global [8 x i32] zeroinitializer
|
||||
// ALL: [[THE_NAME_LOCK:@.+]] = common global [8 x i32] zeroinitializer
|
||||
// ALL: [[THE_NAME_LOCK1:@.+]] = common global [8 x i32] zeroinitializer
|
||||
|
||||
// CHECK: define {{.*}}void [[FOO:@.+]]()
|
||||
// ALL: define {{.*}}void [[FOO:@.+]]()
|
||||
|
||||
void foo() {}
|
||||
|
||||
// CHECK-LABEL: @main
|
||||
// ALL-LABEL: @main
|
||||
// TERM_DEBUG-LABEL: @main
|
||||
int main() {
|
||||
// CHECK: [[A_ADDR:%.+]] = alloca i8
|
||||
// ALL: [[A_ADDR:%.+]] = alloca i8
|
||||
char a;
|
||||
|
||||
// CHECK: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// CHECK: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]])
|
||||
// CHECK-NEXT: store i8 2, i8* [[A_ADDR]]
|
||||
// CHECK-NEXT: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]])
|
||||
// ALL: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// ALL: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]])
|
||||
// ALL-NEXT: store i8 2, i8* [[A_ADDR]]
|
||||
// ALL-NEXT: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[UNNAMED_LOCK]])
|
||||
#pragma omp critical
|
||||
a = 2;
|
||||
// CHECK: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
|
||||
// CHECK-NEXT: invoke {{.*}}void [[FOO]]()
|
||||
// CHECK: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
|
||||
// IRBUILDER: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// ALL: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
|
||||
// IRBUILDER-NEXT: call {{.*}}void [[FOO]]()
|
||||
// NORMAL-NEXT: invoke {{.*}}void [[FOO]]()
|
||||
// ALL: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
|
||||
#pragma omp critical(the_name)
|
||||
foo();
|
||||
// CHECK: call {{.*}}void @__kmpc_critical_with_hint([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK1]], i{{64|32}} 23)
|
||||
// CHECK-NEXT: invoke {{.*}}void [[FOO]]()
|
||||
// CHECK: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK1]])
|
||||
// IRBUILDER: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// ALL: call {{.*}}void @__kmpc_critical_with_hint([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK1]], i{{64|32}} 23)
|
||||
// IRBUILDER-NEXT: call {{.*}}void [[FOO]]()
|
||||
// NORMAL-NEXT: invoke {{.*}}void [[FOO]]()
|
||||
// ALL: call {{.*}}void @__kmpc_end_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK1]])
|
||||
#pragma omp critical(the_name1) hint(23)
|
||||
foo();
|
||||
// CHECK: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
|
||||
// CHECK: br label
|
||||
// CHECK-NOT: call {{.*}}void @__kmpc_end_critical(
|
||||
// CHECK: br label
|
||||
// CHECK-NOT: call {{.*}}void @__kmpc_end_critical(
|
||||
// CHECK: br label
|
||||
// IRBUILDER: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// ALL: call {{.*}}void @__kmpc_critical([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], [8 x i32]* [[THE_NAME_LOCK]])
|
||||
// ALL: br label
|
||||
// ALL-NOT: call {{.*}}void @__kmpc_end_critical(
|
||||
// ALL: br label
|
||||
// ALL-NOT: call {{.*}}void @__kmpc_end_critical(
|
||||
// NORMAL: br label
|
||||
if (a)
|
||||
#pragma omp critical(the_name)
|
||||
while (1)
|
||||
;
|
||||
// CHECK: call {{.*}}void [[FOO]]()
|
||||
// ALL: call {{.*}}void [[FOO]]()
|
||||
foo();
|
||||
// CHECK-NOT: call void @__kmpc_critical
|
||||
// CHECK-NOT: call void @__kmpc_end_critical
|
||||
// ALL-NOT: call void @__kmpc_critical
|
||||
// ALL-NOT: call void @__kmpc_end_critical
|
||||
return a;
|
||||
}
|
||||
|
||||
struct S {
|
||||
int a;
|
||||
};
|
||||
// CHECK-LABEL: critical_ref
|
||||
// ALL-LABEL: critical_ref
|
||||
void critical_ref(S &s) {
|
||||
// CHECK: [[S_ADDR:%.+]] = alloca %struct.S*,
|
||||
// CHECK: [[S_REF:%.+]] = load %struct.S*, %struct.S** [[S_ADDR]],
|
||||
// CHECK: [[S_A_REF:%.+]] = getelementptr inbounds %struct.S, %struct.S* [[S_REF]], i32 0, i32 0
|
||||
// ALL: [[S_ADDR:%.+]] = alloca %struct.S*,
|
||||
// ALL: [[S_REF:%.+]] = load %struct.S*, %struct.S** [[S_ADDR]],
|
||||
// ALL: [[S_A_REF:%.+]] = getelementptr inbounds %struct.S, %struct.S* [[S_REF]], i32 0, i32 0
|
||||
++s.a;
|
||||
// CHECK: [[S_REF:%.+]] = load %struct.S*, %struct.S** [[S_ADDR]],
|
||||
// CHECK: store %struct.S* [[S_REF]], %struct.S** [[S_ADDR:%.+]],
|
||||
// CHECK: call void @__kmpc_critical(
|
||||
// NORMAL: [[S_REF:%.+]] = load %struct.S*, %struct.S** [[S_ADDR]],
|
||||
// NORMAL: store %struct.S* [[S_REF]], %struct.S** [[S_ADDR:%.+]],
|
||||
// ALL: call void @__kmpc_critical(
|
||||
#pragma omp critical
|
||||
// CHECK: [[S_REF:%.+]] = load %struct.S*, %struct.S** [[S_ADDR]],
|
||||
// CHECK: [[S_A_REF:%.+]] = getelementptr inbounds %struct.S, %struct.S* [[S_REF]], i32 0, i32 0
|
||||
// ALL: [[S_REF:%.+]] = load %struct.S*, %struct.S** [[S_ADDR]],
|
||||
// ALL: [[S_A_REF:%.+]] = getelementptr inbounds %struct.S, %struct.S* [[S_REF]], i32 0, i32 0
|
||||
++s.a;
|
||||
// CHECK: call void @__kmpc_end_critical(
|
||||
// ALL: call void @__kmpc_end_critical(
|
||||
}
|
||||
|
||||
// CHECK-LABEL: parallel_critical
|
||||
// ALL-LABEL: parallel_critical
|
||||
// TERM_DEBUG-LABEL: parallel_critical
|
||||
void parallel_critical() {
|
||||
#pragma omp parallel
|
||||
|
@ -1,7 +1,10 @@
|
||||
// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --check-prefixes=ALL,NORMAL
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefixes=ALL,NORMAL
|
||||
// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG
|
||||
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-enable-irbuilder -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s --check-prefixes=ALL,IRBUILDER
|
||||
// RUN: %clang_cc1 -fopenmp -fopenmp-enable-irbuilder -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp -fopenmp-enable-irbuilder -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s --check-prefixes=ALL,IRBUILDER
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck --check-prefix SIMD-ONLY0 %s
|
||||
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s
|
||||
@ -12,45 +15,47 @@
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
|
||||
// ALL: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
|
||||
|
||||
// CHECK: define {{.*}}void [[FOO:@.+]]()
|
||||
// ALL: define {{.*}}void [[FOO:@.+]]()
|
||||
|
||||
void foo() {}
|
||||
|
||||
// CHECK-LABEL: @main
|
||||
// ALL-LABEL: @main
|
||||
// TERM_DEBUG-LABEL: @main
|
||||
int main() {
|
||||
// CHECK: [[A_ADDR:%.+]] = alloca i8
|
||||
// ALL: [[A_ADDR:%.+]] = alloca i8
|
||||
char a;
|
||||
|
||||
// CHECK: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// CHECK: [[RES:%.+]] = call {{.*}}i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0
|
||||
// CHECK-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
|
||||
// CHECK: [[THEN]]
|
||||
// CHECK-NEXT: store i8 2, i8* [[A_ADDR]]
|
||||
// CHECK-NEXT: call {{.*}}void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: br label {{%?}}[[EXIT]]
|
||||
// CHECK: [[EXIT]]
|
||||
// ALL: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// ALL: [[RES:%.+]] = call {{.*}}i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// ALL-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0
|
||||
// ALL-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
|
||||
// ALL: [[THEN]]
|
||||
// ALL-NEXT: store i8 2, i8* [[A_ADDR]]
|
||||
// ALL-NEXT: call {{.*}}void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// ALL-NEXT: br label {{%?}}[[EXIT]]
|
||||
// ALL: [[EXIT]]
|
||||
#pragma omp master
|
||||
a = 2;
|
||||
// CHECK: [[RES:%.+]] = call {{.*}}i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0
|
||||
// CHECK-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
|
||||
// CHECK: [[THEN]]
|
||||
// CHECK-NEXT: invoke {{.*}}void [[FOO]]()
|
||||
// CHECK: call {{.*}}void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// CHECK-NEXT: br label {{%?}}[[EXIT]]
|
||||
// CHECK: [[EXIT]]
|
||||
// IRBUILDER: [[GTID:%.+]] = call {{.*}}i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
|
||||
// ALL: [[RES:%.+]] = call {{.*}}i32 @__kmpc_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// ALL-NEXT: [[IS_MASTER:%.+]] = icmp ne i32 [[RES]], 0
|
||||
// ALL-NEXT: br i1 [[IS_MASTER]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
|
||||
// ALL: [[THEN]]
|
||||
// IRBUILDER-NEXT: call {{.*}}void [[FOO]]()
|
||||
// NORMAL-NEXT: invoke {{.*}}void [[FOO]]()
|
||||
// ALL: call {{.*}}void @__kmpc_end_master([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
|
||||
// ALL-NEXT: br label {{%?}}[[EXIT]]
|
||||
// ALL: [[EXIT]]
|
||||
#pragma omp master
|
||||
foo();
|
||||
// CHECK-NOT: call i32 @__kmpc_master
|
||||
// CHECK-NOT: call void @__kmpc_end_master
|
||||
// ALL-NOT: call i32 @__kmpc_master
|
||||
// ALL-NOT: call void @__kmpc_end_master
|
||||
return a;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: parallel_master
|
||||
// ALL-LABEL: parallel_master
|
||||
// TERM_DEBUG-LABEL: parallel_master
|
||||
void parallel_master() {
|
||||
#pragma omp parallel
|
||||
|
@ -20,6 +20,7 @@
|
||||
namespace llvm {
|
||||
class Type;
|
||||
class Module;
|
||||
class ArrayType;
|
||||
class StructType;
|
||||
class PointerType;
|
||||
class FunctionType;
|
||||
@ -85,6 +86,9 @@ StringRef getOpenMPDirectiveName(Directive D);
|
||||
namespace types {
|
||||
|
||||
#define OMP_TYPE(VarName, InitValue) extern Type *VarName;
|
||||
#define OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize) \
|
||||
extern ArrayType *VarName##Ty; \
|
||||
extern PointerType *VarName##PtrTy;
|
||||
#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...) \
|
||||
extern FunctionType *VarName; \
|
||||
extern PointerType *VarName##Ptr;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Frontend/OpenMP/OMPConstants.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -254,6 +255,119 @@ private:
|
||||
|
||||
/// Map to remember existing ident_t*.
|
||||
DenseMap<std::pair<Constant *, uint64_t>, GlobalVariable *> IdentMap;
|
||||
|
||||
/// An ordered map of auto-generated variables to their unique names.
|
||||
/// It stores variables with the following names: 1) ".gomp_critical_user_" +
|
||||
/// <critical_section_name> + ".var" for "omp critical" directives; 2)
|
||||
/// <mangled_name_for_global_var> + ".cache." for cache for threadprivate
|
||||
/// variables.
|
||||
StringMap<AssertingVH<Constant>, BumpPtrAllocator> InternalVars;
|
||||
|
||||
public:
|
||||
/// Generator for '#omp master'
|
||||
///
|
||||
/// \param Loc The insert and source location description.
|
||||
/// \param BodyGenCB Callback that will generate the region code.
|
||||
/// \param FiniCB Callback to finalize variable copies.
|
||||
///
|
||||
/// \returns The insertion position *after* the master.
|
||||
InsertPointTy CreateMaster(const LocationDescription &Loc,
|
||||
BodyGenCallbackTy BodyGenCB,
|
||||
FinalizeCallbackTy FiniCB);
|
||||
|
||||
/// Generator for '#omp master'
|
||||
///
|
||||
/// \param Loc The insert and source location description.
|
||||
/// \param BodyGenCB Callback that will generate the region body code.
|
||||
/// \param FiniCB Callback to finalize variable copies.
|
||||
/// \param CriticalName name of the lock used by the critical directive
|
||||
/// \param HintInst Hint Instruction for hint clause associated with critical
|
||||
///
|
||||
/// \returns The insertion position *after* the master.
|
||||
InsertPointTy CreateCritical(const LocationDescription &Loc,
|
||||
BodyGenCallbackTy BodyGenCB,
|
||||
FinalizeCallbackTy FiniCB,
|
||||
StringRef CriticalName, Value *HintInst);
|
||||
|
||||
private:
|
||||
/// Common interface for generating entry calls for OMP Directives.
|
||||
/// if the directive has a region/body, It will set the insertion
|
||||
/// point to the body
|
||||
///
|
||||
/// \param OMPD Directive to generate entry blocks for
|
||||
/// \param EntryCall Call to the entry OMP Runtime Function
|
||||
/// \param ExitBB block where the region ends.
|
||||
/// \param Conditional indicate if the entry call result will be used
|
||||
/// to evaluate a conditional of whether a thread will execute
|
||||
/// body code or not.
|
||||
///
|
||||
/// \return The insertion position in exit block
|
||||
InsertPointTy emitCommonDirectiveEntry(omp::Directive OMPD, Value *EntryCall,
|
||||
BasicBlock *ExitBB,
|
||||
bool Conditional = false);
|
||||
|
||||
/// Common interface to finalize the region
|
||||
///
|
||||
/// \param OMPD Directive to generate exiting code for
|
||||
/// \param FinIP Insertion point for emitting Finalization code and exit call
|
||||
/// \param ExitCall Call to the ending OMP Runtime Function
|
||||
/// \param HasFinalize indicate if the directive will require finalization
|
||||
/// and has a finalization callback in the stack that
|
||||
/// should be called.
|
||||
///
|
||||
/// \return The insertion position in exit block
|
||||
InsertPointTy emitCommonDirectiveExit(omp::Directive OMPD,
|
||||
InsertPointTy FinIP,
|
||||
Instruction *ExitCall,
|
||||
bool HasFinalize = true);
|
||||
|
||||
/// Common Interface to generate OMP inlined regions
|
||||
///
|
||||
/// \param OMPD Directive to generate inlined region for
|
||||
/// \param EntryCall Call to the entry OMP Runtime Function
|
||||
/// \param ExitCall Call to the ending OMP Runtime Function
|
||||
/// \param BodyGenCB Body code generation callback.
|
||||
/// \param FiniCB Finalization Callback. Will be called when finalizing region
|
||||
/// \param Conditional indicate if the entry call result will be used
|
||||
/// to evaluate a conditional of whether a thread will execute
|
||||
/// body code or not.
|
||||
/// \param HasFinalize indicate if the directive will require finalization
|
||||
/// and has a finalization callback in the stack that should
|
||||
/// be called.
|
||||
///
|
||||
/// \return The insertion point after the region
|
||||
|
||||
InsertPointTy
|
||||
EmitOMPInlinedRegion(omp::Directive OMPD, Instruction *EntryCall,
|
||||
Instruction *ExitCall, BodyGenCallbackTy BodyGenCB,
|
||||
FinalizeCallbackTy FiniCB, bool Conditional = false,
|
||||
bool HasFinalize = true);
|
||||
|
||||
/// Get the platform-specific name separator.
|
||||
/// \param Parts different parts of the final name that needs separation
|
||||
/// \param FirstSeparator First separator used between the initial two
|
||||
/// parts of the name.
|
||||
/// \param Separator separator used between all of the rest consecutinve
|
||||
/// parts of the name
|
||||
static std::string getNameWithSeparators(ArrayRef<StringRef> Parts,
|
||||
StringRef FirstSeparator,
|
||||
StringRef Separator);
|
||||
|
||||
/// Gets (if variable with the given name already exist) or creates
|
||||
/// internal global variable with the specified Name. The created variable has
|
||||
/// linkage CommonLinkage by default and is initialized by null value.
|
||||
/// \param Ty Type of the global variable. If it is exist already the type
|
||||
/// must be the same.
|
||||
/// \param Name Name of the variable.
|
||||
Constant *getOrCreateOMPInternalVariable(Type *Ty, const Twine &Name,
|
||||
unsigned AddressSpace = 0);
|
||||
|
||||
/// Returns corresponding lock object for the specified critical region
|
||||
/// name. If the lock object does not exist it is created, otherwise the
|
||||
/// reference to the existing copy is returned.
|
||||
/// \param CriticalName Name of the critical region.
|
||||
///
|
||||
Value *getOMPCriticalRegionLock(StringRef CriticalName);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -122,6 +122,24 @@ __OMP_TYPE(Int32Ptr)
|
||||
|
||||
///}
|
||||
|
||||
/// array types
|
||||
///
|
||||
///{
|
||||
|
||||
#ifndef OMP_ARRAY_TYPE
|
||||
#define OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize)
|
||||
#endif
|
||||
|
||||
#define __OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize) \
|
||||
OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize)
|
||||
|
||||
__OMP_ARRAY_TYPE(KmpCriticalName, Int32, 8)
|
||||
|
||||
#undef __OMP_ARRAY_TYPE
|
||||
#undef OMP_ARRAY_TYPE
|
||||
|
||||
///}
|
||||
|
||||
/// Struct and function types
|
||||
///
|
||||
///{
|
||||
@ -207,6 +225,12 @@ __OMP_RTL(omp_set_max_active_levels, false, Void, Int32)
|
||||
|
||||
__OMP_RTL(__last, false, Void, )
|
||||
|
||||
__OMP_RTL(__kmpc_master, false, Int32, IdentPtr, Int32)
|
||||
__OMP_RTL(__kmpc_end_master, false, Void, IdentPtr, Int32)
|
||||
__OMP_RTL(__kmpc_critical, false, Void, IdentPtr, Int32, KmpCriticalNamePtrTy)
|
||||
__OMP_RTL(__kmpc_critical_with_hint, false, Void, IdentPtr, Int32, KmpCriticalNamePtrTy, Int32)
|
||||
__OMP_RTL(__kmpc_end_critical, false, Void, IdentPtr, Int32, KmpCriticalNamePtrTy)
|
||||
|
||||
#undef __OMP_RTL
|
||||
#undef OMP_RTL
|
||||
|
||||
|
@ -36,14 +36,16 @@ StringRef llvm::omp::getOpenMPDirectiveName(Directive Kind) {
|
||||
llvm_unreachable("Invalid OpenMP directive kind");
|
||||
}
|
||||
|
||||
/// Declarations for LLVM-IR types (simple, function and structure) are
|
||||
/// Declarations for LLVM-IR types (simple, array, function and structure) are
|
||||
/// generated below. Their names are defined and used in OpenMPKinds.def. Here
|
||||
/// we provide the declarations, the initializeTypes function will provide the
|
||||
/// values.
|
||||
///
|
||||
///{
|
||||
|
||||
#define OMP_TYPE(VarName, InitValue) Type *llvm::omp::types::VarName = nullptr;
|
||||
#define OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize) \
|
||||
ArrayType *llvm::omp::types::VarName##Ty = nullptr; \
|
||||
PointerType *llvm::omp::types::VarName##PtrTy = nullptr;
|
||||
#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...) \
|
||||
FunctionType *llvm::omp::types::VarName = nullptr; \
|
||||
PointerType *llvm::omp::types::VarName##Ptr = nullptr;
|
||||
@ -63,6 +65,9 @@ void llvm::omp::types::initializeTypes(Module &M) {
|
||||
// the llvm::PointerTypes of them for easy access later.
|
||||
StructType *T;
|
||||
#define OMP_TYPE(VarName, InitValue) VarName = InitValue;
|
||||
#define OMP_ARRAY_TYPE(VarName, ElemTy, ArraySize) \
|
||||
VarName##Ty = ArrayType::get(ElemTy, ArraySize); \
|
||||
VarName##PtrTy = PointerType::getUnqual(VarName##Ty);
|
||||
#define OMP_FUNCTION_TYPE(VarName, IsVarArg, ReturnType, ...) \
|
||||
VarName = FunctionType::get(ReturnType, {__VA_ARGS__}, IsVarArg); \
|
||||
VarName##Ptr = PointerType::getUnqual(VarName);
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/MDBuilder.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
@ -558,9 +558,9 @@ IRBuilder<>::InsertPoint OpenMPIRBuilder::CreateParallel(
|
||||
// callback callee.
|
||||
F->addMetadata(
|
||||
llvm::LLVMContext::MD_callback,
|
||||
*llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
|
||||
2, {-1, -1},
|
||||
/* VarArgsArePassed */ true)}));
|
||||
*llvm::MDNode::get(
|
||||
Ctx, {MDB.createCallbackEncoding(2, {-1, -1},
|
||||
/* VarArgsArePassed */ true)}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,8 +631,7 @@ IRBuilder<>::InsertPoint OpenMPIRBuilder::CreateParallel(
|
||||
return AfterIP;
|
||||
}
|
||||
|
||||
void OpenMPIRBuilder::emitFlush(const LocationDescription &Loc)
|
||||
{
|
||||
void OpenMPIRBuilder::emitFlush(const LocationDescription &Loc) {
|
||||
// Build call void __kmpc_flush(ident_t *loc)
|
||||
Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
|
||||
Value *Args[] = {getOrCreateIdent(SrcLocStr)};
|
||||
@ -640,9 +639,245 @@ void OpenMPIRBuilder::emitFlush(const LocationDescription &Loc)
|
||||
Builder.CreateCall(getOrCreateRuntimeFunction(OMPRTL___kmpc_flush), Args);
|
||||
}
|
||||
|
||||
void OpenMPIRBuilder::CreateFlush(const LocationDescription &Loc)
|
||||
{
|
||||
void OpenMPIRBuilder::CreateFlush(const LocationDescription &Loc) {
|
||||
if (!updateToLocation(Loc))
|
||||
return;
|
||||
return;
|
||||
emitFlush(Loc);
|
||||
}
|
||||
|
||||
OpenMPIRBuilder::InsertPointTy
|
||||
OpenMPIRBuilder::CreateMaster(const LocationDescription &Loc,
|
||||
BodyGenCallbackTy BodyGenCB,
|
||||
FinalizeCallbackTy FiniCB) {
|
||||
|
||||
if (!updateToLocation(Loc))
|
||||
return Loc.IP;
|
||||
|
||||
Directive OMPD = Directive::OMPD_master;
|
||||
Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
|
||||
Value *Ident = getOrCreateIdent(SrcLocStr);
|
||||
Value *ThreadId = getOrCreateThreadID(Ident);
|
||||
Value *Args[] = {Ident, ThreadId};
|
||||
|
||||
Function *EntryRTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_master);
|
||||
Instruction *EntryCall = Builder.CreateCall(EntryRTLFn, Args);
|
||||
|
||||
Function *ExitRTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_end_master);
|
||||
Instruction *ExitCall = Builder.CreateCall(ExitRTLFn, Args);
|
||||
|
||||
return EmitOMPInlinedRegion(OMPD, EntryCall, ExitCall, BodyGenCB, FiniCB,
|
||||
/*Conditional*/ true, /*hasFinalize*/ true);
|
||||
}
|
||||
|
||||
OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::CreateCritical(
|
||||
const LocationDescription &Loc, BodyGenCallbackTy BodyGenCB,
|
||||
FinalizeCallbackTy FiniCB, StringRef CriticalName, Value *HintInst) {
|
||||
|
||||
if (!updateToLocation(Loc))
|
||||
return Loc.IP;
|
||||
|
||||
Directive OMPD = Directive::OMPD_critical;
|
||||
Constant *SrcLocStr = getOrCreateSrcLocStr(Loc);
|
||||
Value *Ident = getOrCreateIdent(SrcLocStr);
|
||||
Value *ThreadId = getOrCreateThreadID(Ident);
|
||||
Value *LockVar = getOMPCriticalRegionLock(CriticalName);
|
||||
Value *Args[] = {Ident, ThreadId, LockVar};
|
||||
|
||||
SmallVector<llvm::Value *, 4> EnterArgs(std::begin(Args), std::end(Args));
|
||||
Function *RTFn = nullptr;
|
||||
if (HintInst) {
|
||||
// Add Hint to entry Args and create call
|
||||
EnterArgs.push_back(HintInst);
|
||||
RTFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_critical_with_hint);
|
||||
} else {
|
||||
RTFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_critical);
|
||||
}
|
||||
Instruction *EntryCall = Builder.CreateCall(RTFn, EnterArgs);
|
||||
|
||||
Function *ExitRTLFn = getOrCreateRuntimeFunction(OMPRTL___kmpc_end_critical);
|
||||
Instruction *ExitCall = Builder.CreateCall(ExitRTLFn, Args);
|
||||
|
||||
return EmitOMPInlinedRegion(OMPD, EntryCall, ExitCall, BodyGenCB, FiniCB,
|
||||
/*Conditional*/ false, /*hasFinalize*/ true);
|
||||
}
|
||||
|
||||
OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::EmitOMPInlinedRegion(
|
||||
Directive OMPD, Instruction *EntryCall, Instruction *ExitCall,
|
||||
BodyGenCallbackTy BodyGenCB, FinalizeCallbackTy FiniCB, bool Conditional,
|
||||
bool HasFinalize) {
|
||||
|
||||
if (HasFinalize)
|
||||
FinalizationStack.push_back({FiniCB, OMPD, /*IsCancellable*/ false});
|
||||
|
||||
// Create inlined region's entry and body blocks, in preparation
|
||||
// for conditional creation
|
||||
BasicBlock *EntryBB = Builder.GetInsertBlock();
|
||||
Instruction *SplitPos = EntryBB->getTerminator();
|
||||
if (!isa_and_nonnull<BranchInst>(SplitPos))
|
||||
SplitPos = new UnreachableInst(Builder.getContext(), EntryBB);
|
||||
BasicBlock *ExitBB = EntryBB->splitBasicBlock(SplitPos, "omp_region.end");
|
||||
BasicBlock *FiniBB =
|
||||
EntryBB->splitBasicBlock(EntryBB->getTerminator(), "omp_region.finalize");
|
||||
|
||||
Builder.SetInsertPoint(EntryBB->getTerminator());
|
||||
emitCommonDirectiveEntry(OMPD, EntryCall, ExitBB, Conditional);
|
||||
|
||||
// generate body
|
||||
BodyGenCB(/* AllocaIP */ InsertPointTy(),
|
||||
/* CodeGenIP */ Builder.saveIP(), *FiniBB);
|
||||
|
||||
// If we didn't emit a branch to FiniBB during body generation, it means
|
||||
// FiniBB is unreachable (e.g. while(1);). stop generating all the
|
||||
// unreachable blocks, and remove anything we are not going to use.
|
||||
auto SkipEmittingRegion = FiniBB->hasNPredecessors(0);
|
||||
if (SkipEmittingRegion) {
|
||||
FiniBB->eraseFromParent();
|
||||
ExitCall->eraseFromParent();
|
||||
// Discard finalization if we have it.
|
||||
if (HasFinalize) {
|
||||
assert(!FinalizationStack.empty() &&
|
||||
"Unexpected finalization stack state!");
|
||||
FinalizationStack.pop_back();
|
||||
}
|
||||
} else {
|
||||
// emit exit call and do any needed finalization.
|
||||
auto FinIP = InsertPointTy(FiniBB, FiniBB->getFirstInsertionPt());
|
||||
assert(FiniBB->getTerminator()->getNumSuccessors() == 1 &&
|
||||
FiniBB->getTerminator()->getSuccessor(0) == ExitBB &&
|
||||
"Unexpected control flow graph state!!");
|
||||
emitCommonDirectiveExit(OMPD, FinIP, ExitCall, HasFinalize);
|
||||
assert(FiniBB->getUniquePredecessor()->getUniqueSuccessor() == FiniBB &&
|
||||
"Unexpected Control Flow State!");
|
||||
MergeBlockIntoPredecessor(FiniBB);
|
||||
}
|
||||
|
||||
// If we are skipping the region of a non conditional, remove the exit
|
||||
// block, and clear the builder's insertion point.
|
||||
BasicBlock *IPBB = SplitPos->getParent();
|
||||
assert(IPBB == ExitBB && "Unexpected Insertion point location!");
|
||||
if (!Conditional && SkipEmittingRegion) {
|
||||
ExitBB->eraseFromParent();
|
||||
Builder.ClearInsertionPoint();
|
||||
} else {
|
||||
auto merged = MergeBlockIntoPredecessor(ExitBB);
|
||||
BasicBlock *ExitPredBB = SplitPos->getParent();
|
||||
auto InsertBB = merged ? ExitPredBB : ExitBB;
|
||||
if (!isa_and_nonnull<BranchInst>(SplitPos))
|
||||
SplitPos->eraseFromParent();
|
||||
Builder.SetInsertPoint(InsertBB);
|
||||
}
|
||||
|
||||
return Builder.saveIP();
|
||||
}
|
||||
|
||||
OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::emitCommonDirectiveEntry(
|
||||
Directive OMPD, Value *EntryCall, BasicBlock *ExitBB, bool Conditional) {
|
||||
|
||||
// if nothing to do, Return current insertion point.
|
||||
if (!Conditional)
|
||||
return Builder.saveIP();
|
||||
|
||||
BasicBlock *EntryBB = Builder.GetInsertBlock();
|
||||
Value *CallBool = Builder.CreateIsNotNull(EntryCall);
|
||||
auto *ThenBB = BasicBlock::Create(M.getContext(), "omp_region.body");
|
||||
auto *UI = new UnreachableInst(Builder.getContext(), ThenBB);
|
||||
|
||||
// Emit thenBB and set the Builder's insertion point there for
|
||||
// body generation next. Place the block after the current block.
|
||||
Function *CurFn = EntryBB->getParent();
|
||||
CurFn->getBasicBlockList().insertAfter(EntryBB->getIterator(), ThenBB);
|
||||
|
||||
// Move Entry branch to end of ThenBB, and replace with conditional
|
||||
// branch (If-stmt)
|
||||
Instruction *EntryBBTI = EntryBB->getTerminator();
|
||||
Builder.CreateCondBr(CallBool, ThenBB, ExitBB);
|
||||
EntryBBTI->removeFromParent();
|
||||
Builder.SetInsertPoint(UI);
|
||||
Builder.Insert(EntryBBTI);
|
||||
UI->eraseFromParent();
|
||||
Builder.SetInsertPoint(ThenBB->getTerminator());
|
||||
|
||||
// return an insertion point to ExitBB.
|
||||
return IRBuilder<>::InsertPoint(ExitBB, ExitBB->getFirstInsertionPt());
|
||||
}
|
||||
|
||||
OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::emitCommonDirectiveExit(
|
||||
omp::Directive OMPD, InsertPointTy FinIP, Instruction *ExitCall,
|
||||
bool HasFinalize) {
|
||||
|
||||
IRBuilder<>::InsertPointGuard IPG(Builder);
|
||||
Builder.restoreIP(FinIP);
|
||||
|
||||
// If there is finalization to do, emit it before the exit call
|
||||
if (HasFinalize) {
|
||||
assert(!FinalizationStack.empty() &&
|
||||
"Unexpected finalization stack state!");
|
||||
|
||||
FinalizationInfo Fi = FinalizationStack.pop_back_val();
|
||||
assert(Fi.DK == OMPD && "Unexpected Directive for Finalization call!");
|
||||
|
||||
Fi.FiniCB(FinIP);
|
||||
|
||||
BasicBlock *FiniBB = FinIP.getBlock();
|
||||
Instruction *FiniBBTI = FiniBB->getTerminator();
|
||||
|
||||
// set Builder IP for call creation
|
||||
Builder.SetInsertPoint(FiniBBTI);
|
||||
}
|
||||
|
||||
// place the Exitcall as last instruction before Finalization block terminator
|
||||
ExitCall->removeFromParent();
|
||||
Builder.Insert(ExitCall);
|
||||
|
||||
return IRBuilder<>::InsertPoint(ExitCall->getParent(),
|
||||
ExitCall->getIterator());
|
||||
}
|
||||
|
||||
std::string OpenMPIRBuilder::getNameWithSeparators(ArrayRef<StringRef> Parts,
|
||||
StringRef FirstSeparator,
|
||||
StringRef Separator) {
|
||||
SmallString<128> Buffer;
|
||||
llvm::raw_svector_ostream OS(Buffer);
|
||||
StringRef Sep = FirstSeparator;
|
||||
for (StringRef Part : Parts) {
|
||||
OS << Sep << Part;
|
||||
Sep = Separator;
|
||||
}
|
||||
return OS.str().str();
|
||||
}
|
||||
|
||||
Constant *OpenMPIRBuilder::getOrCreateOMPInternalVariable(
|
||||
llvm::Type *Ty, const llvm::Twine &Name, unsigned AddressSpace) {
|
||||
// TODO: Replace the twine arg with stringref to get rid of the conversion
|
||||
// logic. However This is taken from current implementation in clang as is.
|
||||
// Since this method is used in many places exclusively for OMP internal use
|
||||
// we will keep it as is for temporarily until we move all users to the
|
||||
// builder and then, if possible, fix it everywhere in one go.
|
||||
SmallString<256> Buffer;
|
||||
llvm::raw_svector_ostream Out(Buffer);
|
||||
Out << Name;
|
||||
StringRef RuntimeName = Out.str();
|
||||
auto &Elem = *InternalVars.try_emplace(RuntimeName, nullptr).first;
|
||||
if (Elem.second) {
|
||||
assert(Elem.second->getType()->getPointerElementType() == Ty &&
|
||||
"OMP internal variable has different type than requested");
|
||||
} else {
|
||||
// TODO: investigate the appropriate linkage type used for the global
|
||||
// variable for possibly changing that to internal or private, or maybe
|
||||
// create different versions of the function for different OMP internal
|
||||
// variables.
|
||||
Elem.second = new llvm::GlobalVariable(
|
||||
M, Ty, /*IsConstant*/ false, llvm::GlobalValue::CommonLinkage,
|
||||
llvm::Constant::getNullValue(Ty), Elem.first(),
|
||||
/*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
|
||||
AddressSpace);
|
||||
}
|
||||
|
||||
return Elem.second;
|
||||
}
|
||||
|
||||
Value *OpenMPIRBuilder::getOMPCriticalRegionLock(StringRef CriticalName) {
|
||||
std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
|
||||
std::string Name = getNameWithSeparators({Prefix, "var"}, ".", ".");
|
||||
return getOrCreateOMPInternalVariable(KmpCriticalNameTy, Name);
|
||||
}
|
||||
|
@ -613,4 +613,161 @@ TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OpenMPIRBuilderTest, MasterDirective) {
|
||||
using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
|
||||
OpenMPIRBuilder OMPBuilder(*M);
|
||||
OMPBuilder.initialize();
|
||||
F->setName("func");
|
||||
IRBuilder<> Builder(BB);
|
||||
|
||||
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
|
||||
|
||||
AllocaInst *PrivAI = nullptr;
|
||||
|
||||
BasicBlock *EntryBB = nullptr;
|
||||
BasicBlock *ExitBB = nullptr;
|
||||
BasicBlock *ThenBB = nullptr;
|
||||
|
||||
auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
|
||||
BasicBlock &FiniBB) {
|
||||
if (AllocaIP.isSet())
|
||||
Builder.restoreIP(AllocaIP);
|
||||
else
|
||||
Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));
|
||||
PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
|
||||
Builder.CreateStore(F->arg_begin(), PrivAI);
|
||||
|
||||
llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
|
||||
llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();
|
||||
EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);
|
||||
|
||||
Builder.restoreIP(CodeGenIP);
|
||||
|
||||
// collect some info for checks later
|
||||
ExitBB = FiniBB.getUniqueSuccessor();
|
||||
ThenBB = Builder.GetInsertBlock();
|
||||
EntryBB = ThenBB->getUniquePredecessor();
|
||||
|
||||
// simple instructions for body
|
||||
Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
|
||||
Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
|
||||
};
|
||||
|
||||
auto FiniCB = [&](InsertPointTy IP) {
|
||||
BasicBlock *IPBB = IP.getBlock();
|
||||
EXPECT_NE(IPBB->end(), IP.getPoint());
|
||||
};
|
||||
|
||||
Builder.restoreIP(OMPBuilder.CreateMaster(Builder, BodyGenCB, FiniCB));
|
||||
Value *EntryBBTI = EntryBB->getTerminator();
|
||||
EXPECT_NE(EntryBBTI, nullptr);
|
||||
EXPECT_TRUE(isa<BranchInst>(EntryBBTI));
|
||||
BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());
|
||||
EXPECT_TRUE(EntryBr->isConditional());
|
||||
EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);
|
||||
EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB);
|
||||
EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);
|
||||
|
||||
CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());
|
||||
EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));
|
||||
|
||||
CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0));
|
||||
EXPECT_EQ(MasterEntryCI->getNumArgOperands(), 2U);
|
||||
EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master");
|
||||
EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0)));
|
||||
|
||||
CallInst *MasterEndCI = nullptr;
|
||||
for (auto &FI : *ThenBB) {
|
||||
Instruction *cur = &FI;
|
||||
if (isa<CallInst>(cur)) {
|
||||
MasterEndCI = cast<CallInst>(cur);
|
||||
if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master")
|
||||
break;
|
||||
MasterEndCI = nullptr;
|
||||
}
|
||||
}
|
||||
EXPECT_NE(MasterEndCI, nullptr);
|
||||
EXPECT_EQ(MasterEndCI->getNumArgOperands(), 2U);
|
||||
EXPECT_TRUE(isa<GlobalVariable>(MasterEndCI->getArgOperand(0)));
|
||||
EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1));
|
||||
}
|
||||
|
||||
TEST_F(OpenMPIRBuilderTest, CriticalDirective) {
|
||||
using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
|
||||
OpenMPIRBuilder OMPBuilder(*M);
|
||||
OMPBuilder.initialize();
|
||||
F->setName("func");
|
||||
IRBuilder<> Builder(BB);
|
||||
|
||||
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
|
||||
|
||||
AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
|
||||
|
||||
BasicBlock *EntryBB = nullptr;
|
||||
|
||||
auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
|
||||
BasicBlock &FiniBB) {
|
||||
// collect some info for checks later
|
||||
EntryBB = FiniBB.getUniquePredecessor();
|
||||
|
||||
// actual start for bodyCB
|
||||
llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
|
||||
llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();
|
||||
EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);
|
||||
EXPECT_EQ(EntryBB, CodeGenIPBB);
|
||||
|
||||
// body begin
|
||||
Builder.restoreIP(CodeGenIP);
|
||||
Builder.CreateStore(F->arg_begin(), PrivAI);
|
||||
Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
|
||||
Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
|
||||
};
|
||||
|
||||
auto FiniCB = [&](InsertPointTy IP) {
|
||||
BasicBlock *IPBB = IP.getBlock();
|
||||
EXPECT_NE(IPBB->end(), IP.getPoint());
|
||||
};
|
||||
|
||||
Builder.restoreIP(OMPBuilder.CreateCritical(Builder, BodyGenCB, FiniCB,
|
||||
"testCRT", nullptr));
|
||||
|
||||
Value *EntryBBTI = EntryBB->getTerminator();
|
||||
EXPECT_EQ(EntryBBTI, nullptr);
|
||||
|
||||
CallInst *CriticalEntryCI = nullptr;
|
||||
for (auto &EI : *EntryBB) {
|
||||
Instruction *cur = &EI;
|
||||
if (isa<CallInst>(cur)) {
|
||||
CriticalEntryCI = cast<CallInst>(cur);
|
||||
if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical")
|
||||
break;
|
||||
CriticalEntryCI = nullptr;
|
||||
}
|
||||
}
|
||||
EXPECT_NE(CriticalEntryCI, nullptr);
|
||||
EXPECT_EQ(CriticalEntryCI->getNumArgOperands(), 3U);
|
||||
EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical");
|
||||
EXPECT_TRUE(isa<GlobalVariable>(CriticalEntryCI->getArgOperand(0)));
|
||||
|
||||
CallInst *CriticalEndCI = nullptr;
|
||||
for (auto &FI : *EntryBB) {
|
||||
Instruction *cur = &FI;
|
||||
if (isa<CallInst>(cur)) {
|
||||
CriticalEndCI = cast<CallInst>(cur);
|
||||
if (CriticalEndCI->getCalledFunction()->getName() ==
|
||||
"__kmpc_end_critical")
|
||||
break;
|
||||
CriticalEndCI = nullptr;
|
||||
}
|
||||
}
|
||||
EXPECT_NE(CriticalEndCI, nullptr);
|
||||
EXPECT_EQ(CriticalEndCI->getNumArgOperands(), 3U);
|
||||
EXPECT_TRUE(isa<GlobalVariable>(CriticalEndCI->getArgOperand(0)));
|
||||
EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1));
|
||||
PointerType *CriticalNamePtrTy =
|
||||
PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx), 8));
|
||||
EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2));
|
||||
EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user