[Lazarus] UTF8LengthFast returning incorrect results on AARCH64 (MacOS)

Noel Duffy noelduffy at xtra.co.nz
Tue Dec 28 22:05:23 CET 2021


On 29/12/21 01:26, Bart via lazarus wrote:
> fpc -al ulen.pas

 > This will produce the file ulen.s
 > You can attach or copy that here.

File is attached.

The output from running this program is:

% ./ulen
Signed version
Len = -100663283
Unsigned version
Len = 1

To add another wrinkle to this, the signed and unsigned versions of the 
code both work if compiled with fpc 3.2.2. It's only when compiled with 
3.3.1 that I get an incorrect result.
-------------- next part --------------
# Begin asmlist al_procedures

.text
	.align 4
.globl	_P$ULEN_$$_UTF8LENGTHFAST_SIGNED$PCHAR$INT64$$INT64
_P$ULEN_$$_UTF8LENGTHFAST_SIGNED$PCHAR$INT64$$INT64:
# [ulen.pas]
# [28] begin
	stp	x29,x30,[sp, #-16]!
	mov	x29,sp
	sub	sp,sp,#64
# Var p located at sp+0, size=OS_64
# Var ByteCount located at sp+8, size=OS_S64
# Var $result located at sp+16, size=OS_S64
# Var nx located at sp+24, size=OS_S64
# Var i located at sp+32, size=OS_S64
# Var cnt located at sp+40, size=OS_S64
# Var e located at sp+48, size=OS_S64
	str	x0,[sp]
	str	x1,[sp, #8]
# [29] Result := 0;
	str	xzr,[sp, #16]
# [30] e := ix+ByteCount; // End marker
	ldr	x0,[sp]
	ldr	x1,[sp, #8]
	add	x0,x1,x0
	str	x0,[sp, #48]
# [32] cnt := (not (ix-1)) and (sizeof(PtrInt)-1);
	ldr	x0,[sp]
	sub	x0,x0,#1
	mvn	x0,x0
	and	x0,x0,#7
	str	x0,[sp, #40]
# [33] if cnt>ByteCount then
	ldr	x0,[sp, #40]
	ldr	x1,[sp, #8]
	cmp	x0,x1
	b.gt	Lj7
	b	Lj8
Lj7:
# [34] cnt := ByteCount;
	ldr	x0,[sp, #8]
	str	x0,[sp, #40]
Lj8:
# [35] for i := 1 to cnt do
	ldr	x1,[sp, #40]
	cmp	x1,#1
	b.ge	Lj9
	b	Lj10
Lj9:
	str	xzr,[sp, #32]
Lj11:
	ldr	x0,[sp, #32]
	add	x0,x0,#1
	str	x0,[sp, #32]
# [43] Result += (pn8^ shr 7) and ((not pn8^) shr 6);
	ldr	x0,[sp]
	ldrsb	w0,[x0]
	eor	w0,w0,#255
	lsr	w0,w0,#6
	ldr	x2,[sp]
	ldrsb	w2,[x2]
	lsr	w2,w2,#7
	and	w0,w2,w0
	sxtw	x0,w0
	ldr	x2,[sp, #16]
	add	x0,x2,x0
	str	x0,[sp, #16]
# [44] inc(pn8);
	ldr	x0,[sp]
	add	x0,x0,#1
	str	x0,[sp]
	ldr	x0,[sp, #32]
	cmp	x1,x0
	b.le	Lj13
	b	Lj11
Lj13:
Lj10:
# [47] for i := 1 to (ByteCount-cnt) div sizeof(PtrUInt) do
	ldr	x0,[sp, #8]
	ldr	x1,[sp, #40]
	sub	x0,x0,x1
	asr	x1,x0,#63
	add	x0,x0,x1,lsr #61
	asr	x0,x0,#3
	cmp	x0,#1
	b.ge	Lj14
	b	Lj15
Lj14:
	str	xzr,[sp, #32]
Lj16:
	ldr	x1,[sp, #32]
	add	x1,x1,#1
	str	x1,[sp, #32]
# [50] nx := ((pnx^ and EIGHTYMASK) shr 7) and ((not pnx^) shr 6);
	ldr	x1,[sp]
	ldr	x1,[x1]
	and	x1,x1,#0x8080808080808080
	lsr	x1,x1,#7
	ldr	x2,[sp]
	ldr	x2,[x2]
	mvn	x2,x2
	lsr	x2,x2,#6
	and	x1,x2,x1
	str	x1,[sp, #24]
# [52] Result += (nx * ONEMASK) >> ((sizeof(PtrInt) - 1) * 8);
	ldr	x1,[sp, #24]
	mov	x2,#72340172838076673
	mul	x1,x1,x2
	lsr	x1,x1,#56
	ldr	x2,[sp, #16]
	add	x1,x2,x1
	str	x1,[sp, #16]
# [54] inc(pnx);
	ldr	x1,[sp]
	add	x1,x1,#8
	str	x1,[sp]
	ldr	x1,[sp, #32]
	cmp	x0,x1
	b.le	Lj18
	b	Lj16
Lj18:
Lj15:
# [57] while ix<e do
	b	Lj20
Lj19:
# [66] Result += (pn8^ shr 7) and ((not pn8^) shr 6);
	ldr	x0,[sp]
	ldrsb	w0,[x0]
	eor	w0,w0,#255
	lsr	w0,w0,#6
	ldr	x1,[sp]
	ldrsb	w1,[x1]
	lsr	w1,w1,#7
	and	w0,w1,w0
	sxtw	x1,w0
	ldr	x0,[sp, #16]
	add	x0,x0,x1
	str	x0,[sp, #16]
# [67] inc(pn8);
	ldr	x0,[sp]
	add	x0,x0,#1
	str	x0,[sp]
Lj20:
	ldr	x0,[sp]
	ldr	x1,[sp, #48]
	cmp	x0,x1
	b.lt	Lj19
	b	Lj21
Lj21:
# [69] Result := ByteCount - Result;
	ldr	x1,[sp, #8]
	ldr	x0,[sp, #16]
	sub	x0,x1,x0
	str	x0,[sp, #16]
# [70] end;
	ldr	x0,[sp, #16]
	mov	sp,x29
	ldp	x29,x30,[sp], #16
	ret

.text
	.align 4
.globl	_P$ULEN_$$_UTF8LENGTHFAST_UNSIGNED$PCHAR$INT64$$INT64
_P$ULEN_$$_UTF8LENGTHFAST_UNSIGNED$PCHAR$INT64$$INT64:
# [88] begin
	stp	x29,x30,[sp, #-16]!
	mov	x29,sp
	sub	sp,sp,#64
# Var p located at sp+0, size=OS_64
# Var ByteCount located at sp+8, size=OS_S64
# Var $result located at sp+16, size=OS_S64
# Var nx located at sp+24, size=OS_64
# Var i located at sp+32, size=OS_S64
# Var cnt located at sp+40, size=OS_S64
# Var e located at sp+48, size=OS_S64
	str	x0,[sp]
	str	x1,[sp, #8]
# [89] Result := 0;
	str	xzr,[sp, #16]
# [90] e := ix+PtrUInt(ByteCount); // End marker
	ldr	x1,[sp]
	ldr	x0,[sp, #8]
	add	x0,x0,x1
	str	x0,[sp, #48]
# [92] cnt := (not (ix-1)) and (sizeof(PtrInt)-1);
	ldr	x0,[sp]
	sub	x0,x0,#1
	mvn	x0,x0
	and	x0,x0,#7
	str	x0,[sp, #40]
# [93] if cnt>ByteCount then
	ldr	x0,[sp, #40]
	ldr	x1,[sp, #8]
	cmp	x0,x1
	b.gt	Lj24
	b	Lj25
Lj24:
# [94] cnt := ByteCount;
	ldr	x0,[sp, #8]
	str	x0,[sp, #40]
Lj25:
# [95] for i := 1 to cnt do
	ldr	x1,[sp, #40]
	cmp	x1,#1
	b.ge	Lj26
	b	Lj27
Lj26:
	str	xzr,[sp, #32]
Lj28:
	ldr	x0,[sp, #32]
	add	x0,x0,#1
	str	x0,[sp, #32]
# [103] Result += (pn8^ shr 7) and ((not pn8^) shr 6);
	ldr	x0,[sp]
	ldrb	w0,[x0]
	eor	w0,w0,#255
	lsr	w0,w0,#6
	ldr	x2,[sp]
	ldrb	w2,[x2]
	lsr	w2,w2,#7
	and	w0,w2,w0
	ldr	x2,[sp, #16]
	add	x0,x2,x0
	str	x0,[sp, #16]
# [104] inc(pn8);
	ldr	x0,[sp]
	add	x0,x0,#1
	str	x0,[sp]
	ldr	x0,[sp, #32]
	cmp	x1,x0
	b.le	Lj30
	b	Lj28
Lj30:
Lj27:
# [107] for i := 1 to (ByteCount-cnt) div sizeof(PtrUInt) do
	ldr	x0,[sp, #8]
	ldr	x1,[sp, #40]
	sub	x0,x0,x1
	asr	x1,x0,#63
	add	x0,x0,x1,lsr #61
	asr	x0,x0,#3
	cmp	x0,#1
	b.ge	Lj31
	b	Lj32
Lj31:
	str	xzr,[sp, #32]
Lj33:
	ldr	x1,[sp, #32]
	add	x1,x1,#1
	str	x1,[sp, #32]
# [110] nx := ((pnx^ and EIGHTYMASK) shr 7) and ((not pnx^) shr 6);
	ldr	x1,[sp]
	ldr	x1,[x1]
	and	x1,x1,#0x8080808080808080
	lsr	x1,x1,#7
	ldr	x2,[sp]
	ldr	x2,[x2]
	mvn	x2,x2
	lsr	x2,x2,#6
	and	x1,x2,x1
	str	x1,[sp, #24]
# [112] Result += (nx * ONEMASK) >> ((sizeof(PtrInt) - 1) * 8);
	ldr	x1,[sp, #24]
	mov	x2,#72340172838076673
	mul	x1,x1,x2
	lsr	x1,x1,#56
	ldr	x2,[sp, #16]
	add	x1,x2,x1
	str	x1,[sp, #16]
# [114] inc(pnx);
	ldr	x1,[sp]
	add	x1,x1,#8
	str	x1,[sp]
	ldr	x1,[sp, #32]
	cmp	x0,x1
	b.le	Lj35
	b	Lj33
Lj35:
Lj32:
# [117] while ix<e do
	b	Lj37
Lj36:
# [126] Result += (pn8^ shr 7) and ((not pn8^) shr 6);
	ldr	x0,[sp]
	ldrb	w0,[x0]
	eor	w0,w0,#255
	lsr	w0,w0,#6
	ldr	x1,[sp]
	ldrb	w1,[x1]
	lsr	w1,w1,#7
	and	w0,w1,w0
	ldr	x1,[sp, #16]
	add	x0,x1,x0
	str	x0,[sp, #16]
# [127] inc(pn8);
	ldr	x0,[sp]
	add	x0,x0,#1
	str	x0,[sp]
Lj37:
	ldr	x0,[sp]
	ldr	x1,[sp, #48]
	cmp	x0,x1
	b.lt	Lj36
	b	Lj38
Lj38:
# [129] Result := ByteCount - Result;
	ldr	x0,[sp, #8]
	ldr	x1,[sp, #16]
	sub	x0,x0,x1
	str	x0,[sp, #16]
# [130] end;
	ldr	x0,[sp, #16]
	mov	sp,x29
	ldp	x29,x30,[sp], #16
	ret

.text
	.align 4
.globl	_main
_main:
	stp	x29,x30,[sp, #-16]!
	mov	x29,sp
	sub	sp,sp,#32
# Var ARGC located at sp+0, size=OS_S32
# Var ARGV located at sp+8, size=OS_64
# Var ARGP located at sp+16, size=OS_64
	str	w0,[sp]
	str	x1,[sp, #8]
	str	x2,[sp, #16]
	ldr	x2,[sp, #16]
	ldr	x1,[sp, #8]
	ldr	w0,[sp]
	bl	_FPC_SYSTEMMAIN
	mov	sp,x29
	ldp	x29,x30,[sp], #16
	ret

.text
	.align 4
.globl	_PASCALMAIN
_PASCALMAIN:
# [ulen.pas]
# [136] begin
	stp	x29,x30,[sp, #-16]!
	mov	x29,sp
	stp	x19,x19,[sp, #-16]!
	bl	fpc_initializeunits
# [137] DefaultSystemCodePage := CP_UTF8;
	movz	w0,#65001
	adrp	x1,_U_$SYSTEM_$$_DEFAULTSYSTEMCODEPAGE at GOTPAGE
	ldr	x1,[x1, _U_$SYSTEM_$$_DEFAULTSYSTEMCODEPAGE at GOTPAGEOFF]
	sturh	w0,[x1]
# [138] Euro := '...';
	adrp	x1,_$$fpclocal$_ld1 at PAGE
	add	x1,x1,_$$fpclocal$_ld1 at PAGEOFF
	add	x1,x1,#16
	adrp	x0,_U_$P$ULEN_$$_EURO at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_EURO at GOTPAGEOFF]
	bl	fpc_ansistr_assign
# [140] writeln('Signed version');
	bl	fpc_get_output
	mov	x19,x0
	adrp	x2,_$ULEN$_Ld2 at GOTPAGE
	ldr	x2,[x2, _$ULEN$_Ld2 at GOTPAGEOFF]
	mov	x1,x19
	movz	w0,#0
	bl	fpc_write_text_shortstr
	bl	fpc_iocheck
	mov	x0,x19
	bl	fpc_writeln_end
	bl	fpc_iocheck
# [141] Len := Utf8LengthFast_Signed(PChar(Euro), Length(Euro));
	adrp	x0,_U_$P$ULEN_$$_EURO at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_EURO at GOTPAGEOFF]
	ldur	x1,[x0]
	cmp	x1,#0
	b.eq	Lj45
	ldur	x1,[x1, #-8]
Lj45:
	adrp	x0,_U_$P$ULEN_$$_EURO at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_EURO at GOTPAGEOFF]
	ldur	x0,[x0]
	cmp	x0,#0
	b.ne	Lj46
	adrp	x0,FPC_EMPTYCHAR at GOTPAGE
	ldr	x0,[x0, FPC_EMPTYCHAR at GOTPAGEOFF]
Lj46:
	bl	_P$ULEN_$$_UTF8LENGTHFAST_SIGNED$PCHAR$INT64$$INT64
	adrp	x1,_U_$P$ULEN_$$_LEN at GOTPAGE
	ldr	x1,[x1, _U_$P$ULEN_$$_LEN at GOTPAGEOFF]
	stur	x0,[x1]
# [142] writeln('Len = ',Len);
	bl	fpc_get_output
	mov	x19,x0
	adrp	x2,_$ULEN$_Ld3 at GOTPAGE
	ldr	x2,[x2, _$ULEN$_Ld3 at GOTPAGEOFF]
	mov	x1,x19
	movz	w0,#0
	bl	fpc_write_text_shortstr
	bl	fpc_iocheck
	adrp	x0,_U_$P$ULEN_$$_LEN at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_LEN at GOTPAGEOFF]
	ldur	x2,[x0]
	mov	x1,x19
	movz	w0,#0
	bl	fpc_write_text_sint
	bl	fpc_iocheck
	mov	x0,x19
	bl	fpc_writeln_end
	bl	fpc_iocheck
# [144] writeln('Unsigned version');
	bl	fpc_get_output
	mov	x19,x0
	adrp	x2,_$ULEN$_Ld4 at GOTPAGE
	ldr	x2,[x2, _$ULEN$_Ld4 at GOTPAGEOFF]
	mov	x1,x19
	movz	w0,#0
	bl	fpc_write_text_shortstr
	bl	fpc_iocheck
	mov	x0,x19
	bl	fpc_writeln_end
	bl	fpc_iocheck
# [145] Len := Utf8LengthFast_Unsigned(PChar(Euro), Length(Euro));
	adrp	x0,_U_$P$ULEN_$$_EURO at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_EURO at GOTPAGEOFF]
	ldur	x1,[x0]
	cmp	x1,#0
	b.eq	Lj47
	ldur	x1,[x1, #-8]
Lj47:
	adrp	x0,_U_$P$ULEN_$$_EURO at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_EURO at GOTPAGEOFF]
	ldur	x0,[x0]
	cmp	x0,#0
	b.ne	Lj48
	adrp	x0,FPC_EMPTYCHAR at GOTPAGE
	ldr	x0,[x0, FPC_EMPTYCHAR at GOTPAGEOFF]
Lj48:
	bl	_P$ULEN_$$_UTF8LENGTHFAST_UNSIGNED$PCHAR$INT64$$INT64
	adrp	x1,_U_$P$ULEN_$$_LEN at GOTPAGE
	ldr	x1,[x1, _U_$P$ULEN_$$_LEN at GOTPAGEOFF]
	stur	x0,[x1]
# [146] writeln('Len = ',Len);
	bl	fpc_get_output
	mov	x19,x0
	adrp	x2,_$ULEN$_Ld3 at GOTPAGE
	ldr	x2,[x2, _$ULEN$_Ld3 at GOTPAGEOFF]
	mov	x1,x19
	movz	w0,#0
	bl	fpc_write_text_shortstr
	bl	fpc_iocheck
	adrp	x0,_U_$P$ULEN_$$_LEN at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_LEN at GOTPAGEOFF]
	ldur	x2,[x0]
	mov	x1,x19
	movz	w0,#0
	bl	fpc_write_text_sint
	bl	fpc_iocheck
	mov	x0,x19
	bl	fpc_writeln_end
	bl	fpc_iocheck
# [147] end.
	bl	fpc_do_exit
	ret

.text
	.align 4
.globl	__P$ULEN_$$_init_implicit$
__P$ULEN_$$_init_implicit$:
	.set _INIT$_$P$ULEN, __P$ULEN_$$_init_implicit$
	.globl _INIT$_$P$ULEN
	stp	x29,x30,[sp, #-16]!
	mov	x29,sp
	ldp	x29,x30,[sp], #16
	ret

.text
	.align 4
.globl	__P$ULEN_$$_finalize_implicit$
__P$ULEN_$$_finalize_implicit$:
	.set _FINALIZE$_$P$ULEN, __P$ULEN_$$_finalize_implicit$
	.globl _FINALIZE$_$P$ULEN
	.set PASCALFINALIZE, __P$ULEN_$$_finalize_implicit$
	.globl PASCALFINALIZE
	stp	x29,x30,[sp, #-16]!
	mov	x29,sp
	adrp	x0,_U_$P$ULEN_$$_EURO at GOTPAGE
	ldr	x0,[x0, _U_$P$ULEN_$$_EURO at GOTPAGEOFF]
	bl	fpc_ansistr_decr_ref
	ldp	x29,x30,[sp], #16
	ret
# End asmlist al_procedures
# Begin asmlist al_globals


	.align 3
# [ulen.pas]
# [134] Len: PtrInt;
	.private_extern _U_$P$ULEN_$$_LEN
.globl _U_$P$ULEN_$$_LEN
.data
.zerofill __DATA, __common, _U_$P$ULEN_$$_LEN, 8,3




	.align 3
# [135] Euro: String;
	.private_extern _U_$P$ULEN_$$_EURO
.globl _U_$P$ULEN_$$_EURO
.data
.zerofill __DATA, __common, _U_$P$ULEN_$$_EURO, 8,3



.data
	.align 3
.globl	INITFINAL
INITFINAL:
	.quad	5,0
	.quad	_INIT$_$SYSTEM
	.quad	0,0
	.quad	_FINALIZE$_$OBJPAS
	.quad	_INIT$_$UNIX
	.quad	_FINALIZE$_$UNIX
	.quad	_INIT$_$SYSUTILS
	.quad	_FINALIZE$_$SYSUTILS
	.quad	_INIT$_$P$ULEN
	.quad	_FINALIZE$_$P$ULEN

.data
	.align 3
.globl	FPC_THREADVARTABLES
FPC_THREADVARTABLES:
	.long	1
	.byte	0,0,0,0
	.quad	_THREADVARLIST_$SYSTEM$indirect

.const_data
	.align 3
.globl	FPC_RESOURCESTRINGTABLES
FPC_RESOURCESTRINGTABLES:
	.quad	1
	.quad	_RESSTR_$SYSCONST_$$_START$indirect
	.quad	_RESSTR_$SYSCONST_$$_END$indirect

.data
	.align 3
.globl	FPC_WIDEINITTABLES
FPC_WIDEINITTABLES:
	.quad	0

.data
	.align 3
.globl	FPC_RESSTRINITTABLES
FPC_RESSTRINITTABLES:
	.quad	0

.section __TEXT, .fpc, regular, no_dead_strip
	.align 4
.reference __fpc_ident
__fpc_ident:
	.ascii	"FPC 3.3.1 [2021/11/12] for aarch64 - Darwin"

.data
	.align 3
.globl	__stklen
__stklen:
	.quad	8388608

.data
	.align 3
.globl	__heapsize
__heapsize:
	.quad	0

.data
	.align 3
.globl	__fpc_valgrind
__fpc_valgrind:
	.byte	0

.const_data
	.align 3
.globl	FPC_RESLOCATION
FPC_RESLOCATION:
	.quad	0
# End asmlist al_globals
# Begin asmlist al_typedconsts

.const
	.align 3
_$$fpclocal$_ld1:
	.short	65001,1
	.long	-1
	.quad	3
	.ascii	"\342\202\254\000"

.const
	.align 3
.globl	_$ULEN$_Ld2
_$ULEN$_Ld2:
	.ascii	"\016Signed version\000"

.const
	.align 3
.globl	_$ULEN$_Ld3
_$ULEN$_Ld3:
	.ascii	"\006Len = \000"

.const
	.align 3
.globl	_$ULEN$_Ld4
_$ULEN$_Ld4:
	.ascii	"\020Unsigned version\000"
# End asmlist al_typedconsts
# Begin asmlist al_rtti

.const_data
	.align 3
.globl	_RTTI_$P$ULEN_$$_def00000008
_RTTI_$P$ULEN_$$_def00000008:
	.byte	9,0,0,0,0,0,0,0
	.quad	0
	.short	65001
	.byte	0,0,0,0,0,0
# End asmlist al_rtti
# Begin asmlist al_indirectglobals

.const_data
	.align 3
.globl	_RTTI_$P$ULEN_$$_def00000008$indirect
_RTTI_$P$ULEN_$$_def00000008$indirect:
	.quad	_RTTI_$P$ULEN_$$_def00000008
# End asmlist al_indirectglobals
	.subsections_via_symbols



More information about the lazarus mailing list