From 382d5060a04504cacc56a365f02100a65108ad19 Mon Sep 17 00:00:00 2001 From: yury Date: Fri, 22 Feb 2019 17:59:54 +0000 Subject: [PATCH] * aarch64: According to ARM64 ABI, function's arguments and the result are not required to be sign/zero extended to a full register size. Obey this rule for all targets except iOS where sign/zero extension is required. git-svn-id: trunk@41412 - --- .gitattributes | 1 + compiler/aarch64/cpupara.pas | 46 +++++++++++++++++--- tests/test/taarch64abi.pp | 84 ++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 tests/test/taarch64abi.pp diff --git a/.gitattributes b/.gitattributes index cc2740de08..05f20fd531 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12745,6 +12745,7 @@ tests/test/packages/win-base/tdispvar1.pp svneol=native#text/plain tests/test/packages/zlib/tzlib1.pp svneol=native#text/plain tests/test/t4cc1.pp svneol=native#text/plain tests/test/t4cc2.pp svneol=native#text/plain +tests/test/taarch64abi.pp svneol=native#text/plain tests/test/tabstract1.pp svneol=native#text/pascal tests/test/tabstrcl.pp svneol=native#text/plain tests/test/tabsvr1.pp svneol=native#text/plain diff --git a/compiler/aarch64/cpupara.pas b/compiler/aarch64/cpupara.pas index 958e46b0bb..048bca9c8a 100644 --- a/compiler/aarch64/cpupara.pas +++ b/compiler/aarch64/cpupara.pas @@ -364,6 +364,24 @@ unit cpupara; if not assigned(result.location) or not(result.location^.loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_VOID]) then internalerror(2014113001); + { + According to ARM64 ABI: "If the size of the argument is less than 8 bytes then + the size of the argument is set to 8 bytes. The effect is as if the argument + was copied to the least significant bits of a 64-bit register and the remaining + bits filled with unspecified values." + + Therefore at caller side force the ordinal result to be always 64-bit, so it + will be stripped to the required size and uneeded bits are discarded. + + This is not required for iOS, where the result is zero/sign extended. + } + if (target_info.abi<>abi_aarch64_darwin) and + (side=callerside) and (result.location^.loc = LOC_REGISTER) and + (result.def.size<8) and is_ordinal(result.def) then + begin + result.location^.size:=OS_64; + result.location^.def:=u64inttype; + end; end; @@ -597,14 +615,28 @@ unit cpupara; responsibility to sign or zero-extend arguments having fewer than 32 bits, and that unused bits in a register are unspecified. In iOS, however, the caller must perform such - extensions, up to 32 bits." } - if (target_info.abi=abi_aarch64_darwin) and - (side=callerside) and - is_ordinal(paradef) and - (paradef.size<4) then + extensions, up to 32 bits." + Zero extend an argument at caller side for iOS and + ignore the argument's unspecified high bits at callee side for + all other platforms. } + if (paradef.size<4) and is_ordinal(paradef) then begin - paraloc^.size:=OS_32; - paraloc^.def:=u32inttype; + if target_info.abi=abi_aarch64_darwin then + begin + if side=callerside then + begin + paraloc^.size:=OS_32; + paraloc^.def:=u32inttype; + end; + end + else + begin + if side=calleeside then + begin + paraloc^.size:=OS_32; + paraloc^.def:=u32inttype; + end; + end; end; { in case it's a composite, "The argument is passed as though diff --git a/tests/test/taarch64abi.pp b/tests/test/taarch64abi.pp new file mode 100644 index 0000000000..802fe5a01b --- /dev/null +++ b/tests/test/taarch64abi.pp @@ -0,0 +1,84 @@ +{ %CPU=aarch64 } +{ %skiptarget=darwin } + +{ + Tests that arguments and the result are not required to be sign/zero extended. +} + +procedure ProcByte(p: byte); +begin + if p <> $78 then + Halt(1); +end; + +procedure ProcWord(p: word); +begin + if p <> $5678 then + Halt(2); +end; + +procedure ProcDWord(p: dword); +begin + if p <> $12345678 then + Halt(3); +end; + +function RetByte: byte; +var + q: qword; +begin + q:=$1111111112345678; + asm + ldr x0,q + end; +end; + +function RetWord: word; +var + q: qword; +begin + q:=$1111111112345678; + asm + ldr x0,q + end; +end; + +function RetDWord: dword; +var + q: qword; +begin + q:=$1111111112345678; + asm + ldr x0,q + end; +end; + +procedure TestParams; +var + q: qword; +begin + q:=$1111111112345678; + asm + ldr x0,q + bl ProcByte + ldr x0,q + bl ProcWord + ldr x0,q + bl ProcDWord + end; +end; + +procedure TestReturns; +begin + if RetByte <> $78 then + Halt(11); + if RetWord <> $5678 then + Halt(12); + if RetDWord <> $12345678 then + Halt(13); +end; + +begin + TestParams; + TestReturns; +end.