#include "CGDebugInfo.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = getDebugInfo()) {
SourceLocation Loc;
Loc = S->getBeginLoc();
DI->EmitLocation(Builder, Loc);
LastStopPoint = Loc;
}
}
void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
assert(S && "Null statement?");
PGO.setCurrentStmt(S);
if (EmitSimpleStmt(S, Attrs))
return;
if (!HaveInsertPoint()) {
if (!ContainsLabel(S)) {
assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
return;
}
EnsureInsertPoint();
}
EmitStopPoint(S);
if (getLangOpts().OpenMP && getLangOpts().OpenMPSimd) {
if (const auto *D = dyn_cast<OMPExecutableDirective>(S)) {
EmitSimpleOMPExecutableDirective(*D);
return;
}
}
switch (S->getStmtClass()) {
case Stmt::NoStmtClass:
case Stmt::CXXCatchStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
case Stmt::MSDependentExistsStmtClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
case Stmt::DeclStmtClass:
case Stmt::LabelStmtClass:
case Stmt::AttributedStmtClass:
case Stmt::GotoStmtClass:
case Stmt::BreakStmtClass:
case Stmt::ContinueStmtClass:
case Stmt::DefaultStmtClass:
case Stmt::CaseStmtClass:
case Stmt::SEHLeaveStmtClass:
llvm_unreachable("should have emitted these statements as simple");
#define STMT(Type, Base)
#define ABSTRACT_STMT(Op)
#define EXPR(Type, Base) \
case Stmt::Type##Class:
#include "clang/AST/StmtNodes.inc"
{
llvm::BasicBlock *incoming = Builder.GetInsertBlock();
assert(incoming && "expression emission must have an insertion point");
EmitIgnoredExpr(cast<Expr>(S));
llvm::BasicBlock *outgoing = Builder.GetInsertBlock();
assert(outgoing && "expression emission cleared block!");
if (incoming != outgoing && outgoing->use_empty()) {
outgoing->eraseFromParent();
Builder.ClearInsertionPoint();
}
break;
}
case Stmt::IndirectGotoStmtClass:
EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S), Attrs); break;
case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*S), Attrs); break;
case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S), Attrs); break;
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::GCCAsmStmtClass: case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
case Stmt::CoroutineBodyStmtClass:
EmitCoroutineBody(cast<CoroutineBodyStmt>(*S));
break;
case Stmt::CoreturnStmtClass:
EmitCoreturnStmt(cast<CoreturnStmt>(*S));
break;
case Stmt::CapturedStmtClass: {
const CapturedStmt *CS = cast<CapturedStmt>(S);
EmitCapturedStmt(*CS, CS->getCapturedRegionKind());
}
break;
case Stmt::ObjCAtTryStmtClass:
EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
break;
case Stmt::ObjCAtCatchStmtClass:
llvm_unreachable(
"@catch statements should be handled by EmitObjCAtTryStmt");
case Stmt::ObjCAtFinallyStmtClass:
llvm_unreachable(
"@finally statements should be handled by EmitObjCAtTryStmt");
case Stmt::ObjCAtThrowStmtClass:
EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
break;
case Stmt::ObjCAtSynchronizedStmtClass:
EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
break;
case Stmt::ObjCForCollectionStmtClass:
EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
break;
case Stmt::ObjCAutoreleasePoolStmtClass:
EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
break;
case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
break;
case Stmt::CXXForRangeStmtClass:
EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs);
break;
case Stmt::SEHTryStmtClass:
EmitSEHTryStmt(cast<SEHTryStmt>(*S));
break;
case Stmt::OMPMetaDirectiveClass:
EmitOMPMetaDirective(cast<OMPMetaDirective>(*S));
break;
case Stmt::OMPCanonicalLoopClass:
EmitOMPCanonicalLoop(cast<OMPCanonicalLoop>(S));
break;
case Stmt::OMPParallelDirectiveClass:
EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
break;
case Stmt::OMPSimdDirectiveClass:
EmitOMPSimdDirective(cast<OMPSimdDirective>(*S));
break;
case Stmt::OMPTileDirectiveClass:
EmitOMPTileDirective(cast<OMPTileDirective>(*S));
break;
case Stmt::OMPUnrollDirectiveClass:
EmitOMPUnrollDirective(cast<OMPUnrollDirective>(*S));
break;
case Stmt::OMPForDirectiveClass:
EmitOMPForDirective(cast<OMPForDirective>(*S));
break;
case Stmt::OMPForSimdDirectiveClass:
EmitOMPForSimdDirective(cast<OMPForSimdDirective>(*S));
break;
case Stmt::OMPSectionsDirectiveClass:
EmitOMPSectionsDirective(cast<OMPSectionsDirective>(*S));
break;
case Stmt::OMPSectionDirectiveClass:
EmitOMPSectionDirective(cast<OMPSectionDirective>(*S));
break;
case Stmt::OMPSingleDirectiveClass:
EmitOMPSingleDirective(cast<OMPSingleDirective>(*S));
break;
case Stmt::OMPMasterDirectiveClass:
EmitOMPMasterDirective(cast<OMPMasterDirective>(*S));
break;
case Stmt::OMPCriticalDirectiveClass:
EmitOMPCriticalDirective(cast<OMPCriticalDirective>(*S));
break;
case Stmt::OMPParallelForDirectiveClass:
EmitOMPParallelForDirective(cast<OMPParallelForDirective>(*S));
break;
case Stmt::OMPParallelForSimdDirectiveClass:
EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S));
break;
case Stmt::OMPParallelMasterDirectiveClass:
EmitOMPParallelMasterDirective(cast<OMPParallelMasterDirective>(*S));
break;
case Stmt::OMPParallelSectionsDirectiveClass:
EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
break;
case Stmt::OMPTaskDirectiveClass:
EmitOMPTaskDirective(cast<OMPTaskDirective>(*S));
break;
case Stmt::OMPTaskyieldDirectiveClass:
EmitOMPTaskyieldDirective(cast<OMPTaskyieldDirective>(*S));
break;
case Stmt::OMPBarrierDirectiveClass:
EmitOMPBarrierDirective(cast<OMPBarrierDirective>(*S));
break;
case Stmt::OMPTaskwaitDirectiveClass:
EmitOMPTaskwaitDirective(cast<OMPTaskwaitDirective>(*S));
break;
case Stmt::OMPTaskgroupDirectiveClass:
EmitOMPTaskgroupDirective(cast<OMPTaskgroupDirective>(*S));
break;
case Stmt::OMPFlushDirectiveClass:
EmitOMPFlushDirective(cast<OMPFlushDirective>(*S));
break;
case Stmt::OMPDepobjDirectiveClass:
EmitOMPDepobjDirective(cast<OMPDepobjDirective>(*S));
break;
case Stmt::OMPScanDirectiveClass:
EmitOMPScanDirective(cast<OMPScanDirective>(*S));
break;
case Stmt::OMPOrderedDirectiveClass:
EmitOMPOrderedDirective(cast<OMPOrderedDirective>(*S));
break;
case Stmt::OMPAtomicDirectiveClass:
EmitOMPAtomicDirective(cast<OMPAtomicDirective>(*S));
break;
case Stmt::OMPTargetDirectiveClass:
EmitOMPTargetDirective(cast<OMPTargetDirective>(*S));
break;
case Stmt::OMPTeamsDirectiveClass:
EmitOMPTeamsDirective(cast<OMPTeamsDirective>(*S));
break;
case Stmt::OMPCancellationPointDirectiveClass:
EmitOMPCancellationPointDirective(cast<OMPCancellationPointDirective>(*S));
break;
case Stmt::OMPCancelDirectiveClass:
EmitOMPCancelDirective(cast<OMPCancelDirective>(*S));
break;
case Stmt::OMPTargetDataDirectiveClass:
EmitOMPTargetDataDirective(cast<OMPTargetDataDirective>(*S));
break;
case Stmt::OMPTargetEnterDataDirectiveClass:
EmitOMPTargetEnterDataDirective(cast<OMPTargetEnterDataDirective>(*S));
break;
case Stmt::OMPTargetExitDataDirectiveClass:
EmitOMPTargetExitDataDirective(cast<OMPTargetExitDataDirective>(*S));
break;
case Stmt::OMPTargetParallelDirectiveClass:
EmitOMPTargetParallelDirective(cast<OMPTargetParallelDirective>(*S));
break;
case Stmt::OMPTargetParallelForDirectiveClass:
EmitOMPTargetParallelForDirective(cast<OMPTargetParallelForDirective>(*S));
break;
case Stmt::OMPTaskLoopDirectiveClass:
EmitOMPTaskLoopDirective(cast<OMPTaskLoopDirective>(*S));
break;
case Stmt::OMPTaskLoopSimdDirectiveClass:
EmitOMPTaskLoopSimdDirective(cast<OMPTaskLoopSimdDirective>(*S));
break;
case Stmt::OMPMasterTaskLoopDirectiveClass:
EmitOMPMasterTaskLoopDirective(cast<OMPMasterTaskLoopDirective>(*S));
break;
case Stmt::OMPMaskedTaskLoopDirectiveClass:
llvm_unreachable("masked taskloop directive not supported yet.");
break;
case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
EmitOMPMasterTaskLoopSimdDirective(
cast<OMPMasterTaskLoopSimdDirective>(*S));
break;
case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
llvm_unreachable("masked taskloop simd directive not supported yet.");
break;
case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
EmitOMPParallelMasterTaskLoopDirective(
cast<OMPParallelMasterTaskLoopDirective>(*S));
break;
case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
llvm_unreachable("parallel masked taskloop directive not supported yet.");
break;
case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
EmitOMPParallelMasterTaskLoopSimdDirective(
cast<OMPParallelMasterTaskLoopSimdDirective>(*S));
break;
case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
llvm_unreachable(
"parallel masked taskloop simd directive not supported yet.");
break;
case Stmt::OMPDistributeDirectiveClass:
EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
break;
case Stmt::OMPTargetUpdateDirectiveClass:
EmitOMPTargetUpdateDirective(cast<OMPTargetUpdateDirective>(*S));
break;
case Stmt::OMPDistributeParallelForDirectiveClass:
EmitOMPDistributeParallelForDirective(
cast<OMPDistributeParallelForDirective>(*S));
break;
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
EmitOMPDistributeParallelForSimdDirective(
cast<OMPDistributeParallelForSimdDirective>(*S));
break;
case Stmt::OMPDistributeSimdDirectiveClass:
EmitOMPDistributeSimdDirective(cast<OMPDistributeSimdDirective>(*S));
break;
case Stmt::OMPTargetParallelForSimdDirectiveClass:
EmitOMPTargetParallelForSimdDirective(
cast<OMPTargetParallelForSimdDirective>(*S));
break;
case Stmt::OMPTargetSimdDirectiveClass:
EmitOMPTargetSimdDirective(cast<OMPTargetSimdDirective>(*S));
break;
case Stmt::OMPTeamsDistributeDirectiveClass:
EmitOMPTeamsDistributeDirective(cast<OMPTeamsDistributeDirective>(*S));
break;
case Stmt::OMPTeamsDistributeSimdDirectiveClass:
EmitOMPTeamsDistributeSimdDirective(
cast<OMPTeamsDistributeSimdDirective>(*S));
break;
case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
EmitOMPTeamsDistributeParallelForSimdDirective(
cast<OMPTeamsDistributeParallelForSimdDirective>(*S));
break;
case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
EmitOMPTeamsDistributeParallelForDirective(
cast<OMPTeamsDistributeParallelForDirective>(*S));
break;
case Stmt::OMPTargetTeamsDirectiveClass:
EmitOMPTargetTeamsDirective(cast<OMPTargetTeamsDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeDirectiveClass:
EmitOMPTargetTeamsDistributeDirective(
cast<OMPTargetTeamsDistributeDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
EmitOMPTargetTeamsDistributeParallelForDirective(
cast<OMPTargetTeamsDistributeParallelForDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
EmitOMPTargetTeamsDistributeParallelForSimdDirective(
cast<OMPTargetTeamsDistributeParallelForSimdDirective>(*S));
break;
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
EmitOMPTargetTeamsDistributeSimdDirective(
cast<OMPTargetTeamsDistributeSimdDirective>(*S));
break;
case Stmt::OMPInteropDirectiveClass:
EmitOMPInteropDirective(cast<OMPInteropDirective>(*S));
break;
case Stmt::OMPDispatchDirectiveClass:
llvm_unreachable("Dispatch directive not supported yet.");
break;
case Stmt::OMPMaskedDirectiveClass:
EmitOMPMaskedDirective(cast<OMPMaskedDirective>(*S));
break;
case Stmt::OMPGenericLoopDirectiveClass:
EmitOMPGenericLoopDirective(cast<OMPGenericLoopDirective>(*S));
break;
case Stmt::OMPTeamsGenericLoopDirectiveClass:
llvm_unreachable("teams loop directive not supported yet.");
break;
case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
llvm_unreachable("target teams loop directive not supported yet.");
break;
case Stmt::OMPParallelGenericLoopDirectiveClass:
llvm_unreachable("parallel loop directive not supported yet.");
break;
case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
llvm_unreachable("target parallel loop directive not supported yet.");
break;
case Stmt::OMPParallelMaskedDirectiveClass:
llvm_unreachable("parallel masked directive not supported yet.");
break;
}
}
bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
ArrayRef<const Attr *> Attrs) {
switch (S->getStmtClass()) {
default:
return false;
case Stmt::NullStmtClass:
break;
case Stmt::CompoundStmtClass:
EmitCompoundStmt(cast<CompoundStmt>(*S));
break;
case Stmt::DeclStmtClass:
EmitDeclStmt(cast<DeclStmt>(*S));
break;
case Stmt::LabelStmtClass:
EmitLabelStmt(cast<LabelStmt>(*S));
break;
case Stmt::AttributedStmtClass:
EmitAttributedStmt(cast<AttributedStmt>(*S));
break;
case Stmt::GotoStmtClass:
EmitGotoStmt(cast<GotoStmt>(*S));
break;
case Stmt::BreakStmtClass:
EmitBreakStmt(cast<BreakStmt>(*S));
break;
case Stmt::ContinueStmtClass:
EmitContinueStmt(cast<ContinueStmt>(*S));
break;
case Stmt::DefaultStmtClass:
EmitDefaultStmt(cast<DefaultStmt>(*S), Attrs);
break;
case Stmt::CaseStmtClass:
EmitCaseStmt(cast<CaseStmt>(*S), Attrs);
break;
case Stmt::SEHLeaveStmtClass:
EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S));
break;
}
return true;
}
Address CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
AggValueSlot AggSlot) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(),
"LLVM IR generation of compound statement ('{}')");
LexicalScope Scope(*this, S.getSourceRange());
return EmitCompoundStmtWithoutScope(S, GetLast, AggSlot);
}
Address
CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
bool GetLast,
AggValueSlot AggSlot) {
const Stmt *ExprResult = S.getStmtExprResult();
assert((!GetLast || (GetLast && ExprResult)) &&
"If GetLast is true then the CompoundStmt must have a StmtExprResult");
Address RetAlloca = Address::invalid();
for (auto *CurStmt : S.body()) {
if (GetLast && ExprResult == CurStmt) {
while (!isa<Expr>(ExprResult)) {
if (const auto *LS = dyn_cast<LabelStmt>(ExprResult)) {
EmitLabel(LS->getDecl());
ExprResult = LS->getSubStmt();
} else if (const auto *AS = dyn_cast<AttributedStmt>(ExprResult)) {
ExprResult = AS->getSubStmt();
} else {
llvm_unreachable("unknown value statement");
}
}
EnsureInsertPoint();
const Expr *E = cast<Expr>(ExprResult);
QualType ExprTy = E->getType();
if (hasAggregateEvaluationKind(ExprTy)) {
EmitAggExpr(E, AggSlot);
} else {
RetAlloca = CreateMemTemp(ExprTy);
EmitAnyExprToMem(E, RetAlloca, Qualifiers(),
false);
}
} else {
EmitStmt(CurStmt);
}
}
return RetAlloca;
}
void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
llvm::BranchInst *BI = dyn_cast<llvm::BranchInst>(BB->getTerminator());
if (!EHStack.empty())
return;
if (!BI || !BI->isUnconditional())
return;
if (BI->getIterator() != BB->begin())
return;
BB->replaceAllUsesWith(BI->getSuccessor(0));
BI->eraseFromParent();
BB->eraseFromParent();
}
void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
EmitBranch(BB);
if (IsFinished && BB->use_empty()) {
delete BB;
return;
}
if (CurBB && CurBB->getParent())
CurFn->getBasicBlockList().insertAfter(CurBB->getIterator(), BB);
else
CurFn->getBasicBlockList().push_back(BB);
Builder.SetInsertPoint(BB);
}
void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
if (!CurBB || CurBB->getTerminator()) {
} else {
Builder.CreateBr(Target);
}
Builder.ClearInsertionPoint();
}
void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) {
bool inserted = false;
for (llvm::User *u : block->users()) {
if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(u)) {
CurFn->getBasicBlockList().insertAfter(insn->getParent()->getIterator(),
block);
inserted = true;
break;
}
}
if (!inserted)
CurFn->getBasicBlockList().push_back(block);
Builder.SetInsertPoint(block);
}
CodeGenFunction::JumpDest
CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
JumpDest &Dest = LabelMap[D];
if (Dest.isValid()) return Dest;
Dest = JumpDest(createBasicBlock(D->getName()),
EHScopeStack::stable_iterator::invalid(),
NextCleanupDestIndex++);
return Dest;
}
void CodeGenFunction::EmitLabel(const LabelDecl *D) {
if (EHStack.hasNormalCleanups() && CurLexicalScope)
CurLexicalScope->addLabel(D);
JumpDest &Dest = LabelMap[D];
if (!Dest.isValid()) {
Dest = getJumpDestInCurrentScope(D->getName());
} else {
assert(!Dest.getScopeDepth().isValid() && "already emitted label!");
Dest.setScopeDepth(EHStack.stable_begin());
ResolveBranchFixups(Dest.getBlock());
}
EmitBlock(Dest.getBlock());
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
DI->setLocation(D->getLocation());
DI->EmitLabel(D, Builder);
}
}
incrementProfileCounter(D->getStmt());
}
void CodeGenFunction::LexicalScope::rescopeLabels() {
assert(!Labels.empty());
EHScopeStack::stable_iterator innermostScope
= CGF.EHStack.getInnermostNormalCleanup();
for (SmallVectorImpl<const LabelDecl*>::const_iterator
i = Labels.begin(), e = Labels.end(); i != e; ++i) {
assert(CGF.LabelMap.count(*i));
JumpDest &dest = CGF.LabelMap.find(*i)->second;
assert(dest.getScopeDepth().isValid());
assert(innermostScope.encloses(dest.getScopeDepth()));
dest.setScopeDepth(innermostScope);
}
if (innermostScope != EHScopeStack::stable_end() && ParentScope) {
ParentScope->Labels.append(Labels.begin(), Labels.end());
}
}
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
EmitLabel(S.getDecl());
if (getLangOpts().EHAsynch && S.isSideEntry())
EmitSehCppScopeBegin();
EmitStmt(S.getSubStmt());
}
void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
bool nomerge = false;
bool noinline = false;
bool alwaysinline = false;
const CallExpr *musttail = nullptr;
for (const auto *A : S.getAttrs()) {
switch (A->getKind()) {
default:
break;
case attr::NoMerge:
nomerge = true;
break;
case attr::NoInline:
noinline = true;
break;
case attr::AlwaysInline:
alwaysinline = true;
break;
case attr::MustTail:
const Stmt *Sub = S.getSubStmt();
const ReturnStmt *R = cast<ReturnStmt>(Sub);
musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
break;
}
}
SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
SaveAndRestore<bool> save_noinline(InNoInlineAttributedStmt, noinline);
SaveAndRestore<bool> save_alwaysinline(InAlwaysInlineAttributedStmt,
alwaysinline);
SaveAndRestore<const CallExpr *> save_musttail(MustTailCall, musttail);
EmitStmt(S.getSubStmt(), S.getAttrs());
}
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel()));
}
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
if (const LabelDecl *Target = S.getConstantTarget()) {
EmitBranchThroughCleanup(getJumpDestForLabel(Target));
return;
}
llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()),
Int8PtrTy, "addr");
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
llvm::BasicBlock *IndGotoBB = GetIndirectGotoBlock();
cast<llvm::PHINode>(IndGotoBB->begin())->addIncoming(V, CurBB);
EmitBranch(IndGotoBB);
}
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
if (S.isConsteval()) {
const Stmt *Executed = S.isNegatedConsteval() ? S.getThen() : S.getElse();
if (Executed) {
RunCleanupsScope ExecutedScope(*this);
EmitStmt(Executed);
}
return;
}
LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
if (S.getInit())
EmitStmt(S.getInit());
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
bool CondConstant;
if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant,
S.isConstexpr())) {
const Stmt *Executed = S.getThen();
const Stmt *Skipped = S.getElse();
if (!CondConstant) std::swap(Executed, Skipped);
if (S.isConstexpr() || !ContainsLabel(Skipped)) {
if (CondConstant)
incrementProfileCounter(&S);
if (Executed) {
RunCleanupsScope ExecutedScope(*this);
EmitStmt(Executed);
}
return;
}
}
llvm::BasicBlock *ThenBlock = createBasicBlock("if.then");
llvm::BasicBlock *ContBlock = createBasicBlock("if.end");
llvm::BasicBlock *ElseBlock = ContBlock;
if (S.getElse())
ElseBlock = createBasicBlock("if.else");
Stmt::Likelihood LH = Stmt::LH_None;
uint64_t Count = getProfileCount(S.getThen());
if (!Count && CGM.getCodeGenOpts().OptimizationLevel)
LH = Stmt::getLikelihood(S.getThen(), S.getElse());
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, LH);
EmitBlock(ThenBlock);
incrementProfileCounter(&S);
{
RunCleanupsScope ThenScope(*this);
EmitStmt(S.getThen());
}
EmitBranch(ContBlock);
if (const Stmt *Else = S.getElse()) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
EmitBlock(ElseBlock);
}
{
RunCleanupsScope ElseScope(*this);
EmitStmt(Else);
}
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
EmitBranch(ContBlock);
}
}
EmitBlock(ContBlock, true);
}
void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
ArrayRef<const Attr *> WhileAttrs) {
JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
EmitBlock(LoopHeader.getBlock());
JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader));
RunCleanupsScope ConditionScope(*this);
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal);
bool CondIsConstInt = C != nullptr;
bool EmitBoolCondBranch = !CondIsConstInt || !C->isOne();
const SourceRange &R = S.getSourceRange();
LoopStack.push(LoopHeader.getBlock(), CGM.getContext(), CGM.getCodeGenOpts(),
WhileAttrs, SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()),
checkIfLoopMustProgress(CondIsConstInt));
llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
if (EmitBoolCondBranch) {
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ConditionScope.requiresCleanups())
ExitBlock = createBasicBlock("while.exit");
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
} else if (const Attr *A = Stmt::getLikelihoodAttr(S.getBody())) {
CGM.getDiags().Report(A->getLocation(),
diag::warn_attribute_has_no_effect_on_infinite_loop)
<< A << A->getRange();
CGM.getDiags().Report(
S.getWhileLoc(),
diag::note_attribute_has_no_effect_on_infinite_loop_here)
<< SourceRange(S.getWhileLoc(), S.getRParenLoc());
}
{
RunCleanupsScope BodyScope(*this);
EmitBlock(LoopBody);
incrementProfileCounter(&S);
EmitStmt(S.getBody());
}
BreakContinueStack.pop_back();
ConditionScope.ForceCleanup();
EmitStopPoint(&S);
EmitBranch(LoopHeader.getBlock());
LoopStack.pop();
EmitBlock(LoopExit.getBlock(), true);
if (!EmitBoolCondBranch)
SimplifyForwardingBlocks(LoopHeader.getBlock());
}
void CodeGenFunction::EmitDoStmt(const DoStmt &S,
ArrayRef<const Attr *> DoAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("do.end");
JumpDest LoopCond = getJumpDestInCurrentScope("do.cond");
uint64_t ParentCount = getCurrentProfileCount();
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
EmitBlockWithFallThrough(LoopBody, &S);
{
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody());
}
EmitBlock(LoopCond.getBlock());
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
BreakContinueStack.pop_back();
llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal);
bool CondIsConstInt = C;
bool EmitBoolCondBranch = !C || !C->isZero();
const SourceRange &R = S.getSourceRange();
LoopStack.push(LoopBody, CGM.getContext(), CGM.getCodeGenOpts(), DoAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()),
checkIfLoopMustProgress(CondIsConstInt));
if (EmitBoolCondBranch) {
uint64_t BackedgeCount = getProfileCount(S.getBody()) - ParentCount;
Builder.CreateCondBr(
BoolCondVal, LoopBody, LoopExit.getBlock(),
createProfileWeightsForLoop(S.getCond(), BackedgeCount));
}
LoopStack.pop();
EmitBlock(LoopExit.getBlock());
if (!EmitBoolCondBranch)
SimplifyForwardingBlocks(LoopCond.getBlock());
}
void CodeGenFunction::EmitForStmt(const ForStmt &S,
ArrayRef<const Attr *> ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
LexicalScope ForScope(*this, S.getSourceRange());
if (S.getInit())
EmitStmt(S.getInit());
JumpDest CondDest = getJumpDestInCurrentScope("for.cond");
llvm::BasicBlock *CondBlock = CondDest.getBlock();
EmitBlock(CondBlock);
Expr::EvalResult Result;
bool CondIsConstInt =
!S.getCond() || S.getCond()->EvaluateAsInt(Result, getContext());
const SourceRange &R = S.getSourceRange();
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()),
checkIfLoopMustProgress(CondIsConstInt));
LexicalScope ConditionScope(*this, S.getSourceRange());
JumpDest Continue;
if (!S.getInc())
Continue = CondDest;
else if (!S.getConditionVariable())
Continue = getJumpDestInCurrentScope("for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
if (S.getCond()) {
if (S.getConditionVariable()) {
EmitDecl(*S.getConditionVariable());
Continue = S.getInc() ? getJumpDestInCurrentScope("for.inc") : CondDest;
BreakContinueStack.back().ContinueBlock = Continue;
}
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ForScope.requiresCleanups())
ExitBlock = createBasicBlock("for.cond.cleanup");
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(ForBody);
} else {
}
incrementProfileCounter(&S);
{
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody());
}
if (S.getInc()) {
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
}
BreakContinueStack.pop_back();
ConditionScope.ForceCleanup();
EmitStopPoint(&S);
EmitBranch(CondBlock);
ForScope.ForceCleanup();
LoopStack.pop();
EmitBlock(LoopExit.getBlock(), true);
}
void
CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
ArrayRef<const Attr *> ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
LexicalScope ForScope(*this, S.getSourceRange());
if (S.getInit())
EmitStmt(S.getInit());
EmitStmt(S.getRangeStmt());
EmitStmt(S.getBeginStmt());
EmitStmt(S.getEndStmt());
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
EmitBlock(CondBlock);
const SourceRange &R = S.getSourceRange();
LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), ForAttrs,
SourceLocToDebugLoc(R.getBegin()),
SourceLocToDebugLoc(R.getEnd()));
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ForScope.requiresCleanups())
ExitBlock = createBasicBlock("for.cond.cleanup");
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
EmitBlock(ForBody);
incrementProfileCounter(&S);
JumpDest Continue = getJumpDestInCurrentScope("for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
{
LexicalScope BodyScope(*this, S.getSourceRange());
EmitStmt(S.getLoopVarStmt());
EmitStmt(S.getBody());
}
EmitStopPoint(&S);
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
BreakContinueStack.pop_back();
EmitBranch(CondBlock);
ForScope.ForceCleanup();
LoopStack.pop();
EmitBlock(LoopExit.getBlock(), true);
}
void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
if (RV.isScalar()) {
Builder.CreateStore(RV.getScalarVal(), ReturnValue);
} else if (RV.isAggregate()) {
LValue Dest = MakeAddrLValue(ReturnValue, Ty);
LValue Src = MakeAddrLValue(RV.getAggregateAddress(), Ty);
EmitAggregateCopy(Dest, Src, Ty, getOverlapForReturnValue());
} else {
EmitStoreOfComplex(RV.getComplexVal(), MakeAddrLValue(ReturnValue, Ty),
true);
}
EmitBranchThroughCleanup(ReturnBlock);
}
namespace {
struct SaveRetExprRAII {
SaveRetExprRAII(const Expr *RetExpr, CodeGenFunction &CGF)
: OldRetExpr(CGF.RetExpr), CGF(CGF) {
CGF.RetExpr = RetExpr;
}
~SaveRetExprRAII() { CGF.RetExpr = OldRetExpr; }
const Expr *OldRetExpr;
CodeGenFunction &CGF;
};
}
static void makeTailCallIfSwiftAsync(const CallExpr *CE, CGBuilderTy &Builder,
const CGFunctionInfo *CurFnInfo) {
auto calleeQualType = CE->getCallee()->getType();
const FunctionType *calleeType = nullptr;
if (calleeQualType->isFunctionPointerType() ||
calleeQualType->isFunctionReferenceType() ||
calleeQualType->isBlockPointerType() ||
calleeQualType->isMemberFunctionPointerType()) {
calleeType = calleeQualType->getPointeeType()->castAs<FunctionType>();
} else if (auto *ty = dyn_cast<FunctionType>(calleeQualType)) {
calleeType = ty;
} else if (auto CMCE = dyn_cast<CXXMemberCallExpr>(CE)) {
if (auto methodDecl = CMCE->getMethodDecl()) {
calleeType = methodDecl->getType()->castAs<FunctionType>();
} else {
return;
}
} else {
return;
}
if (calleeType->getCallConv() == CallingConv::CC_SwiftAsync &&
(CurFnInfo->getASTCallingConvention() == CallingConv::CC_SwiftAsync)) {
auto CI = cast<llvm::CallInst>(&Builder.GetInsertBlock()->back());
CI->setTailCallKind(llvm::CallInst::TCK_MustTail);
Builder.CreateRetVoid();
Builder.ClearInsertionPoint();
}
}
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
if (requiresReturnValueCheck()) {
llvm::Constant *SLoc = EmitCheckSourceLocation(S.getBeginLoc());
auto *SLocPtr =
new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false,
llvm::GlobalVariable::PrivateLinkage, SLoc);
SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
assert(ReturnLocation.isValid() && "No valid return location");
Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy),
ReturnLocation);
}
if (IsOutlinedSEHHelper) {
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
const Expr *RV = S.getRetValue();
SaveRetExprRAII SaveRetExpr(RV, *this);
RunCleanupsScope cleanupScope(*this);
if (const auto *EWC = dyn_cast_or_null<ExprWithCleanups>(RV))
RV = EWC->getSubExpr();
if (getLangOpts().ElideConstructors && S.getNRVOCandidate() &&
S.getNRVOCandidate()->isNRVOVariable() &&
(!getLangOpts().OpenMP ||
!CGM.getOpenMPRuntime()
.getAddressOfLocalVariable(*this, S.getNRVOCandidate())
.isValid())) {
if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()])
Builder.CreateFlagStore(Builder.getTrue(), NRVOFlag);
} else if (!ReturnValue.isValid() || (RV && RV->getType()->isVoidType())) {
if (RV) {
EmitAnyExpr(RV);
if (auto *CE = dyn_cast<CallExpr>(RV))
makeTailCallIfSwiftAsync(CE, Builder, CurFnInfo);
}
} else if (!RV) {
} else if (FnRetTy->isReferenceType()) {
RValue Result = EmitReferenceBindingToExpr(RV);
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
} else {
switch (getEvaluationKind(RV->getType())) {
case TEK_Scalar:
Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
break;
case TEK_Complex:
EmitComplexExprIntoLValue(RV, MakeAddrLValue(ReturnValue, RV->getType()),
true);
break;
case TEK_Aggregate:
EmitAggExpr(RV, AggValueSlot::forAddr(
ReturnValue, Qualifiers(),
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
getOverlapForReturnValue()));
break;
}
}
++NumReturnExprs;
if (!RV || RV->isEvaluatable(getContext()))
++NumSimpleReturnExprs;
cleanupScope.ForceCleanup();
EmitBranchThroughCleanup(ReturnBlock);
}
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
for (const auto *I : S.decls())
EmitDecl(*I);
}
void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranchThroughCleanup(BreakContinueStack.back().BreakBlock);
}
void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranchThroughCleanup(BreakContinueStack.back().ContinueBlock);
}
void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S,
ArrayRef<const Attr *> Attrs) {
assert(S.getRHS() && "Expected RHS value in CaseStmt");
llvm::APSInt LHS = S.getLHS()->EvaluateKnownConstInt(getContext());
llvm::APSInt RHS = S.getRHS()->EvaluateKnownConstInt(getContext());
llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
EmitBlockWithFallThrough(CaseDest, &S);
EmitStmt(S.getSubStmt());
if (LHS.isSigned() ? RHS.slt(LHS) : RHS.ult(LHS))
return;
Stmt::Likelihood LH = Stmt::getLikelihood(Attrs);
llvm::APInt Range = RHS - LHS;
if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
uint64_t Total = getProfileCount(&S);
unsigned NCases = Range.getZExtValue() + 1;
uint64_t Weight = Total / NCases, Rem = Total % NCases;
for (unsigned I = 0; I != NCases; ++I) {
if (SwitchWeights)
SwitchWeights->push_back(Weight + (Rem ? 1 : 0));
else if (SwitchLikelihood)
SwitchLikelihood->push_back(LH);
if (Rem)
Rem--;
SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
++LHS;
}
return;
}
llvm::BasicBlock *RestoreBB = Builder.GetInsertBlock();
llvm::BasicBlock *FalseDest = CaseRangeBlock;
CaseRangeBlock = createBasicBlock("sw.caserange");
CurFn->getBasicBlockList().push_back(CaseRangeBlock);
Builder.SetInsertPoint(CaseRangeBlock);
llvm::Value *Diff =
Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS));
llvm::Value *Cond =
Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds");
llvm::MDNode *Weights = nullptr;
if (SwitchWeights) {
uint64_t ThisCount = getProfileCount(&S);
uint64_t DefaultCount = (*SwitchWeights)[0];
Weights = createProfileWeights(ThisCount, DefaultCount);
(*SwitchWeights)[0] += ThisCount;
} else if (SwitchLikelihood)
Cond = emitCondLikelihoodViaExpectIntrinsic(Cond, LH);
Builder.CreateCondBr(Cond, CaseDest, FalseDest, Weights);
if (RestoreBB)
Builder.SetInsertPoint(RestoreBB);
else
Builder.ClearInsertionPoint();
}
void CodeGenFunction::EmitCaseStmt(const CaseStmt &S,
ArrayRef<const Attr *> Attrs) {
if (!SwitchInsn) {
EmitStmt(S.getSubStmt());
return;
}
if (S.getRHS()) {
EmitCaseStmtRange(S, Attrs);
return;
}
llvm::ConstantInt *CaseVal =
Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext()));
const ConstantExpr *CE;
if (auto ICE = dyn_cast<ImplicitCastExpr>(S.getLHS()))
CE = dyn_cast<ConstantExpr>(ICE->getSubExpr());
else
CE = dyn_cast<ConstantExpr>(S.getLHS());
if (CE) {
if (auto DE = dyn_cast<DeclRefExpr>(CE->getSubExpr()))
if (CGDebugInfo *Dbg = getDebugInfo())
if (CGM.getCodeGenOpts().hasReducedDebugInfo())
Dbg->EmitGlobalVariable(DE->getDecl(),
APValue(llvm::APSInt(CaseVal->getValue())));
}
if (SwitchLikelihood)
SwitchLikelihood->push_back(Stmt::getLikelihood(Attrs));
if (!CGM.getCodeGenOpts().hasProfileClangInstr() &&
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
isa<BreakStmt>(S.getSubStmt())) {
JumpDest Block = BreakContinueStack.back().BreakBlock;
if (isObviouslyBranchWithoutCleanups(Block)) {
if (SwitchWeights)
SwitchWeights->push_back(getProfileCount(&S));
SwitchInsn->addCase(CaseVal, Block.getBlock());
if (Builder.GetInsertBlock()) {
Builder.CreateBr(Block.getBlock());
Builder.ClearInsertionPoint();
}
return;
}
}
llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
EmitBlockWithFallThrough(CaseDest, &S);
if (SwitchWeights)
SwitchWeights->push_back(getProfileCount(&S));
SwitchInsn->addCase(CaseVal, CaseDest);
const CaseStmt *CurCase = &S;
const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
while (NextCase && NextCase->getRHS() == nullptr) {
CurCase = NextCase;
llvm::ConstantInt *CaseVal =
Builder.getInt(CurCase->getLHS()->EvaluateKnownConstInt(getContext()));
if (SwitchWeights)
SwitchWeights->push_back(getProfileCount(NextCase));
if (CGM.getCodeGenOpts().hasProfileClangInstr()) {
CaseDest = createBasicBlock("sw.bb");
EmitBlockWithFallThrough(CaseDest, CurCase);
}
if (SwitchLikelihood)
SwitchLikelihood->push_back(Stmt::LH_None);
SwitchInsn->addCase(CaseVal, CaseDest);
NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
}
if (CurCase->getSubStmt()->getStmtClass() == Stmt::DefaultStmtClass)
EmitStopPoint(CurCase);
EmitStmt(CurCase->getSubStmt());
}
void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S,
ArrayRef<const Attr *> Attrs) {
if (!SwitchInsn) {
EmitStmt(S.getSubStmt());
return;
}
llvm::BasicBlock *DefaultBlock = SwitchInsn->getDefaultDest();
assert(DefaultBlock->empty() &&
"EmitDefaultStmt: Default block already defined?");
if (SwitchLikelihood)
SwitchLikelihood->front() = Stmt::getLikelihood(Attrs);
EmitBlockWithFallThrough(DefaultBlock, &S);
EmitStmt(S.getSubStmt());
}
enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success };
static CSFC_Result CollectStatementsForCase(const Stmt *S,
const SwitchCase *Case,
bool &FoundCase,
SmallVectorImpl<const Stmt*> &ResultStmts) {
if (!S)
return Case ? CSFC_Success : CSFC_FallThrough;
if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) {
if (S == Case) {
FoundCase = true;
return CollectStatementsForCase(SC->getSubStmt(), nullptr, FoundCase,
ResultStmts);
}
return CollectStatementsForCase(SC->getSubStmt(), Case, FoundCase,
ResultStmts);
}
if (!Case && isa<BreakStmt>(S))
return CSFC_Success;
if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
CompoundStmt::const_body_iterator I = CS->body_begin(), E = CS->body_end();
bool StartedInLiveCode = FoundCase;
unsigned StartSize = ResultStmts.size();
if (Case) {
bool HadSkippedDecl = false;
for (; Case && I != E; ++I) {
HadSkippedDecl |= CodeGenFunction::mightAddDeclToScope(*I);
switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
case CSFC_Success:
if (FoundCase) {
if (HadSkippedDecl)
return CSFC_Failure;
for (++I; I != E; ++I)
if (CodeGenFunction::ContainsLabel(*I, true))
return CSFC_Failure;
return CSFC_Success;
}
break;
case CSFC_FallThrough:
assert(FoundCase && "Didn't find case but returned fallthrough?");
Case = nullptr;
if (HadSkippedDecl)
return CSFC_Failure;
break;
}
}
if (!FoundCase)
return CSFC_Success;
assert(!HadSkippedDecl && "fallthrough after skipping decl");
}
bool AnyDecls = false;
for (; I != E; ++I) {
AnyDecls |= CodeGenFunction::mightAddDeclToScope(*I);
switch (CollectStatementsForCase(*I, nullptr, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
case CSFC_FallThrough:
break;
case CSFC_Success:
for (++I; I != E; ++I)
if (CodeGenFunction::ContainsLabel(*I, true))
return CSFC_Failure;
return CSFC_Success;
}
}
if (AnyDecls) {
if (StartedInLiveCode && !CodeGenFunction::containsBreak(S)) {
ResultStmts.resize(StartSize);
ResultStmts.push_back(S);
} else {
return CSFC_Failure;
}
}
return CSFC_FallThrough;
}
if (Case) {
if (CodeGenFunction::ContainsLabel(S, true))
return CSFC_Failure;
return CSFC_Success;
}
if (CodeGenFunction::containsBreak(S)) return CSFC_Failure;
ResultStmts.push_back(S);
return CSFC_FallThrough;
}
static bool FindCaseStatementsForValue(const SwitchStmt &S,
const llvm::APSInt &ConstantCondValue,
SmallVectorImpl<const Stmt*> &ResultStmts,
ASTContext &C,
const SwitchCase *&ResultCase) {
const SwitchCase *Case = S.getSwitchCaseList();
const DefaultStmt *DefaultCase = nullptr;
for (; Case; Case = Case->getNextSwitchCase()) {
if (const DefaultStmt *DS = dyn_cast<DefaultStmt>(Case)) {
DefaultCase = DS;
continue;
}
const CaseStmt *CS = cast<CaseStmt>(Case);
if (CS->getRHS()) return false;
if (CS->getLHS()->EvaluateKnownConstInt(C) == ConstantCondValue)
break;
}
if (!Case) {
if (!DefaultCase)
return !CodeGenFunction::ContainsLabel(&S);
Case = DefaultCase;
}
bool FoundCase = false;
ResultCase = Case;
return CollectStatementsForCase(S.getBody(), Case, FoundCase,
ResultStmts) != CSFC_Failure &&
FoundCase;
}
static Optional<SmallVector<uint64_t, 16>>
getLikelihoodWeights(ArrayRef<Stmt::Likelihood> Likelihoods) {
if (Likelihoods.size() <= 1)
return None;
uint64_t NumUnlikely = 0;
uint64_t NumNone = 0;
uint64_t NumLikely = 0;
for (const auto LH : Likelihoods) {
switch (LH) {
case Stmt::LH_Unlikely:
++NumUnlikely;
break;
case Stmt::LH_None:
++NumNone;
break;
case Stmt::LH_Likely:
++NumLikely;
break;
}
}
if (NumUnlikely == 0 && NumLikely == 0)
return None;
const uint64_t Likely = INT32_MAX / (NumLikely + 2);
const uint64_t None = Likely / (NumNone + 1);
const uint64_t Unlikely = 0;
SmallVector<uint64_t, 16> Result;
Result.reserve(Likelihoods.size());
for (const auto LH : Likelihoods) {
switch (LH) {
case Stmt::LH_Unlikely:
Result.push_back(Unlikely);
break;
case Stmt::LH_None:
Result.push_back(None);
break;
case Stmt::LH_Likely:
Result.push_back(Likely);
break;
}
}
return Result;
}
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
SmallVector<uint64_t, 16> *SavedSwitchWeights = SwitchWeights;
SmallVector<Stmt::Likelihood, 16> *SavedSwitchLikelihood = SwitchLikelihood;
llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
llvm::APSInt ConstantCondValue;
if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) {
SmallVector<const Stmt*, 4> CaseStmts;
const SwitchCase *Case = nullptr;
if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts,
getContext(), Case)) {
if (Case)
incrementProfileCounter(Case);
RunCleanupsScope ExecutedScope(*this);
if (S.getInit())
EmitStmt(S.getInit());
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
SwitchInsn = nullptr;
for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
EmitStmt(CaseStmts[i]);
incrementProfileCounter(&S);
SwitchInsn = SavedSwitchInsn;
return;
}
}
JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
RunCleanupsScope ConditionScope(*this);
if (S.getInit())
EmitStmt(S.getInit());
if (S.getConditionVariable())
EmitDecl(*S.getConditionVariable());
llvm::Value *CondV = EmitScalarExpr(S.getCond());
llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
if (PGO.haveRegionCounts()) {
uint64_t DefaultCount = 0;
unsigned NumCases = 0;
for (const SwitchCase *Case = S.getSwitchCaseList();
Case;
Case = Case->getNextSwitchCase()) {
if (isa<DefaultStmt>(Case))
DefaultCount = getProfileCount(Case);
NumCases += 1;
}
SwitchWeights = new SmallVector<uint64_t, 16>();
SwitchWeights->reserve(NumCases);
SwitchWeights->push_back(DefaultCount);
} else if (CGM.getCodeGenOpts().OptimizationLevel) {
SwitchLikelihood = new SmallVector<Stmt::Likelihood, 16>();
SwitchLikelihood->push_back(Stmt::LH_None);
}
CaseRangeBlock = DefaultBlock;
Builder.ClearInsertionPoint();
JumpDest OuterContinue;
if (!BreakContinueStack.empty())
OuterContinue = BreakContinueStack.back().ContinueBlock;
BreakContinueStack.push_back(BreakContinue(SwitchExit, OuterContinue));
EmitStmt(S.getBody());
BreakContinueStack.pop_back();
SwitchInsn->setDefaultDest(CaseRangeBlock);
if (!DefaultBlock->getParent()) {
if (ConditionScope.requiresCleanups()) {
EmitBlock(DefaultBlock);
} else {
DefaultBlock->replaceAllUsesWith(SwitchExit.getBlock());
delete DefaultBlock;
}
}
ConditionScope.ForceCleanup();
EmitBlock(SwitchExit.getBlock(), true);
incrementProfileCounter(&S);
auto *Call = dyn_cast<CallExpr>(S.getCond());
if (Call && CGM.getCodeGenOpts().OptimizationLevel != 0) {
auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
llvm::MDBuilder MDHelper(getLLVMContext());
SwitchInsn->setMetadata(llvm::LLVMContext::MD_unpredictable,
MDHelper.createUnpredictable());
}
}
if (SwitchWeights) {
assert(SwitchWeights->size() == 1 + SwitchInsn->getNumCases() &&
"switch weights do not match switch cases");
if (SwitchWeights->size() > 1)
SwitchInsn->setMetadata(llvm::LLVMContext::MD_prof,
createProfileWeights(*SwitchWeights));
delete SwitchWeights;
} else if (SwitchLikelihood) {
assert(SwitchLikelihood->size() == 1 + SwitchInsn->getNumCases() &&
"switch likelihoods do not match switch cases");
Optional<SmallVector<uint64_t, 16>> LHW =
getLikelihoodWeights(*SwitchLikelihood);
if (LHW) {
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
SwitchInsn->setMetadata(llvm::LLVMContext::MD_prof,
createProfileWeights(*LHW));
}
delete SwitchLikelihood;
}
SwitchInsn = SavedSwitchInsn;
SwitchWeights = SavedSwitchWeights;
SwitchLikelihood = SavedSwitchLikelihood;
CaseRangeBlock = SavedCRBlock;
}
static std::string
SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=nullptr) {
std::string Result;
while (*Constraint) {
switch (*Constraint) {
default:
Result += Target.convertConstraint(Constraint);
break;
case '*':
case '?':
case '!':
case '=': case '+':
break;
case '#': while (Constraint[1] && Constraint[1] != ',')
Constraint++;
break;
case '&':
case '%':
Result += *Constraint;
while (Constraint[1] && Constraint[1] == *Constraint)
Constraint++;
break;
case ',':
Result += "|";
break;
case 'g':
Result += "imr";
break;
case '[': {
assert(OutCons &&
"Must pass output names to constraints with a symbolic name");
unsigned Index;
bool result = Target.resolveSymbolicName(Constraint, *OutCons, Index);
assert(result && "Could not resolve symbolic name"); (void)result;
Result += llvm::utostr(Index);
break;
}
}
Constraint++;
}
return Result;
}
static std::string
AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr,
const TargetInfo &Target, CodeGenModule &CGM,
const AsmStmt &Stmt, const bool EarlyClobber,
std::string *GCCReg = nullptr) {
const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(&AsmExpr);
if (!AsmDeclRef)
return Constraint;
const ValueDecl &Value = *AsmDeclRef->getDecl();
const VarDecl *Variable = dyn_cast<VarDecl>(&Value);
if (!Variable)
return Constraint;
if (Variable->getStorageClass() != SC_Register)
return Constraint;
AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>();
if (!Attr)
return Constraint;
StringRef Register = Attr->getLabel();
assert(Target.isValidGCCRegisterName(Register));
TargetInfo::ConstraintInfo Info(Constraint, "");
if (Target.validateOutputConstraint(Info) &&
!Info.allowsRegister()) {
CGM.ErrorUnsupported(&Stmt, "__asm__");
return Constraint;
}
Register = Target.getNormalizedGCCRegisterName(Register);
if (GCCReg != nullptr)
*GCCReg = Register.str();
return (EarlyClobber ? "&{" : "{") + Register.str() + "}";
}
std::pair<llvm::Value*, llvm::Type *> CodeGenFunction::EmitAsmInputLValue(
const TargetInfo::ConstraintInfo &Info, LValue InputValue,
QualType InputType, std::string &ConstraintStr, SourceLocation Loc) {
if (Info.allowsRegister() || !Info.allowsMemory()) {
if (CodeGenFunction::hasScalarEvaluationKind(InputType))
return {EmitLoadOfLValue(InputValue, Loc).getScalarVal(), nullptr};
llvm::Type *Ty = ConvertType(InputType);
uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
if ((Size <= 64 && llvm::isPowerOf2_64(Size)) ||
getTargetHooks().isScalarizableAsmOperand(*this, Ty)) {
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
return {Builder.CreateLoad(Builder.CreateElementBitCast(
InputValue.getAddress(*this), Ty)),
nullptr};
}
}
Address Addr = InputValue.getAddress(*this);
ConstraintStr += '*';
return {Addr.getPointer(), Addr.getElementType()};
}
std::pair<llvm::Value *, llvm::Type *>
CodeGenFunction::EmitAsmInput(const TargetInfo::ConstraintInfo &Info,
const Expr *InputExpr,
std::string &ConstraintStr) {
if (!Info.allowsRegister() && !Info.allowsMemory()) {
if (Info.requiresImmediateConstant()) {
Expr::EvalResult EVResult;
InputExpr->EvaluateAsRValue(EVResult, getContext(), true);
llvm::APSInt IntResult;
if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
getContext()))
return {llvm::ConstantInt::get(getLLVMContext(), IntResult), nullptr};
}
Expr::EvalResult Result;
if (InputExpr->EvaluateAsInt(Result, getContext()))
return {llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt()),
nullptr};
}
if (Info.allowsRegister() || !Info.allowsMemory())
if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
return {EmitScalarExpr(InputExpr), nullptr};
if (InputExpr->getStmtClass() == Expr::CXXThisExprClass)
return {EmitScalarExpr(InputExpr), nullptr};
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
LValue Dest = EmitLValue(InputExpr);
return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr,
InputExpr->getExprLoc());
}
static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
CodeGenFunction &CGF) {
SmallVector<llvm::Metadata *, 8> Locs;
Locs.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
CGF.Int64Ty, Str->getBeginLoc().getRawEncoding())));
StringRef StrVal = Str->getString();
if (!StrVal.empty()) {
const SourceManager &SM = CGF.CGM.getContext().getSourceManager();
const LangOptions &LangOpts = CGF.CGM.getLangOpts();
unsigned StartToken = 0;
unsigned ByteOffset = 0;
for (unsigned i = 0, e = StrVal.size() - 1; i != e; ++i) {
if (StrVal[i] != '\n') continue;
SourceLocation LineLoc = Str->getLocationOfByte(
i + 1, SM, LangOpts, CGF.getTarget(), &StartToken, &ByteOffset);
Locs.push_back(llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(CGF.Int64Ty, LineLoc.getRawEncoding())));
}
}
return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
}
static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
bool HasUnwindClobber, bool ReadOnly,
bool ReadNone, bool NoMerge, const AsmStmt &S,
const std::vector<llvm::Type *> &ResultRegTypes,
const std::vector<llvm::Type *> &ArgElemTypes,
CodeGenFunction &CGF,
std::vector<llvm::Value *> &RegResults) {
if (!HasUnwindClobber)
Result.addFnAttr(llvm::Attribute::NoUnwind);
if (NoMerge)
Result.addFnAttr(llvm::Attribute::NoMerge);
if (!HasSideEffect) {
if (ReadNone)
Result.addFnAttr(llvm::Attribute::ReadNone);
else if (ReadOnly)
Result.addFnAttr(llvm::Attribute::ReadOnly);
}
for (auto Pair : llvm::enumerate(ArgElemTypes)) {
if (Pair.value()) {
auto Attr = llvm::Attribute::get(
CGF.getLLVMContext(), llvm::Attribute::ElementType, Pair.value());
Result.addParamAttr(Pair.index(), Attr);
}
}
if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
Result.setMetadata("srcloc",
getAsmSrcLocInfo(gccAsmStmt->getAsmString(), CGF));
else {
llvm::Constant *Loc =
llvm::ConstantInt::get(CGF.Int64Ty, S.getAsmLoc().getRawEncoding());
Result.setMetadata("srcloc",
llvm::MDNode::get(CGF.getLLVMContext(),
llvm::ConstantAsMetadata::get(Loc)));
}
if (CGF.getLangOpts().assumeFunctionsAreConvergent())
Result.addFnAttr(llvm::Attribute::Convergent);
if (ResultRegTypes.size() == 1) {
RegResults.push_back(&Result);
} else {
for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
llvm::Value *Tmp = CGF.Builder.CreateExtractValue(&Result, i, "asmresult");
RegResults.push_back(Tmp);
}
}
}
void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
CodeGenFunction::RunCleanupsScope Cleanups(*this);
std::string AsmString = S.generateAsmString(getContext());
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
StringRef Name;
if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
Name = GAS->getOutputName(i);
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name);
bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid;
assert(IsValid && "Failed to parse output constraint");
OutputConstraintInfos.push_back(Info);
}
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
StringRef Name;
if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
Name = GAS->getInputName(i);
TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name);
bool IsValid =
getTarget().validateInputConstraint(OutputConstraintInfos, Info);
assert(IsValid && "Failed to parse input constraint"); (void)IsValid;
InputConstraintInfos.push_back(Info);
}
std::string Constraints;
std::vector<LValue> ResultRegDests;
std::vector<QualType> ResultRegQualTys;
std::vector<llvm::Type *> ResultRegTypes;
std::vector<llvm::Type *> ResultTruncRegTypes;
std::vector<llvm::Type *> ArgTypes;
std::vector<llvm::Type *> ArgElemTypes;
std::vector<llvm::Value*> Args;
llvm::BitVector ResultTypeRequiresCast;
llvm::BitVector ResultRegIsFlagReg;
std::string InOutConstraints;
std::vector<llvm::Value*> InOutArgs;
std::vector<llvm::Type*> InOutArgTypes;
std::vector<llvm::Type*> InOutArgElemTypes;
std::vector<std::string> OutputConstraints;
llvm::SmallSet<std::string, 8> PhysRegOutputs;
bool ReadOnly = true, ReadNone = true;
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
std::string OutputConstraint(S.getOutputConstraint(i));
OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1,
getTarget(), &OutputConstraintInfos);
const Expr *OutExpr = S.getOutputExpr(i);
OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
std::string GCCReg;
OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr,
getTarget(), CGM, S,
Info.earlyClobber(),
&GCCReg);
if (!GCCReg.empty() && !PhysRegOutputs.insert(GCCReg).second)
CGM.Error(S.getAsmLoc(), "multiple outputs to hard register: " + GCCReg);
OutputConstraints.push_back(OutputConstraint);
LValue Dest = EmitLValue(OutExpr);
if (!Constraints.empty())
Constraints += ',';
QualType QTy = OutExpr->getType();
const bool IsScalarOrAggregate = hasScalarEvaluationKind(QTy) ||
hasAggregateEvaluationKind(QTy);
if (!Info.allowsMemory() && IsScalarOrAggregate) {
Constraints += "=" + OutputConstraint;
ResultRegQualTys.push_back(QTy);
ResultRegDests.push_back(Dest);
bool IsFlagReg = llvm::StringRef(OutputConstraint).startswith("{@cc");
ResultRegIsFlagReg.push_back(IsFlagReg);
llvm::Type *Ty = ConvertTypeForMem(QTy);
const bool RequiresCast = Info.allowsRegister() &&
(getTargetHooks().isScalarizableAsmOperand(*this, Ty) ||
Ty->isAggregateType());
ResultTruncRegTypes.push_back(Ty);
ResultTypeRequiresCast.push_back(RequiresCast);
if (RequiresCast) {
unsigned Size = getContext().getTypeSize(QTy);
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
}
ResultRegTypes.push_back(Ty);
if (Info.hasMatchingInput()) {
unsigned InputNo;
for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
if (Input.hasTiedOperand() && Input.getTiedOperand() == i)
break;
}
assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
QualType InputTy = S.getInputExpr(InputNo)->getType();
QualType OutputType = OutExpr->getType();
uint64_t InputSize = getContext().getTypeSize(InputTy);
if (getContext().getTypeSize(OutputType) < InputSize) {
ResultRegTypes.back() = ConvertType(InputTy);
}
}
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
ResultRegTypes.back()))
ResultRegTypes.back() = AdjTy;
else {
CGM.getDiags().Report(S.getAsmLoc(),
diag::err_asm_invalid_type_in_input)
<< OutExpr->getType() << OutputConstraint;
}
if (auto *VT = dyn_cast<llvm::VectorType>(ResultRegTypes.back()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
} else {
Address DestAddr = Dest.getAddress(*this);
if (isa<MatrixType>(OutExpr->getType().getCanonicalType()))
DestAddr = Builder.CreateElementBitCast(
DestAddr, ConvertType(OutExpr->getType()));
ArgTypes.push_back(DestAddr.getType());
ArgElemTypes.push_back(DestAddr.getElementType());
Args.push_back(DestAddr.getPointer());
Constraints += "=*";
Constraints += OutputConstraint;
ReadOnly = ReadNone = false;
}
if (Info.isReadWrite()) {
InOutConstraints += ',';
const Expr *InputExpr = S.getOutputExpr(i);
llvm::Value *Arg;
llvm::Type *ArgElemType;
std::tie(Arg, ArgElemType) = EmitAsmInputLValue(
Info, Dest, InputExpr->getType(), InOutConstraints,
InputExpr->getExprLoc());
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, OutputConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
if (Info.allowsRegister() && (GCCReg.empty() || Info.earlyClobber()))
InOutConstraints += llvm::utostr(i);
else
InOutConstraints += OutputConstraint;
InOutArgTypes.push_back(Arg->getType());
InOutArgElemTypes.push_back(ArgElemType);
InOutArgs.push_back(Arg);
}
}
if (isa<MSAsmStmt>(&S)) {
const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
if (RetAI.isDirect() || RetAI.isExtend()) {
LValue ReturnSlot = MakeAddrLValueWithoutTBAA(ReturnValue, FnRetTy);
CGM.getTargetCodeGenInfo().addReturnRegisterOutputs(
*this, ReturnSlot, Constraints, ResultRegTypes, ResultTruncRegTypes,
ResultRegDests, AsmString, S.getNumOutputs());
SawAsmBlock = true;
}
}
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
const Expr *InputExpr = S.getInputExpr(i);
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
if (Info.allowsMemory())
ReadNone = false;
if (!Constraints.empty())
Constraints += ',';
std::string InputConstraint(S.getInputConstraint(i));
InputConstraint = SimplifyConstraint(InputConstraint.c_str(), getTarget(),
&OutputConstraintInfos);
InputConstraint = AddVariableConstraints(
InputConstraint, *InputExpr->IgnoreParenNoopCasts(getContext()),
getTarget(), CGM, S, false );
std::string ReplaceConstraint (InputConstraint);
llvm::Value *Arg;
llvm::Type *ArgElemType;
std::tie(Arg, ArgElemType) = EmitAsmInput(Info, InputExpr, Constraints);
if (Info.hasTiedOperand()) {
unsigned Output = Info.getTiedOperand();
QualType OutputType = S.getOutputExpr(Output)->getType();
QualType InputTy = InputExpr->getType();
if (getContext().getTypeSize(OutputType) >
getContext().getTypeSize(InputTy)) {
if (isa<llvm::PointerType>(Arg->getType()))
Arg = Builder.CreatePtrToInt(Arg, IntPtrTy);
llvm::Type *OutputTy = ConvertType(OutputType);
if (isa<llvm::IntegerType>(OutputTy))
Arg = Builder.CreateZExt(Arg, OutputTy);
else if (isa<llvm::PointerType>(OutputTy))
Arg = Builder.CreateZExt(Arg, IntPtrTy);
else if (OutputTy->isFloatingPointTy())
Arg = Builder.CreateFPExt(Arg, OutputTy);
}
ReplaceConstraint = OutputConstraints[Output];
}
if (llvm::Type* AdjTy =
getTargetHooks().adjustInlineAsmType(*this, ReplaceConstraint,
Arg->getType()))
Arg = Builder.CreateBitCast(Arg, AdjTy);
else
CGM.getDiags().Report(S.getAsmLoc(), diag::err_asm_invalid_type_in_input)
<< InputExpr->getType() << InputConstraint;
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
VT->getPrimitiveSizeInBits().getKnownMinSize());
ArgTypes.push_back(Arg->getType());
ArgElemTypes.push_back(ArgElemType);
Args.push_back(Arg);
Constraints += InputConstraint;
}
for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) {
ArgTypes.push_back(InOutArgTypes[i]);
ArgElemTypes.push_back(InOutArgElemTypes[i]);
Args.push_back(InOutArgs[i]);
}
Constraints += InOutConstraints;
SmallVector<llvm::BasicBlock *, 16> Transfer;
llvm::BasicBlock *Fallthrough = nullptr;
bool IsGCCAsmGoto = false;
if (const auto *GS = dyn_cast<GCCAsmStmt>(&S)) {
IsGCCAsmGoto = GS->isAsmGoto();
if (IsGCCAsmGoto) {
for (const auto *E : GS->labels()) {
JumpDest Dest = getJumpDestForLabel(E->getLabel());
Transfer.push_back(Dest.getBlock());
if (!Constraints.empty())
Constraints += ',';
Constraints += "!i";
}
Fallthrough = createBasicBlock("asm.fallthrough");
}
}
bool HasUnwindClobber = false;
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
StringRef Clobber = S.getClobber(i);
if (Clobber == "memory")
ReadOnly = ReadNone = false;
else if (Clobber == "unwind") {
HasUnwindClobber = true;
continue;
} else if (Clobber != "cc") {
Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
if (CGM.getCodeGenOpts().StackClashProtector &&
getTarget().isSPRegName(Clobber)) {
CGM.getDiags().Report(S.getAsmLoc(),
diag::warn_stack_clash_protection_inline_asm);
}
}
if (isa<MSAsmStmt>(&S)) {
if (Clobber == "eax" || Clobber == "edx") {
if (Constraints.find("=&A") != std::string::npos)
continue;
std::string::size_type position1 =
Constraints.find("={" + Clobber.str() + "}");
if (position1 != std::string::npos) {
Constraints.insert(position1 + 1, "&");
continue;
}
std::string::size_type position2 = Constraints.find("=A");
if (position2 != std::string::npos) {
Constraints.insert(position2 + 1, "&");
continue;
}
}
}
if (!Constraints.empty())
Constraints += ',';
Constraints += "~{";
Constraints += Clobber;
Constraints += '}';
}
assert(!(HasUnwindClobber && IsGCCAsmGoto) &&
"unwind clobber can't be used with asm goto");
std::string MachineClobbers = getTarget().getClobbers();
if (!MachineClobbers.empty()) {
if (!Constraints.empty())
Constraints += ',';
Constraints += MachineClobbers;
}
llvm::Type *ResultType;
if (ResultRegTypes.empty())
ResultType = VoidTy;
else if (ResultRegTypes.size() == 1)
ResultType = ResultRegTypes[0];
else
ResultType = llvm::StructType::get(getLLVMContext(), ResultRegTypes);
llvm::FunctionType *FTy =
llvm::FunctionType::get(ResultType, ArgTypes, false);
bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
llvm::InlineAsm::AsmDialect GnuAsmDialect =
CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
? llvm::InlineAsm::AD_ATT
: llvm::InlineAsm::AD_Intel;
llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ?
llvm::InlineAsm::AD_Intel : GnuAsmDialect;
llvm::InlineAsm *IA = llvm::InlineAsm::get(
FTy, AsmString, Constraints, HasSideEffect,
false, AsmDialect, HasUnwindClobber);
std::vector<llvm::Value*> RegResults;
if (IsGCCAsmGoto) {
llvm::CallBrInst *Result =
Builder.CreateCallBr(IA, Fallthrough, Transfer, Args);
EmitBlock(Fallthrough);
UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
ResultRegTypes, ArgElemTypes, *this, RegResults);
} else if (HasUnwindClobber) {
llvm::CallBase *Result = EmitCallOrInvoke(IA, Args, "");
UpdateAsmCallInst(*Result, HasSideEffect, true, ReadOnly, ReadNone,
InNoMergeAttributedStmt, S, ResultRegTypes, ArgElemTypes,
*this, RegResults);
} else {
llvm::CallInst *Result =
Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
UpdateAsmCallInst(cast<llvm::CallBase>(*Result), HasSideEffect, false,
ReadOnly, ReadNone, InNoMergeAttributedStmt, S,
ResultRegTypes, ArgElemTypes, *this, RegResults);
}
assert(RegResults.size() == ResultRegTypes.size());
assert(RegResults.size() == ResultTruncRegTypes.size());
assert(RegResults.size() == ResultRegDests.size());
assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
assert(ResultRegIsFlagReg.size() <= ResultRegDests.size());
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
llvm::Value *Tmp = RegResults[i];
llvm::Type *TruncTy = ResultTruncRegTypes[i];
if ((i < ResultRegIsFlagReg.size()) && ResultRegIsFlagReg[i]) {
llvm::Constant *Two = llvm::ConstantInt::get(Tmp->getType(), 2);
llvm::Value *IsBooleanValue =
Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, Two);
llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
Builder.CreateCall(FnAssume, IsBooleanValue);
}
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
if (TruncTy->isFloatingPointTy())
Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy);
Tmp = Builder.CreateTrunc(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
} else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
uint64_t TmpSize =CGM.getDataLayout().getTypeSizeInBits(Tmp->getType());
Tmp = Builder.CreatePtrToInt(Tmp,
llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize));
Tmp = Builder.CreateTrunc(Tmp, TruncTy);
} else if (TruncTy->isIntegerTy()) {
Tmp = Builder.CreateZExtOrTrunc(Tmp, TruncTy);
} else if (TruncTy->isVectorTy()) {
Tmp = Builder.CreateBitCast(Tmp, TruncTy);
}
}
LValue Dest = ResultRegDests[i];
if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) {
unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
Address A = Builder.CreateElementBitCast(Dest.getAddress(*this),
ResultRegTypes[i]);
if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) {
Builder.CreateStore(Tmp, A);
continue;
}
QualType Ty = getContext().getIntTypeForBitwidth(Size, false);
if (Ty.isNull()) {
const Expr *OutExpr = S.getOutputExpr(i);
CGM.getDiags().Report(OutExpr->getExprLoc(),
diag::err_store_value_to_reg);
return;
}
Dest = MakeAddrLValue(A, Ty);
}
EmitStoreThroughLValue(RValue::get(Tmp), Dest);
}
}
LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) {
const RecordDecl *RD = S.getCapturedRecordDecl();
QualType RecordTy = getContext().getRecordType(RD);
LValue SlotLV =
MakeAddrLValue(CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
RecordDecl::field_iterator CurField = RD->field_begin();
for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(),
E = S.capture_init_end();
I != E; ++I, ++CurField) {
LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
if (CurField->hasCapturedVLAType()) {
EmitLambdaVLACapture(CurField->getCapturedVLAType(), LV);
} else {
EmitInitializerForField(*CurField, LV, *I);
}
}
return SlotLV;
}
llvm::Function *
CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
LValue CapStruct = InitCapturedStruct(S);
CodeGenFunction CGF(CGM, true);
CGCapturedStmtRAII CapInfoRAII(CGF, new CGCapturedStmtInfo(S, K));
llvm::Function *F = CGF.GenerateCapturedStmtFunction(S);
delete CGF.CapturedStmtInfo;
EmitCallOrInvoke(F, CapStruct.getPointer(*this));
return F;
}
Address CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) {
LValue CapStruct = InitCapturedStruct(S);
return CapStruct.getAddress(*this);
}
llvm::Function *
CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) {
assert(CapturedStmtInfo &&
"CapturedStmtInfo should be set when generating the captured function");
const CapturedDecl *CD = S.getCapturedDecl();
const RecordDecl *RD = S.getCapturedRecordDecl();
SourceLocation Loc = S.getBeginLoc();
assert(CD->hasBody() && "missing CapturedDecl body");
ASTContext &Ctx = CGM.getContext();
FunctionArgList Args;
Args.append(CD->param_begin(), CD->param_end());
const CGFunctionInfo &FuncInfo =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Function *F =
llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
CapturedStmtInfo->getHelperName(), &CGM.getModule());
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
if (CD->isNothrow())
F->addFnAttr(llvm::Attribute::NoUnwind);
StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(),
CD->getBody()->getBeginLoc());
Address DeclPtr = GetAddrOfLocalVar(CD->getContextParam());
CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
LValue Base = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
Ctx.getTagDeclType(RD));
for (auto *FD : RD->fields()) {
if (FD->hasCapturedVLAType()) {
auto *ExprArg =
EmitLoadOfLValue(EmitLValueForField(Base, FD), S.getBeginLoc())
.getScalarVal();
auto VAT = FD->getCapturedVLAType();
VLASizeMap[VAT->getSizeExpr()] = ExprArg;
}
}
if (CapturedStmtInfo->isCXXThisExprCaptured()) {
FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
LValue ThisLValue = EmitLValueForField(Base, FD);
CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
}
PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
return F;
}