[llvm-commits] [dragonegg] r132085 - in /dragonegg/trunk: include/dragonegg/Internals.h src/Convert.cpp

Duncan Sands baldrick at free.fr
Wed May 25 14:43:52 PDT 2011


Author: baldrick
Date: Wed May 25 16:43:51 2011
New Revision: 132085

URL: http://llvm.org/viewvc/llvm-project?rev=132085&view=rev
Log:
Add support for the cexpi builtin (exponential of a purely
imaginary complex number) but turning it into a call to sincos
or a call to cexp.  This fixes PR9692.

Modified:
    dragonegg/trunk/include/dragonegg/Internals.h
    dragonegg/trunk/src/Convert.cpp

Modified: dragonegg/trunk/include/dragonegg/Internals.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/include/dragonegg/Internals.h?rev=132085&r1=132084&r2=132085&view=diff
==============================================================================
--- dragonegg/trunk/include/dragonegg/Internals.h (original)
+++ dragonegg/trunk/include/dragonegg/Internals.h Wed May 25 16:43:51 2011
@@ -760,6 +760,7 @@
   Value *EmitBuiltinPOW(gimple_statement_d *stmt);
   Value *EmitBuiltinLCEIL(gimple_statement_d *stmt);
   Value *EmitBuiltinLFLOOR(gimple_statement_d *stmt);
+  Value *EmitBuiltinCEXPI(gimple_statement_d *stmt);
 
   bool EmitBuiltinConstantP(gimple_statement_d *stmt, Value *&Result);
   bool EmitBuiltinAlloca(gimple_statement_d *stmt, Value *&Result);

Modified: dragonegg/trunk/src/Convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Convert.cpp?rev=132085&r1=132084&r2=132085&view=diff
==============================================================================
--- dragonegg/trunk/src/Convert.cpp (original)
+++ dragonegg/trunk/src/Convert.cpp Wed May 25 16:43:51 2011
@@ -4106,6 +4106,11 @@
   case BUILT_IN_LLFLOORL:
     Result = EmitBuiltinLFLOOR(stmt);
     return true;
+  case BUILT_IN_CEXPI:
+  case BUILT_IN_CEXPIF:
+  case BUILT_IN_CEXPIL:
+    Result = EmitBuiltinCEXPI(stmt);
+    return true;
 //TODO  case BUILT_IN_FLT_ROUNDS: {
 //TODO    Result =
 //TODO      Builder.CreateCall(Intrinsic::getDeclaration(TheModule,
@@ -4747,6 +4752,154 @@
     Builder.CreateFPToSI(Call, RetTy);
 }
 
