]> granicus.if.org Git - clang/commitdiff
Implement PR6845. We allow matching constraints to have different
authorChris Lattner <sabre@nondot.org>
Fri, 23 Apr 2010 17:27:29 +0000 (17:27 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 23 Apr 2010 17:27:29 +0000 (17:27 +0000)
input and output types when the smaller value isn't mentioned in the
asm string.  Extend this support from integers to also allowing
fp values to be mismatched (if not mentioned in the asm string).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102188 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGStmt.cpp
lib/Sema/SemaStmt.cpp
test/CodeGen/asm.c

index 70cb1a2eca0fe172a19c0fcf16d7e4ded0647722..b90e1c40158be8bc0334eccb4450124de0f12957 100644 (file)
@@ -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);
       }
     }
index 9c7affdb9680485b41fe6679ad7ce31d39637c17..ee7cc69242070c52bb27d222e5b3708d43a69080 100644 (file)
@@ -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()
index ace0db9af6d4e5d638afd7a92cc4cbd8324af153..507702887866b136df9a2c052fa587730f1993f2 100644 (file)
@@ -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
+}