diff options
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 101 | ||||
-rw-r--r-- | test/CodeGen/asm.c | 21 |
3 files changed, 104 insertions, 59 deletions
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 70cb1a2eca..b90e1c4015 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/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/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9c7affdb96..ee7cc69242 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/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() diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c index ace0db9af6..5077028878 100644 --- a/test/CodeGen/asm.c +++ b/test/CodeGen/asm.c @@ -147,3 +147,24 @@ int t19(unsigned data) { // CHECK: = call {{.*}}asm "x$(abc$|def$|ghi$)z" } + +// PR6845 - Mismatching source/dest fp types. +double t20(double x) { + register long double result; + __asm __volatile ("frndint" : "=t" (result) : "0" (x)); + return result; + + // CHECK: @t20 + // CHECK: fpext double {{.*}} to x86_fp80 + // CHECK-NEXT: call x86_fp80 asm sideeffect "frndint" + // CHECK: fptrunc x86_fp80 {{.*}} to double +} + +float t21(long double x) { + register float result; + __asm __volatile ("frndint" : "=t" (result) : "0" (x)); + return result; + // CHECK: @t21 + // CHECK: call x86_fp80 asm sideeffect "frndint" + // CHECK-NEXT: fptrunc x86_fp80 {{.*}} to float +} |