File: funcgenstate.cpp

package info (click to toggle)
ldc 1%3A1.30.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 59,248 kB
  • sloc: cpp: 61,598; ansic: 14,545; sh: 1,014; makefile: 972; asm: 510; objc: 135; exp: 48; python: 12
file content (152 lines) | stat: -rw-r--r-- 5,375 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//===-- funcgenstate.cpp --------------------------------------------------===//
//
//                         LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//

#include "gen/funcgenstate.h"

#include "dmd/identifier.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/ms-cxx-helper.h"
#include "gen/runtime.h"
#include "ir/irfunction.h"

JumpTarget::JumpTarget(llvm::BasicBlock *targetBlock,
                       CleanupCursor cleanupScope, Statement *targetStatement)
    : targetBlock(targetBlock), cleanupScope(cleanupScope),
      targetStatement(targetStatement) {}

JumpTargets::JumpTargets(TryCatchFinallyScopes &scopes) : scopes(scopes) {}

void JumpTargets::pushLoopTarget(Statement *loopStatement,
                                 llvm::BasicBlock *continueTarget,
                                 llvm::BasicBlock *breakTarget) {
  continueTargets.emplace_back(continueTarget, scopes.currentCleanupScope(),
                               loopStatement);
  breakTargets.emplace_back(breakTarget, scopes.currentCleanupScope(),
                            loopStatement);
}

void JumpTargets::popLoopTarget() {
  continueTargets.pop_back();
  breakTargets.pop_back();
}

void JumpTargets::pushBreakTarget(Statement *switchStatement,
                                  llvm::BasicBlock *targetBlock) {
  breakTargets.push_back(
      {targetBlock, scopes.currentCleanupScope(), switchStatement});
}

void JumpTargets::popBreakTarget() { breakTargets.pop_back(); }

void JumpTargets::addLabelTarget(Identifier *labelName,
                                 llvm::BasicBlock *targetBlock) {
  labelTargets[labelName] = {targetBlock, scopes.currentCleanupScope(),
                             nullptr};

  // See whether any of the unresolved gotos target this label, and resolve
  // those that do.
  scopes.tryResolveGotos(labelName, targetBlock);
}

void JumpTargets::jumpToLabel(Loc loc, Identifier *labelName) {
  // If we have already seen that label, branch to it, executing any cleanups
  // as necessary.
  auto it = labelTargets.find(labelName);
  if (it != labelTargets.end()) {
    scopes.runCleanups(it->second.cleanupScope, it->second.targetBlock);
  } else {
    scopes.registerUnresolvedGoto(loc, labelName);
  }
}

void JumpTargets::jumpToStatement(std::vector<JumpTarget> &targets,
                                  Statement *loopOrSwitchStatement) {
  for (auto it = targets.rbegin(), end = targets.rend(); it != end; ++it) {
    if (it->targetStatement == loopOrSwitchStatement) {
      scopes.runCleanups(it->cleanupScope, it->targetBlock);
      return;
    }
  }
  assert(false && "Target for labeled break not found.");
}

void JumpTargets::jumpToClosest(std::vector<JumpTarget> &targets) {
  assert(!targets.empty() &&
         "Encountered break/continue but no loop in scope.");
  JumpTarget &t = targets.back();
  scopes.runCleanups(t.cleanupScope, t.targetBlock);
}

llvm::BasicBlock *SwitchCaseTargets::get(Statement *stmt) {
  auto it = targetBBs.find(stmt);
  assert(it != targetBBs.end());
  return it->second;
}

llvm::BasicBlock *SwitchCaseTargets::getOrCreate(Statement *stmt,
                                                 const llvm::Twine &name,
                                                 IRState &irs) {
  auto &bb = targetBBs[stmt];
  if (!bb)
    bb = irs.insertBB(name);
  return bb;
}

FuncGenState::FuncGenState(IrFunction &irFunc, IRState &irs)
    : irFunc(irFunc), scopes(irs), jumpTargets(scopes), switchTargets(),
      irs(irs) {}

LLCallBasePtr FuncGenState::callOrInvoke(llvm::Value *callee,
                                         llvm::FunctionType *calleeType,
                                         llvm::ArrayRef<llvm::Value *> args,
                                         const char *name, bool isNothrow) {
  // If this is a direct call, we might be able to use the callee attributes
  // to our advantage.
  llvm::Function *calleeFn = llvm::dyn_cast<llvm::Function>(callee);

  // Ignore 'nothrow' if there are active catch blocks handling non-Exception
  // Throwables.
  if (isNothrow && scopes.isCatchingNonExceptions())
    isNothrow = false;

  // Intrinsics don't support invoking and 'nounwind' functions don't need it.
  const bool doesNotThrow =
      isNothrow || global.params.betterC ||
      (calleeFn && (calleeFn->isIntrinsic() || calleeFn->doesNotThrow()));

  // calls inside a funclet must be annotated with its value
  llvm::SmallVector<llvm::OperandBundleDef, 2> BundleList;

#if LDC_LLVM_VER >= 1100
  llvm::FunctionCallee calleeArg(calleeType, callee);
#else
  auto calleeArg = callee;
#endif

  if (doesNotThrow || scopes.empty()) {
    auto call = irs.ir->CreateCall(calleeArg, args, BundleList, name);
    if (calleeFn) {
      call->setAttributes(calleeFn->getAttributes());
    }
    return call;
  }

  llvm::BasicBlock *landingPad = scopes.getLandingPad();

  llvm::BasicBlock *postinvoke = irs.insertBB("postinvoke");
  auto invoke = irs.ir->CreateInvoke(calleeArg, postinvoke, landingPad, args,
                                     BundleList, name);
  if (calleeFn) {
    invoke->setAttributes(calleeFn->getAttributes());
  }

  irs.ir->SetInsertPoint(postinvoke);
  return invoke;
}