[FastISel][AArch64] Add lowering support for frem.
authorJuergen Ributzka <juergen@apple.com>
Mon, 15 Sep 2014 22:07:49 +0000 (22:07 +0000)
committerJuergen Ributzka <juergen@apple.com>
Mon, 15 Sep 2014 22:07:49 +0000 (22:07 +0000)
This lowers frem to a runtime libcall inside fast-isel.

The test case also checks the CallLoweringInfo bug that was exposed by this
change.

This fixes rdar://problem/18342783.

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

include/llvm/CodeGen/FastISel.h
lib/Target/AArch64/AArch64FastISel.cpp
test/CodeGen/AArch64/fast-isel-frem.ll [new file with mode: 0644]

index 80b3a40017dabb06601874f0126e503550ef50f3..b5405f97d4c4179b1f0439c29d800630ada144d4 100644 (file)
@@ -141,8 +141,19 @@ public:
       RetTy = ResultTy;
       Callee = Target;
       CallConv = CC;
+      Args = std::move(ArgsList);
       NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
+      return *this;
+    }
+
+    CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultTy,
+                                const char *Target, ArgListTy &&ArgsList,
+                                unsigned FixedArgs = ~0U) {
+      RetTy = ResultTy;
+      SymName = Target;
+      CallConv = CC;
       Args = std::move(ArgsList);
+      NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
       return *this;
     }
 
index 0ea99d442bb97075562f3af2f370c7495c9d12b7..9658834b75004e6750838d8e57e1b07d9ddfa3be 100644 (file)
@@ -132,6 +132,7 @@ private:
   bool SelectMul(const Instruction *I);
   bool SelectShift(const Instruction *I);
   bool SelectBitCast(const Instruction *I);
+  bool selectFRem(const Instruction *I);
 
   // Utility helper routines.
   bool isTypeLegal(Type *Ty, MVT &VT);
@@ -2322,6 +2323,9 @@ bool AArch64FastISel::fastLowerCall(CallLoweringInfo &CLI) {
   const Value *Callee = CLI.Callee;
   const char *SymName = CLI.SymName;
 
+  if (!Callee && !SymName)
+    return false;
+
   // Allow SelectionDAG isel to handle tail calls.
   if (IsTailCall)
     return false;
@@ -2368,7 +2372,7 @@ bool AArch64FastISel::fastLowerCall(CallLoweringInfo &CLI) {
   }
 
   Address Addr;
-  if (!ComputeCallAddress(Callee, Addr))
+  if (Callee && !ComputeCallAddress(Callee, Addr))
     return false;
 
   // Handle the arguments now that we've gotten them.
@@ -3624,6 +3628,43 @@ bool AArch64FastISel::SelectBitCast(const Instruction *I) {
   return true;
 }
 
+bool AArch64FastISel::selectFRem(const Instruction *I) {
+  MVT RetVT;
+  if (!isTypeLegal(I->getType(), RetVT))
+    return false;
+
+  RTLIB::Libcall LC;
+  switch (RetVT.SimpleTy) {
+  default:
+    return false;
+  case MVT::f32:
+    LC = RTLIB::REM_F32;
+    break;
+  case MVT::f64:
+    LC = RTLIB::REM_F64;
+    break;
+  }
+
+  ArgListTy Args;
+  Args.reserve(I->getNumOperands());
+
+  // Populate the argument list.
+  for (auto &Arg : I->operands()) {
+    ArgListEntry Entry;
+    Entry.Val = Arg;
+    Entry.Ty = Arg->getType();
+    Args.push_back(Entry);
+  }
+
+  CallLoweringInfo CLI;
+  CLI.setCallee(TLI.getLibcallCallingConv(LC), I->getType(),
+                TLI.getLibcallName(LC), std::move(Args));
+  if (!lowerCallTo(CLI))
+    return false;
+  updateValueMap(I, CLI.ResultReg);
+  return true;
+}
+
 bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
   switch (I->getOpcode()) {
   default:
@@ -3698,6 +3739,8 @@ bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
     return SelectSelect(I);
   case Instruction::Ret:
     return SelectRet(I);
+  case Instruction::FRem:
+    return selectFRem(I);
   }
 
   // fall-back to target-independent instruction selection.
diff --git a/test/CodeGen/AArch64/fast-isel-frem.ll b/test/CodeGen/AArch64/fast-isel-frem.ll
new file mode 100644 (file)
index 0000000..3907fd3
--- /dev/null
@@ -0,0 +1,24 @@
+; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel -fast-isel-abort -code-model=small -verify-machineinstrs < %s | FileCheck %s --check-prefix=SMALL
+; RUN: llc -mtriple=aarch64-apple-darwin -fast-isel -fast-isel-abort -code-model=large -verify-machineinstrs < %s | FileCheck %s --check-prefix=LARGE
+
+define float @frem_f32(float %a, float %b) {
+; SMALL-LABEL: frem_f32
+; SMALL:       bl _fmodf
+; LARGE-LABEL: frem_f32
+; LARGE:       adrp  [[REG:x[0-9]+]], _fmodf@GOTPAGE
+; LARGE:       ldr [[REG]], {{\[}}[[REG]], _fmodf@GOTPAGEOFF{{\]}}
+; LARGE-NEXT:  blr [[REG]]
+  %1 = frem float %a, %b
+  ret float %1
+}
+
+define double @frem_f64(double %a, double %b) {
+; SMALL-LABEL: frem_f64
+; SMALL:       bl _fmod
+; LARGE-LABEL: frem_f64
+; LARGE:       adrp  [[REG:x[0-9]+]], _fmod@GOTPAGE
+; LARGE:       ldr [[REG]], {{\[}}[[REG]], _fmod@GOTPAGEOFF{{\]}}
+; LARGE-NEXT:  blr [[REG]]
+  %1 = frem double %a, %b
+  ret double %1
+}