From f80899cb3eb75f7f5640b4519e83bd96991bffb8 Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Wed, 7 Nov 2018 23:10:31 +0100 Subject: [PATCH] [mono] respect hardfloat/softloat setting in ARM ABI (#16) Mono's LLVM backend was always emitting code like this: > 000d7234 : > d7234: e92d4800 push {fp, lr} > d7238: ed2d8b02 vpush {d8} > d723c: ed908b00 vldr d8, [r0] > d7240: eb12e4e2 bl 5905d0 > d7244: e1a03000 mov r3, r0 > d7248: ec510b18 vmov r0, r1, d8 > d724c: e3a02000 mov r2, #0 > d7250: eb12e91a bl 5916c0 > d7254: ecbd8b02 vpop {d8} > d7258: e8bd8800 pop {fp, pc} despite the correct setting passed to `llc`. Note that passing the floating point value (`d8`) in the integer registers `r0` and `r1` is wrong. With this change we get the following: > 000d9934 : > d9934: e92d4800 push {fp, lr} > d9938: ed2d8b02 vpush {d8} > d993c: ed908b00 vldr d8, [r0] > d9940: eb137c2e bl 5b8a00 > d9944: eeb00b48 vmov.f64 d0, d8 > d9948: e1a01000 mov r1, r0 > d994c: e3a00000 mov r0, #0 > d9950: eb138066 bl 5b9af0 > d9954: ecbd8b02 vpop {d8} > d9958: e8bd4800 pop {fp, lr} > d995c: e1a0f00e mov pc, lr Which matches with what the Mono JIT emits: > 0: e92d4100 push {r8, lr} > 4: e24dd028 sub sp, sp, #40 ; 0x28 > 8: e58d0018 str r0, [sp, #24] > c: e59d0018 ldr r0, [sp, #24] > 10: ed900b00 vldr d0, [r0] > 14: ed8d0b08 vstr d0, [sp, #32] > 18: eb00000e bl 0x58 > 1c: e1a01000 mov r1, r0 > 20: ed9d0b08 vldr d0, [sp, #32] > 24: e3a00000 mov r0, #0 > 28: eb000007 bl 0x4c > 2c: e28dd028 add sp, sp, #40 ; 0x28 > 30: e8bd8100 pop {r8, pc} Both are passing the floating point argument correctly via `d0`. Fixes https://github.com/mono/mono/issues/11095 --- lib/Target/ARM/ARMCallingConv.td | 8 ++++++++ lib/Target/ARM/ARMISelLowering.cpp | 11 +++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/Target/ARM/ARMCallingConv.td b/lib/Target/ARM/ARMCallingConv.td index 956696c7d02..0380983ef54 100644 --- a/lib/Target/ARM/ARMCallingConv.td +++ b/lib/Target/ARM/ARMCallingConv.td @@ -261,3 +261,11 @@ def CSR_GenericInt : CalleeSavedRegs<(add LR, (sequence "R%u", 12, 0))>; def CSR_FIQ : CalleeSavedRegs<(add LR, R11, (sequence "R%u", 7, 0))>; +def CC_ARM_Mono_AAPCS_VFP : CallingConv<[ + // Mono marks the parameter it wants to pass in this non-abi register with + // the 'inreg' attribute. + CCIfInReg>, + + CCDelegateTo +]>; + diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 637107c021f..e3df48343f7 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -1322,10 +1322,13 @@ CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC, if (Return) { return CCAssignFnForNode(CallingConv::C, true, isVarArg); } else { - if (Subtarget->isAAPCS_ABI()) - return CC_ARM_Mono_AAPCS; - else - return CC_ARM_Mono_APCS; + if (Subtarget->isAAPCS_ABI()) { + if (Subtarget->hasVFP2() && !Subtarget->isThumb1Only() && !isVarArg) + return CC_ARM_Mono_AAPCS_VFP; + else + return CC_ARM_Mono_AAPCS; + } else + return CC_ARM_Mono_APCS; } } }