diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/CGStmt.cpp | 41 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 101 | 
2 files changed, 83 insertions, 59 deletions
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 70cb1a2eca0..b90e1c40158 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -981,19 +981,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {          unsigned InputNo;          for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {            TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo]; -          if (Input.hasTiedOperand() && -              Input.getTiedOperand() == i) +          if (Input.hasTiedOperand() && Input.getTiedOperand() == i)              break;          }          assert(InputNo != S.getNumInputs() && "Didn't find matching input!");          QualType InputTy = S.getInputExpr(InputNo)->getType(); -        QualType OutputTy = OutExpr->getType(); +        QualType OutputType = OutExpr->getType();          uint64_t InputSize = getContext().getTypeSize(InputTy); -        if (getContext().getTypeSize(OutputTy) < InputSize) { -          // Form the asm to return the value as a larger integer type. -          ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize); +        if (getContext().getTypeSize(OutputType) < InputSize) { +          // Form the asm to return the value as a larger integer or fp type. +          ResultRegTypes.back() = ConvertType(InputTy);          }        }      } else { @@ -1043,18 +1042,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {      // that is usually cheaper, but LLVM IR should really get an anyext someday.      if (Info.hasTiedOperand()) {        unsigned Output = Info.getTiedOperand(); -      QualType OutputTy = S.getOutputExpr(Output)->getType(); +      QualType OutputType = S.getOutputExpr(Output)->getType();        QualType InputTy = InputExpr->getType(); -      if (getContext().getTypeSize(OutputTy) > +      if (getContext().getTypeSize(OutputType) >            getContext().getTypeSize(InputTy)) {          // Use ptrtoint as appropriate so that we can do our extension.          if (isa<llvm::PointerType>(Arg->getType()))            Arg = Builder.CreatePtrToInt(Arg,                             llvm::IntegerType::get(VMContext, LLVMPointerWidth)); -        unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy); -        Arg = Builder.CreateZExt(Arg, -                                 llvm::IntegerType::get(VMContext, OutputSize)); +        const llvm::Type *OutputTy = ConvertType(OutputType); +        if (isa<llvm::IntegerType>(OutputTy)) +          Arg = Builder.CreateZExt(Arg, OutputTy); +        else +          Arg = Builder.CreateFPExt(Arg, OutputTy);        }      } @@ -1135,13 +1136,17 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {      // the expression, do the conversion.      if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {        const llvm::Type *TruncTy = ResultTruncRegTypes[i]; -      // Truncate the integer result to the right size, note that -      // ResultTruncRegTypes can be a pointer. -      uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); -      Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize)); - -      if (Tmp->getType() != TruncTy) { -        assert(isa<llvm::PointerType>(TruncTy)); +       +      // Truncate the integer result to the right size, note that TruncTy can be +      // a pointer. +      if (TruncTy->isFloatingPointTy()) +        Tmp = Builder.CreateFPTrunc(Tmp, TruncTy); +      else if (!isa<llvm::PointerType>(TruncTy)) +        Tmp = Builder.CreateTrunc(Tmp, TruncTy); +      else { +        uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); +        Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, +                                                            (unsigned)ResSize));          Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);        }      } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 9c7affdb968..ee7cc692420 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1446,53 +1446,72 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,      if (Context.hasSameType(InTy, OutTy))        continue;  // All types can be tied to themselves. -    // Int/ptr operands have some special cases that we allow. -    if ((OutTy->isIntegerType() || OutTy->isPointerType()) && -        (InTy->isIntegerType() || InTy->isPointerType())) { - -      // They are ok if they are the same size.  Tying void* to int is ok if -      // they are the same size, for example.  This also allows tying void* to -      // int*. -      uint64_t OutSize = Context.getTypeSize(OutTy); -      uint64_t InSize = Context.getTypeSize(InTy); -      if (OutSize == InSize) -        continue; - -      // If the smaller input/output operand is not mentioned in the asm string, -      // then we can promote it and the asm string won't notice.  Check this -      // case now. -      bool SmallerValueMentioned = false; -      for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { -        AsmStmt::AsmStringPiece &Piece = Pieces[p]; -        if (!Piece.isOperand()) continue; - -        // If this is a reference to the input and if the input was the smaller -        // one, then we have to reject this asm. -        if (Piece.getOperandNo() == i+NumOutputs) { -          if (InSize < OutSize) { -            SmallerValueMentioned = true; -            break; -          } -        } +    // Decide if the input and output are in the same domain (integer/ptr or +    // floating point. +    enum AsmDomain { +      AD_Int, AD_FP, AD_Other +    } InputDomain, OutputDomain; +     +    if (InTy->isIntegerType() || InTy->isPointerType()) +      InputDomain = AD_Int; +    else if (InTy->isFloatingType()) +      InputDomain = AD_FP; +    else +      InputDomain = AD_Other; -        // If this is a reference to the input and if the input was the smaller -        // one, then we have to reject this asm. -        if (Piece.getOperandNo() == TiedTo) { -          if (InSize > OutSize) { -            SmallerValueMentioned = true; -            break; -          } +    if (OutTy->isIntegerType() || OutTy->isPointerType()) +      OutputDomain = AD_Int; +    else if (OutTy->isFloatingType()) +      OutputDomain = AD_FP; +    else +      OutputDomain = AD_Other; +     +    // They are ok if they are the same size and in the same domain.  This +    // allows tying things like: +    //   void* to int* +    //   void* to int            if they are the same size. +    //   double to long double   if they are the same size. +    //  +    uint64_t OutSize = Context.getTypeSize(OutTy); +    uint64_t InSize = Context.getTypeSize(InTy); +    if (OutSize == InSize && InputDomain == OutputDomain && +        InputDomain != AD_Other) +      continue; +     +    // If the smaller input/output operand is not mentioned in the asm string, +    // then we can promote it and the asm string won't notice.  Check this +    // case now. +    bool SmallerValueMentioned = false; +    for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { +      AsmStmt::AsmStringPiece &Piece = Pieces[p]; +      if (!Piece.isOperand()) continue; + +      // If this is a reference to the input and if the input was the smaller +      // one, then we have to reject this asm. +      if (Piece.getOperandNo() == i+NumOutputs) { +        if (InSize < OutSize) { +          SmallerValueMentioned = true; +          break;          }        } -      // If the smaller value wasn't mentioned in the asm string, and if the -      // output was a register, just extend the shorter one to the size of the -      // larger one. -      if (!SmallerValueMentioned && -          OutputConstraintInfos[TiedTo].allowsRegister()) -        continue; +      // If this is a reference to the input and if the input was the smaller +      // one, then we have to reject this asm. +      if (Piece.getOperandNo() == TiedTo) { +        if (InSize > OutSize) { +          SmallerValueMentioned = true; +          break; +        } +      }      } +    // If the smaller value wasn't mentioned in the asm string, and if the +    // output was a register, just extend the shorter one to the size of the +    // larger one. +    if (!SmallerValueMentioned && InputDomain != AD_Other && +        OutputConstraintInfos[TiedTo].allowsRegister()) +      continue; +      Diag(InputExpr->getLocStart(),           diag::err_asm_tying_incompatible_types)        << InTy << OutTy << OutputExpr->getSourceRange()  | 

