1//===----- 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"
22#include <cassert>
23
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 */,
32      CGM.Int8PtrTy /* psource */, NULL);
33  // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
34  llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty),
35                               llvm::PointerType::getUnqual(CGM.Int32Ty)};
36  Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
37}
38
39llvm::Value *
40CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
41  llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags);
42  if (!Entry) {
43    if (!DefaultOpenMPPSource) {
44      // Initialize default location for psource field of ident_t structure of
45      // all ident_t objects. Format is ";file;function;line;column;;".
46      // Taken from
47      // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c
48      DefaultOpenMPPSource =
49          CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;");
50      DefaultOpenMPPSource =
51          llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
52    }
53    llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
54        CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
55    DefaultOpenMPLocation->setUnnamedAddr(true);
56    DefaultOpenMPLocation->setConstant(true);
57    DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
58
59    llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
60    llvm::Constant *Values[] = {Zero,
61                                llvm::ConstantInt::get(CGM.Int32Ty, Flags),
62                                Zero, Zero, DefaultOpenMPPSource};
63    llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
64    DefaultOpenMPLocation->setInitializer(Init);
65    return DefaultOpenMPLocation;
66  }
67  return Entry;
68}
69
70llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
71    CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) {
72  // If no debug info is generated - return global default location.
73  if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo ||
74      Loc.isInvalid())
75    return GetOrCreateDefaultOpenMPLocation(Flags);
76
77  assert(CGF.CurFn && "No function in current CodeGenFunction.");
78
79  llvm::Value *LocValue = nullptr;
80  OpenMPLocMapTy::iterator I = OpenMPLocMap.find(CGF.CurFn);
81  if (I != OpenMPLocMap.end()) {
82    LocValue = I->second;
83  } else {
84    // Generate "ident_t .kmpc_loc.addr;"
85    llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr");
86    AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy));
87    OpenMPLocMap[CGF.CurFn] = AI;
88    LocValue = AI;
89
90    CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
91    CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
92    CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags),
93                             llvm::ConstantExpr::getSizeOf(IdentTy),
94                             CGM.PointerAlignInBytes);
95  }
96
97  // char **psource = &.kmpc_loc_<flags>.addr.psource;
98  llvm::Value *PSource =
99      CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource);
100
101  auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
102  if (OMPDebugLoc == nullptr) {
103    SmallString<128> Buffer2;
104    llvm::raw_svector_ostream OS2(Buffer2);
105    // Build debug location
106    PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
107    OS2 << ";" << PLoc.getFilename() << ";";
108    if (const FunctionDecl *FD =
109            dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) {
110      OS2 << FD->getQualifiedNameAsString();
111    }
112    OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
113    OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str());
114    OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc;
115  }
116  // *psource = ";<File>;<Function>;<Line>;<Column>;;";
117  CGF.Builder.CreateStore(OMPDebugLoc, PSource);
118
119  return LocValue;
120}
121
122llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
123                                                       SourceLocation Loc) {
124  assert(CGF.CurFn && "No function in current CodeGenFunction.");
125
126  llvm::Value *GTid = nullptr;
127  OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
128  if (I != OpenMPGtidMap.end()) {
129    GTid = I->second;
130  } else {
131    // Generate "int32 .kmpc_global_thread_num.addr;"
132    CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
133    CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
134    llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
135    GTid = CGF.EmitRuntimeCall(
136        CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
137    OpenMPGtidMap[CGF.CurFn] = GTid;
138  }
139  return GTid;
140}
141
142void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
143  assert(CGF.CurFn && "No function in current CodeGenFunction.");
144  if (OpenMPGtidMap.count(CGF.CurFn))
145    OpenMPGtidMap.erase(CGF.CurFn);
146  if (OpenMPLocMap.count(CGF.CurFn))
147    OpenMPLocMap.erase(CGF.CurFn);
148}
149
150llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
151  return llvm::PointerType::getUnqual(IdentTy);
152}
153
154llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
155  return llvm::PointerType::getUnqual(Kmpc_MicroTy);
156}
157
158llvm::Constant *
159CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
160  llvm::Constant *RTLFn = nullptr;
161  switch (Function) {
162  case OMPRTL__kmpc_fork_call: {
163    // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
164    // microtask, ...);
165    llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
166                                getKmpc_MicroPointerTy()};
167    llvm::FunctionType *FnTy =
168        llvm::FunctionType::get(CGM.VoidTy, TypeParams, true);
169    RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
170    break;
171  }
172  case OMPRTL__kmpc_global_thread_num: {
173    // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc);
174    llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
175    llvm::FunctionType *FnTy =
176        llvm::FunctionType::get(CGM.Int32Ty, TypeParams, false);
177    RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
178    break;
179  }
180  }
181  return RTLFn;
182}
183