blob: 9dfcd0753b224d32a3e0d4ac3c29b8c2adb4665d [file] [log] [blame]
Alexey Bataev9959db52014-05-06 10:08:46 +00001//===----- CGOpenMPRuntime.cpp - Interface to OpenMP Runtimes -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This provides a class for OpenMP runtime code generation.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CGOpenMPRuntime.h"
15#include "CodeGenFunction.h"
16#include "clang/AST/Decl.h"
17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/IR/DerivedTypes.h"
19#include "llvm/IR/GlobalValue.h"
20#include "llvm/IR/Value.h"
21#include "llvm/Support/raw_ostream.h"
Alexey Bataev23b69422014-06-18 07:08:49 +000022#include <cassert>
Alexey Bataev9959db52014-05-06 10:08:46 +000023
24using namespace clang;
25using namespace CodeGen;
26
27CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
28 : CGM(CGM), DefaultOpenMPPSource(nullptr) {
29 IdentTy = llvm::StructType::create(
30 "ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
31 CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
Alexander Musmanfdfa8552014-09-11 08:10:57 +000032 CGM.Int8PtrTy /* psource */, nullptr);
Alexey Bataev9959db52014-05-06 10:08:46 +000033 // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
Alexey Bataev23b69422014-06-18 07:08:49 +000034 llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty),
35 llvm::PointerType::getUnqual(CGM.Int32Ty)};
Alexey Bataev9959db52014-05-06 10:08:46 +000036 Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
Alexey Bataev3a3bf0b2014-09-22 10:01:53 +000037 KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
Alexey Bataev9959db52014-05-06 10:08:46 +000038}
39
40llvm::Value *
41CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
Alexey Bataev15007ba2014-05-07 06:18:01 +000042 llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags);
Alexey Bataev9959db52014-05-06 10:08:46 +000043 if (!Entry) {
44 if (!DefaultOpenMPPSource) {
45 // Initialize default location for psource field of ident_t structure of
46 // all ident_t objects. Format is ";file;function;line;column;;".
47 // Taken from
48 // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c
49 DefaultOpenMPPSource =
50 CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;");
51 DefaultOpenMPPSource =
52 llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
53 }
54 llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
Alexey Bataev15007ba2014-05-07 06:18:01 +000055 CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
Alexey Bataev9959db52014-05-06 10:08:46 +000056 DefaultOpenMPLocation->setUnnamedAddr(true);
57 DefaultOpenMPLocation->setConstant(true);
58 DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
59
60 llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
Alexey Bataev23b69422014-06-18 07:08:49 +000061 llvm::Constant *Values[] = {Zero,
62 llvm::ConstantInt::get(CGM.Int32Ty, Flags),
63 Zero, Zero, DefaultOpenMPPSource};
Alexey Bataev9959db52014-05-06 10:08:46 +000064 llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
65 DefaultOpenMPLocation->setInitializer(Init);
66 return DefaultOpenMPLocation;
67 }
68 return Entry;
69}
70
71llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
72 CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) {
73 // If no debug info is generated - return global default location.
74 if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo ||
75 Loc.isInvalid())
76 return GetOrCreateDefaultOpenMPLocation(Flags);
77
78 assert(CGF.CurFn && "No function in current CodeGenFunction.");
79
Alexey Bataev9959db52014-05-06 10:08:46 +000080 llvm::Value *LocValue = nullptr;
81 OpenMPLocMapTy::iterator I = OpenMPLocMap.find(CGF.CurFn);
82 if (I != OpenMPLocMap.end()) {
83 LocValue = I->second;
84 } else {
Alexey Bataev15007ba2014-05-07 06:18:01 +000085 // Generate "ident_t .kmpc_loc.addr;"
86 llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr");
Alexey Bataev9959db52014-05-06 10:08:46 +000087 AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy));
88 OpenMPLocMap[CGF.CurFn] = AI;
89 LocValue = AI;
90
91 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
92 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
93 CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags),
94 llvm::ConstantExpr::getSizeOf(IdentTy),
95 CGM.PointerAlignInBytes);
96 }
97
98 // char **psource = &.kmpc_loc_<flags>.addr.psource;
99 llvm::Value *PSource =
100 CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource);
101
Alexey Bataevf002aca2014-05-30 05:48:40 +0000102 auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
103 if (OMPDebugLoc == nullptr) {
104 SmallString<128> Buffer2;
105 llvm::raw_svector_ostream OS2(Buffer2);
106 // Build debug location
107 PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
108 OS2 << ";" << PLoc.getFilename() << ";";
109 if (const FunctionDecl *FD =
110 dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) {
111 OS2 << FD->getQualifiedNameAsString();
112 }
113 OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
114 OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str());
115 OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc;
Alexey Bataev9959db52014-05-06 10:08:46 +0000116 }
Alexey Bataev9959db52014-05-06 10:08:46 +0000117 // *psource = ";<File>;<Function>;<Line>;<Column>;;";
Alexey Bataevf002aca2014-05-30 05:48:40 +0000118 CGF.Builder.CreateStore(OMPDebugLoc, PSource);
119
Alexey Bataev9959db52014-05-06 10:08:46 +0000120 return LocValue;
121}
122
123llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
124 SourceLocation Loc) {
125 assert(CGF.CurFn && "No function in current CodeGenFunction.");
126
127 llvm::Value *GTid = nullptr;
128 OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
129 if (I != OpenMPGtidMap.end()) {
130 GTid = I->second;
131 } else {
Alexey Bataevd6c57552014-07-25 07:55:17 +0000132 // Check if current function is a function which has first parameter
133 // with type int32 and name ".global_tid.".
134 if (!CGF.CurFn->arg_empty() &&
135 CGF.CurFn->arg_begin()->getType()->isPointerTy() &&
136 CGF.CurFn->arg_begin()
137 ->getType()
138 ->getPointerElementType()
139 ->isIntegerTy() &&
140 CGF.CurFn->arg_begin()
141 ->getType()
142 ->getPointerElementType()
143 ->getIntegerBitWidth() == 32 &&
144 CGF.CurFn->arg_begin()->hasName() &&
145 CGF.CurFn->arg_begin()->getName() == ".global_tid.") {
146 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
147 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
148 GTid = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
149 } else {
150 // Generate "int32 .kmpc_global_thread_num.addr;"
151 CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
152 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
153 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
154 GTid = CGF.EmitRuntimeCall(
155 CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
156 }
Alexey Bataev9959db52014-05-06 10:08:46 +0000157 OpenMPGtidMap[CGF.CurFn] = GTid;
158 }
159 return GTid;
160}
161
162void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
163 assert(CGF.CurFn && "No function in current CodeGenFunction.");
164 if (OpenMPGtidMap.count(CGF.CurFn))
165 OpenMPGtidMap.erase(CGF.CurFn);
166 if (OpenMPLocMap.count(CGF.CurFn))
167 OpenMPLocMap.erase(CGF.CurFn);
168}
169
170llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
171 return llvm::PointerType::getUnqual(IdentTy);
172}
173
174llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
175 return llvm::PointerType::getUnqual(Kmpc_MicroTy);
176}
177
178llvm::Constant *
179CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
180 llvm::Constant *RTLFn = nullptr;
181 switch (Function) {
182 case OMPRTL__kmpc_fork_call: {
183 // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
184 // microtask, ...);
Alexey Bataev23b69422014-06-18 07:08:49 +0000185 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
186 getKmpc_MicroPointerTy()};
Alexey Bataev9959db52014-05-06 10:08:46 +0000187 llvm::FunctionType *FnTy =
188 llvm::FunctionType::get(CGM.VoidTy, TypeParams, true);
189 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
190 break;
191 }
192 case OMPRTL__kmpc_global_thread_num: {
193 // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc);
Alexey Bataev23b69422014-06-18 07:08:49 +0000194 llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
Alexey Bataev9959db52014-05-06 10:08:46 +0000195 llvm::FunctionType *FnTy =
196 llvm::FunctionType::get(CGM.Int32Ty, TypeParams, false);
197 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
198 break;
199 }
Alexey Bataev3a3bf0b2014-09-22 10:01:53 +0000200 case OMPRTL__kmpc_critical: {
Alexey Bataevf9472182014-09-22 12:32:31 +0000201 // Build void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
202 // kmp_critical_name *crit);
Alexey Bataev3a3bf0b2014-09-22 10:01:53 +0000203 llvm::Type *TypeParams[] = {
204 getIdentTyPointerTy(), CGM.Int32Ty,
205 llvm::PointerType::getUnqual(KmpCriticalNameTy)};
206 llvm::FunctionType *FnTy =
207 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
208 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical");
209 break;
210 }
211 case OMPRTL__kmpc_end_critical: {
Alexey Bataevf9472182014-09-22 12:32:31 +0000212 // Build void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
213 // kmp_critical_name *crit);
Alexey Bataev3a3bf0b2014-09-22 10:01:53 +0000214 llvm::Type *TypeParams[] = {
215 getIdentTyPointerTy(), CGM.Int32Ty,
216 llvm::PointerType::getUnqual(KmpCriticalNameTy)};
217 llvm::FunctionType *FnTy =
218 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
219 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
220 break;
221 }
Alexey Bataev9959db52014-05-06 10:08:46 +0000222 }
223 return RTLFn;
224}
Alexey Bataev3a3bf0b2014-09-22 10:01:53 +0000225
226llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
227 SmallString<256> Buffer;
228 llvm::raw_svector_ostream Out(Buffer);
229 Out << ".gomp_critical_user_" << CriticalName << ".var";
230 auto RuntimeCriticalName = Out.str();
231 auto &Elem = CriticalRegionVarNames.GetOrCreateValue(RuntimeCriticalName);
232 if (Elem.getValue() != nullptr)
233 return Elem.getValue();
234
235 auto Lock = new llvm::GlobalVariable(
236 CGM.getModule(), KmpCriticalNameTy, /*IsConstant*/ false,
237 llvm::GlobalValue::CommonLinkage,
238 llvm::Constant::getNullValue(KmpCriticalNameTy), Elem.getKey());
239 Elem.setValue(Lock);
240 return Lock;
241}
242
243void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
244 llvm::Value *RegionLock,
245 SourceLocation Loc) {
246 // Prepare other arguments and build a call to __kmpc_critical
247 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
248 GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
249 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
250 CGF.EmitRuntimeCall(RTLFn, Args);
251}
252
253void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
254 llvm::Value *RegionLock,
255 SourceLocation Loc) {
Alexey Bataevf9472182014-09-22 12:32:31 +0000256 // Prepare other arguments and build a call to __kmpc_end_critical
Alexey Bataev3a3bf0b2014-09-22 10:01:53 +0000257 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
258 GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
259 auto RTLFn =
260 CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
261 CGF.EmitRuntimeCall(RTLFn, Args);
262}