ARM support status (GHC/ARM new calling convention)

Hello,

I'm working on implementing GHC specific call convention into LLVM 2.9. I've chosen LLVM 2.9 as a kind of stable reference point and I would like to know how mature is ARM code generation chain inside this release. I've had a hope that perhaps Apple as a main sponsor of LLVM is using LLVM for their ARM based iOS software development, but I'm not sure if I'm right at this.
Anyway what I need to do is already done for x86/x64 by David Terei last year. He describes it well here:

and he submitted the patch here:
http://lists.cs.uiuc.edu/pipermail/llvmdev/attachments/20100307/714e5c37/attachment-0001.obj

Please bear with me, I'm neither LLVM nor GHC nor ARM expert but this is my own hobby project to start learning at least Haskell and ARM. My current state of the work is attached in the form of patch against LLVM 2.9. Basically speaking I'm just trying to mimic work done by David for x86 and do the similar thing for ARM. This is also the case of ghc-cc.ll testcase which I've directly got from David's x64 version -- so instructions with CHECK/CHECK-NEXT are still from x86. I just would like to get testcase run through the llc which is still not the case. In fact llc crashes with:

(gdb) set args < /export/home/karel/vcs/llvm-2.9/test/CodeGen/ARM/ghc-cc.ll -tailcallopt -mtriple=arm-linux-gnu
(gdb) run
Starting program: /export/home/karel/vcs/llvm-2.9/Debug/bin/llc < /export/home/karel/vcs/llvm-2.9/test/CodeGen/ARM/ghc-cc.ll -tailcallopt -mtriple=arm-linux-gnu
warning: Lowest section in /lib/libpthread.so.1 is .dynamic at 00000074
  .syntax unified
  .eabi_attribute 6, 2
  .eabi_attribute 8, 1
  .eabi_attribute 9, 1
  .eabi_attribute 20, 1
  .eabi_attribute 21, 1
  .eabi_attribute 23, 3
  .eabi_attribute 24, 1
  .eabi_attribute 25, 1
  .file "<stdin>"
  .text
  .globl zap
  .align 2
  .type zap,%function
zap: @ @zap
@ BB#0: @ %entry
  push {r4, r5, lr}
  mov r4, r0
  mov r5, r1
  bl addtwo
  bl foo
  pop {r4, r5, lr}
  bx lr
.Ltmp0:
  .size zap, .Ltmp0-zap

  .globl addtwo
  .align 2
  .type addtwo,%function
addtwo: @ @addtwo
@ BB#0: @ %entry
  str lr, [sp, #-4]!
  add r4, r4, r5
  ldr lr, [sp], #4
  bx lr
.Ltmp1:
  .size addtwo, .Ltmp1-addtwo

UNREACHABLE executed!

Program received signal SIGABRT, Aborted.
0xfeda2945 in _lwp_kill () from /lib/libc.so.1
(gdb) where
#0 0xfeda2945 in _lwp_kill () from /lib/libc.so.1
#1 0xfed9b27c in thr_kill () from /lib/libc.so.1
#2 0xfed49f4a in raise () from /lib/libc.so.1
#3 0xfed2197c in abort () from /lib/libc.so.1
#4 0x08fc40fa in llvm::llvm_unreachable_internal (msg=0x0, file=0x0, line=0) at ErrorHandling.cpp:99
#5 0x08bcbf19 in llvm::CCState::AnalyzeCallOperands (this=0x8045c80, Outs=@0x8046350,
     Fn=0x88c7838 <ARM_AAPCS_GHC>) at CallingConvLower.cpp:126
#6 0x088cb08a in llvm::ARMTargetLowering::LowerCall (this=0x92b4c58, Chain=
       {Node = 0x92d1b50, ResNo = 0}, Callee={Node = 0x92d1c60, ResNo = 0},
     CallConv=llvm::CallingConv::GHC, isVarArg=false, isTailCall=@0x804656b, Outs=@0x8046350,
     OutVals=@0x8046230, Ins=@0x8045f30, dl={LineCol = 0, ScopeIdx = 0}, DAG=@0x92bdea8,
     InVals=@0x80461f0) at ARMISelLowering.cpp:1209
