1 //===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===// 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 contains code to emit OpenMP nodes as LLVM code. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "CGOpenMPRuntime.h" 15 #include "CodeGenFunction.h" 16 #include "CodeGenModule.h" 17 #include "clang/AST/Stmt.h" 18 #include "clang/AST/StmtOpenMP.h" 19 #include "TargetInfo.h" 20 using namespace clang; 21 using namespace CodeGen; 22 23 //===----------------------------------------------------------------------===// 24 // OpenMP Directive Emission 25 //===----------------------------------------------------------------------===// 26 27 /// \brief Emits code for OpenMP 'if' clause using specified \a CodeGen 28 /// function. Here is the logic: 29 /// if (Cond) { 30 /// CodeGen(true); 31 /// } else { 32 /// CodeGen(false); 33 /// } 34 static void EmitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond, 35 const std::function<void(bool)> &CodeGen) { 36 CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange()); 37 38 // If the condition constant folds and can be elided, try to avoid emitting 39 // the condition and the dead arm of the if/else. 40 bool CondConstant; 41 if (CGF.ConstantFoldsToSimpleInteger(Cond, CondConstant)) { 42 CodeGen(CondConstant); 43 return; 44 } 45 46 // Otherwise, the condition did not fold, or we couldn't elide it. Just 47 // emit the conditional branch. 48 auto ThenBlock = CGF.createBasicBlock(/*name*/ "omp_if.then"); 49 auto ElseBlock = CGF.createBasicBlock(/*name*/ "omp_if.else"); 50 auto ContBlock = CGF.createBasicBlock(/*name*/ "omp_if.end"); 51 CGF.EmitBranchOnBoolExpr(Cond, ThenBlock, ElseBlock, /*TrueCount*/ 0); 52 53 // Emit the 'then' code. 54 CGF.EmitBlock(ThenBlock); 55 CodeGen(/*ThenBlock*/ true); 56 CGF.EmitBranch(ContBlock); 57 // Emit the 'else' code if present. 58 { 59 // There is no need to emit line number for unconditional branch. 60 SuppressDebugLocation SDL(CGF.Builder); 61 CGF.EmitBlock(ElseBlock); 62 } 63 CodeGen(/*ThenBlock*/ false); 64 { 65 // There is no need to emit line number for unconditional branch. 66 SuppressDebugLocation SDL(CGF.Builder); 67 CGF.EmitBranch(ContBlock); 68 } 69 // Emit the continuation block for code after the if. 70 CGF.EmitBlock(ContBlock, /*IsFinished*/ true); 71 } 72 73 void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr, 74 llvm::Value *PrivateAddr, 75 const Expr *AssignExpr, 76 QualType OriginalType, 77 const VarDecl *VDInit) { 78 EmitBlock(createBasicBlock(".omp.assign.begin.")); 79 if (!isa<CXXConstructExpr>(AssignExpr) || isTrivialInitializer(AssignExpr)) { 80 // Perform simple memcpy. 81 EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(), 82 AssignExpr->getType()); 83 } else { 84 // Perform element-by-element initialization. 85 QualType ElementTy; 86 auto SrcBegin = OriginalAddr.getAddress(); 87 auto DestBegin = PrivateAddr; 88 auto ArrayTy = OriginalType->getAsArrayTypeUnsafe(); 89 auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin); 90 auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin); 91 auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements); 92 auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements); 93 // The basic structure here is a do-while loop, because we don't 94 // need to check for the zero-element case. 95 auto BodyBB = createBasicBlock("omp.arraycpy.body"); 96 auto DoneBB = createBasicBlock("omp.arraycpy.done"); 97 auto IsEmpty = 98 Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty"); 99 Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); 100 101 // Enter the loop body, making that address the current address. 102 auto EntryBB = Builder.GetInsertBlock(); 103 EmitBlock(BodyBB); 104 auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2, 105 "omp.arraycpy.srcElementPast"); 106 SrcElementPast->addIncoming(SrcEnd, EntryBB); 107 auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2, 108 "omp.arraycpy.destElementPast"); 109 DestElementPast->addIncoming(DestEnd, EntryBB); 110 111 // Shift the address back by one element. 112 auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true); 113 auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne, 114 "omp.arraycpy.dest.element"); 115 auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne, 116 "omp.arraycpy.src.element"); 117 { 118 // Create RunCleanScope to cleanup possible temps. 119 CodeGenFunction::RunCleanupsScope Init(*this); 120 // Emit initialization for single element. 121 LocalDeclMap[VDInit] = SrcElement; 122 EmitAnyExprToMem(AssignExpr, DestElement, 123 AssignExpr->getType().getQualifiers(), 124 /*IsInitializer*/ false); 125 LocalDeclMap.erase(VDInit); 126 } 127 128 // Check whether we've reached the end. 129 auto Done = 130 Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done"); 131 Builder.CreateCondBr(Done, DoneBB, BodyBB); 132 DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock()); 133 SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock()); 134 135 // Done. 136 EmitBlock(DoneBB, true); 137 } 138 EmitBlock(createBasicBlock(".omp.assign.end.")); 139 } 140 141 void CodeGenFunction::EmitOMPFirstprivateClause( 142 const OMPExecutableDirective &D, 143 CodeGenFunction::OMPPrivateScope &PrivateScope) { 144 auto PrivateFilter = [](const OMPClause *C) -> bool { 145 return C->getClauseKind() == OMPC_firstprivate; 146 }; 147 for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)> 148 I(D.clauses(), PrivateFilter); I; ++I) { 149 auto *C = cast<OMPFirstprivateClause>(*I); 150 auto IRef = C->varlist_begin(); 151 auto InitsRef = C->inits().begin(); 152 for (auto IInit : C->private_copies()) { 153 auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()); 154 auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl()); 155 bool IsRegistered; 156 if (*InitsRef != nullptr) { 157 // Emit VarDecl with copy init for arrays. 158 auto *FD = CapturedStmtInfo->lookup(OrigVD); 159 LValue Base = MakeNaturalAlignAddrLValue( 160 CapturedStmtInfo->getContextValue(), 161 getContext().getTagDeclType(FD->getParent())); 162 auto OriginalAddr = EmitLValueForField(Base, FD); 163 auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl()); 164 IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * { 165 auto Emission = EmitAutoVarAlloca(*VD); 166 // Emit initialization of aggregate firstprivate vars. 167 EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(), 168 VD->getInit(), (*IRef)->getType(), VDInit); 169 EmitAutoVarCleanups(Emission); 170 return Emission.getAllocatedAddress(); 171 }); 172 } else 173 IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * { 174 // Emit private VarDecl with copy init. 175 EmitDecl(*VD); 176 return GetAddrOfLocalVar(VD); 177 }); 178 assert(IsRegistered && "counter already registered as private"); 179 // Silence the warning about unused variable. 180 (void)IsRegistered; 181 ++IRef, ++InitsRef; 182 } 183 } 184 } 185 186 /// \brief Emits code for OpenMP parallel directive in the parallel region. 187 static void EmitOMPParallelCall(CodeGenFunction &CGF, 188 const OMPParallelDirective &S, 189 llvm::Value *OutlinedFn, 190 llvm::Value *CapturedStruct) { 191 if (auto C = S.getSingleClause(/*K*/ OMPC_num_threads)) { 192 CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF); 193 auto NumThreadsClause = cast<OMPNumThreadsClause>(C); 194 auto NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(), 195 /*IgnoreResultAssign*/ true); 196 CGF.CGM.getOpenMPRuntime().EmitOMPNumThreadsClause( 197 CGF, NumThreads, NumThreadsClause->getLocStart()); 198 } 199 CGF.CGM.getOpenMPRuntime().EmitOMPParallelCall(CGF, S.getLocStart(), 200 OutlinedFn, CapturedStruct); 201 } 202 203 void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { 204 auto CS = cast<CapturedStmt>(S.getAssociatedStmt()); 205 auto CapturedStruct = GenerateCapturedStmtArgument(*CS); 206 auto OutlinedFn = CGM.getOpenMPRuntime().EmitOpenMPOutlinedFunction( 207 S, *CS->getCapturedDecl()->param_begin()); 208 if (auto C = S.getSingleClause(/*K*/ OMPC_if)) { 209 auto Cond = cast<OMPIfClause>(C)->getCondition(); 210 EmitOMPIfClause(*this, Cond, [&](bool ThenBlock) { 211 if (ThenBlock) 212 EmitOMPParallelCall(*this, S, OutlinedFn, CapturedStruct); 213 else 214 CGM.getOpenMPRuntime().EmitOMPSerialCall(*this, S.getLocStart(), 215 OutlinedFn, CapturedStruct); 216 }); 217 } else 218 EmitOMPParallelCall(*this, S, OutlinedFn, CapturedStruct); 219 } 220 221 void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S, 222 bool SeparateIter) { 223 RunCleanupsScope BodyScope(*this); 224 // Update counters values on current iteration. 225 for (auto I : S.updates()) { 226 EmitIgnoredExpr(I); 227 } 228 // On a continue in the body, jump to the end. 229 auto Continue = getJumpDestInCurrentScope("omp.body.continue"); 230 BreakContinueStack.push_back(BreakContinue(JumpDest(), Continue)); 231 // Emit loop body. 232 EmitStmt(S.getBody()); 233 // The end (updates/cleanups). 234 EmitBlock(Continue.getBlock()); 235 BreakContinueStack.pop_back(); 236 if (SeparateIter) { 237 // TODO: Update lastprivates if the SeparateIter flag is true. 238 // This will be implemented in a follow-up OMPLastprivateClause patch, but 239 // result should be still correct without it, as we do not make these 240 // variables private yet. 241 } 242 } 243 244 void CodeGenFunction::EmitOMPInnerLoop(const OMPLoopDirective &S, 245 OMPPrivateScope &LoopScope, 246 bool SeparateIter) { 247 auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end"); 248 auto Cnt = getPGORegionCounter(&S); 249 250 // Start the loop with a block that tests the condition. 251 auto CondBlock = createBasicBlock("omp.inner.for.cond"); 252 EmitBlock(CondBlock); 253 LoopStack.push(CondBlock); 254 255 // If there are any cleanups between here and the loop-exit scope, 256 // create a block to stage a loop exit along. 257 auto ExitBlock = LoopExit.getBlock(); 258 if (LoopScope.requiresCleanups()) 259 ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup"); 260 261 auto LoopBody = createBasicBlock("omp.inner.for.body"); 262 263 // Emit condition: "IV < LastIteration + 1 [ - 1]" 264 // ("- 1" when lastprivate clause is present - separate one iteration). 265 llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond(SeparateIter)); 266 Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, 267 PGO.createLoopWeights(S.getCond(SeparateIter), Cnt)); 268 269 if (ExitBlock != LoopExit.getBlock()) { 270 EmitBlock(ExitBlock); 271 EmitBranchThroughCleanup(LoopExit); 272 } 273 274 EmitBlock(LoopBody); 275 Cnt.beginRegion(Builder); 276 277 // Create a block for the increment. 278 auto Continue = getJumpDestInCurrentScope("omp.inner.for.inc"); 279 BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); 280 281 EmitOMPLoopBody(S); 282 EmitStopPoint(&S); 283 284 // Emit "IV = IV + 1" and a back-edge to the condition block. 285 EmitBlock(Continue.getBlock()); 286 EmitIgnoredExpr(S.getInc()); 287 BreakContinueStack.pop_back(); 288 EmitBranch(CondBlock); 289 LoopStack.pop(); 290 // Emit the fall-through block. 291 EmitBlock(LoopExit.getBlock()); 292 } 293 294 void CodeGenFunction::EmitOMPSimdFinal(const OMPLoopDirective &S) { 295 auto IC = S.counters().begin(); 296 for (auto F : S.finals()) { 297 if (LocalDeclMap.lookup(cast<DeclRefExpr>((*IC))->getDecl())) { 298 EmitIgnoredExpr(F); 299 } 300 ++IC; 301 } 302 } 303 304 static void EmitOMPAlignedClause(CodeGenFunction &CGF, CodeGenModule &CGM, 305 const OMPAlignedClause &Clause) { 306 unsigned ClauseAlignment = 0; 307 if (auto AlignmentExpr = Clause.getAlignment()) { 308 auto AlignmentCI = 309 cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr)); 310 ClauseAlignment = static_cast<unsigned>(AlignmentCI->getZExtValue()); 311 } 312 for (auto E : Clause.varlists()) { 313 unsigned Alignment = ClauseAlignment; 314 if (Alignment == 0) { 315 // OpenMP [2.8.1, Description] 316 // If no optional parameter is specified, implementation-defined default 317 // alignments for SIMD instructions on the target platforms are assumed. 318 Alignment = CGM.getTargetCodeGenInfo().getOpenMPSimdDefaultAlignment( 319 E->getType()); 320 } 321 assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) && 322 "alignment is not power of 2"); 323 if (Alignment != 0) { 324 llvm::Value *PtrValue = CGF.EmitScalarExpr(E); 325 CGF.EmitAlignmentAssumption(PtrValue, Alignment); 326 } 327 } 328 } 329 330 static void EmitPrivateLoopCounters(CodeGenFunction &CGF, 331 CodeGenFunction::OMPPrivateScope &LoopScope, 332 ArrayRef<Expr *> Counters) { 333 for (auto *E : Counters) { 334 auto VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); 335 bool IsRegistered = LoopScope.addPrivate(VD, [&]() -> llvm::Value * { 336 // Emit var without initialization. 337 auto VarEmission = CGF.EmitAutoVarAlloca(*VD); 338 CGF.EmitAutoVarCleanups(VarEmission); 339 return VarEmission.getAllocatedAddress(); 340 }); 341 assert(IsRegistered && "counter already registered as private"); 342 // Silence the warning about unused variable. 343 (void)IsRegistered; 344 } 345 (void)LoopScope.Privatize(); 346 } 347 348 void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { 349 // Pragma 'simd' code depends on presence of 'lastprivate'. 350 // If present, we have to separate last iteration of the loop: 351 // 352 // if (LastIteration != 0) { 353 // for (IV in 0..LastIteration-1) BODY; 354 // BODY with updates of lastprivate vars; 355 // <Final counter/linear vars updates>; 356 // } 357 // 358 // otherwise (when there's no lastprivate): 359 // 360 // for (IV in 0..LastIteration) BODY; 361 // <Final counter/linear vars updates>; 362 // 363 364 // Walk clauses and process safelen/lastprivate. 365 bool SeparateIter = false; 366 LoopStack.setParallel(); 367 LoopStack.setVectorizerEnable(true); 368 for (auto C : S.clauses()) { 369 switch (C->getClauseKind()) { 370 case OMPC_safelen: { 371 RValue Len = EmitAnyExpr(cast<OMPSafelenClause>(C)->getSafelen(), 372 AggValueSlot::ignored(), true); 373 llvm::ConstantInt *Val = cast<llvm::ConstantInt>(Len.getScalarVal()); 374 LoopStack.setVectorizerWidth(Val->getZExtValue()); 375 // In presence of finite 'safelen', it may be unsafe to mark all 376 // the memory instructions parallel, because loop-carried 377 // dependences of 'safelen' iterations are possible. 378 LoopStack.setParallel(false); 379 break; 380 } 381 case OMPC_aligned: 382 EmitOMPAlignedClause(*this, CGM, cast<OMPAlignedClause>(*C)); 383 break; 384 case OMPC_lastprivate: 385 SeparateIter = true; 386 break; 387 default: 388 // Not handled yet 389 ; 390 } 391 } 392 393 RunCleanupsScope DirectiveScope(*this); 394 395 CGDebugInfo *DI = getDebugInfo(); 396 if (DI) 397 DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin()); 398 399 // Emit the loop iteration variable. 400 const Expr *IVExpr = S.getIterationVariable(); 401 const VarDecl *IVDecl = cast<VarDecl>(cast<DeclRefExpr>(IVExpr)->getDecl()); 402 EmitVarDecl(*IVDecl); 403 EmitIgnoredExpr(S.getInit()); 404 405 // Emit the iterations count variable. 406 // If it is not a variable, Sema decided to calculate iterations count on each 407 // iteration (e.g., it is foldable into a constant). 408 if (auto LIExpr = dyn_cast<DeclRefExpr>(S.getLastIteration())) { 409 EmitVarDecl(*cast<VarDecl>(LIExpr->getDecl())); 410 // Emit calculation of the iterations count. 411 EmitIgnoredExpr(S.getCalcLastIteration()); 412 } 413 414 if (SeparateIter) { 415 // Emit: if (LastIteration > 0) - begin. 416 RegionCounter Cnt = getPGORegionCounter(&S); 417 auto ThenBlock = createBasicBlock("simd.if.then"); 418 auto ContBlock = createBasicBlock("simd.if.end"); 419 EmitBranchOnBoolExpr(S.getPreCond(), ThenBlock, ContBlock, Cnt.getCount()); 420 EmitBlock(ThenBlock); 421 Cnt.beginRegion(Builder); 422 // Emit 'then' code. 423 { 424 OMPPrivateScope LoopScope(*this); 425 EmitPrivateLoopCounters(*this, LoopScope, S.counters()); 426 EmitOMPInnerLoop(S, LoopScope, /* SeparateIter */ true); 427 EmitOMPLoopBody(S, /* SeparateIter */ true); 428 } 429 EmitOMPSimdFinal(S); 430 // Emit: if (LastIteration != 0) - end. 431 EmitBranch(ContBlock); 432 EmitBlock(ContBlock, true); 433 } else { 434 { 435 OMPPrivateScope LoopScope(*this); 436 EmitPrivateLoopCounters(*this, LoopScope, S.counters()); 437 EmitOMPInnerLoop(S, LoopScope); 438 } 439 EmitOMPSimdFinal(S); 440 } 441 442 if (DI) 443 DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd()); 444 } 445 446 void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &) { 447 llvm_unreachable("CodeGen for 'omp for' is not supported yet."); 448 } 449 450 void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &) { 451 llvm_unreachable("CodeGen for 'omp for simd' is not supported yet."); 452 } 453 454 void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &) { 455 llvm_unreachable("CodeGen for 'omp sections' is not supported yet."); 456 } 457 458 void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &) { 459 llvm_unreachable("CodeGen for 'omp section' is not supported yet."); 460 } 461 462 void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &) { 463 llvm_unreachable("CodeGen for 'omp single' is not supported yet."); 464 } 465 466 void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &) { 467 llvm_unreachable("CodeGen for 'omp master' is not supported yet."); 468 } 469 470 void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { 471 // __kmpc_critical(); 472 // <captured_body> 473 // __kmpc_end_critical(); 474 // 475 476 auto Lock = CGM.getOpenMPRuntime().GetCriticalRegionLock( 477 S.getDirectiveName().getAsString()); 478 CGM.getOpenMPRuntime().EmitOMPCriticalRegionStart(*this, Lock, 479 S.getLocStart()); 480 { 481 RunCleanupsScope Scope(*this); 482 EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt()); 483 EnsureInsertPoint(); 484 } 485 CGM.getOpenMPRuntime().EmitOMPCriticalRegionEnd(*this, Lock, S.getLocEnd()); 486 } 487 488 void 489 CodeGenFunction::EmitOMPParallelForDirective(const OMPParallelForDirective &) { 490 llvm_unreachable("CodeGen for 'omp parallel for' is not supported yet."); 491 } 492 493 void CodeGenFunction::EmitOMPParallelForSimdDirective( 494 const OMPParallelForSimdDirective &) { 495 llvm_unreachable("CodeGen for 'omp parallel for simd' is not supported yet."); 496 } 497 498 void CodeGenFunction::EmitOMPParallelSectionsDirective( 499 const OMPParallelSectionsDirective &) { 500 llvm_unreachable("CodeGen for 'omp parallel sections' is not supported yet."); 501 } 502 503 void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &) { 504 llvm_unreachable("CodeGen for 'omp task' is not supported yet."); 505 } 506 507 void CodeGenFunction::EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &) { 508 llvm_unreachable("CodeGen for 'omp taskyield' is not supported yet."); 509 } 510 511 void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &) { 512 llvm_unreachable("CodeGen for 'omp barrier' is not supported yet."); 513 } 514 515 void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &) { 516 llvm_unreachable("CodeGen for 'omp taskwait' is not supported yet."); 517 } 518 519 void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &) { 520 llvm_unreachable("CodeGen for 'omp flush' is not supported yet."); 521 } 522 523 void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &) { 524 llvm_unreachable("CodeGen for 'omp ordered' is not supported yet."); 525 } 526 527 void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &) { 528 llvm_unreachable("CodeGen for 'omp atomic' is not supported yet."); 529 } 530 531 void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &) { 532 llvm_unreachable("CodeGen for 'omp target' is not supported yet."); 533 } 534 535 void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &) { 536 llvm_unreachable("CodeGen for 'omp teams' is not supported yet."); 537 } 538 539