Partial CBackend support for 128-bit integers. This is needed
[oota-llvm.git] / lib / Target / CBackend / CBackend.cpp
index 12711c5ea3d70d8ac07b4be9f8430f92c513c0f6..161c6be0f9e3cd5d63bf32f3969a579caa2a5e3b 100644 (file)
@@ -18,7 +18,6 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/Module.h"
 #include "llvm/Instructions.h"
-#include "llvm/ParamAttrsList.h"
 #include "llvm/Pass.h"
 #include "llvm/PassManager.h"
 #include "llvm/TypeSymbolTable.h"
@@ -91,7 +90,7 @@ namespace {
 
   public:
     static char ID;
-    CWriter(std::ostream &o) 
+    explicit CWriter(std::ostream &o)
       : FunctionPass((intptr_t)&ID), Out(o), IL(0), Mang(0), LI(0), 
         TheModule(0), TAsm(0), TD(0) {}
 
@@ -131,13 +130,13 @@ namespace {
                             bool isSigned = false,
                             const std::string &VariableName = "",
                             bool IgnoreName = false,
-                            const ParamAttrsList *PAL = 0);
+                            const PAListPtr &PAL = PAListPtr());
     std::ostream &printSimpleType(std::ostream &Out, const Type *Ty, 
                                   bool isSigned, 
                                   const std::string &NameSoFar = "");
 
     void printStructReturnPointerFunctionType(std::ostream &Out,
-                                              const ParamAttrsList *PAL,
+                                              const PAListPtr &PAL,
                                               const PointerType *Ty);
 
     /// writeOperandDeref - Print the result of dereferencing the specified
