[llvm-commits] [dragonegg] r118499 - in /dragonegg/trunk: llvm-convert.cpp llvm-internal.h

Duncan Sands baldrick at free.fr
Tue Nov 9 05:30:26 PST 2010


Author: baldrick
Date: Tue Nov  9 07:30:26 2010
New Revision: 118499

URL: http://llvm.org/viewvc/llvm-project?rev=118499&view=rev
Log:
Add support for the LFLOOR and LCEIL builtins, which represent a call
to floor (resp. ceil) with the result cast to an integer type.  Before,
programs that performed such a cast would fail to link due to an undefined
reference to __builtin_lfloor or __builtin_lceil, or a variant of these.
Use some of the added infrastructure to simplify the handling of ABS_EXPR
(in the floating point case) while there.

Modified:
    dragonegg/trunk/llvm-convert.cpp
    dragonegg/trunk/llvm-internal.h

Modified: dragonegg/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-convert.cpp?rev=118499&r1=118498&r2=118499&view=diff
==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Tue Nov  9 07:30:26 2010
@@ -210,6 +210,21 @@
   }
 }
 
+/// SelectFPName - Helper for choosing a name depending on whether a floating
+/// point type is float, double or long double.
+static StringRef SelectFPName(tree type, StringRef FloatName,
+                              StringRef DoubleName, StringRef LongDoubleName) {
+  assert(SCALAR_FLOAT_TYPE_P(type) && "Expected a floating point type!");
+  if (TYPE_MODE(type) == TYPE_MODE(float_type_node))
+    return FloatName;
+  if (TYPE_MODE(type) == TYPE_MODE(double_type_node))
+    return DoubleName;
+  assert(TYPE_MODE(type) == TYPE_MODE(long_double_type_node) &&
+         "Unknown floating point type!");
+  return LongDoubleName;
+}
+
+
 //===----------------------------------------------------------------------===//
 //                         ... High-Level Methods ...
 //===----------------------------------------------------------------------===//
@@ -2983,6 +2998,67 @@
   return 0;
 }
 
+/// EmitSimpleCall - Emit a call to the function with the given name and return
+/// type, passing the provided arguments (which should all be gimple registers
+/// or local constants of register type).  No marshalling is done: the arguments
+/// are directly passed through.
+CallInst *TreeToLLVM::EmitSimpleCall(StringRef CalleeName, tree_node *ret_type,
+                                     /* arguments */ ...) {
+  va_list ops;
+  va_start(ops, ret_type);
+
+  // Build the list of arguments.
+  std::vector<Value*> Args;
+#ifdef TARGET_ADJUST_LLVM_CC
+  // Build the list of GCC argument types.
+  tree arg_types;
+  tree *chainp = &arg_types;
+#endif
+  while (tree arg = va_arg(ops, tree)) {
+    Args.push_back(EmitRegister(arg));
+#ifdef TARGET_ADJUST_LLVM_CC
+    *chainp = build_tree_list(NULL, TREE_TYPE(arg));
+    chainp = &TREE_CHAIN(*chainp);
+#endif
+  }
+#ifdef TARGET_ADJUST_LLVM_CC
+  // Indicate that this function is not varargs.
+  *chainp = void_list_node;
+#endif
+  va_end(ops);
+
+  const Type *RetTy = TREE_CODE(ret_type) == VOID_TYPE ?
+    Type::getVoidTy(Context) : GetRegType(ret_type);
+
+  // The LLVM argument types.
+  std::vector<const Type*> ArgTys;
+  ArgTys.reserve(Args.size());
+  for (unsigned i = 0, e = Args.size(); i != e; ++i)
+    ArgTys.push_back(Args[i]->getType());
+
+  // Determine the calling convention.
+  CallingConv::ID CC = CallingConv::C;
+#ifdef TARGET_ADJUST_LLVM_CC
+  // Query the target for the calling convention to use.
+  tree fntype = build_function_type(ret_type, arg_types);
+  TARGET_ADJUST_LLVM_CC(CC, fntype);
+#endif
+
+  // Get the function declaration for the callee.
+  const FunctionType *FTy = FunctionType::get(RetTy, ArgTys, /*isVarArg*/false);
+  Constant *Func = TheModule->getOrInsertFunction(CalleeName, FTy);
+
+  // If the function already existed with the wrong prototype then don't try to
+  // muck with its calling convention.  Otherwise, set the calling convention.
+  if (Function *F = dyn_cast<Function>(Func))
+    F->setCallingConv(CC);
+
+  // Finally, call the function.
+  CallInst *CI = Builder.CreateCall(Func, Args.begin(), Args.end());
+  CI->setCallingConv(CC);
+  return CI;
+}
+
 
 //===----------------------------------------------------------------------===//
 //               ... Inline Assembly and Register Variables ...
