Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FreeBSD/aarch64 support #1904

Merged
merged 2 commits into from Mar 22, 2019

Conversation

@myfreeweb
Copy link
Contributor

commented Jul 15, 2018

Getting OCaml to run on FreeBSD/aarch64 was mostly trivial :) There was an interesting assembler problem though.

Using the clang/llvm assembler avoids an extra dependency on GNU binutils, and that's what 32-bit arm is using:

as="${TOOLPREF}cc -c"

But on aarch64, the following error has occurred:

gmake[4]: Entering directory '/usr/home/greg/ocaml-4.07.0/stdlib'
../boot/ocamlrun ../ocamlopt -strict-sequence -absname -w +a-4-9-41-42-44-45-48 -g -warn-error A -bin-annot -nostdlib -safe-string -strict-formats    \
					 -o stdlib__bytes.cmx -c bytes.ml
../boot/ocamlrun ../ocamlopt -strict-sequence -absname -w +a-4-9-41-42-44-45-48 -g -warn-error A -bin-annot -nostdlib -safe-string -strict-formats    \
					 -o stdlib__array.cmx -c array.ml
../boot/ocamlrun ../ocamlopt -strict-sequence -absname -w +a-4-9-41-42-44-45-48 -g -warn-error A -bin-annot -nostdlib -safe-string -strict-formats    \
					 -o stdlib__set.cmx -c set.ml                                                                                                                
../boot/ocamlrun ../ocamlopt -strict-sequence -absname -w +a-4-9-41-42-44-45-48 -g -warn-error A -bin-annot -nostdlib -safe-string -strict-formats    \
					 -o stdlib__stack.cmx -c stack.ml                                                                                                            
../boot/ocamlrun ../ocamlopt -strict-sequence -absname -w +a-4-9-41-42-44-45-48 -g -warn-error A -bin-annot -nostdlib -safe-string -strict-formats    \
					 -o stdlib__complex.cmx -c complex.ml
/tmp/camlasmb8ca65.s:465:13: error: encoded floating point value out of range
				fmov    d12, #0x3ff0000000000000                                     
											^                                                      
/tmp/camlasmb8ca65.s:488:12: error: encoded floating point value out of range
				fmov    d7, #0x3ff0000000000000                                      
										 ^                                                       
/tmp/camlasmb8ca65.s:638:12: error: encoded floating point value out of range
				fmov    d9, #0x3ff0000000000000                                      
										 ^                                                       
/tmp/camlasmb8ca65.s:645:13: error: encoded floating point value out of range
				fmov    d14, #0x3fe0000000000000                                     
											^                                                      
/tmp/camlasmb8ca65.s:658:13: error: encoded floating point value out of range
				fmov    d20, #0x3ff0000000000000                                     
											^                                                      
/tmp/camlasmb8ca65.s:665:13: error: encoded floating point value out of range
				fmov    d24, #0x3fe0000000000000                                     
											^                                                      
/tmp/camlasmb8ca65.s:690:12: error: encoded floating point value out of range
				fmov    d6, #0x3fe0000000000000
										 ^
/tmp/camlasmb8ca65.s:720:12: error: encoded floating point value out of range
				fmov    d2, #0x3fe0000000000000
										 ^
File "/usr/home/greg/ocaml-4.07.0/stdlib/complex.ml", line 1:
Error: Assembler error, input left in file /tmp/camlasmb8ca65.s
gmake[4]: *** [Makefile:252: stdlib__complex.cmx] Error 2

