Esempio n. 1
0
DValue *binAdd(Loc &loc, Type *type, DValue *lhs, Expression *rhs,
               bool loadLhsAfterRhs) {
  Type *lhsType = lhs->type->toBasetype();
  Type *rhsType = rhs->type->toBasetype();

  if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) {
    Logger::println("Adding integer to pointer");
    return emitPointerOffset(loc, lhs, rhs, false, type, loadLhsAfterRhs);
  }

  auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs);

  if (type->ty == Tnull)
    return DtoNullValue(type, loc);
  if (type->iscomplex())
    return DtoComplexAdd(loc, type, rvals.lhs, rvals.rhs);

  LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type));
  LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type));

  if (auto aa = isAssociativeArrayAndNull(type, l, r))
    return aa;

  LLValue *res = (type->isfloating() ? gIR->ir->CreateFAdd(l, r)
                                     : gIR->ir->CreateAdd(l, r));

  return new DImValue(type, res);
}
Esempio n. 2
0
void DtoGetComplexParts(Loc &loc, Type *to, DValue *val, LLValue *&re,
                        LLValue *&im) {
  DValue *dre, *dim;
  DtoGetComplexParts(loc, to, val, dre, dim);
  re = dre ? DtoRVal(dre) : nullptr;
  im = dim ? DtoRVal(dim) : nullptr;
}
Esempio n. 3
0
void DtoGetComplexParts(Loc &loc, Type *to, DValue *val, DValue *&re,
                        DValue *&im) {
  Type *baserety;
  Type *baseimty;
  switch (to->toBasetype()->ty) {
  default:
    llvm_unreachable("Unexpected complex floating point type");
  case Tcomplex32:
    baserety = Type::tfloat32;
    baseimty = Type::timaginary32;
    break;
  case Tcomplex64:
    baserety = Type::tfloat64;
    baseimty = Type::timaginary64;
    break;
  case Tcomplex80:
    baserety = Type::tfloat80;
    baseimty = Type::timaginary80;
    break;
  }

  Type *t = val->type->toBasetype();

  if (t->iscomplex()) {
    DValue *v = DtoCastComplex(loc, val, to);
    if (to->iscomplex()) {
      if (v->isLVal()) {
        LLValue *reVal =
            DtoGEPi(DtoLVal(v), 0, 0, ".re_part");
        LLValue *imVal =
            DtoGEPi(DtoLVal(v), 0, 1, ".im_part");
        re = new DLValue(baserety, reVal);
        im = new DLValue(baseimty, imVal);
      } else {
        LLValue *reVal =
            gIR->ir->CreateExtractValue(DtoRVal(v), 0, ".re_part");
        LLValue *imVal =
            gIR->ir->CreateExtractValue(DtoRVal(v), 1, ".im_part");
        re = new DImValue(baserety, reVal);
        im = new DImValue(baseimty, imVal);
      }
    } else {
      DtoGetComplexParts(loc, to, v, re, im);
    }
  } else if (t->isimaginary()) {
    re = nullptr;
    im = DtoCastFloat(loc, val, baseimty);
  } else if (t->isfloating()) {
    re = DtoCastFloat(loc, val, baserety);
    im = nullptr;
  } else if (t->isintegral()) {
    re = DtoCastInt(loc, val, baserety);
    im = nullptr;
  } else {
    llvm_unreachable("Unexpected numeric type.");
  }
}
Esempio n. 4
0
DValue *binMul(Loc &loc, Type *type, DValue *lhs, Expression *rhs,
               bool loadLhsAfterRhs) {
  auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs);

  if (type->iscomplex())
    return DtoComplexMul(loc, type, rvals.lhs, rvals.rhs);

  LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type));
  LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type));
  LLValue *res = (type->isfloating() ? gIR->ir->CreateFMul(l, r)
                                     : gIR->ir->CreateMul(l, r));

  return new DImValue(type, res);
}
Esempio n. 5
0
LLValue *DtoCallableValue(DValue *fn) {
  Type *type = fn->type->toBasetype();
  if (type->ty == Tfunction) {
    return DtoRVal(fn);
  }
  if (type->ty == Tdelegate) {
    if (fn->isLVal()) {
      LLValue *dg = DtoLVal(fn);
      LLValue *funcptr = DtoGEPi(dg, 0, 1);
      return DtoLoad(funcptr, ".funcptr");
    }
    LLValue *dg = DtoRVal(fn);
    assert(isaStruct(dg));
    return gIR->ir->CreateExtractValue(dg, 1, ".funcptr");
  }

  llvm_unreachable("Not a callable type.");
}
Esempio n. 6
0
 void vaCopy(DLValue *dest, DValue *src) override {
   // Analog to va_start, we first need to allocate a new __va_list struct on
   // the stack and set `dest` to its address.
   LLValue *valistmem = DtoRawAlloca(getValistType(), 0, "__va_list_mem");
   DtoStore(valistmem,
            DtoBitCast(DtoLVal(dest), getPtrToType(valistmem->getType())));
   // Then fill the new struct with a bitcopy of the source struct.
   // `src` is a char* pointer to the source struct.
   DtoMemCpy(valistmem, DtoRVal(src));
 }
