Example #1
0
    void rewriteArgument(IrFuncTy& fty, IrFuncTyArg& arg)
    {
        Type* ty = arg.type->toBasetype();

        if (ty->ty == Tstruct || ty->ty == Tsarray)
        {
            if (canRewriteAsInt(ty))
            {
                arg.rewrite = &integerRewrite;
                arg.ltype = integerRewrite.type(arg.type, arg.ltype);
            }
            else
            {
                // these types are passed byval:
                // the caller allocates a copy and then passes a pointer to the copy
                arg.rewrite = &byvalRewrite;
                arg.ltype = byvalRewrite.type(arg.type, arg.ltype);

                // the copy is treated as a local variable of the callee
                // hence add the NoAlias and NoCapture attributes
                arg.attrs.clear()
                         .add(LDC_ATTRIBUTE(NoAlias))
                         .add(LDC_ATTRIBUTE(NoCapture));
            }
        }
    }
Example #2
0
void Win64TargetABI::rewriteArgument(IrFuncTy& fty, IrFuncTyArg& arg)
{
    LLType* originalLType = arg.ltype;
    Type* t = arg.type->toBasetype();

    if (isPassedWithByvalSemantics(t))
    {
        // these types are passed byval:
        // the caller allocates a copy and then passes a pointer to the copy
        arg.rewrite = &byvalRewrite;
        arg.ltype = byvalRewrite.type(arg.type, arg.ltype);

        // the copy is treated as a local variable of the callee
        // hence add the NoAlias and NoCapture attributes
        arg.attrs.clear()
                 .add(LDC_ATTRIBUTE(NoAlias))
                 .add(LDC_ATTRIBUTE(NoCapture));
    }
    else if (isAggregate(t) && canRewriteAsInt(t) && !IntegerRewrite::isObsoleteFor(originalLType))
    {
        arg.rewrite = &integerRewrite;
        arg.ltype = integerRewrite.type(arg.type, arg.ltype);
    }

    IF_LOG if (arg.rewrite)
    {
        Logger::println("Rewriting argument type %s", t->toChars());
        LOG_SCOPE;
        Logger::cout() << *originalLType << " => " << *arg.ltype << '\n';
    }
}
Example #3
0
  void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override {
    Type *retTy = fty.ret->type->toBasetype();
    if (!fty.ret->byref && retTy->ty == Tstruct) {
      // Rewrite HFAs only because union HFAs are turned into IR types that are
      // non-HFA and messes up register selection
      if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) {
        fty.ret->rewrite = &hfaToArray;
        fty.ret->ltype = hfaToArray.type(fty.ret->type);
      }
      else {
        fty.ret->rewrite = &integerRewrite;
        fty.ret->ltype = integerRewrite.type(fty.ret->type);
      }
    }

    for (auto arg : fty.args) {
      if (!arg->byref)
        rewriteArgument(fty, *arg);
    }

    // extern(D): reverse parameter order for non variadics, for DMD-compliance
    if (tf->linkage == LINKd && tf->varargs != 1 && fty.args.size() > 1) {
      fty.reverseParams = true;
    }
  }
Example #4
0
  void rewriteFunctionType(IrFuncTy &fty) override {
    Type *retTy = fty.ret->type->toBasetype();
    if (!fty.ret->byref && retTy->ty == Tstruct) {
      // Rewrite HFAs only because union HFAs are turned into IR types that are
      // non-HFA and messes up register selection
      if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) {
        hfaToArray.applyTo(*fty.ret, fty.ret->ltype);
      } else {
        integerRewrite.applyTo(*fty.ret);
      }
    }

    for (auto arg : fty.args) {
      if (!arg->byref)
        rewriteArgument(fty, *arg);
    }
  }
Example #5
0
 void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override {
   Type *ty = arg.type->toBasetype();
   if (ty->ty == Tstruct || ty->ty == Tsarray) {
     if (ty->ty == Tstruct && isHFA((TypeStruct *)ty, &arg.ltype, 8)) {
       arg.rewrite = &hfaToArray;
       arg.ltype = hfaToArray.type(arg.type);
     } else if (canRewriteAsInt(ty, true)) {
       arg.rewrite = &integerRewrite;
       arg.ltype = integerRewrite.type(arg.type);
     } else {
       arg.rewrite = &compositeToArray64;
       arg.ltype = compositeToArray64.type(arg.type);
     }
   } else if (ty->isintegral()) {
     arg.attrs.add(ty->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt);
   }
 }