Turns out LLVM thinks that if floating point immediates are written in hex, they must be integer values between 0 and 255:

  if (Tok.is(AsmToken::Real) || Tok.is(AsmToken::Integer)) {
    int64_t Val;
    if (Tok.is(AsmToken::Integer) && !isNegative && Tok.getString().startswith("0x")) {
      Val = Tok.getIntVal();
      if (Val > 255 || Val < 0) {
        TokError("encoded floating point value out of range");
        return MatchOperand_ParseFail;
      }
    } else {

As a workaround, I turned off the immediates :D I guess a better one would be to print the values as floats e.g. fmov d2, 123.456. How would I do that and could there be any problems with that?

// Other than that: runtime-C-exceptions and runtime-errors tests pass; OPAM compiled successfully (after updating extlib); currently running all tests — everything is fine so far.

// Source for the CONTEXT_PC being gp_elr: this mail.

UPD: 1758 tests passed, 29 tests skipped, 3 tests failed, 88 tests not started

 ... testing 'exec.ml' with 1.2 (native) => failed (Files /usr/home/greg/ocaml/testsuite/_ocamltest/tests/lib-unix/unix-execvpe/exec/ocamlopt.byte/exec.opt and /usr/ho
me/greg/ocaml/testsuite/_ocamltest/tests/lib-unix/unix-execvpe/exec/ocamlopt.opt/exec.opt are different)
 ... testing 'testpreempt.ml' with 1.1 (bytecode) => failed (program output /usr/home/greg/ocaml/testsuite/_ocamltest/tests/lib-systhreads/testpreempt/ocamlc.byte/test
preempt.byte.output differs from reference /usr/home/greg/ocaml/testsuite/tests/lib-systhreads/testpreempt.reference:
--- /usr/home/greg/ocaml/testsuite/tests/lib-systhreads/testpreempt.reference   2018-07-15 01:02:56.471201000 +0300
+++ /usr/home/greg/ocaml/testsuite/_ocamltest/tests/lib-systhreads/testpreempt/ocamlc.byte/testpreempt.byte.output      2018-07-15 03:33:07.554411000 +0300
@@ -1,3 +1,2 @@                                                                   
-Interaction 1                             
-Interaction 2  
 Long computation result: 100000
+Interaction 1                                                    
                                                   
)                                           
 ... testing 'testpreempt.ml' with 1.2 (native) => failed (program output /usr/home/greg/ocaml/testsuite/_ocamltest/tests/lib-systhreads/testpreempt/ocamlopt.byte/test
preempt.opt.output differs from reference /usr/home/greg/ocaml/testsuite/tests/lib-systhreads/testpreempt.reference:
--- /usr/home/greg/ocaml/testsuite/tests/lib-systhreads/testpreempt.reference   2018-07-15 01:02:56.471201000 +0300
+++ /usr/home/greg/ocaml/testsuite/_ocamltest/tests/lib-systhreads/testpreempt/ocamlopt.byte/testpreempt.opt.output     2018-07-15 03:33:13.898101000 +0300
@@ -1,3 +1 @@                                              
-Interaction 1
-Interaction 2
 Long computation result: 100000
                  
)
@shindere

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2018

@stedolan

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2018

Nice!

I'm a little worried by the Config.system = "freebsd" check, though: that's not a great way to detect the LLVM assembler (you can use that assembler on Linux, and you can use the gnu assembler on FreeBSD, so this only detects defaults correctly). I think the workaround you suggest (printing immediates as floats) would be a better idea, and you can implement it by changing the printf format on line 590.

For anyone following along, here's the problem as I understand it: Aarch64 has a fmov instruction for loading floating-point constants that takes an 8-bit immediate, which can represent one of 256 different floating-point numbers using a custom compressed format (sign bit, 3-bit exponent, 4-bit mantissa). However, when parsing an assembler operand expressed in hex, the GNU assembler expects a 64-bit IEEE754 double (which it then checks is one of the 256 values that can be encoded in 8 bits), while the LLVM assembler expects an 8-bit encoded value. However, I think both assemblers agree on how to parse an operand expressed using floating-point syntax.

@myfreeweb myfreeweb force-pushed the myfreeweb:freebsd-aarch64 branch from 71a3fb2 to 5b5b82c Jul 16, 2018
@myfreeweb

This comment has been minimized.

Copy link
Contributor Author

commented Jul 16, 2018

I was slightly afraid of float literals (parsing incompatibility or something) but I guess IEEE is IEEE :) Using the float literal now.

About continuous integration: QEMU to the rescue! It's not perfect, but seems to work for OCaml — I just built a compiler under it.

Here's how to use it:

pkg install -y qemu-user-static
/usr/sbin/binmiscctl add arm64 --interpreter "/usr/local/bin/qemu-aarch64-static" --magic "\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00" --mask "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff" --size 20 --set-enabled

wget "https://download.freebsd.org/ftp/snapshots/arm64/12.0-CURRENT/base.txz"
mkdir /tmp/aarch64
cd /tmp/aarch64
tar -xvf /where/you/downloaded/base.txz
cp /etc/resolv.conf etc/
mkdir usr/local/bin
cp /usr/local/bin/qemu-aarch64-static usr/local/bin
mkdir ocaml
mount -t nullfs /some/path/to/ocaml ocaml

chroot .
pkg install -y gmake
cd ocaml
./configure
gmake -j16 world.opt

(Most commands here should be run as root)

(No idea how well a 12-CURRENT qemu chroot would work on an <=11 host, you might want to download an 11.2-STABLE snapshot instead. 12 has 64-bit inodes after all…)

@XVilka

This comment has been minimized.

Copy link
Contributor

commented Dec 14, 2018

What was decided on this one by the way?

@shindere

This comment has been minimized.

Copy link
Contributor

commented Dec 19, 2018

@myfreeweb

This comment has been minimized.

Copy link
Contributor Author

commented Dec 19, 2018

Yeah I can rebase, sure

@shindere

This comment has been minimized.

Copy link
Contributor

commented Dec 19, 2018

@damiendoligez

This comment has been minimized.

Copy link
Member

commented Jan 23, 2019

Autoconf is merged, feel free to rebase when you have time.

About float format, you need to make sure you are not losing any precision when printing the float as a decimal. This was the rationale for using hex format in the first place, and I'm almost sure %f doesn't cut it.

Could a float expert look into this? @nojb @alainfrisch @dbuenzli @Chris00 @bobot

@myfreeweb myfreeweb force-pushed the myfreeweb:freebsd-aarch64 branch from 5b5b82c to a852aa1 Jan 26, 2019
@stedolan

This comment has been minimized.

Copy link
Contributor

commented Jan 29, 2019

About float format, you need to make sure you are not losing any precision when printing the float as a decimal. This was the rationale for using hex format in the first place, and I'm almost sure %f doesn't cut it.

I started writing a comment explaining why I thought you were wrong, because this mechanism only needs to print very low-precision numbers (3-bit exp, 4-bit mantissa). But when I tested it, it turns out you're right - %f misrenders 16 of these floats. %.7f works, though.

Copy link
Contributor

left a comment

Let's try to get this to a point where it can be merged.

Adding a test for those special FP values wouldn't hurt either. I'll have a look.

asmcomp/arm64/emit.mlp Outdated Show resolved Hide resolved
@xavierleroy

This comment has been minimized.

Copy link
Contributor

commented Mar 9, 2019

I just wrote a test and took the liberty of pushing it to your branch. Will give it a round of CI next.

@myfreeweb myfreeweb force-pushed the myfreeweb:freebsd-aarch64 branch from cbd52b5 to acf78a1 Mar 9, 2019
@xavierleroy

This comment has been minimized.

Copy link
Contributor

commented Mar 10, 2019

CI is happy, meaning that the ARM64-Linux port still works.

I guess a Changes entry is needed. I'll let others hand-hold you through that process.

@nojb

This comment has been minimized.

Copy link
Contributor

commented Mar 22, 2019

This PR has been accepted. @myfreeweb: If you update Changes we can merge. Let me know if you need help doing this.

@myfreeweb myfreeweb force-pushed the myfreeweb:freebsd-aarch64 branch from acf78a1 to 86f476f Mar 22, 2019
@myfreeweb

This comment has been minimized.

Copy link
Contributor Author

commented Mar 22, 2019

Added changes entry, hopefully it's correct

@nojb

This comment has been minimized.

Copy link
Contributor

commented Mar 22, 2019

- GPR#7931, GPR#1904: Add ...
myfreeweb and others added 2 commits Jul 14, 2018
Using the clang/llvm assembler avoids an extra dependency on GNU binutils, and that's what 32-bit arm is using.
But in this case, there was a problem with floating point immediates: LLVM thinks that if they're written in hex, they must be integer values between 0 and 255.
Changed them to float literals.
Some ocamlopt code generators use special instructions to load specific FP
constants into an FP register, instead of loading the value from memory.
This is the case for i386, amd64, and arm64.
This test checks that these special instructions produce the correct
FP values.
@myfreeweb myfreeweb force-pushed the myfreeweb:freebsd-aarch64 branch from 86f476f to f746a00 Mar 22, 2019
@myfreeweb

This comment has been minimized.

Copy link
Contributor Author

commented Mar 22, 2019

done

@nojb

This comment has been minimized.

Copy link
Contributor

commented Mar 22, 2019

Great! As soon as CI passes I'll merge it. Thanks for your contribution @myfreeweb!

@nojb nojb merged commit dbb889e into ocaml:trunk Mar 22, 2019
1 of 2 checks passed
1 of 2 checks passed
continuous-integration/appveyor/pr Waiting for AppVeyor build to complete
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.