#7 0x08aece19 in llvm::TargetLowering::LowerCallTo (this=0x92b4c58, Chain=
       {Node = 0x92d1b50, ResNo = 0}, RetTy=0x92aee1c, RetSExt=false, RetZExt=false, isVarArg=false,
     isInreg=false, NumFixedArgs=7, CallConv=llvm::CallingConv::GHC, isTailCall=false,
     isReturnValueUsed=false, Callee={Node = 0x92d1c60, ResNo = 0}, Args=@0x80468d0, DAG=@0x92bdea8,
     dl={LineCol = 0, ScopeIdx = 0}) at SelectionDAGBuilder.cpp:6135
#8 0x08ae73df in llvm::SelectionDAGBuilder::LowerCallTo (this=0x92be358, CS=
           {<llvm::CallSiteBase<const llvm::Function,const llvm::Value,const llvm::User,const llvm::Instruction,const llvm::CallInst,const llvm::InvokeInst,const llvm::Use*>> = {I = {Value = 153830658}}, <No data fields>}, Callee={Node = 0x92d1c60, ResNo = 0}, isTailCall=true, LandingPad=0x0)
     at SelectionDAGBuilder.cpp:4880
#9 0x08ae9302 in llvm::SelectionDAGBuilder::visitCall (this=0x92be358, I=@0x92b4500)
     at SelectionDAGBuilder.cpp:5211
#10 0x08acfc5c in llvm::SelectionDAGBuilder::visit (this=0x92be358, Opcode=45, I=@0x92b4500)
     at /export/home/karel/vcs/llvm-2.9/include/llvm/Instruction.def:161
#11 0x08acf7be in llvm::SelectionDAGBuilder::visit (this=0x92be358, I=@0x92b4500)
     at SelectionDAGBuilder.cpp:864
#12 0x08b02903 in llvm::SelectionDAGISel::SelectBasicBlock (this=0x92bdb50, Begin=
       {<std::iterator<std::bidirectional_iterator_tag,const llvm::Instruction,ptrdiff_t,const llvm::Instruction*,const llvm::Instruction&>> = {<No data fields>}, NodePtr = 0x92b41ac}, End=
       {<std::iterator<std::bidirectional_iterator_tag,const llvm::Instruction,ptrdiff_t,const llvm::Instruction*,const llvm::Instruction&>> = {<No data fields>}, NodePtr = 0x92af688},
     HadTailCall=@0x8046c7b) at SelectionDAGISel.cpp:432
#13 0x08b0442e in llvm::SelectionDAGISel::SelectAllBasicBlocks (this=0x92bdb50, Fn=@0x92b3f50)
     at SelectionDAGISel.cpp:981
#14 0x08b01f7c in llvm::SelectionDAGISel::runOnMachineFunction (this=0x92bdb50, mf=@0x92ce000)
     at SelectionDAGISel.cpp:307
#15 0x08c0ddc3 in llvm::MachineFunctionPass::runOnFunction (this=0x92bdb50, F=@0x92b3f50)
     at MachineFunctionPass.cpp:33
#16 0x08f18f30 in llvm::FPPassManager::runOnFunction (this=0x92ba4d8, F=@0x92b3f50)
     at PassManager.cpp:1483
#17 0x08f190c3 in llvm::FPPassManager::runOnModule (this=0x92ba4d8, M=@0x92b3428)
     at PassManager.cpp:1503
#18 0x08f193b5 in llvm::MPPassManager::runOnModule (this=0x92b8438, M=@0x92b3428)
     at PassManager.cpp:1557
#19 0x08f197ad in llvm::PassManagerImpl::run (this=0x92b8288, M=@0x92b3428) at PassManager.cpp:1638
#20 0x08f19cde in llvm::PassManager::run (this=0x8047030, M=@0x92b3428) at PassManager.cpp:1682
#21 0x086e8ed1 in main (argc=3, argv=0x8047170) at llc.cpp:341
(gdb)

it seems my modified LLVM does not like passing i32 type argument into function @foo. If I comment out line:
   %6 = load i32* @splim

llc does not crash. Also in the llvm::ARMTargetLowering::LowerCall I see a comment about disabling tailcalls just to not break things.
I'm quite curious if this is still the case since tailcalls are used in GHC, that's also the reason why I ask about status of LLVM on ARM platform above. If the status is all right, then could someone here be so kind and guide me thorough the LLVM doc and recommend what to read and what not in order to perform my task of LLVM modification for GHC calling convention on ARM platform? So far I'm just blindly attempting to fix things which just crashes... Also is there any way how to convince llc to support -debug argument? I've build debug build, but it looks like -debug is missing...

