Пример #1
0
void DtoFinalizeClass(Loc &loc, LLValue *inst) {
  // get runtime function
  llvm::Function *fn =
      getRuntimeFunction(loc, gIR->module, "_d_callfinalizer");

  gIR->CreateCallOrInvoke(
      fn, DtoBitCast(inst, fn->getFunctionType()->getParamType(0)), "");
}
Пример #2
0
/// Builds the body for the ldc.dso_ctor and ldc.dso_dtor functions.
///
/// Pseudocode:
/// if (dsoInitialized == executeWhenInitialized) {
///     dsoInitialized = !executeWhenInitialized;
///     auto record = {1, dsoSlot, minfoBeg, minfoEnd, minfoUsedPointer};
///     _d_dso_registry(cast(CompilerDSOData*)&record);
/// }
static void build_dso_ctor_dtor_body(
    llvm::Function *targetFunc, llvm::Value *dsoInitialized,
    llvm::Value *dsoSlot, llvm::Value *minfoBeg, llvm::Value *minfoEnd,
    llvm::Value *minfoUsedPointer, bool executeWhenInitialized) {
  llvm::Function *const dsoRegistry =
      getRuntimeFunction(Loc(), gIR->module, "_d_dso_registry");
  llvm::Type *const recordPtrTy =
      dsoRegistry->getFunctionType()->getContainedType(1);

  llvm::BasicBlock *const entryBB =
      llvm::BasicBlock::Create(gIR->context(), "", targetFunc);
  llvm::BasicBlock *const initBB =
      llvm::BasicBlock::Create(gIR->context(), "init", targetFunc);
  llvm::BasicBlock *const endBB =
      llvm::BasicBlock::Create(gIR->context(), "end", targetFunc);

  {
    IRBuilder<> b(entryBB);
    llvm::Value *condEval =
        b.CreateICmp(executeWhenInitialized ? llvm::ICmpInst::ICMP_NE
                                            : llvm::ICmpInst::ICMP_EQ,
                     b.CreateLoad(dsoInitialized), b.getInt8(0));
    b.CreateCondBr(condEval, initBB, endBB);
  }
  {
    IRBuilder<> b(initBB);
    b.CreateStore(b.getInt8(!executeWhenInitialized), dsoInitialized);

    llvm::Constant *version = DtoConstSize_t(1);
    llvm::Type *memberTypes[] = {version->getType(), dsoSlot->getType(),
                                 minfoBeg->getType(), minfoEnd->getType(),
                                 minfoUsedPointer->getType()};
    llvm::StructType *stype =
        llvm::StructType::get(gIR->context(), memberTypes, false);
    llvm::Value *record = b.CreateAlloca(stype);
#if LDC_LLVM_VER >= 307
    b.CreateStore(version, b.CreateStructGEP(stype, record, 0)); // version
    b.CreateStore(dsoSlot, b.CreateStructGEP(stype, record, 1)); // slot
    b.CreateStore(minfoBeg, b.CreateStructGEP(stype, record, 2));
    b.CreateStore(minfoEnd, b.CreateStructGEP(stype, record, 3));
    b.CreateStore(minfoUsedPointer, b.CreateStructGEP(stype, record, 4));
#else
    b.CreateStore(version, b.CreateStructGEP(record, 0)); // version
    b.CreateStore(dsoSlot, b.CreateStructGEP(record, 1)); // slot
    b.CreateStore(minfoBeg, b.CreateStructGEP(record, 2));
    b.CreateStore(minfoEnd, b.CreateStructGEP(record, 3));
    b.CreateStore(minfoUsedPointer, b.CreateStructGEP(record, 4));
#endif

    b.CreateCall(dsoRegistry, b.CreateBitCast(record, recordPtrTy));
    b.CreateBr(endBB);
  }
  {
    IRBuilder<> b(endBB);
    b.CreateRetVoid();
  }
}
Пример #3
0
llvm::BasicBlock *TryCatchFinallyScopes::getOrCreateResumeUnwindBlock() {
  if (!resumeUnwindBlock) {
    resumeUnwindBlock = irs.insertBB("eh.resume");

    llvm::BasicBlock *oldBB = irs.scopebb();
    irs.scope() = IRScope(resumeUnwindBlock);

    llvm::Function *resumeFn =
        getRuntimeFunction(Loc(), irs.module, "_d_eh_resume_unwind");
    irs.ir->CreateCall(resumeFn, DtoLoad(getOrCreateEhPtrSlot()));
    irs.ir->CreateUnreachable();

    irs.scope() = IRScope(oldBB);
  }
  return resumeUnwindBlock;
}
Пример #4
0
llvm::BasicBlock *
TryCatchFinallyScopes::emitLandingPadMSVC(CleanupCursor cleanupScope) {
  if (!irs.func()->hasLLVMPersonalityFn()) {
    const char *personality = "__CxxFrameHandler3";
    irs.func()->setLLVMPersonalityFn(
        getRuntimeFunction(Loc(), irs.module, personality));
  }

  if (cleanupScope == 0)
    return runCleanupPad(cleanupScope, nullptr);

  llvm::BasicBlock *&pad = getLandingPadRef(cleanupScope);
  if (!pad)
    pad = emitLandingPadMSVC(cleanupScope - 1);

  return runCleanupPad(cleanupScope, pad);
}
Пример #5
0
void TryCatchScope::emitCatchBodiesMSVC(IRState &irs, llvm::Value *) {
  assert(catchBlocks.empty());

  auto &scopes = irs.funcGen().scopes;
  auto &PGO = irs.funcGen().pgo;

  auto catchSwitchBlock = irs.insertBBBefore(endbb, "catch.dispatch");
  llvm::BasicBlock *unwindto =
      scopes.currentCleanupScope() > 0 ? scopes.getLandingPad() : nullptr;
  auto catchSwitchInst = llvm::CatchSwitchInst::Create(
      llvm::ConstantTokenNone::get(irs.context()), unwindto, stmt->catches->dim,
      "", catchSwitchBlock);

  for (auto c : *stmt->catches) {
    auto catchBB =
        irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());

    irs.scope() = IRScope(catchBB);
    irs.DBuilder.EmitBlockStart(c->loc);
    PGO.emitCounterIncrement(c);

    emitBeginCatchMSVC(irs, c, catchSwitchInst);

    // Emit handler, if there is one. The handler is zero, for instance,
    // when building 'catch { debug foo(); }' in non-debug mode.
    if (c->handler)
      Statement_toIR(c->handler, &irs);

    if (!irs.scopereturned())
      irs.ir->CreateBr(endbb);

    irs.DBuilder.EmitBlockEnd();
  }

  scopes.pushCleanup(catchSwitchBlock, catchSwitchBlock);

  // if no landing pad is created, the catch blocks are unused, but
  // the verifier complains if there are catchpads without personality
  // so we can just set it unconditionally
  if (!irs.func()->func->hasPersonalityFn()) {
    const char *personality = "__CxxFrameHandler3";
    LLFunction *personalityFn =
        getRuntimeFunction(Loc(), irs.module, personality);
    irs.func()->func->setPersonalityFn(personalityFn);
  }
}
Пример #6
0
DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key) {
  // D1:
  // call:
  // extern(C) void* _aaIn(AA aa*, TypeInfo keyti, void* pkey)

  // D2:
  // call:
  // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)

  // first get the runtime function
  llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaInX");
  LLFunctionType *funcTy = func->getFunctionType();

  IF_LOG Logger::cout() << "_aaIn = " << *func << '\n';

  // aa param
  LLValue *aaval = aa->getRVal();
  IF_LOG {
    Logger::cout() << "aaval: " << *aaval << '\n';
    Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n';
  }
  aaval = DtoBitCast(aaval, funcTy->getParamType(0));

  // keyti param
  LLValue *keyti = to_keyti(aa);
  keyti = DtoBitCast(keyti, funcTy->getParamType(1));

  // pkey param
  LLValue *pkey = makeLValue(loc, key);
  pkey = DtoBitCast(pkey, getVoidPtrType());

  // call runtime
  LLValue *ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in")
                     .getInstruction();

  // cast return value
  LLType *targettype = DtoType(type);
  if (ret->getType() != targettype) {
    ret = DtoBitCast(ret, targettype);
  }

  return new DImValue(type, ret);
}
Пример #7
0
llvm::BasicBlock *IrFunction::getOrCreateResumeUnwindBlock() {
  assert(func == gIR->topfunc() &&
         "Should only access unwind resume block while emitting function.");
  if (!resumeUnwindBlock) {
    resumeUnwindBlock =
        llvm::BasicBlock::Create(gIR->context(), "eh.resume", func);

    llvm::BasicBlock *oldBB = gIR->scopebb();
    gIR->scope() = IRScope(resumeUnwindBlock);

    llvm::Function *resumeFn =
        getRuntimeFunction(Loc(), gIR->module, "_d_eh_resume_unwind");
    gIR->ir->CreateCall(resumeFn, gIR->ir->CreateLoad(getOrCreateEhPtrSlot()));
    gIR->ir->CreateUnreachable();

    gIR->scope() = IRScope(oldBB);
  }
  return resumeUnwindBlock;
}
Пример #8
0
LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
  Type *t = l->type->toBasetype();
  assert(t == r->type->toBasetype() &&
         "aa equality is only defined for aas of same type");
  llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaEqual");
  LLFunctionType *funcTy = func->getFunctionType();

  LLValue *aaval = DtoBitCast(DtoRVal(l), funcTy->getParamType(1));
  LLValue *abval = DtoBitCast(DtoRVal(r), funcTy->getParamType(2));
  LLValue *aaTypeInfo = DtoTypeInfoOf(t);
  LLValue *res =
      gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes")
          .getInstruction();

  const auto predicate = eqTokToICmpPred(op, /* invert = */ true);
  res = gIR->ir->CreateICmp(predicate, res, DtoConstInt(0));

  return res;
}
Пример #9
0
LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
  Type *t = l->getType()->toBasetype();
  assert(t == r->getType()->toBasetype() &&
         "aa equality is only defined for aas of same type");
  llvm::Function *func =
      getRuntimeFunction(loc, gIR->module, "_aaEqual");
  LLFunctionType *funcTy = func->getFunctionType();

  LLValue *aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(1));
  LLValue *abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2));
  LLValue *aaTypeInfo = DtoTypeInfoOf(t);
  LLValue *res =
      gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes")
          .getInstruction();
  res = gIR->ir->CreateICmpNE(res, DtoConstInt(0));
  if (op == TOKnotequal) {
    res = gIR->ir->CreateNot(res);
  }
  return res;
}
Пример #10
0
DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key) {
  // D1:
  // call:
  // extern(C) void _aaDel(AA aa, TypeInfo keyti, void* pkey)

  // D2:
  // call:
  // extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey)

  // first get the runtime function
  llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaDelX");
  LLFunctionType *funcTy = func->getFunctionType();

  IF_LOG Logger::cout() << "_aaDel = " << *func << '\n';

  // aa param
  LLValue *aaval = aa->getRVal();
  IF_LOG {
    Logger::cout() << "aaval: " << *aaval << '\n';
    Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n';
  }
  aaval = DtoBitCast(aaval, funcTy->getParamType(0));

  // keyti param
  LLValue *keyti = to_keyti(aa);
  keyti = DtoBitCast(keyti, funcTy->getParamType(1));

  // pkey param
  LLValue *pkey = makeLValue(loc, key);
  pkey = DtoBitCast(pkey, funcTy->getParamType(2));

  // call runtime
  LLCallSite call = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);

  return new DImValue(Type::tbool, call.getInstruction());
}
Пример #11
0
DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {
  // D2:
  // call:
  // extern(C) void* _aaGetY(AA* aa, TypeInfo aati, size_t valuesize, void*
  // pkey)
  // or
  // extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)

  // first get the runtime function
  llvm::Function *func = getRuntimeFunction(
      loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
  LLFunctionType *funcTy = func->getFunctionType();

  // aa param
  LLValue *aaval = lvalue ? aa->getLVal() : aa->getRVal();
  aaval = DtoBitCast(aaval, funcTy->getParamType(0));

  // pkey param
  LLValue *pkey = makeLValue(loc, key);
  pkey = DtoBitCast(pkey, funcTy->getParamType(lvalue ? 3 : 2));

  // call runtime
  LLValue *ret;
  if (lvalue) {
    LLValue *rawAATI =
        DtoTypeInfoOf(aa->type->unSharedOf()->mutableOf(), false);
    LLValue *castedAATI = DtoBitCast(rawAATI, funcTy->getParamType(1));
    LLValue *valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
    ret = gIR->CreateCallOrInvoke(func, aaval, castedAATI, valsize, pkey,
                                  "aa.index")
              .getInstruction();
  } else {
    LLValue *keyti = DtoBitCast(to_keyti(aa), funcTy->getParamType(1));
    ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index")
              .getInstruction();
  }

  // cast return value
  LLType *targettype = DtoPtrToType(type);
  if (ret->getType() != targettype) {
    ret = DtoBitCast(ret, targettype);
  }

  // Only check bounds for rvalues ('aa[key]').
  // Lvalue use ('aa[key] = value') auto-adds an element.
  if (!lvalue && gIR->emitArrayBoundsChecks()) {
    llvm::BasicBlock *failbb = llvm::BasicBlock::Create(
        gIR->context(), "aaboundscheckfail", gIR->topfunc());
    llvm::BasicBlock *okbb =
        llvm::BasicBlock::Create(gIR->context(), "aaboundsok", gIR->topfunc());

    LLValue *nullaa = LLConstant::getNullValue(ret->getType());
    LLValue *cond = gIR->ir->CreateICmpNE(nullaa, ret, "aaboundscheck");
    gIR->ir->CreateCondBr(cond, okbb, failbb);

    // set up failbb to call the array bounds error runtime function

    gIR->scope() = IRScope(failbb);

    llvm::Function *errorfn =
        getRuntimeFunction(loc, gIR->module, "_d_arraybounds");
    gIR->CreateCallOrInvoke(
        errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc),
        DtoConstUint(loc.linnum));

    // the function does not return
    gIR->ir->CreateUnreachable();

    // if ok, proceed in okbb
    gIR->scope() = IRScope(okbb);
  }
  return new DVarValue(type, ret);
}
Пример #12
0
llvm::BasicBlock *
TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
                                     llvm::BasicBlock *unwindTo) {
  // a catch switch never needs to be cloned and is an unwind target itself
  if (isCatchSwitchBlock(cleanupScopes[scope].beginBlock()))
    return cleanupScopes[scope].beginBlock();

  // each cleanup block is bracketed by a pair of cleanuppad/cleanupret
  // instructions, any unwinding should also just continue at the next
  // cleanup block, e.g.:
  //
  // cleanuppad:
  //   %0 = cleanuppad within %funclet[]
  //   %frame = nullptr
  //   if (!_d_enter_cleanup(%frame)) br label %cleanupret
  //                                  else br label %copy
  //
  // copy:
  //   invoke _dtor to %cleanupret unwind %unwindTo [ "funclet"(token %0) ]
  //
  // cleanupret:
  //   _d_leave_cleanup(%frame)
  //   cleanupret %0 unwind %unwindTo
  //
  llvm::BasicBlock *cleanupbb = irs.insertBB("cleanuppad");
  auto funcletToken = llvm::ConstantTokenNone::get(irs.context());
  auto cleanuppad =
      llvm::CleanupPadInst::Create(funcletToken, {}, "", cleanupbb);

  llvm::BasicBlock *cleanupret = irs.insertBBAfter(cleanupbb, "cleanupret");

  // preparation to allocate some space on the stack where _d_enter_cleanup
  //  can place an exception frame (but not done here)
  auto frame = getNullPtr(getVoidPtrType());

  auto savedInsertBlock = irs.ir->GetInsertBlock();
  auto savedInsertPoint = irs.ir->GetInsertPoint();
  auto savedDbgLoc = irs.DBuilder.GetCurrentLoc();

  auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
  irs.ir->SetInsertPoint(cleanupret);
  irs.DBuilder.EmitStopPoint(irs.func()->decl->loc);
  irs.ir->CreateCall(endFn, frame,
                     {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
  llvm::CleanupReturnInst::Create(cleanuppad, unwindTo, cleanupret);

  auto copybb = cleanupScopes[scope].runCopying(irs, cleanupbb, cleanupret,
                                                unwindTo, cleanuppad);

  auto beginFn = getRuntimeFunction(Loc(), irs.module, "_d_enter_cleanup");
  irs.ir->SetInsertPoint(cleanupbb);
  irs.DBuilder.EmitStopPoint(irs.func()->decl->loc);
  auto exec = irs.ir->CreateCall(
      beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
  llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);

  irs.ir->SetInsertPoint(savedInsertBlock, savedInsertPoint);
  irs.DBuilder.EmitStopPoint(savedDbgLoc);

  return cleanupbb;
}
Пример #13
0
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
  assert(catchBlocks.empty());

  auto &PGO = irs.funcGen().pgo;
  const auto entryCount = PGO.setCurrentStmt(stmt);

  struct CBPrototype {
    Type *t;
    llvm::BasicBlock *catchBB;
    uint64_t catchCount;
    uint64_t uncaughtCount;
  };
  llvm::SmallVector<CBPrototype, 8> cbPrototypes;
  cbPrototypes.reserve(stmt->catches->dim);

  for (auto c : *stmt->catches) {
    auto catchBB =
        irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
    irs.scope() = IRScope(catchBB);
    irs.DBuilder.EmitBlockStart(c->loc);
    PGO.emitCounterIncrement(c);

    bool isCPPclass = false;

    if (auto lp = c->langPlugin()) // CALYPSO
      lp->codegen()->toBeginCatch(irs, c);
    else
    {

    const auto cd = c->type->toBasetype()->isClassHandle();
    isCPPclass = cd->isCPPclass();

    const auto enterCatchFn = getRuntimeFunction(
        Loc(), irs.module,
        isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch");
    const auto ptr = DtoLoad(ehPtrSlot);
    const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr);

    // For catches that use the Throwable object, create storage for it.
    // We will set it in the code that branches from the landing pads
    // (there might be more than one) to catchBB.
    if (c->var) {
      // This will alloca if we haven't already and take care of nested refs
      // if there are any.
      DtoDeclarationExp(c->var);

      // Copy the exception reference over from the _d_eh_enter_catch return
      // value.
      DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)),
               getIrLocal(c->var)->value);
    }
    }

    // Emit handler, if there is one. The handler is zero, for instance,
    // when building 'catch { debug foo(); }' in non-debug mode.
    if (isCPPclass) {
      // from DMD:

      /* C++ catches need to end with call to __cxa_end_catch().
       * Create:
       *   try { handler } finally { __cxa_end_catch(); }
       * Note that this is worst case code because it always sets up an
       * exception handler. At some point should try to do better.
       */
      FuncDeclaration *fdend =
          FuncDeclaration::genCfunc(nullptr, Type::tvoid, "__cxa_end_catch");
      Expression *efunc = VarExp::create(Loc(), fdend);
      Expression *ecall = CallExp::create(Loc(), efunc);
      ecall->type = Type::tvoid;
      Statement *call = ExpStatement::create(Loc(), ecall);
      Statement *stmt =
          c->handler ? TryFinallyStatement::create(Loc(), c->handler, call)
                     : call;
      Statement_toIR(stmt, &irs);
    } else {
      if (c->handler)
        Statement_toIR(c->handler, &irs);
    }

    if (!irs.scopereturned())
    {
      // CALYPSO FIXME: _cxa_end_catch won't be called if it has already returned
      if (auto lp = c->langPlugin())
        lp->codegen()->toEndCatch(irs, c);
      irs.ir->CreateBr(endbb);
    }

    irs.DBuilder.EmitBlockEnd();

    // PGO information, currently unused
    auto catchCount = PGO.getRegionCount(c);
    // uncaughtCount is handled in a separate pass below

    cbPrototypes.push_back({c->type->toBasetype(), catchBB, catchCount, 0}); // CALYPSO
  }

  // Total number of uncaught exceptions is equal to the execution count at
  // the start of the try block minus the one after the continuation.
  // uncaughtCount keeps track of the exception type mismatch count while
  // iterating through the catch block prototypes in reversed order.
  auto uncaughtCount = entryCount - PGO.getRegionCount(stmt);
  for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end;
       ++it) {
    it->uncaughtCount = uncaughtCount;
    // Add this catch block's match count to the uncaughtCount, because these
    // failed to match the remaining (lexically preceding) catch blocks.
    uncaughtCount += it->catchCount;
  }

  catchBlocks.reserve(stmt->catches->dim);

  auto c_it = stmt->catches->begin(); // CALYPSO
  for (const auto &p : cbPrototypes) {
    auto branchWeights =
        PGO.createProfileWeights(p.catchCount, p.uncaughtCount);
    LLGlobalVariable *ci;
    if (auto lp = (*c_it)->langPlugin()) // CALYPSO
      ci = lp->codegen()->toCatchScopeType(irs, p.t);
    else {
      ClassDeclaration *cd = p.t->isClassHandle();
      DtoResolveClass(cd);
      if (cd->isCPPclass()) {
        const char *name = Target::cppTypeInfoMangle(cd);
        auto cpp_ti = getOrCreateGlobal(
            cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true,
            LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name);

        // Wrap std::type_info pointers inside a __cpp_type_info_ptr class instance so that
        // the personality routine may differentiate C++ catch clauses from D ones.
        OutBuffer mangleBuf;
        mangleBuf.writestring("_D");
        mangleToBuffer(cd, &mangleBuf);
        mangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr");
        const auto wrapperMangle = getIRMangledVarName(mangleBuf.peekString(), LINKd);

        RTTIBuilder b(ClassDeclaration::cpp_type_info_ptr);
        b.push(cpp_ti);

        auto wrapperType = llvm::cast<llvm::StructType>(
            static_cast<IrTypeClass*>(ClassDeclaration::cpp_type_info_ptr->type->ctype)->getMemoryLLType());
        auto wrapperInit = b.get_constant(wrapperType);

        ci = getOrCreateGlobal(
            cd->loc, irs.module, wrapperType, /*isConstant=*/true,
            LLGlobalValue::LinkOnceODRLinkage, wrapperInit, wrapperMangle);
      } else {
        ci = getIrAggr(cd)->getClassInfoSymbol();
      }
    }
    catchBlocks.push_back({ci, p.catchBB, branchWeights});
    c_it++;
  }
}
Пример #14
0
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) {
  assert(catchBlocks.empty());

  auto &PGO = irs.funcGen().pgo;
  const auto entryCount = PGO.setCurrentStmt(stmt);

  struct CBPrototype {
    ClassDeclaration *cd;
    llvm::BasicBlock *catchBB;
    uint64_t catchCount;
    uint64_t uncaughtCount;
  };
  llvm::SmallVector<CBPrototype, 8> cbPrototypes;
  cbPrototypes.reserve(stmt->catches->dim);

  for (auto c : *stmt->catches) {
    auto catchBB =
        irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars());
    irs.scope() = IRScope(catchBB);
    irs.DBuilder.EmitBlockStart(c->loc);
    PGO.emitCounterIncrement(c);

    const auto enterCatchFn =
        getRuntimeFunction(Loc(), irs.module, "_d_eh_enter_catch");
    auto ptr = DtoLoad(ehPtrSlot);
    auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr);

    // For catches that use the Throwable object, create storage for it.
    // We will set it in the code that branches from the landing pads
    // (there might be more than one) to catchBB.
    if (c->var) {
      // This will alloca if we haven't already and take care of nested refs
      // if there are any.
      DtoDeclarationExp(c->var);

      // Copy the exception reference over from the _d_eh_enter_catch return
      // value.
      DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)),
               getIrLocal(c->var)->value);
    }

    // Emit handler, if there is one. The handler is zero, for instance,
    // when building 'catch { debug foo(); }' in non-debug mode.
    if (c->handler)
      Statement_toIR(c->handler, &irs);

    if (!irs.scopereturned())
      irs.ir->CreateBr(endbb);

    irs.DBuilder.EmitBlockEnd();

    // PGO information, currently unused
    auto catchCount = PGO.getRegionCount(c);
    // uncaughtCount is handled in a separate pass below

    auto cd = c->type->toBasetype()->isClassHandle();
    cbPrototypes.push_back({cd, catchBB, catchCount, 0});
  }

  // Total number of uncaught exceptions is equal to the execution count at
  // the start of the try block minus the one after the continuation.
  // uncaughtCount keeps track of the exception type mismatch count while
  // iterating through the catch block prototypes in reversed order.
  auto uncaughtCount = entryCount - PGO.getRegionCount(stmt);
  for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end;
       ++it) {
    it->uncaughtCount = uncaughtCount;
    // Add this catch block's match count to the uncaughtCount, because these
    // failed to match the remaining (lexically preceding) catch blocks.
    uncaughtCount += it->catchCount;
  }

  catchBlocks.reserve(stmt->catches->dim);

  for (const auto &p : cbPrototypes) {
    auto branchWeights =
        PGO.createProfileWeights(p.catchCount, p.uncaughtCount);
    DtoResolveClass(p.cd);
    auto ci = getIrAggr(p.cd)->getClassInfoSymbol();
    catchBlocks.push_back({ci, p.catchBB, branchWeights});
  }
}
Пример #15
0
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
  // resolve type
  DtoResolveClass(tc->sym);

  // allocate
  LLValue *mem;
  bool doInit = true;
  if (newexp->onstack) {
    unsigned alignment = tc->sym->alignsize;
    if (alignment == STRUCTALIGN_DEFAULT)
      alignment = 0;
    mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), alignment,
                       ".newclass_alloca");
  }
  // custom allocator
  else if (newexp->allocator) {
    DtoResolveFunction(newexp->allocator);
    DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator));
    DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs);
    mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom");
  }
  // default allocator
  else {
    const bool useEHAlloc = global.params.ehnogc && newexp->thrownew;
    llvm::Function *fn = getRuntimeFunction(
        loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass");
    LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
                                DtoType(getClassInfoType()));
    mem = gIR->CreateCallOrInvoke(fn, ci,
                                  useEHAlloc ? ".newthrowable_alloc"
                                             : ".newclass_gc_alloc")
              .getInstruction();
    mem = DtoBitCast(mem, DtoType(tc),
                     useEHAlloc ? ".newthrowable" : ".newclass_gc");
    doInit = !useEHAlloc;
  }

  // init
  if (doInit)
    DtoInitClass(tc, mem);

  // init inner-class outer reference
  if (newexp->thisexp) {
    Logger::println("Resolving outer class");
    LOG_SCOPE;
    unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
    LLValue *src = DtoRVal(newexp->thisexp);
    LLValue *dst = DtoGEPi(mem, 0, idx);
    IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
    DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType())));
  }
  // set the context for nested classes
  else if (tc->sym->isNested() && tc->sym->vthis) {
    DtoResolveNestedContext(loc, tc->sym, mem);
  }

  // call constructor
  if (newexp->member) {
    // evaluate argprefix
    if (newexp->argprefix) {
      toElemDtor(newexp->argprefix);
    }

    Logger::println("Calling constructor");
    assert(newexp->arguments != NULL);
    DtoResolveFunction(newexp->member);
    DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem);
    // ignore ctor return value (C++ ctors on Posix may not return `this`)
    DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments);
    return new DImValue(tc, mem);
  }

  assert(newexp->argprefix == NULL);

  // return default constructed class
  return new DImValue(tc, mem);
}
Пример #16
0
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
  // resolve type
  DtoResolveClass(tc->sym);

  // allocate
  LLValue *mem;
  if (newexp->onstack) {
    mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), DtoAlignment(tc),
                       ".newclass_alloca");
  }
  // custom allocator
  else if (newexp->allocator) {
    DtoResolveFunction(newexp->allocator);
    DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator));
    DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs);
    mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom");
  }
  // default allocator
  else {
    llvm::Function *fn =
        getRuntimeFunction(loc, gIR->module, "_d_allocclass");
    LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
                                DtoType(Type::typeinfoclass->type));
    mem =
        gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction();
    mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc");
  }

  // init
  DtoInitClass(tc, mem);

  // init inner-class outer reference
  if (newexp->thisexp) {
    Logger::println("Resolving outer class");
    LOG_SCOPE;
    unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
    LLValue *src = DtoRVal(newexp->thisexp);
    LLValue *dst = DtoGEPi(mem, 0, idx);
    IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
    DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType())));
  }
  // set the context for nested classes
  else if (tc->sym->isNested() && tc->sym->vthis) {
    DtoResolveNestedContext(loc, tc->sym, mem);
  }

  // call constructor
  if (newexp->member) {
    // evaluate argprefix
    if (newexp->argprefix) {
      toElemDtor(newexp->argprefix);
    }

    Logger::println("Calling constructor");
    assert(newexp->arguments != NULL);
    DtoResolveFunction(newexp->member);
    DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem);
    return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments);
  }

  assert(newexp->argprefix == NULL);

  // return default constructed class
  return new DImValue(tc, mem);
}