@@ -271,6 +270,7 @@ namespace {
     void visitSelectInst(SelectInst &I);
     void visitCallInst (CallInst &I);
     void visitInlineAsm(CallInst &I);
+    bool visitBuiltinCall(CallInst &I, Intrinsic::ID ID, bool &WroteCallee);
 
     void visitMallocInst(MallocInst &I);
     void visitAllocaInst(AllocaInst &I);
@@ -394,7 +394,7 @@ bool CBackendNameAllUsedStructsAndMergeFunctions::runOnModule(Module &M) {
 /// return type, except, instead of printing the type as void (*)(Struct*, ...)
 /// print it as "Struct (*)(...)", for struct return functions.
 void CWriter::printStructReturnPointerFunctionType(std::ostream &Out,
-                                                   const ParamAttrsList *PAL,
+                                                   const PAListPtr &PAL,
                                                    const PointerType *TheTy) {
   const FunctionType *FTy = cast<FunctionType>(TheTy->getElementType());
   std::stringstream FunctionInnards;
@@ -408,12 +408,12 @@ void CWriter::printStructReturnPointerFunctionType(std::ostream &Out,
     if (PrintedType)
       FunctionInnards << ", ";
     const Type *ArgTy = *I;
-    if (PAL && PAL->paramHasAttr(Idx, ParamAttr::ByVal)) {
+    if (PAL.paramHasAttr(Idx, ParamAttr::ByVal)) {
       assert(isa<PointerType>(ArgTy));
       ArgTy = cast<PointerType>(ArgTy)->getElementType();
     }
     printType(FunctionInnards, ArgTy,
-        /*isSigned=*/PAL && PAL->paramHasAttr(Idx, ParamAttr::SExt), "");
+        /*isSigned=*/PAL.paramHasAttr(Idx, ParamAttr::SExt), "");
     PrintedType = true;
   }
   if (FTy->isVarArg()) {
@@ -425,7 +425,7 @@ void CWriter::printStructReturnPointerFunctionType(std::ostream &Out,
   FunctionInnards << ')';
   std::string tstr = FunctionInnards.str();
   printType(Out, RetTy, 
-      /*isSigned=*/PAL && PAL->paramHasAttr(0, ParamAttr::SExt), tstr);
+      /*isSigned=*/PAL.paramHasAttr(0, ParamAttr::SExt), tstr);
 }
 
 std::ostream &
@@ -445,9 +445,11 @@ CWriter::printSimpleType(std::ostream &Out, const Type *Ty, bool isSigned,
       return Out << (isSigned?"signed":"unsigned") << " short " << NameSoFar;
     else if (NumBits <= 32)
       return Out << (isSigned?"signed":"unsigned") << " int " << NameSoFar;
-    else { 
-      assert(NumBits <= 64 && "Bit widths > 64 not implemented yet");
+    else if (NumBits <= 64)
       return Out << (isSigned?"signed":"unsigned") << " long long "<< NameSoFar;
+    else { 
+      assert(NumBits <= 128 && "Bit widths > 128 not implemented yet");
+      return Out << (isSigned?"llvmInt128":"llvmUInt128") << " " << NameSoFar;
     }
   }
   case Type::FloatTyID:  return Out << "float "   << NameSoFar;
@@ -476,7 +478,7 @@ CWriter::printSimpleType(std::ostream &Out, const Type *Ty, bool isSigned,
 //
 std::ostream &CWriter::printType(std::ostream &Out, const Type *Ty,
                                  bool isSigned, const std::string &NameSoFar,
-                                 bool IgnoreName, const ParamAttrsList* PAL) {
+                                 bool IgnoreName, const PAListPtr &PAL) {
   if (Ty->isPrimitiveType() || Ty->isInteger() || isa<VectorType>(Ty)) {
     printSimpleType(Out, Ty, isSigned, NameSoFar);
     return Out;
@@ -497,14 +499,14 @@ std::ostream &CWriter::printType(std::ostream &Out, const Type *Ty,
     for (FunctionType::param_iterator I = FTy->param_begin(),
            E = FTy->param_end(); I != E; ++I) {
       const Type *ArgTy = *I;
-      if (PAL && PAL->paramHasAttr(Idx, ParamAttr::ByVal)) {
+      if (PAL.paramHasAttr(Idx, ParamAttr::ByVal)) {
         assert(isa<PointerType>(ArgTy));
         ArgTy = cast<PointerType>(ArgTy)->getElementType();
       }
       if (I != FTy->param_begin())
         FunctionInnards << ", ";
       printType(FunctionInnards, ArgTy,
-        /*isSigned=*/PAL && PAL->paramHasAttr(Idx, ParamAttr::SExt), "");
+        /*isSigned=*/PAL.paramHasAttr(Idx, ParamAttr::SExt), "");
       ++Idx;
     }
     if (FTy->isVarArg()) {
@@ -516,7 +518,7 @@ std::ostream &CWriter::printType(std::ostream &Out, const Type *Ty,
     FunctionInnards << ')';
     std::string tstr = FunctionInnards.str();
     printType(Out, FTy->getReturnType(), 
-      /*isSigned=*/PAL && PAL->paramHasAttr(0, ParamAttr::SExt), tstr);
+      /*isSigned=*/PAL.paramHasAttr(0, ParamAttr::SExt), tstr);
     return Out;
   }
   case Type::StructTyID: {
@@ -543,7 +545,7 @@ std::ostream &CWriter::printType(std::ostream &Out, const Type *Ty,
         isa<VectorType>(PTy->getElementType()))
       ptrName = "(" + ptrName + ")";
 
-    if (PAL)
+    if (!PAL.isEmpty())
       // Must be a function ptr cast!
       return printType(Out, PTy->getElementType(), false, ptrName, true, PAL);
     return printType(Out, PTy->getElementType(), false, ptrName);
@@ -913,7 +915,12 @@ void CWriter::printConstant(Constant *CPV) {
   } else if (isa<UndefValue>(CPV) && CPV->getType()->isFirstClassType()) {
     Out << "((";
     printType(Out, CPV->getType()); // sign doesn't matter
-    Out << ")/*UNDEF*/0)";
+    Out << ")/*UNDEF*/";
+    if (!isa<VectorType>(CPV->getType())) {
+      Out << "0)";
+    } else {
+      Out << "{})";
+    }
     return;
   }
 
@@ -1473,6 +1480,11 @@ static void generateCompilerSpecificCode(std::ostream& Out) {
       << "#define __builtin_stack_restore(X) /* noop */\n"
       << "#endif\n\n";
 
+  Out << "#ifdef __GNUC__ /* 128-bit integer types */\n"
+      << "typedef int __attribute__((mode(TI))) llvmInt128;\n"
+      << "typedef unsigned __attribute__((mode(TI))) llvmUInt128;\n"
+      << "#endif\n\n";
+
   // Output target-specific code that should be inserted into main.
   Out << "#define CODE_FOR_MAIN() /* Any target-specific code for main()*/\n";
 }
@@ -1898,7 +1910,7 @@ void CWriter::printContainedStructs(const Type *Ty,
 
 void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
   /// isStructReturn - Should this function actually return a struct by-value?
-  bool isStructReturn = F->isStructReturn();
+  bool isStructReturn = F->hasStructRetAttr();
   
   if (F->hasInternalLinkage()) Out << "static ";
   if (F->hasDLLImportLinkage()) Out << "__declspec(dllimport) ";
@@ -1914,7 +1926,7 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
   
   // Loop over the arguments, printing them...
   const FunctionType *FT = cast<FunctionType>(F->getFunctionType());
-  const ParamAttrsList *PAL = F->getParamAttrs();
+  const PAListPtr &PAL = F->getParamAttrs();
 
   std::stringstream FunctionInnards;
 
@@ -1943,12 +1955,12 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
         else
           ArgName = "";
         const Type *ArgTy = I->getType();
-        if (PAL && PAL->paramHasAttr(Idx, ParamAttr::ByVal)) {
+        if (PAL.paramHasAttr(Idx, ParamAttr::ByVal)) {
           ArgTy = cast<PointerType>(ArgTy)->getElementType();
           ByValParams.insert(I);
         }
         printType(FunctionInnards, ArgTy,
-            /*isSigned=*/PAL && PAL->paramHasAttr(Idx, ParamAttr::SExt),
+            /*isSigned=*/PAL.paramHasAttr(Idx, ParamAttr::SExt),
             ArgName);
         PrintedArg = true;
         ++Idx;
@@ -1970,12 +1982,12 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
     for (; I != E; ++I) {
       if (PrintedArg) FunctionInnards << ", ";
       const Type *ArgTy = *I;
-      if (PAL && PAL->paramHasAttr(Idx, ParamAttr::ByVal)) {
+      if (PAL.paramHasAttr(Idx, ParamAttr::ByVal)) {
         assert(isa<PointerType>(ArgTy));
         ArgTy = cast<PointerType>(ArgTy)->getElementType();
       }
       printType(FunctionInnards, ArgTy,
-             /*isSigned=*/PAL && PAL->paramHasAttr(Idx, ParamAttr::SExt));
+             /*isSigned=*/PAL.paramHasAttr(Idx, ParamAttr::SExt));
       PrintedArg = true;
       ++Idx;
     }
@@ -2003,7 +2015,7 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
     
   // Print out the return type and the signature built above.
   printType(Out, RetTy, 
-            /*isSigned=*/ PAL && PAL->paramHasAttr(0, ParamAttr::SExt),
+            /*isSigned=*/PAL.paramHasAttr(0, ParamAttr::SExt),
             FunctionInnards.str());
 }
 
@@ -2018,7 +2030,7 @@ static inline bool isFPIntBitCast(const Instruction &I) {
 
 void CWriter::printFunction(Function &F) {
   /// isStructReturn - Should this function actually return a struct by-value?
-  bool isStructReturn = F.isStructReturn();
+  bool isStructReturn = F.hasStructRetAttr();
 
   printFunctionSignature(&F, false);
   Out << " {\n";
@@ -2142,7 +2154,7 @@ void CWriter::printBasicBlock(BasicBlock *BB) {
 //
 void CWriter::visitReturnInst(ReturnInst &I) {
   // If this is a struct return function, return the temporary struct.
-  bool isStructReturn = I.getParent()->getParent()->isStructReturn();
+  bool isStructReturn = I.getParent()->getParent()->hasStructRetAttr();
 
   if (isStructReturn) {
     Out << "  return StructReturn;\n";
@@ -2501,7 +2513,12 @@ void CWriter::lowerIntrinsics(Function &F) {
           case Intrinsic::prefetch:
           case Intrinsic::dbg_stoppoint:
           case Intrinsic::powi:
-            // We directly implement these intrinsics
+          case Intrinsic::x86_sse_cmp_ss:
+          case Intrinsic::x86_sse_cmp_ps:
+          case Intrinsic::x86_sse2_cmp_sd:
+          case Intrinsic::x86_sse2_cmp_pd:
+          case Intrinsic::ppc_altivec_lvsl:
+              // We directly implement these intrinsics
             break;
           default:
             // If this is an intrinsic that directly corresponds to a GCC
@@ -2549,7 +2566,6 @@ void CWriter::lowerIntrinsics(Function &F) {
   }
 }
 
-
 void CWriter::visitCallInst(CallInst &I) {
   //check if we have inline asm
   if (isInlineAsm(I)) {
@@ -2561,114 +2577,9 @@ void CWriter::visitCallInst(CallInst &I) {
 
   // Handle intrinsic function calls first...
   if (Function *F = I.getCalledFunction())
-    if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) {
-      switch (ID) {
-      default: {
-        // If this is an intrinsic that directly corresponds to a GCC
-        // builtin, we emit it here.
-        const char *BuiltinName = "";
-#define GET_GCC_BUILTIN_NAME
-#include "llvm/Intrinsics.gen"
-#undef GET_GCC_BUILTIN_NAME
-        assert(BuiltinName[0] && "Unknown LLVM intrinsic!");
-
-        Out << BuiltinName;
-        WroteCallee = true;
-        break;
-      }
-      case Intrinsic::memory_barrier:
-        Out << "0; __sync_syncronize()";
-        return;
-      case Intrinsic::vastart:
-        Out << "0; ";
-
-        Out << "va_start(*(va_list*)";
-        writeOperand(I.getOperand(1));
-        Out << ", ";
-        // Output the last argument to the enclosing function...
-        if (I.getParent()->getParent()->arg_empty()) {
-          cerr << "The C backend does not currently support zero "
-               << "argument varargs functions, such as '"
-               << I.getParent()->getParent()->getName() << "'!\n";
-          abort();
-        }
-        writeOperand(--I.getParent()->getParent()->arg_end());
-        Out << ')';
-        return;
-      case Intrinsic::vaend:
-        if (!isa<ConstantPointerNull>(I.getOperand(1))) {
-          Out << "0; va_end(*(va_list*)";
-          writeOperand(I.getOperand(1));
-          Out << ')';
-        } else {
-          Out << "va_end(*(va_list*)0)";
-        }
-        return;
-      case Intrinsic::vacopy:
-        Out << "0; ";
-        Out << "va_copy(*(va_list*)";
-        writeOperand(I.getOperand(1));
-        Out << ", *(va_list*)";
-        writeOperand(I.getOperand(2));
-        Out << ')';
-        return;
-      case Intrinsic::returnaddress:
-        Out << "__builtin_return_address(";
-        writeOperand(I.getOperand(1));
-        Out << ')';
-        return;
-      case Intrinsic::frameaddress:
-        Out << "__builtin_frame_address(";
-        writeOperand(I.getOperand(1));
-        Out << ')';
-        return;
-      case Intrinsic::powi:
-        Out << "__builtin_powi(";
-        writeOperand(I.getOperand(1));
-        Out << ", ";
-        writeOperand(I.getOperand(2));
-        Out << ')';
+    if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
+      if (visitBuiltinCall(I, ID, WroteCallee))
         return;
-      case Intrinsic::setjmp:
-        Out << "setjmp(*(jmp_buf*)";
-        writeOperand(I.getOperand(1));
-        Out << ')';
-        return;
-      case Intrinsic::longjmp:
-        Out << "longjmp(*(jmp_buf*)";
-        writeOperand(I.getOperand(1));
-        Out << ", ";
-        writeOperand(I.getOperand(2));
-        Out << ')';
-        return;
-      case Intrinsic::prefetch:
-        Out << "LLVM_PREFETCH((const void *)";
-        writeOperand(I.getOperand(1));
-        Out << ", ";
-        writeOperand(I.getOperand(2));
-        Out << ", ";
-        writeOperand(I.getOperand(3));
-        Out << ")";
-        return;
-      case Intrinsic::stacksave:
-        // Emit this as: Val = 0; *((void**)&Val) = __builtin_stack_save()
-        // to work around GCC bugs (see PR1809).
-        Out << "0; *((void**)&" << GetValueName(&I)
-            << ") = __builtin_stack_save()";
-        return;
-      case Intrinsic::dbg_stoppoint: {
-        // If we use writeOperand directly we get a "u" suffix which is rejected
-        // by gcc.
-        DbgStopPointInst &SPI = cast<DbgStopPointInst>(I);
-
-        Out << "\n#line "
-            << SPI.getLine()
-            << " \"" << SPI.getDirectory()
-            << SPI.getFileName() << "\"\n";
-        return;
-      }
-      }
-    }
 
   Value *Callee = I.getCalledValue();
 
@@ -2677,9 +2588,9 @@ void CWriter::visitCallInst(CallInst &I) {
 
   // If this is a call to a struct-return function, assign to the first
   // parameter instead of passing it to the call.
-  const ParamAttrsList *PAL = I.getParamAttrs();
+  const PAListPtr &PAL = I.getParamAttrs();
   bool hasByVal = I.hasByValArgument();
-  bool isStructRet = I.isStructReturn();
+  bool isStructRet = I.hasStructRetAttr();
   if (isStructRet) {
     writeOperandDeref(I.getOperand(1));
     Out << " = ";
@@ -2745,7 +2656,7 @@ void CWriter::visitCallInst(CallInst &I) {
         (*AI)->getType() != FTy->getParamType(ArgNo)) {
       Out << '(';
       printType(Out, FTy->getParamType(ArgNo), 
-            /*isSigned=*/PAL && PAL->paramHasAttr(ArgNo+1, ParamAttr::SExt));
+            /*isSigned=*/PAL.paramHasAttr(ArgNo+1, ParamAttr::SExt));
       Out << ')';
     }
     // Check if the argument is expected to be passed by value.
@@ -2758,6 +2669,160 @@ void CWriter::visitCallInst(CallInst &I) {
   Out << ')';
 }
 
+/// visitBuiltinCall - Handle the call to the specified builtin.  Returns true
+/// if the entire call is handled, return false it it wasn't handled, and
+/// optionally set 'WroteCallee' if the callee has already been printed out.
+bool CWriter::visitBuiltinCall(CallInst &I, Intrinsic::ID ID,
+                               bool &WroteCallee) {
+  switch (ID) {
+  default: {
+    // If this is an intrinsic that directly corresponds to a GCC
+    // builtin, we emit it here.
+    const char *BuiltinName = "";
+    Function *F = I.getCalledFunction();
+#define GET_GCC_BUILTIN_NAME
+#include "llvm/Intrinsics.gen"
+#undef GET_GCC_BUILTIN_NAME
+    assert(BuiltinName[0] && "Unknown LLVM intrinsic!");
+    
+    Out << BuiltinName;
+    WroteCallee = true;
+    return false;
+  }
+  case Intrinsic::memory_barrier:
+    Out << "__sync_synchronize()";
+    return true;
+  case Intrinsic::vastart:
+    Out << "0; ";
+      
+    Out << "va_start(*(va_list*)";
+    writeOperand(I.getOperand(1));
+    Out << ", ";
+    // Output the last argument to the enclosing function.
+    if (I.getParent()->getParent()->arg_empty()) {
+      cerr << "The C backend does not currently support zero "
+           << "argument varargs functions, such as '"
+           << I.getParent()->getParent()->getName() << "'!\n";
+      abort();
+    }
+    writeOperand(--I.getParent()->getParent()->arg_end());
+    Out << ')';
+    return true;
+  case Intrinsic::vaend:
+    if (!isa<ConstantPointerNull>(I.getOperand(1))) {
+      Out << "0; va_end(*(va_list*)";
+      writeOperand(I.getOperand(1));
+      Out << ')';
+    } else {
+      Out << "va_end(*(va_list*)0)";
+    }
+    return true;
+  case Intrinsic::vacopy:
+    Out << "0; ";
+    Out << "va_copy(*(va_list*)";
+    writeOperand(I.getOperand(1));
+    Out << ", *(va_list*)";
+    writeOperand(I.getOperand(2));
+    Out << ')';
+    return true;
+  case Intrinsic::returnaddress:
+    Out << "__builtin_return_address(";
+    writeOperand(I.getOperand(1));
+    Out << ')';
+    return true;
+  case Intrinsic::frameaddress:
+    Out << "__builtin_frame_address(";
+    writeOperand(I.getOperand(1));
+    Out << ')';
+    return true;
+  case Intrinsic::powi:
+    Out << "__builtin_powi(";
+    writeOperand(I.getOperand(1));
+    Out << ", ";
+    writeOperand(I.getOperand(2));
+    Out << ')';
+    return true;
+  case Intrinsic::setjmp:
+    Out << "setjmp(*(jmp_buf*)";
+    writeOperand(I.getOperand(1));
+    Out << ')';
+    return true;
+  case Intrinsic::longjmp:
+    Out << "longjmp(*(jmp_buf*)";
+    writeOperand(I.getOperand(1));
+    Out << ", ";
+    writeOperand(I.getOperand(2));
+    Out << ')';
+    return true;
+  case Intrinsic::prefetch:
+    Out << "LLVM_PREFETCH((const void *)";
+    writeOperand(I.getOperand(1));
+    Out << ", ";
+    writeOperand(I.getOperand(2));
+    Out << ", ";
+    writeOperand(I.getOperand(3));
+    Out << ")";
+    return true;
+  case Intrinsic::stacksave:
+    // Emit this as: Val = 0; *((void**)&Val) = __builtin_stack_save()
+    // to work around GCC bugs (see PR1809).
+    Out << "0; *((void**)&" << GetValueName(&I)
+        << ") = __builtin_stack_save()";
+    return true;
+  case Intrinsic::dbg_stoppoint: {
+    // If we use writeOperand directly we get a "u" suffix which is rejected
+    // by gcc.
+    DbgStopPointInst &SPI = cast<DbgStopPointInst>(I);
+    Out << "\n#line "
+        << SPI.getLine()
+        << " \"" << SPI.getDirectory()
+        << SPI.getFileName() << "\"\n";
+    return true;
+  }
+  case Intrinsic::x86_sse_cmp_ss:
+  case Intrinsic::x86_sse_cmp_ps:
+  case Intrinsic::x86_sse2_cmp_sd:
+  case Intrinsic::x86_sse2_cmp_pd:
+    Out << '(';
+    printType(Out, I.getType());
+    Out << ')';  
+    // Multiple GCC builtins multiplex onto this intrinsic.
+    switch (cast<ConstantInt>(I.getOperand(3))->getZExtValue()) {
+    default: assert(0 && "Invalid llvm.x86.sse.cmp!");
+    case 0: Out << "__builtin_ia32_cmpeq"; break;
+    case 1: Out << "__builtin_ia32_cmplt"; break;
+    case 2: Out << "__builtin_ia32_cmple"; break;
+    case 3: Out << "__builtin_ia32_cmpunord"; break;
+    case 4: Out << "__builtin_ia32_cmpneq"; break;
+    case 5: Out << "__builtin_ia32_cmpnlt"; break;
+    case 6: Out << "__builtin_ia32_cmpnle"; break;
+    case 7: Out << "__builtin_ia32_cmpord"; break;
+    }
+    if (ID == Intrinsic::x86_sse_cmp_ps || ID == Intrinsic::x86_sse2_cmp_pd)
+      Out << 'p';
+    else
+      Out << 's';
+    if (ID == Intrinsic::x86_sse_cmp_ss || ID == Intrinsic::x86_sse_cmp_ps)
+      Out << 's';
+    else
+      Out << 'd';
+      
+    Out << "(";
+    writeOperand(I.getOperand(1));
+    Out << ", ";
+    writeOperand(I.getOperand(2));
+    Out << ")";
+    return true;
+  case Intrinsic::ppc_altivec_lvsl:
+    Out << '(';
+    printType(Out, I.getType());
+    Out << ')';  
+    Out << "__builtin_altivec_lvsl(0, (void*)";
+    writeOperand(I.getOperand(1));
+    Out << ")";
+    return true;
+  }
+}
 
 //This converts the llvm constraint string to something gcc is expecting.
 //TODO: work out platform independent constraints and factor those out
@@ -2767,7 +2832,7 @@ std::string CWriter::InterpretASMConstraint(InlineAsm::ConstraintInfo& c) {
 
   assert(c.Codes.size() == 1 && "Too many asm constraint codes to handle");
 
-  const char** table = 0;
+  const char *const *table = 0;
   
   //Grab the translation table from TargetAsmInfo if it exists
   if (!TAsm) {