Thanks a lot!
Karel

ghc-llvm-arm.diff (4.36 KB)

ghc-cc.ll (2.76 KB)

I'm working on implementing GHC specific call convention into LLVM 2.9. I've chosen LLVM 2.9 as a kind of stable reference point and I would like to know how mature is ARM code generation chain inside this release. I've had a hope that perhaps Apple as a main sponsor of LLVM is using LLVM for their ARM based iOS software development, but I'm not sure if I'm right at this.

You are right about this. ARM code generation is quite mature.

Please bear with me, I'm neither LLVM nor GHC nor ARM expert but this is my own hobby project to start learning at least Haskell and ARM. My current state of the work is attached in the form of patch against LLVM 2.9.

I'm not really qualified to judge your patch, but please note that to have it accepted into LLVM you'll need to make it work on ToT.

Also in the llvm::ARMTargetLowering::LowerCall I see a comment about disabling tailcalls just to not break things.

I believe this has been changed on ToT, so since Haskell is presumably completely dependent on tail calls working, you'll need to work there.

Also is there any way how to convince llc to support -debug argument? I've build debug build, but it looks like -debug is missing...

What are you trying to do here? Emit debug info?

John.

I'm working on implementing GHC specific call convention into LLVM
2.9. I've chosen LLVM 2.9 as a kind of stable reference point and I
would like to know how mature is ARM code generation chain inside
this release. I've had a hope that perhaps Apple as a main sponsor
of LLVM is using LLVM for their ARM based iOS software development,
but I'm not sure if I'm right at this.

You are right about this. ARM code generation is quite mature.

Great to hear that.

Please bear with me, I'm neither LLVM nor GHC nor ARM expert but
this is my own hobby project to start learning at least Haskell and
ARM. My current state of the work is attached in the form of patch
against LLVM 2.9.

I'm not really qualified to judge your patch, but please note that to
have it accepted into LLVM you'll need to make it work on ToT.

OK, I'll move to git then.

Also is there any way how to convince llc to support -debug
argument? I've build debug build, but it looks like -debug is
missing...

What are you trying to do here? Emit debug info?

Just to execute printing like:
#ifndef NDEBUG
       dbgs() << "Call operand #" << i << " has unhandled type "
              << EVT(ArgVT).getEVTString();
#endif

Thanks a lot!
Karel

Use the DEBUG() macro. It'll handle this sort of thing for you. Have a look at some of the existing passes for usage examples It interacts with DEBUG_TYPE to selectively handle debug information.

-Jim

John,

I've moved with patches to HEAD and unfortunately the comments about disabling tailcalls do not go away with this update. Please see ARMTargetLowering::LowerCall in lib/Target/ARM/ARMISelLowering.cpp line 1208 and later. It looks like man can use -arm-tail-calls, but one never knows how good it is since the comment tells it clearly:

// Temporarily disable tail calls so things don't break.

so I would like to ask what's the status of tailcalls in LLVM on ARM platform?

Thanks a lot!
Karel

They work pretty well now, at least on Thumb2 / Darwin. It is still fairly conservative about when to use tail calls, and doesn't support GuaranteedTailCallOpt, which might be necessary for GHC.

Cameron

Hello Cameron,

thanks a lot for your fast answer, which just makes me curious if making ARM tailcalls on par with x86 in the future is on some of the development plans already? If not, then what do you think is the complexity of such work?

Thanks!
Karel

I don't know if GuaranteedTailCallOpt is in anyone's plans. It might be a good idea to implement some time. I am not sure what GHC's exact needs are, though.

Cameron

I don't know if GuaranteedTailCallOpt is in anyone's plans. It might be a good idea to implement some time. I am not sure what GHC's exact needs are, though.

We (GHC) simply rely of the sibling call optimisation:

http://llvm.org/docs/CodeGenerator.html#sibcallopt

We don't use the GuaranteedTailCallOpt any more as we always generate
code that meets the condition for sibling call opt and it generates
much better code than GuaranteedTailCallOpt. (GuaranteedTailCallOpt
did a lot of silly stack ptr movement, not sure if still the case).

Cheers,
David