@@ -3950,6 +4026,22 @@
                                   Result);
     return true;
   }
+  case BUILT_IN_LCEIL:
+  case BUILT_IN_LCEILF:
+  case BUILT_IN_LCEILL:
+  case BUILT_IN_LLCEIL:
+  case BUILT_IN_LLCEILF:
+  case BUILT_IN_LLCEILL:
+    Result = EmitBuiltinLCEIL(stmt);
+    return true;
+  case BUILT_IN_LFLOOR:
+  case BUILT_IN_LFLOORF:
+  case BUILT_IN_LFLOORL:
+  case BUILT_IN_LLFLOOR:
+  case BUILT_IN_LLFLOORF:
+  case BUILT_IN_LLFLOORL:
+    Result = EmitBuiltinLFLOOR(stmt);
+    return true;
 //TODO  case BUILT_IN_FLT_ROUNDS: {
 //TODO    Result =
 //TODO      Builder.CreateCall(Intrinsic::getDeclaration(TheModule,
@@ -4552,6 +4644,44 @@
                             Args.begin(), Args.end());
 }
 
+Value *TreeToLLVM::EmitBuiltinLCEIL(gimple stmt) {
+  if (!validate_gimple_arglist(stmt, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  // Cast the result of "ceil" to the appropriate integer type.
+  // First call the appropriate version of "ceil".
+  tree op = gimple_call_arg(stmt, 0);
+  StringRef Name = SelectFPName(TREE_TYPE(op), "ceilf", "ceil", "ceill");
+  CallInst *Call = EmitSimpleCall(Name, TREE_TYPE(op), op, NULL);
+  Call->setDoesNotThrow();
+  Call->setDoesNotAccessMemory();
+
+  // Then type cast the result of the "ceil" call.
+  tree type = gimple_call_return_type(stmt);
+  const Type *RetTy = GetRegType(type);
+  return TYPE_UNSIGNED(type) ? Builder.CreateFPToUI(Call, RetTy) :
+    Builder.CreateFPToSI(Call, RetTy);
+}
+
+Value *TreeToLLVM::EmitBuiltinLFLOOR(gimple stmt) {
+  if (!validate_gimple_arglist(stmt, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  // Cast the result of "floor" to the appropriate integer type.
+  // First call the appropriate version of "floor".
+  tree op = gimple_call_arg(stmt, 0);
+  StringRef Name = SelectFPName(TREE_TYPE(op), "floorf", "floor", "floorl");
+  CallInst *Call = EmitSimpleCall(Name, TREE_TYPE(op), op, NULL);
+  Call->setDoesNotThrow();
+  Call->setDoesNotAccessMemory();
+
+  // Then type cast the result of the "floor" call.
+  tree type = gimple_call_return_type(stmt);
+  const Type *RetTy = GetRegType(type);
+  return TYPE_UNSIGNED(type) ? Builder.CreateFPToUI(Call, RetTy) :
+    Builder.CreateFPToSI(Call, RetTy);
+}
+
 bool TreeToLLVM::EmitBuiltinConstantP(gimple stmt, Value *&Result) {
   Result = Constant::getNullValue(ConvertType(gimple_call_return_type(stmt)));
   return true;
@@ -5926,8 +6056,8 @@
 
 // Unary expressions.
 Value *TreeToLLVM::EmitReg_ABS_EXPR(tree op) {
-  Value *Op = EmitRegister(op);
-  if (!Op->getType()->isFloatingPointTy()) {
+  if (!FLOAT_TYPE_P(TREE_TYPE(op))) {
+    Value *Op = EmitRegister(op);
     Value *OpN = Builder.CreateNeg(Op, Op->getName()+"neg");
     ICmpInst::Predicate pred = TYPE_UNSIGNED(TREE_TYPE(op)) ?
       ICmpInst::ICMP_UGE : ICmpInst::ICMP_SGE;
@@ -5937,42 +6067,10 @@
   }
 
   // Turn FP abs into fabs/fabsf.
-  const char *Name = 0;
-
-  tree ArgType;
-  switch (Op->getType()->getTypeID()) {
-  default: assert(0 && "Unknown FP type!");
-  case Type::FloatTyID:
-    Name = "fabsf";
-    ArgType = float_type_node;
-    break;
-  case Type::DoubleTyID:
-    Name = "fabs";
-    ArgType = double_type_node;
-    break;
-  case Type::X86_FP80TyID:
-  case Type::PPC_FP128TyID:
-  case Type::FP128TyID:
-    Name = "fabsl";
-    ArgType = long_double_type_node;
-    break;
-  }
-
-  Value *V = TheModule->getOrInsertFunction(Name, Op->getType(), Op->getType(),
-                                            NULL);
-  // Determine the calling convention.
-  CallingConv::ID CallingConvention = CallingConv::C;
-#ifdef TARGET_ADJUST_LLVM_CC
-  tree FunctionType = build_function_type_list(ArgType, ArgType, NULL);
-  TARGET_ADJUST_LLVM_CC(CallingConvention, FunctionType);
-#endif
-
-  Function *F = cast<Function>(V);
-  F->setCallingConv(CallingConvention);
-  CallInst *Call = Builder.CreateCall(V, Op);
+  StringRef Name = SelectFPName(TREE_TYPE(op), "fabsf", "fabs", "fabsl");
+  CallInst *Call = EmitSimpleCall(Name, TREE_TYPE(op), op, NULL);
   Call->setDoesNotThrow();
   Call->setDoesNotAccessMemory();
-  Call->setCallingConv(CallingConvention);
   return Call;
 }
 

Modified: dragonegg/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-internal.h?rev=118499&r1=118498&r2=118499&view=diff
==============================================================================
--- dragonegg/trunk/llvm-internal.h (original)
+++ dragonegg/trunk/llvm-internal.h Tue Nov  9 07:30:26 2010
@@ -693,6 +693,8 @@
   Value *EmitADDR_EXPR(tree_node *exp);
   Value *EmitCallOf(Value *Callee, gimple_statement_d *stmt,
                     const MemRef *DestLoc, const AttrListPtr &PAL);
+  CallInst *EmitSimpleCall(StringRef CalleeName, tree_node *ret_type,
+                           /* arguments */ ...) END_WITH_NULL;
   Value *EmitFieldAnnotation(Value *FieldPtr, tree_node *FieldDecl);
 
   // Inline Assembly and Register Variables.
@@ -718,6 +720,8 @@
   Value *EmitBuiltinSQRT(gimple_statement_d *stmt);
   Value *EmitBuiltinPOWI(gimple_statement_d *stmt);
   Value *EmitBuiltinPOW(gimple_statement_d *stmt);
+  Value *EmitBuiltinLCEIL(gimple_statement_d *stmt);
+  Value *EmitBuiltinLFLOOR(gimple_statement_d *stmt);
 
   bool EmitBuiltinConstantP(gimple_statement_d *stmt, Value *&Result);
   bool EmitBuiltinAlloca(gimple_statement_d *stmt, Value *&Result);





More information about the llvm-commits mailing list