Esempio n. 7
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;
}
Esempio n. 8
0
DValue *binMod(Loc &loc, Type *type, DValue *lhs, Expression *rhs,
               bool loadLhsAfterRhs) {
  auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs);

  if (type->iscomplex())
    return DtoComplexMod(loc, type, rvals.lhs, rvals.rhs);

  LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type));
  LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type));
  LLValue *res;
  if (type->isfloating()) {
    res = gIR->ir->CreateFRem(l, r);
  } else if (!isLLVMUnsigned(type)) {
    res = gIR->ir->CreateSRem(l, r);
  } else {
    res = gIR->ir->CreateURem(l, r);
  }

  return new DImValue(type, res);
}
Esempio n. 9
0
DValue *binMin(Loc &loc, Type *type, DValue *lhs, Expression *rhs,
               bool loadLhsAfterRhs) {
  Type *lhsType = lhs->type->toBasetype();
  Type *rhsType = rhs->type->toBasetype();

  if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) {
    Logger::println("Subtracting integer from pointer");
    return emitPointerOffset(loc, lhs, rhs, true, type, loadLhsAfterRhs);
  }

  auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs);

  if (lhsType->ty == Tpointer && rhsType->ty == Tpointer) {
    LLValue *l = DtoRVal(rvals.lhs);
    LLValue *r = DtoRVal(rvals.rhs);
    LLType *llSizeT = DtoSize_t();
    l = gIR->ir->CreatePtrToInt(l, llSizeT);
    r = gIR->ir->CreatePtrToInt(r, llSizeT);
    LLValue *diff = gIR->ir->CreateSub(l, r);
    LLType *llType = DtoType(type);
    if (diff->getType() != llType)
      diff = gIR->ir->CreateIntToPtr(diff, llType);
    return new DImValue(type, diff);
  }

  if (type->ty == Tnull)
    return DtoNullValue(type, loc);
  if (type->iscomplex())
    return DtoComplexMin(loc, type, rvals.lhs, rvals.rhs);

  LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type));
  LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type));

  if (auto aa = isAssociativeArrayAndNull(type, l, r))
    return aa;

  LLValue *res = (type->isfloating() ? gIR->ir->CreateFSub(l, r)
                                     : gIR->ir->CreateSub(l, r));

  return new DImValue(type, res);
}
Esempio n. 10
0
LLValue *DtoBinFloatsEquals(Loc &loc, DValue *lhs, DValue *rhs, TOK op) {
  LLValue *res = nullptr;
  if (op == TOKequal || op == TOKnotequal) {
    LLValue *l = DtoRVal(lhs);
    LLValue *r = DtoRVal(rhs);
    res = (op == TOKequal ? gIR->ir->CreateFCmpOEQ(l, r)
                          : gIR->ir->CreateFCmpUNE(l, r));
    if (lhs->type->toBasetype()->ty == Tvector) {
      res = mergeVectorEquals(res, op);
    }
  } else {
    const auto cmpop =
        op == TOKidentity ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE;
    LLValue *sz = DtoConstSize_t(getTypeStoreSize(DtoType(lhs->type)));
    LLValue *val = DtoMemCmp(makeLValue(loc, lhs), makeLValue(loc, rhs), sz);
    res = gIR->ir->CreateICmp(cmpop, val,
                              LLConstantInt::get(val->getType(), 0, false));
  }
  assert(res);
  return res;
}
Esempio n. 11
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 = DtoRVal(aa);
  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);
}
Esempio n. 12
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 = DtoRVal(aa);
  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());
}
Esempio n. 13
0
void AsmStatement_toIR(InlineAsmStatement *stmt, IRState *irs) {
  IF_LOG Logger::println("InlineAsmStatement::toIR(): %s", stmt->loc.toChars());
  LOG_SCOPE;

  // sanity check
  assert(irs->func()->decl->hasReturnExp & 8);

  // get asm block
  IRAsmBlock *asmblock = irs->asmBlock;
  assert(asmblock);

  // debug info
  gIR->DBuilder.EmitStopPoint(stmt->loc);

  if (!stmt->asmcode) {
    return;
  }

  static std::string i_cns = "i";
  static std::string p_cns = "i";
  static std::string m_cns = "*m";
  static std::string mw_cns = "=*m";
  static std::string mrw_cns = "+*m";
  static std::string memory_name = "memory";

  AsmCode *code = static_cast<AsmCode *>(stmt->asmcode);
  std::vector<LLValue *> input_values;
  std::vector<std::string> input_constraints;
  std::vector<LLValue *> output_values;
  std::vector<std::string> output_constraints;
  std::vector<std::string> clobbers;

  // FIXME
  //#define HOST_WIDE_INT long
  // HOST_WIDE_INT var_frame_offset; // "frame_offset" is a macro
  bool clobbers_mem = code->clobbersMemory;
  int input_idx = 0;
  int n_outputs = 0;
  int arg_map[10];

  assert(code->args.size() <= 10);

  auto arg = code->args.begin();
  for (unsigned i = 0; i < code->args.size(); i++, ++arg) {
    bool is_input = true;
    LLValue *arg_val = nullptr;
    std::string cns;

    switch (arg->type) {
    case Arg_Integer:
      arg_val = DtoRVal(arg->expr);
    do_integer:
      cns = i_cns;
      break;
    case Arg_Pointer:
      assert(arg->expr->op == TOKvar);
      arg_val = DtoRVal(arg->expr);
      cns = p_cns;

      break;
    case Arg_Memory:
      arg_val = DtoRVal(arg->expr);

      switch (arg->mode) {
      case Mode_Input:
        cns = m_cns;
        break;
      case Mode_Output:
        cns = mw_cns;
        is_input = false;
        break;
      case Mode_Update:
        cns = mrw_cns;
        is_input = false;
        break;
      }
      break;
    case Arg_FrameRelative:
      // FIXME
      llvm_unreachable("Arg_FrameRelative not supported.");
    /*          if (arg->expr->op == TOKvar)
                    arg_val = ((VarExp *) arg->expr)->var->toSymbol()->Stree;
                else
                    assert(0);
                if ( getFrameRelativeValue(arg_val, & var_frame_offset) ) {
    //              arg_val = irs->integerConstant(var_frame_offset);
                    cns = i_cns;
                } else {
                    this->error("%s", "argument not frame relative");
                    return;
                }
                if (arg->mode != Mode_Input)
                    clobbers_mem = true;
                break;*/
    case Arg_LocalSize:
      // FIXME
      llvm_unreachable("Arg_LocalSize not supported.");
      /*          var_frame_offset = cfun->x_frame_offset;
                  if (var_frame_offset < 0)
                      var_frame_offset = - var_frame_offset;
                  arg_val = irs->integerConstant( var_frame_offset );*/
      goto do_integer;
    default:
      llvm_unreachable("Unknown inline asm reference type.");
    }

    if (is_input) {
      arg_map[i] = --input_idx;
      input_values.push_back(arg_val);
      input_constraints.push_back(cns);
    } else {
      arg_map[i] = n_outputs++;
      output_values.push_back(arg_val);
      output_constraints.push_back(cns);
    }
  }

  // Telling GCC that callee-saved registers are clobbered makes it preserve
  // those registers.   This changes the stack from what a naked function
  // expects.

  // FIXME
  //    if (! irs->func->naked) {
  assert(asmparser);
  for (size_t i = 0; i < code->regs.size(); i++) {
    if (code->regs[i]) {
      clobbers.push_back(asmparser->getRegName(i));
    }
  }
  if (clobbers_mem) {
    clobbers.push_back(memory_name);
  }
  //    }

  // Remap argument numbers
  for (unsigned i = 0; i < code->args.size(); i++) {
    if (arg_map[i] < 0) {
      arg_map[i] = -arg_map[i] - 1 + n_outputs;
    }
  }

  bool pct = false;
  auto p = code->insnTemplate.begin();
  auto q = code->insnTemplate.end();
  // printf("start: %.*s\n", code->insnTemplateLen, code->insnTemplate);
  while (p < q) {
    if (pct) {
      if (*p >= '0' && *p <= '9') {
        // %% doesn't check against nargs
        *p = '0' + arg_map[*p - '0'];
        pct = false;
      } else if (*p == '$') {
        pct = false;
      }
      // assert(*p == '%');// could be 'a', etc. so forget it..
    } else if (*p == '$') {
      pct = true;
    }
    ++p;
  }

  IF_LOG {
    Logger::cout() << "final asm: " << code->insnTemplate << '\n';
    std::ostringstream ss;

    ss << "GCC-style output constraints: {";
    for (const auto &oc : output_constraints) {
      ss << " " << oc;
    }
    ss << " }";
    Logger::println("%s", ss.str().c_str());

    ss.str("");
    ss << "GCC-style input constraints: {";
    for (const auto &ic : input_constraints) {
      ss << " " << ic;
    }
    ss << " }";
    Logger::println("%s", ss.str().c_str());

    ss.str("");
    ss << "GCC-style clobbers: {";
    for (const auto &c : clobbers) {
      ss << " " << c;
    }
    ss << " }";
    Logger::println("%s", ss.str().c_str());
  }

  // rewrite GCC-style constraints to LLVM-style constraints
  std::string llvmOutConstraints;
  std::string llvmInConstraints;
  int n = 0;
  for (auto &oc : output_constraints) {
    // rewrite update constraint to in and out constraints
    if (oc[0] == '+') {
      assert(oc == mrw_cns && "What else are we updating except memory?");
      /* LLVM doesn't support updating operands, so split into an input
       * and an output operand.
       */

      // Change update operand to pure output operand.
      oc = mw_cns;

      // Add input operand with same value, with original as "matching output".
      std::ostringstream ss;
      ss << '*' << (n + asmblock->outputcount);
      // Must be at the back; unused operands before used ones screw up
      // numbering.
      input_constraints.push_back(ss.str());
      input_values.push_back(output_values[n]);
    }
    llvmOutConstraints += oc;
    llvmOutConstraints += ",";
    n++;
  }
  asmblock->outputcount += n;

  for (const auto &ic : input_constraints) {
    llvmInConstraints += ic;
    llvmInConstraints += ",";
  }

  std::string clobstr;
  for (const auto &c : clobbers) {
    clobstr = "~{" + c + "},";
    asmblock->clobs.insert(clobstr);
  }

  IF_LOG {
    {
      Logger::println("Output values:");
      LOG_SCOPE
      size_t i = 0;
      for (auto ov : output_values) {
        Logger::cout() << "Out " << i++ << " = " << *ov << '\n';
      }
    }
    {
      Logger::println("Input values:");
      LOG_SCOPE
      size_t i = 0;
      for (auto iv : input_values) {
        Logger::cout() << "In  " << i++ << " = " << *iv << '\n';
      }
    }
  }

  // excessive commas are removed later...

  replace_func_name(irs, code->insnTemplate);

  // push asm statement
  auto asmStmt = new IRAsmStmt;
  asmStmt->code = code->insnTemplate;
  asmStmt->out_c = llvmOutConstraints;
  asmStmt->in_c = llvmInConstraints;
  asmStmt->out.insert(asmStmt->out.begin(), output_values.begin(),
                      output_values.end());
  asmStmt->in.insert(asmStmt->in.begin(), input_values.begin(),
                     input_values.end());
  asmStmt->isBranchToLabel = stmt->isBranchToLabel;
  asmblock->s.push_back(asmStmt);
}
Esempio n. 14
0
DLValue *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 ? DtoLVal(aa) : DtoRVal(aa);
  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(getTypeAllocSize(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 *okbb = gIR->insertBB("aaboundsok");
    llvm::BasicBlock *failbb = gIR->insertBBAfter(okbb, "aaboundscheckfail");

    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 DLValue(type, ret);
}
Esempio n. 15
0
DValue *DtoCastComplex(Loc &loc, DValue *val, Type *_to) {
  Type *to = _to->toBasetype();
  Type *vty = val->type->toBasetype();
  if (to->iscomplex()) {
    if (vty->size() == to->size()) {
      return val;
    }

    llvm::Value *re, *im;
    DtoGetComplexParts(loc, val->type, val, re, im);
    LLType *toty = DtoComplexBaseType(to);

    if (to->size() < vty->size()) {
      re = gIR->ir->CreateFPTrunc(re, toty);
      im = gIR->ir->CreateFPTrunc(im, toty);
    } else {
      re = gIR->ir->CreateFPExt(re, toty);
      im = gIR->ir->CreateFPExt(im, toty);
    }

    LLValue *pair = DtoAggrPair(DtoType(_to), re, im);
    return new DImValue(_to, pair);
  }
  if (to->isimaginary()) {
    // FIXME: this loads both values, even when we only need one
    LLValue *v = DtoRVal(val);
    LLValue *impart = gIR->ir->CreateExtractValue(v, 1, ".im_part");
    Type *extractty;
    switch (vty->ty) {
    default:
      llvm_unreachable("Unexpected complex floating point type");
    case Tcomplex32:
      extractty = Type::timaginary32;
      break;
    case Tcomplex64:
      extractty = Type::timaginary64;
      break;
    case Tcomplex80:
      extractty = Type::timaginary80;
      break;
    }
    auto im = new DImValue(extractty, impart);
    return DtoCastFloat(loc, im, to);
  }
  if (to->ty == Tbool) {
    return new DImValue(
        _to, DtoComplexEquals(loc, TOKnotequal, val, DtoNullValue(vty)));
  }
  if (to->isfloating() || to->isintegral()) {
    // FIXME: this loads both values, even when we only need one
    LLValue *v = DtoRVal(val);
    LLValue *repart = gIR->ir->CreateExtractValue(v, 0, ".re_part");
    Type *extractty;
    switch (vty->ty) {
    default:
      llvm_unreachable("Unexpected complex floating point type");
    case Tcomplex32:
      extractty = Type::tfloat32;
      break;
    case Tcomplex64:
      extractty = Type::tfloat64;
      break;
    case Tcomplex80:
      extractty = Type::tfloat80;
      break;
    }
    auto re = new DImValue(extractty, repart);
    return DtoCastFloat(loc, re, to);
  }
  error(loc, "Don't know how to cast %s to %s", vty->toChars(), to->toChars());
  fatal();
}
Esempio n. 16
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);
}
Esempio n. 17
0
DValue *DtoCastClass(Loc &loc, DValue *val, Type *_to) {
  IF_LOG Logger::println("DtoCastClass(%s, %s)", val->type->toChars(),
                         _to->toChars());
  LOG_SCOPE;

  Type *to = _to->toBasetype();

  // class -> pointer
  if (to->ty == Tpointer) {
    IF_LOG Logger::println("to pointer");
    LLType *tolltype = DtoType(_to);
    LLValue *rval = DtoBitCast(DtoRVal(val), tolltype);
    return new DImValue(_to, rval);
  }
  // class -> bool
  if (to->ty == Tbool) {
    IF_LOG Logger::println("to bool");
    LLValue *llval = DtoRVal(val);
    LLValue *zero = LLConstant::getNullValue(llval->getType());
    return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero));
  }
  // class -> integer
  if (to->isintegral()) {
    IF_LOG Logger::println("to %s", to->toChars());

    // get class ptr
    LLValue *v = DtoRVal(val);
    // cast to size_t
    v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), "");
    // cast to the final int type
    DImValue im(Type::tsize_t, v);
    return DtoCastInt(loc, &im, _to);
  }
  // class -> typeof(null)
  if (to->ty == Tnull) {
    IF_LOG Logger::println("to %s", to->toChars());
    return new DImValue(_to, LLConstant::getNullValue(DtoType(_to)));
  }

  // must be class/interface
  assert(to->ty == Tclass);
  TypeClass *tc = static_cast<TypeClass *>(to);

  // from type
  Type *from = val->type->toBasetype();
  TypeClass *fc = static_cast<TypeClass *>(from);

  // copy DMD logic:
  // if to isBaseOf from with offset:   (to ? to + offset : null)
  // else if from is C++ and to is C++:  to
  // else if from is C++ and to is D:    null
  // else if from is interface:          _d_interface_cast(to)
  // else if from is class:              _d_dynamic_cast(to)

  LLType *toType = DtoType(_to);
  int offset = 0;
  if (tc->sym->isBaseOf(fc->sym, &offset)) {
    Logger::println("static down cast");
    // interface types don't cover the full object in case of multiple inheritence
    //  so GEP on the original type is inappropriate

    // offset pointer
    LLValue *orig = DtoRVal(val);
    LLValue *v = orig;
    if (offset != 0) {
      v = DtoBitCast(v, getVoidPtrType());
      LLValue *off =
          LLConstantInt::get(LLType::getInt32Ty(gIR->context()), offset);
      v = gIR->ir->CreateGEP(v, off);
    }
    IF_LOG {
      Logger::cout() << "V = " << *v << std::endl;
      Logger::cout() << "T = " << *toType << std::endl;
    }
    v = DtoBitCast(v, toType);

    // Check whether the original value was null, and return null if so.
    // Sure we could have jumped over the code above in this case, but
    // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it
    // should be pretty cheap and perfectly safe even if the original was
    // null.
    LLValue *isNull = gIR->ir->CreateICmpEQ(
        orig, LLConstant::getNullValue(orig->getType()), ".nullcheck");
    v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(toType), v,
                              ".interface");
    // return r-value
    return new DImValue(_to, v);
  }
Esempio n. 18
0
 LLValue *prepareVaArg(DLValue *ap) override {
   // Pass a i8* pointer to the actual __va_list struct to LLVM's va_arg
   // intrinsic.
   return DtoRVal(ap);
 }
Esempio n. 19
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);
}