Example #6
0
  void rewriteFunctionType(TypeFunction *tf, IrFuncTy &fty) override {
    Type *retTy = fty.ret->type->toBasetype();
    if (!fty.ret->byref && retTy->ty == Tstruct) {
      // Rewrite HFAs only because union HFAs are turned into IR types that are
      // non-HFA and messes up register selection
      if (isHFA((TypeStruct *)retTy, &fty.ret->ltype)) {
        fty.ret->rewrite = &hfaToArray;
        fty.ret->ltype = hfaToArray.type(fty.ret->type);
      }
      else {
        fty.ret->rewrite = &integerRewrite;
        fty.ret->ltype = integerRewrite.type(fty.ret->type);
      }
    }

    for (auto arg : fty.args) {
      if (!arg->byref)
        rewriteArgument(fty, *arg);
      else if (passByVal(arg->type))
        arg->attrs.remove(LLAttribute::ByVal);
    }
  }
Example #7
0
  void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override {
    Type *ty = arg.type->toBasetype();

    if (ty->ty == Tstruct || ty->ty == Tsarray) {
      if (canRewriteAsInt(ty, Is64Bit)) {
        if (!IntegerRewrite::isObsoleteFor(arg.ltype)) {
          arg.rewrite = &integerRewrite;
          arg.ltype = integerRewrite.type(arg.type, arg.ltype);
        }
      } else {
        // these types are passed byval:
        // the caller allocates a copy and then passes a pointer to the copy
        arg.rewrite = &byvalRewrite;
        arg.ltype = byvalRewrite.type(arg.type, arg.ltype);

        // the copy is treated as a local variable of the callee
        // hence add the NoAlias and NoCapture attributes
        arg.attrs.clear()
            .add(LLAttribute::NoAlias)
            .add(LLAttribute::NoCapture)
            .addAlignment(byvalRewrite.alignment(arg.type));
      }
    }
  }
Example #8
0
  void rewriteFunctionType(IrFuncTy &fty) override {
    const bool externD = (fty.type->linkage == LINKd &&
                          fty.type->parameterList.varargs != VARARGvariadic);

    // return value:
    if (!fty.ret->byref) {
      Type *rt = fty.type->next->toBasetype(); // for sret, rt == void
      if (isAggregate(rt) && !isMagicCppStruct(rt) && canRewriteAsInt(rt) &&
          // don't rewrite cfloat for extern(D)
          !(externD && rt->ty == Tcomplex32)) {
        integerRewrite.applyToIfNotObsolete(*fty.ret);
      }
    }

    // extern(D): try passing an argument in EAX
    if (externD) {

      // try an implicit argument...
      if (fty.arg_this) {
        Logger::println("Putting 'this' in register");
        fty.arg_this->attrs.addAttribute(LLAttribute::InReg);
      } else if (fty.arg_nest) {
        Logger::println("Putting context ptr in register");
        fty.arg_nest->attrs.addAttribute(LLAttribute::InReg);
      } else if (IrFuncTyArg *sret = fty.arg_sret) {
        Logger::println("Putting sret ptr in register");
        // sret and inreg are incompatible, but the ABI requires the
        // sret parameter to be in EAX in this situation...
        sret->attrs.removeAttribute(LLAttribute::StructRet);
        sret->attrs.addAttribute(LLAttribute::InReg);
      }

      // ... otherwise try the last argument
      else if (!fty.args.empty()) {
        // The last parameter is passed in EAX rather than being pushed on the
        // stack if the following conditions are met:
        //   * It fits in EAX.
        //   * It is not a 3 byte struct.
        //   * It is not a floating point type.

        IrFuncTyArg *last = fty.args.back();
        Type *lastTy = last->type->toBasetype();
        unsigned sz = lastTy->size();

        if (last->byref && !last->isByVal()) {
          Logger::println("Putting last (byref) parameter in register");
          last->attrs.addAttribute(LLAttribute::InReg);
        } else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) {
          // rewrite aggregates as integers to make inreg work
          if (lastTy->ty == Tstruct || lastTy->ty == Tsarray) {
            integerRewrite.applyTo(*last);
            // undo byval semantics applied via passByVal() returning true
            last->byref = false;
            last->attrs.clear();
          }
          last->attrs.addAttribute(LLAttribute::InReg);
        }
      }

      // all other arguments are passed on the stack, don't rewrite
    }
    // extern(C++) on Posix: non-POD args are passed indirectly by-value
    else if (!isMSVC && fty.type->linkage == LINKcpp) {
      for (auto arg : fty.args) {
        if (!arg->byref && !isPOD(arg->type))
          indirectByvalRewrite.applyTo(*arg);
      }
    }

    workaroundIssue1356(fty.args);

    // Clang does not pass empty structs, while it seems that GCC does,
    // at least on Linux x86. We don't know whether the C compiler will
    // be Clang or GCC, so just assume Clang on OS X and G++ on Linux.
    if (externD || !isOSX)
      return;

    size_t i = 0;
    while (i < fty.args.size()) {
      Type *type = fty.args[i]->type->toBasetype();
      if (type->ty == Tstruct) {
        // Do not pass empty structs at all for C++ ABI compatibility.
        // Tests with clang reveal that more complex "empty" types, for
        // example a struct containing an empty struct, are not
        // optimized in the same way.
        auto sd = static_cast<TypeStruct *>(type)->sym;
        if (sd->fields.empty()) {
          fty.args.erase(fty.args.begin() + i);
          continue;
        }
      }
      ++i;
    }
  }
