Beispiel #1
0
 void vaCopy(LLValue* pDest, LLValue* src) {
     // Analog to va_start, we need to allocate a new __va_list struct on the stack,
     // fill it with a bitcopy of the source struct...
     src = DtoLoad(DtoBitCast(src, getValistType()->getPointerTo())); // *(__va_list*)src
     LLValue* valistmem = DtoAllocaDump(src, 0, "__va_list_mem");
     // ... and finally set the passed 'dest' char* pointer to the new struct's address.
     DtoStore(DtoBitCast(valistmem, getVoidPtrType()),
         DtoBitCast(pDest, getPtrToType(getVoidPtrType())));
 }
Beispiel #2
0
 LLValue *get(Type *dty, LLValue *v) override {
   LLValue *address = DtoAllocaDump(v, dty, ".X86_64_C_struct_rewrite_dump");
   LLType *type = DtoType(dty);
   return loadFromMemory(address, type, ".X86_64_C_struct_rewrite_getResult");
 }
Beispiel #3
0
void CompoundAsmStatement_toIR(CompoundAsmStatement *stmt, IRState *p) {
  IF_LOG Logger::println("CompoundAsmStatement::toIR(): %s",
                         stmt->loc.toChars());
  LOG_SCOPE;

  // disable inlining by default
  if (!p->func()->decl->allowInlining) {
    p->func()->setNeverInline();
  }

  // create asm block structure
  assert(!p->asmBlock);
  auto asmblock = new IRAsmBlock(stmt);
  assert(asmblock);
  p->asmBlock = asmblock;

  // do asm statements
  for (unsigned i = 0; i < stmt->statements->dim; i++) {
    if (Statement *s = (*stmt->statements)[i]) {
      Statement_toIR(s, p);
    }
  }

  // build forwarder for in-asm branches to external labels
  // this additional asm code sets the __llvm_jump_target variable
  // to a unique value that will identify the jump target in
  // a post-asm switch

  // maps each goto destination to its special value
  std::map<LabelDsymbol *, int> gotoToVal;

  // location of the special value determining the goto label
  // will be set if post-asm dispatcher block is needed
  LLValue *jump_target = nullptr;

  {
    FuncDeclaration *fd = gIR->func()->decl;
    OutBuffer mangleBuf;
    mangleToBuffer(fd, &mangleBuf);
    const char *fdmangle = mangleBuf.peekString();

    // we use a simple static counter to make sure the new end labels are unique
    static size_t uniqueLabelsId = 0;
    std::ostringstream asmGotoEndLabel;
    printLabelName(asmGotoEndLabel, fdmangle, "_llvm_asm_end");
    asmGotoEndLabel << uniqueLabelsId++;

    // initialize the setter statement we're going to build
    auto outSetterStmt = new IRAsmStmt;
    std::string asmGotoEnd = "\n\tjmp " + asmGotoEndLabel.str() + "\n";
    std::ostringstream code;
    code << asmGotoEnd;

    int n_goto = 1;

    size_t n = asmblock->s.size();
    for (size_t i = 0; i < n; ++i) {
      IRAsmStmt *a = asmblock->s[i];

      // skip non-branch statements
      if (!a->isBranchToLabel) {
        continue;
      }

      // if internal, no special handling is necessary, skip
      std::vector<Identifier *>::const_iterator it, end;
      end = asmblock->internalLabels.end();
      bool skip = false;
      for (auto il : asmblock->internalLabels) {
        if (il->equals(a->isBranchToLabel->ident)) {
          skip = true;
        }
      }
      if (skip) {
        continue;
      }

      // if we already set things up for this branch target, skip
      if (gotoToVal.find(a->isBranchToLabel) != gotoToVal.end()) {
        continue;
      }

      // record that the jump needs to be handled in the post-asm dispatcher
      gotoToVal[a->isBranchToLabel] = n_goto;

      // provide an in-asm target for the branch and set value
      IF_LOG Logger::println(
          "statement '%s' references outer label '%s': creating forwarder",
          a->code.c_str(), a->isBranchToLabel->ident->toChars());
      printLabelName(code, fdmangle, a->isBranchToLabel->ident->toChars());
      code << ":\n\t";
      code << "movl $<<in" << n_goto << ">>, $<<out0>>\n";
      // FIXME: Store the value -> label mapping somewhere, so it can be
      // referenced later
      outSetterStmt->in.push_back(DtoConstUint(n_goto));
      outSetterStmt->in_c += "i,";
      code << asmGotoEnd;

      ++n_goto;
    }
    if (code.str() != asmGotoEnd) {
      // finalize code
      outSetterStmt->code = code.str();
      outSetterStmt->code += asmGotoEndLabel.str() + ":\n";

      // create storage for and initialize the temporary
      jump_target = DtoAllocaDump(DtoConstUint(0), 0, "__llvm_jump_target");
      // setup variable for output from asm
      outSetterStmt->out_c = "=*m,";
      outSetterStmt->out.push_back(jump_target);

      asmblock->s.push_back(outSetterStmt);
    } else {
      delete outSetterStmt;
    }
  }

  // build a fall-off-end-properly asm statement

  FuncDeclaration *thisfunc = p->func()->decl;
  bool useabiret = false;
  p->asmBlock->asmBlock->abiret = nullptr;
  if (thisfunc->fbody->endsWithAsm() == stmt &&
      thisfunc->type->nextOf()->ty != Tvoid) {
    // there can't be goto forwarders in this case
    assert(gotoToVal.empty());
    emitABIReturnAsmStmt(asmblock, stmt->loc, thisfunc);
    useabiret = true;
  }

  // build asm block
  std::vector<LLValue *> outargs;
  std::vector<LLValue *> inargs;
  std::vector<LLType *> outtypes;
  std::vector<LLType *> intypes;
  std::string out_c;
  std::string in_c;
  std::string clobbers;
  std::string code;
  size_t asmIdx = asmblock->retn;

  Logger::println("do outputs");
  size_t n = asmblock->s.size();
  for (size_t i = 0; i < n; ++i) {
    IRAsmStmt *a = asmblock->s[i];
    assert(a);
    size_t onn = a->out.size();
    for (size_t j = 0; j < onn; ++j) {
      outargs.push_back(a->out[j]);
      outtypes.push_back(a->out[j]->getType());
    }
    if (!a->out_c.empty()) {
      out_c += a->out_c;
    }
    remap_outargs(a->code, onn + a->in.size(), asmIdx);
    asmIdx += onn;
  }

  Logger::println("do inputs");
  for (size_t i = 0; i < n; ++i) {
    IRAsmStmt *a = asmblock->s[i];
    assert(a);
    size_t inn = a->in.size();
    for (size_t j = 0; j < inn; ++j) {
      inargs.push_back(a->in[j]);
      intypes.push_back(a->in[j]->getType());
    }
    if (!a->in_c.empty()) {
      in_c += a->in_c;
    }
    remap_inargs(a->code, inn + a->out.size(), asmIdx);
    asmIdx += inn;
    if (!code.empty()) {
      code += "\n\t";
    }
    code += a->code;
  }
  asmblock->s.clear();

  // append inputs
  out_c += in_c;

  // append clobbers
  for (const auto &c : asmblock->clobs) {
    out_c += c;
  }

  // remove excessive comma
  if (!out_c.empty()) {
    out_c.resize(out_c.size() - 1);
  }

  IF_LOG {
    Logger::println("code = \"%s\"", code.c_str());
    Logger::println("constraints = \"%s\"", out_c.c_str());
  }

  // build return types
  LLType *retty;
  if (asmblock->retn) {
    retty = asmblock->retty;
  } else {
    retty = llvm::Type::getVoidTy(gIR->context());
  }

  // build argument types
  std::vector<LLType *> types;
  types.insert(types.end(), outtypes.begin(), outtypes.end());
  types.insert(types.end(), intypes.begin(), intypes.end());
  llvm::FunctionType *fty = llvm::FunctionType::get(retty, types, false);
  IF_LOG Logger::cout() << "function type = " << *fty << '\n';

  std::vector<LLValue *> args;
  args.insert(args.end(), outargs.begin(), outargs.end());
  args.insert(args.end(), inargs.begin(), inargs.end());

  IF_LOG {
    Logger::cout() << "Arguments:" << '\n';
    Logger::indent();
    size_t i = 0;
    for (auto arg : args) {
      Stream cout = Logger::cout();
      cout << '$' << i << " ==> " << *arg;
      if (!llvm::isa<llvm::Instruction>(arg) &&
          !llvm::isa<LLGlobalValue>(arg)) {
        cout << '\n';
      }
      ++i;
    }
    Logger::undent();
  }

  llvm::InlineAsm *ia = llvm::InlineAsm::get(fty, code, out_c, true);

  llvm::CallInst *call = p->ir->CreateCall(
      ia, args, retty == LLType::getVoidTy(gIR->context()) ? "" : "asm");

  IF_LOG Logger::cout() << "Complete asm statement: " << *call << '\n';

  // capture abi return value
  if (useabiret) {
    IRAsmBlock *block = p->asmBlock;
    if (block->retfixup) {
      block->asmBlock->abiret = (*block->retfixup)(p->ir, call);
    } else if (p->asmBlock->retemu) {
      block->asmBlock->abiret = DtoLoad(block->asmBlock->abiret);
    } else {
      block->asmBlock->abiret = call;
    }
  }

  p->asmBlock = nullptr;

  // if asm contained external branches, emit goto forwarder code
  if (!gotoToVal.empty()) {
    assert(jump_target);

    // make new blocks
    llvm::BasicBlock *bb = p->insertBB("afterasmgotoforwarder");

    llvm::LoadInst *val =
        p->ir->CreateLoad(jump_target, "__llvm_jump_target_value");
    llvm::SwitchInst *sw = p->ir->CreateSwitch(val, bb, gotoToVal.size());

    // add all cases
    for (const auto &pair : gotoToVal) {
      llvm::BasicBlock *casebb = p->insertBBBefore(bb, "case");
      sw->addCase(LLConstantInt::get(llvm::IntegerType::get(gIR->context(), 32),
                                     pair.second),
                  casebb);

      p->scope() = IRScope(casebb);
      DtoGoto(stmt->loc, pair.first);
    }

    p->scope() = IRScope(bb);
  }
}
Beispiel #4
0
 LLValue *getLVal(Type *dty, LLValue *v) override {
   return DtoAllocaDump(v, dty, ".X86_64_C_struct_rewrite_dump");
 }