Mterp/arm: Add CFI directives.
Includes reworking of float_to_long and double_to_long to
elminate frame (as suggested by vmarko).
Test: m ART_TEST_INTERPRETER=true test-art-target (in progress)
Bug: 31456348
Change-Id: Ic4e985b977f76c4df926559b187d92d969206514
diff --git a/runtime/interpreter/mterp/arm/entry.S b/runtime/interpreter/mterp/arm/entry.S
index a6b131d..e53c054 100644
--- a/runtime/interpreter/mterp/arm/entry.S
+++ b/runtime/interpreter/mterp/arm/entry.S
@@ -31,10 +31,19 @@
*
*/
-ExecuteMterpImpl:
- .fnstart
- .save {r3-r10,fp,lr}
+ENTRY ExecuteMterpImpl
stmfd sp!, {r3-r10,fp,lr} @ save 10 regs, (r3 just to align 64)
+ .cfi_adjust_cfa_offset 40
+ .cfi_rel_offset r3, 0
+ .cfi_rel_offset r4, 4
+ .cfi_rel_offset r5, 8
+ .cfi_rel_offset r6, 12
+ .cfi_rel_offset r7, 16
+ .cfi_rel_offset r8, 20
+ .cfi_rel_offset r9, 24
+ .cfi_rel_offset r10, 28
+ .cfi_rel_offset fp, 32
+ .cfi_rel_offset lr, 36
/* Remember the return register */
str r3, [r2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
diff --git a/runtime/interpreter/mterp/arm/footer.S b/runtime/interpreter/mterp/arm/footer.S
index cd32ea2..c6801e5 100644
--- a/runtime/interpreter/mterp/arm/footer.S
+++ b/runtime/interpreter/mterp/arm/footer.S
@@ -294,6 +294,5 @@
mov r0, rINST @ restore return value
ldmfd sp!, {r3-r10,fp,pc} @ restore 10 regs and return
- .fnend
- .size ExecuteMterpImpl, .-ExecuteMterpImpl
+ END ExecuteMterpImpl
diff --git a/runtime/interpreter/mterp/arm/header.S b/runtime/interpreter/mterp/arm/header.S
index 039bcbe..597d9d4 100644
--- a/runtime/interpreter/mterp/arm/header.S
+++ b/runtime/interpreter/mterp/arm/header.S
@@ -287,3 +287,24 @@
.macro REFRESH_IBASE
ldr rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
.endm
+
+/*
+ * cfi support macros.
+ */
+.macro ENTRY name
+ .arm
+ .type \name, #function
+ .hidden \name // Hide this as a global symbol, so we do not incur plt calls.
+ .global \name
+ /* Cache alignment for function entry */
+ .balign 16
+\name:
+ .cfi_startproc
+ .fnstart
+.endm
+
+.macro END name
+ .fnend
+ .cfi_endproc
+ .size \name, .-\name
+.endm
diff --git a/runtime/interpreter/mterp/arm/op_double_to_long.S b/runtime/interpreter/mterp/arm/op_double_to_long.S
index b100810..19ff723 100644
--- a/runtime/interpreter/mterp/arm/op_double_to_long.S
+++ b/runtime/interpreter/mterp/arm/op_double_to_long.S
@@ -1,4 +1,3 @@
-@include "arm/unopWide.S" {"instr":"bl __aeabi_d2lz"}
%include "arm/unopWide.S" {"instr":"bl d2l_doconv"}
%break
@@ -10,43 +9,25 @@
* to modest integer. The EABI convert function isn't doing this for us.
*/
d2l_doconv:
- stmfd sp!, {r4, r5, lr} @ save regs
- mov r3, #0x43000000 @ maxlong, as a double (high word)
- add r3, #0x00e00000 @ 0x43e00000
- mov r2, #0 @ maxlong, as a double (low word)
- sub sp, sp, #4 @ align for EABI
- mov r4, r0 @ save a copy of r0
- mov r5, r1 @ and r1
- bl __aeabi_dcmpge @ is arg >= maxlong?
- cmp r0, #0 @ nonzero == yes
- mvnne r0, #0 @ return maxlong (7fffffffffffffff)
- mvnne r1, #0x80000000
- bne 1f
-
- mov r0, r4 @ recover arg
- mov r1, r5
- mov r3, #0xc3000000 @ minlong, as a double (high word)
- add r3, #0x00e00000 @ 0xc3e00000
- mov r2, #0 @ minlong, as a double (low word)
- bl __aeabi_dcmple @ is arg <= minlong?
- cmp r0, #0 @ nonzero == yes
- movne r0, #0 @ return minlong (8000000000000000)
- movne r1, #0x80000000
- bne 1f
-
- mov r0, r4 @ recover arg
- mov r1, r5
- mov r2, r4 @ compare against self
- mov r3, r5
- bl __aeabi_dcmpeq @ is arg == self?
- cmp r0, #0 @ zero == no
- moveq r1, #0 @ return zero for NaN
- beq 1f
-
- mov r0, r4 @ recover arg
- mov r1, r5
- bl __aeabi_d2lz @ convert double to long
-
-1:
- add sp, sp, #4
- ldmfd sp!, {r4, r5, pc}
+ ubfx r2, r1, #20, #11 @ grab the exponent
+ movw r3, #0x43e
+ cmp r2, r3 @ MINLONG < x > MAXLONG?
+ bhs d2l_special_cases
+ b __aeabi_d2lz @ tail call to convert double to long
+d2l_special_cases:
+ movw r3, #0x7ff
+ cmp r2, r3
+ beq d2l_maybeNaN @ NaN?
+d2l_notNaN:
+ adds r1, r1, r1 @ sign bit to carry
+ mov r0, #0xffffffff @ assume maxlong for lsw
+ mov r1, #0x7fffffff @ assume maxlong for msw
+ adc r0, r0, #0
+ adc r1, r1, #0 @ convert maxlong to minlong if exp negative
+ bx lr @ return
+d2l_maybeNaN:
+ orrs r3, r0, r1, lsl #12
+ beq d2l_notNaN @ if fraction is non-zero, it's a NaN
+ mov r0, #0
+ mov r1, #0
+ bx lr @ return 0 for NaN
diff --git a/runtime/interpreter/mterp/arm/op_float_to_long.S b/runtime/interpreter/mterp/arm/op_float_to_long.S
index 5c8680f..1770ea0 100644
--- a/runtime/interpreter/mterp/arm/op_float_to_long.S
+++ b/runtime/interpreter/mterp/arm/op_float_to_long.S
@@ -1,4 +1,3 @@
-@include "arm/unopWider.S" {"instr":"bl __aeabi_f2lz"}
%include "arm/unopWider.S" {"instr":"bl f2l_doconv"}
%break
@@ -10,30 +9,23 @@
* to modest integer. The EABI convert function isn't doing this for us.
*/
f2l_doconv:
- stmfd sp!, {r4, lr}
- mov r1, #0x5f000000 @ (float)maxlong
- mov r4, r0
- bl __aeabi_fcmpge @ is arg >= maxlong?
- cmp r0, #0 @ nonzero == yes
- mvnne r0, #0 @ return maxlong (7fffffff)
- mvnne r1, #0x80000000
- popne {r4, pc}
-
- mov r0, r4 @ recover arg
- mov r1, #0xdf000000 @ (float)minlong
- bl __aeabi_fcmple @ is arg <= minlong?
- cmp r0, #0 @ nonzero == yes
- movne r0, #0 @ return minlong (80000000)
- movne r1, #0x80000000
- popne {r4, pc}
-
- mov r0, r4 @ recover arg
- mov r1, r4
- bl __aeabi_fcmpeq @ is arg == self?
- cmp r0, #0 @ zero == no
- moveq r1, #0 @ return zero for NaN
- popeq {r4, pc}
-
- mov r0, r4 @ recover arg
- bl __aeabi_f2lz @ convert float to long
- ldmfd sp!, {r4, pc}
+ ubfx r2, r0, #23, #8 @ grab the exponent
+ cmp r2, #0xbe @ MININT < x > MAXINT?
+ bhs f2l_special_cases
+ b __aeabi_f2lz @ tail call to convert float to long
+f2l_special_cases:
+ cmp r2, #0xff @ NaN or infinity?
+ beq f2l_maybeNaN
+f2l_notNaN:
+ adds r0, r0, r0 @ sign bit to carry
+ mov r0, #0xffffffff @ assume maxlong for lsw
+ mov r1, #0x7fffffff @ assume maxlong for msw
+ adcs r0, r0, #0 @ convert maxlong to minlong if exp negative
+ adc r1, r1, #0 @ convert maxlong to minlong if exp negative
+ bx lr @ return
+f2l_maybeNaN:
+ lsls r3, r0, #9
+ beq f2l_notNaN @ if fraction is non-zero, it's a NaN
+ mov r0, #0
+ mov r1, #0
+ bx lr @ return 0 for NaN
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index 4d540d7..c80d6b9 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -295,6 +295,27 @@
ldr rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET]
.endm
+/*
+ * cfi support macros.
+ */
+.macro ENTRY name
+ .arm
+ .type \name, #function
+ .hidden \name // Hide this as a global symbol, so we do not incur plt calls.
+ .global \name
+ /* Cache alignment for function entry */
+ .balign 16
+\name:
+ .cfi_startproc
+ .fnstart
+.endm
+
+.macro END name
+ .fnend
+ .cfi_endproc
+ .size \name, .-\name
+.endm
+
/* File: arm/entry.S */
/*
* Copyright (C) 2016 The Android Open Source Project
@@ -329,10 +350,19 @@
*
*/
-ExecuteMterpImpl:
- .fnstart
- .save {r3-r10,fp,lr}
+ENTRY ExecuteMterpImpl
stmfd sp!, {r3-r10,fp,lr} @ save 10 regs, (r3 just to align 64)
+ .cfi_adjust_cfa_offset 40
+ .cfi_rel_offset r3, 0
+ .cfi_rel_offset r4, 4
+ .cfi_rel_offset r5, 8
+ .cfi_rel_offset r6, 12
+ .cfi_rel_offset r7, 16
+ .cfi_rel_offset r8, 20
+ .cfi_rel_offset r9, 24
+ .cfi_rel_offset r10, 28
+ .cfi_rel_offset fp, 32
+ .cfi_rel_offset lr, 36
/* Remember the return register */
str r3, [r2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
@@ -3664,7 +3694,6 @@
.balign 128
.L_op_float_to_long: /* 0x88 */
/* File: arm/op_float_to_long.S */
-@include "arm/unopWider.S" {"instr":"bl __aeabi_f2lz"}
/* File: arm/unopWider.S */
/*
* Generic 32bit-to-64bit unary operation. Provide an "instr" line
@@ -3742,7 +3771,6 @@
.balign 128
.L_op_double_to_long: /* 0x8b */
/* File: arm/op_double_to_long.S */
-@include "arm/unopWide.S" {"instr":"bl __aeabi_d2lz"}
/* File: arm/unopWide.S */
/*
* Generic 64-bit unary operation. Provide an "instr" line that
@@ -7386,33 +7414,26 @@
* to modest integer. The EABI convert function isn't doing this for us.
*/
f2l_doconv:
- stmfd sp!, {r4, lr}
- mov r1, #0x5f000000 @ (float)maxlong
- mov r4, r0
- bl __aeabi_fcmpge @ is arg >= maxlong?
- cmp r0, #0 @ nonzero == yes
- mvnne r0, #0 @ return maxlong (7fffffff)
- mvnne r1, #0x80000000
- popne {r4, pc}
-
- mov r0, r4 @ recover arg
- mov r1, #0xdf000000 @ (float)minlong
- bl __aeabi_fcmple @ is arg <= minlong?
- cmp r0, #0 @ nonzero == yes
- movne r0, #0 @ return minlong (80000000)
- movne r1, #0x80000000
- popne {r4, pc}
-
- mov r0, r4 @ recover arg
- mov r1, r4
- bl __aeabi_fcmpeq @ is arg == self?
- cmp r0, #0 @ zero == no
- moveq r1, #0 @ return zero for NaN
- popeq {r4, pc}
-
- mov r0, r4 @ recover arg
- bl __aeabi_f2lz @ convert float to long
- ldmfd sp!, {r4, pc}
+ ubfx r2, r0, #23, #8 @ grab the exponent
+ cmp r2, #0xbe @ MININT < x > MAXINT?
+ bhs f2l_special_cases
+ b __aeabi_f2lz @ tail call to convert float to long
+f2l_special_cases:
+ cmp r2, #0xff @ NaN or infinity?
+ beq f2l_maybeNaN
+f2l_notNaN:
+ adds r0, r0, r0 @ sign bit to carry
+ mov r0, #0xffffffff @ assume maxlong for lsw
+ mov r1, #0x7fffffff @ assume maxlong for msw
+ adcs r0, r0, #0 @ convert maxlong to minlong if exp negative
+ adc r1, r1, #0 @ convert maxlong to minlong if exp negative
+ bx lr @ return
+f2l_maybeNaN:
+ lsls r3, r0, #9
+ beq f2l_notNaN @ if fraction is non-zero, it's a NaN
+ mov r0, #0
+ mov r1, #0
+ bx lr @ return 0 for NaN
/* continuation for op_double_to_long */
/*
@@ -7423,46 +7444,28 @@
* to modest integer. The EABI convert function isn't doing this for us.
*/
d2l_doconv:
- stmfd sp!, {r4, r5, lr} @ save regs
- mov r3, #0x43000000 @ maxlong, as a double (high word)
- add r3, #0x00e00000 @ 0x43e00000
- mov r2, #0 @ maxlong, as a double (low word)
- sub sp, sp, #4 @ align for EABI
- mov r4, r0 @ save a copy of r0
- mov r5, r1 @ and r1
- bl __aeabi_dcmpge @ is arg >= maxlong?
- cmp r0, #0 @ nonzero == yes
- mvnne r0, #0 @ return maxlong (7fffffffffffffff)
- mvnne r1, #0x80000000
- bne 1f
-
- mov r0, r4 @ recover arg
- mov r1, r5
- mov r3, #0xc3000000 @ minlong, as a double (high word)
- add r3, #0x00e00000 @ 0xc3e00000
- mov r2, #0 @ minlong, as a double (low word)
- bl __aeabi_dcmple @ is arg <= minlong?
- cmp r0, #0 @ nonzero == yes
- movne r0, #0 @ return minlong (8000000000000000)
- movne r1, #0x80000000
- bne 1f
-
- mov r0, r4 @ recover arg
- mov r1, r5
- mov r2, r4 @ compare against self
- mov r3, r5
- bl __aeabi_dcmpeq @ is arg == self?
- cmp r0, #0 @ zero == no
- moveq r1, #0 @ return zero for NaN
- beq 1f
-
- mov r0, r4 @ recover arg
- mov r1, r5
- bl __aeabi_d2lz @ convert double to long
-
-1:
- add sp, sp, #4
- ldmfd sp!, {r4, r5, pc}
+ ubfx r2, r1, #20, #11 @ grab the exponent
+ movw r3, #0x43e
+ cmp r2, r3 @ MINLONG < x > MAXLONG?
+ bhs d2l_special_cases
+ b __aeabi_d2lz @ tail call to convert double to long
+d2l_special_cases:
+ movw r3, #0x7ff
+ cmp r2, r3
+ beq d2l_maybeNaN @ NaN?
+d2l_notNaN:
+ adds r1, r1, r1 @ sign bit to carry
+ mov r0, #0xffffffff @ assume maxlong for lsw
+ mov r1, #0x7fffffff @ assume maxlong for msw
+ adcs r0, r0, #0
+ adc r1, r1, #0 @ convert maxlong to minlong if exp negative
+ bx lr @ return
+d2l_maybeNaN:
+ orrs r3, r0, r1, lsl #12
+ beq d2l_notNaN @ if fraction is non-zero, it's a NaN
+ mov r0, #0
+ mov r1, #0
+ bx lr @ return 0 for NaN
.size artMterpAsmSisterStart, .-artMterpAsmSisterStart
.global artMterpAsmSisterEnd
@@ -12115,6 +12118,17 @@
cmp rPROFILE, #0
bgt MterpProfileActive @ if > 0, we may have some counts to report.
ldmfd sp!, {r3-r10,fp,pc} @ restore 10 regs and return
+ .cfi_restore r3
+ .cfi_restore r4
+ .cfi_restore r5
+ .cfi_restore r6
+ .cfi_restore r7
+ .cfi_restore r9
+ .cfi_restore r9
+ .cfi_restore r10
+ .cfi_restore fp
+ .cfi_restore pc
+ .cfi_adjust_cfa_offset -40
MterpProfileActive:
mov rINST, r0 @ stash return value
@@ -12126,8 +12140,18 @@
bl MterpAddHotnessBatch @ (method, shadow_frame, self)
mov r0, rINST @ restore return value
ldmfd sp!, {r3-r10,fp,pc} @ restore 10 regs and return
+ .cfi_restore r3
+ .cfi_restore r4
+ .cfi_restore r5
+ .cfi_restore r6
+ .cfi_restore r7
+ .cfi_restore r9
+ .cfi_restore r9
+ .cfi_restore r10
+ .cfi_restore fp
+ .cfi_restore pc
+ .cfi_adjust_cfa_offset -40
- .fnend
- .size ExecuteMterpImpl, .-ExecuteMterpImpl
+ END ExecuteMterpImpl
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 146f309..7754b75 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -390,6 +390,8 @@
assertLongEquals(9223372036854775807L, $opt$noinline$FloatToLong(9223372036854775807F)); // 2^63 - 1
assertLongEquals(-9223372036854775808L, $opt$noinline$FloatToLong(-9223372036854775807F)); // -(2^63 - 1)
assertLongEquals(-9223372036854775808L, $opt$noinline$FloatToLong(-9223372036854775808F)); // -(2^63)
+ assertLongEquals(9223371487098961920L, $opt$noinline$FloatToLong(9223371487098961920F)); // Math.nextAfter(2F^63, 0)
+ assertLongEquals(-9223371487098961920L, $opt$noinline$FloatToLong(-9223371487098961920F)); // Math.nextAfter(-2F^63, 0)
assertLongEquals(0L, $opt$noinline$FloatToLong(Float.NaN));
assertLongEquals(9223372036854775807L, $opt$noinline$FloatToLong(Float.POSITIVE_INFINITY));
assertLongEquals(-9223372036854775808L, $opt$noinline$FloatToLong(Float.NEGATIVE_INFINITY));
@@ -469,6 +471,8 @@
assertLongEquals(-9223372036854775808L, $opt$noinline$DoubleToLong(-9223372036854775807D)); // -(2^63 - 1)
assertLongEquals(-9223372036854775808L, $opt$noinline$DoubleToLong(-9223372036854775808D)); // -(2^63)
assertLongEquals(0L, $opt$noinline$DoubleToLong(Double.NaN));
+ assertLongEquals(9223372036854774784L, $opt$noinline$DoubleToLong(9223372036854774784D)); // Math.nextAfter(2D^63, 0)
+ assertLongEquals(-9223372036854774784L, $opt$noinline$DoubleToLong(-9223372036854774784D)); // Math.nextAfter(-2D^63, 0)
assertLongEquals(9223372036854775807L, $opt$noinline$DoubleToLong(Double.POSITIVE_INFINITY));
assertLongEquals(-9223372036854775808L, $opt$noinline$DoubleToLong(Double.NEGATIVE_INFINITY));
}