Example #9
0
    void rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
    {
        // extern(D)
        if (tf->linkage == LINKd)
        {
            // IMPLICIT PARAMETERS

            // mark this/nested params inreg
            if (fty.arg_this)
            {
                Logger::println("Putting 'this' in register");
                fty.arg_this->attrs.clear()
                                   .add(LDC_ATTRIBUTE(InReg));
            }
            else if (fty.arg_nest)
            {
                Logger::println("Putting context ptr in register");
                fty.arg_nest->attrs.clear()
                                   .add(LDC_ATTRIBUTE(InReg));
            }
            else if (IrFuncTyArg* sret = fty.arg_sret)
            {
                Logger::println("Putting sret ptr in register");
                // sret and inreg are incompatible, but the ABI requires the
                // sret parameter to be in EAX in this situation...
                sret->attrs.add(LDC_ATTRIBUTE(InReg)).remove(LDC_ATTRIBUTE(StructRet));
            }
            // otherwise try to mark the last param inreg
            else if (!fty.args.empty())
            {
                // The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met:
                //   * It fits in EAX.
                //   * It is not a 3 byte struct.
                //   * It is not a floating point type.

                IrFuncTyArg* last = fty.args.back();
                Type* lastTy = last->type->toBasetype();
                unsigned sz = lastTy->size();

                if (last->byref && !last->isByVal())
                {
                    Logger::println("Putting last (byref) parameter in register");
                    last->attrs.add(LDC_ATTRIBUTE(InReg));
                }
                else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) // right?
                {
                    // rewrite the struct into an integer to make inreg work
                    if (lastTy->ty == Tstruct || lastTy->ty == Tsarray)
                    {
                        last->rewrite = &integerRewrite;
                        last->ltype = integerRewrite.type(last->type, last->ltype);
                        last->byref = false;
                        // erase previous attributes
                        last->attrs.clear();
                    }
                    last->attrs.add(LDC_ATTRIBUTE(InReg));
                }
            }

            // FIXME: tf->varargs == 1 need to use C calling convention and vararg mechanism to live up to the spec:
            // "The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee."

            // EXPLICIT PARAMETERS

            // reverse parameter order
            // for non variadics
            if (!fty.args.empty() && tf->varargs != 1)
            {
                fty.reverseParams = true;
            }
        }

        // extern(C) and all others
        else
        {
            // RETURN VALUE

            // cfloat -> i64
            if (tf->next->toBasetype() == Type::tcomplex32)
            {
                fty.ret->rewrite = &integerRewrite;
                fty.ret->ltype = integerRewrite.type(fty.ret->type, fty.ret->ltype);
            }

            // IMPLICIT PARAMETERS

            // EXPLICIT PARAMETERS
        }
    }