+Value *TreeToLLVM::EmitBuiltinCEXPI(gimple stmt) {
+  if (!validate_gimple_arglist(stmt, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  if (TARGET_HAS_SINCOS) {
+    // exp(i*arg) = cos(arg) + i*sin(arg).  Emit a call to sincos.  First
+    // determine which version of sincos to call.
+    tree arg = gimple_call_arg(stmt, 0);
+    tree arg_type = TREE_TYPE(arg);
+    StringRef Name = SelectFPName(arg_type, "sincosf", "sincos", "sincosl");
+
+    // Create stack slots to store the real (cos) and imaginary (sin) parts in.
+    Value *Val = EmitRegister(arg);
+    Value *SinPtr = CreateTemporary(Val->getType());
+    Value *CosPtr = CreateTemporary(Val->getType());
+
+    // Get the LLVM function declaration for sincos.
+    const Type *ArgTys[3] =
+      { Val->getType(), SinPtr->getType(), CosPtr->getType() };
+    const FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context),
+                                                ArgTys, /*isVarArg*/false);
+    Constant *Func = TheModule->getOrInsertFunction(Name, FTy);
+
+    // 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_list(void_type_node, arg_type,
+                                           TYPE_POINTER_TO(arg_type),
+                                           TYPE_POINTER_TO(arg_type),
+                                           NULL_TREE);
+    TARGET_ADJUST_LLVM_CC(CC, fntype);
+#endif
+
+    // 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);
+
+    // Call sincos.
+    Value *Args[3] = { Val, SinPtr, CosPtr };
+    CallInst *CI = Builder.CreateCall(Func, Args);
+    CI->setCallingConv(CC);
+    CI->setDoesNotThrow();
+
+    // Load out the real (cos) and imaginary (sin) parts.
+    Value *Sin = Builder.CreateLoad(SinPtr);
+    Value *Cos = Builder.CreateLoad(CosPtr);
+
+    // Return the complex number "cos(arg) + i*sin(arg)".
+    return CreateComplex(Cos, Sin);
+  } else {
+    // Emit a call to cexp.  First determine which version of cexp to call.
+    tree arg = gimple_call_arg(stmt, 0);
+    tree arg_type = TREE_TYPE(arg);
+    StringRef Name = SelectFPName(arg_type, "cexpf", "cexp", "cexpl");
+
+    // Get the GCC and LLVM function types for cexp.
+    tree cplx_type = gimple_call_return_type(stmt);
+    tree fntype = build_function_type_list(cplx_type, cplx_type, NULL_TREE);
+    const FunctionType *FTy = cast<FunctionType>(ConvertType(fntype));
+
+    // Get the LLVM function declaration for cexp.
+    Constant *Func = TheModule->getOrInsertFunction(Name, FTy);
+
+    // Determine the calling convention.
+    CallingConv::ID CC = CallingConv::C;
+#ifdef TARGET_ADJUST_LLVM_CC
+    // Query the target for the calling convention to use.
+    TARGET_ADJUST_LLVM_CC(CC, fntype);
+#endif
+
+    // 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);
+
+    // Form the complex number "0 + i*arg".
+    Value *Arg = EmitRegister(arg);
+    Value *CplxArg = CreateComplex(Constant::getNullValue(Arg->getType()), Arg);
+
+    // Call cexp and return the result.  This is rather painful because complex
+    // numbers may be passed in funky ways and we don't have a proper interface
+    // for marshalling call parameters.
+    SmallVector<Value*, 16> CallOperands;
+    FunctionCallArgumentConversion Client(CallOperands, FTy, /*destloc*/0,
+                                          /*ReturnSlotOpt*/false, Builder, CC);
+    DefaultABI ABIConverter(Client);
+
+    // Handle the result.
+    ABIConverter.HandleReturnType(cplx_type, fntype, false);
+
+    // Push the argument.
+    bool PassedInMemory;
+    const Type *CplxTy = CplxArg->getType();
+    if (LLVM_SHOULD_PASS_AGGREGATE_AS_FCA(cplx_type, CplxTy)) {
+      Client.pushValue(CplxArg);
+      PassedInMemory = false;
+    } else {
+      // Push the address of a temporary copy.
+      MemRef Copy = CreateTempLoc(CplxTy);
+      StoreRegisterToMemory(CplxArg, Copy, cplx_type, Builder);
+      Client.pushAddress(Copy.Ptr);
+      PassedInMemory = true;
+    }
+
+    Attributes Attrs = Attribute::None;
+    std::vector<const Type*> ScalarArgs;
+    ABIConverter.HandleArgument(cplx_type, ScalarArgs, &Attrs);
+    assert(Attrs == Attribute::None && "Got attributes but none given!");
+    Client.clear();
+
+    // Create the call.
+    CallInst *CI = Builder.CreateCall(Func, CallOperands);
+    CI->setCallingConv(CC);
+    CI->setDoesNotThrow();
+    if (!PassedInMemory)
+      CI->setDoesNotAccessMemory();
+
+    // Extract and return the result.
+    if (Client.isShadowReturn())
+      return Client.EmitShadowResult(cplx_type, 0);
+
+    if (Client.isAggrReturn()) {
+      // Extract to a temporary then load the value out later.
+      MemRef Target = CreateTempLoc(CplxTy);
+
+      assert(TD.getTypeAllocSize(CI->getType()) <= TD.getTypeAllocSize(CplxTy)
+             && "Complex number returned in too large registers!");
+      Value *Dest = Builder.CreateBitCast(Target.Ptr,
+                                          CI->getType()->getPointerTo());
+      LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(CI, Dest, Target.Volatile, Builder);
+      return Builder.CreateLoad(Target.Ptr);
+    }
+
+    if (CI->getType() == CplxTy)
+      return CI;   // Normal scalar return.
+
+    // Probably { float, float } being returned as a double.
+    assert(TD.getTypeAllocSize(CI->getType()) == TD.getTypeAllocSize(CplxTy) &&
+           "Size mismatch in scalar to scalar conversion!");
+    Value *Tmp = CreateTemporary(CI->getType());
+    Builder.CreateStore(CI, Tmp);
+    const Type *CplxPtrTy = CplxTy->getPointerTo();
+    return Builder.CreateLoad(Builder.CreateBitCast(Tmp, CplxPtrTy));
+  }
+}
+
 bool TreeToLLVM::EmitBuiltinConstantP(gimple stmt, Value *&Result) {
   Result = Constant::getNullValue(ConvertType(gimple_call_return_type(stmt)));
   return true;





More information about the llvm-commits mailing list