From 653bb6745595746d04ad4acacaaab66caaaeb69b Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 21 Oct 2010 19:02:02 +0000 Subject: [PATCH] Import compiler-rt r117047. --- .gitignore | 4 + BlocksRuntime/Block.h | 59 + BlocksRuntime/Block_private.h | 179 + BlocksRuntime/CMakeLists.txt | 13 + BlocksRuntime/data.c | 41 + BlocksRuntime/runtime.c | 700 + BlocksRuntime/tests/block-static.c | 25 + BlocksRuntime/tests/blockimport.c | 51 + BlocksRuntime/tests/byrefaccess.c | 34 + BlocksRuntime/tests/byrefcopy.c | 41 + BlocksRuntime/tests/byrefcopycopy.c | 46 + BlocksRuntime/tests/byrefcopyinner.c | 32 + BlocksRuntime/tests/byrefcopyint.c | 69 + BlocksRuntime/tests/byrefcopystack.c | 41 + BlocksRuntime/tests/byrefsanity.c | 73 + BlocksRuntime/tests/byrefstruct.c | 57 + BlocksRuntime/tests/c99.c | 20 + BlocksRuntime/tests/cast.c | 37 + BlocksRuntime/tests/constassign.c | 28 + .../tests/copy-block-literal-rdar6439600.c | 29 + BlocksRuntime/tests/copyconstructor.C | 85 + BlocksRuntime/tests/copynull.c | 37 + BlocksRuntime/tests/dispatch_async.c | 57 + .../tests/dispatch_call_Block_with_release.c | 31 + BlocksRuntime/tests/fail.c | 107 + BlocksRuntime/tests/flagsisa.c | 21 + BlocksRuntime/tests/globalexpression.c | 42 + BlocksRuntime/tests/goto.c | 34 + BlocksRuntime/tests/hasdescriptor.c | 29 + BlocksRuntime/tests/josh.C | 32 + BlocksRuntime/tests/k-and-r.c | 33 + BlocksRuntime/tests/large-struct.c | 51 + BlocksRuntime/tests/localisglobal.c | 42 + BlocksRuntime/tests/macro.c | 14 + BlocksRuntime/tests/makefile | 70 + BlocksRuntime/tests/modglobal.c | 18 + BlocksRuntime/tests/nestedimport.c | 44 + BlocksRuntime/tests/nullblockisa.c | 43 + BlocksRuntime/tests/objectRRGC.c | 77 + BlocksRuntime/tests/objectassign.c | 76 + BlocksRuntime/tests/orbars.c | 23 + BlocksRuntime/tests/rdar6396238.c | 32 + BlocksRuntime/tests/rdar6405500.c | 29 + BlocksRuntime/tests/rdar6414583.c | 31 + BlocksRuntime/tests/recursive-block.c | 55 + BlocksRuntime/tests/recursive-test.c | 74 + BlocksRuntime/tests/recursiveassign.c | 44 + BlocksRuntime/tests/reference.C | 95 + BlocksRuntime/tests/rettypepromotion.c | 36 + BlocksRuntime/tests/returnfunctionptr.c | 23 + BlocksRuntime/tests/shorthandexpression.c | 24 + BlocksRuntime/tests/sizeof.c | 26 + BlocksRuntime/tests/small-struct.c | 45 + BlocksRuntime/tests/structmember.c | 45 + BlocksRuntime/tests/testfilerunner.h | 110 + BlocksRuntime/tests/testfilerunner.m | 805 + BlocksRuntime/tests/varargs-bad-assign.c | 44 + BlocksRuntime/tests/varargs.c | 39 + BlocksRuntime/tests/variadic.c | 66 + BlocksRuntime/tests/voidarg.c | 27 + CMakeLists.txt | 55 + CREDITS.TXT | 21 + LICENSE.TXT | 63 + Makefile | 243 + README.txt | 330 + cmake/ConfigureChecks.cmake | 38 + cmake/Modules/DefineCompilerFlags.cmake | 6 + cmake/Modules/MacroAddCheckTest.cmake | 12 + .../Modules/MacroEnsureOutOfSourceBuild.cmake | 18 + cmake/config.h.cmake | 12 + lib/CMakeLists.txt | 81 + lib/Makefile.mk | 17 + lib/absvdi2.c | 30 + lib/absvsi2.c | 30 + lib/absvti2.c | 34 + lib/adddf3.c | 154 + lib/addsf3.c | 164 + lib/addvdi3.c | 37 + lib/addvsi3.c | 37 + lib/addvti3.c | 41 + lib/apple_versioning.c | 150 + lib/arm/CMakeLists.txt | 0 lib/arm/Makefile.mk | 19 + lib/arm/adddf3vfp.S | 24 + lib/arm/addsf3vfp.S | 24 + lib/arm/bswapdi2.S | 36 + lib/arm/bswapsi2.S | 28 + lib/arm/comparesf2.S | 130 + lib/arm/divdf3vfp.S | 24 + lib/arm/divsf3vfp.S | 24 + lib/arm/eqdf2vfp.S | 27 + lib/arm/eqsf2vfp.S | 28 + lib/arm/extendsfdf2vfp.S | 24 + lib/arm/fixdfsivfp.S | 24 + lib/arm/fixsfsivfp.S | 24 + lib/arm/fixunsdfsivfp.S | 25 + lib/arm/fixunssfsivfp.S | 25 + lib/arm/floatsidfvfp.S | 24 + lib/arm/floatsisfvfp.S | 24 + lib/arm/floatunssidfvfp.S | 24 + lib/arm/floatunssisfvfp.S | 24 + lib/arm/gedf2vfp.S | 27 + lib/arm/gesf2vfp.S | 28 + lib/arm/gtdf2vfp.S | 27 + lib/arm/gtsf2vfp.S | 28 + lib/arm/ledf2vfp.S | 27 + lib/arm/lesf2vfp.S | 28 + lib/arm/ltdf2vfp.S | 27 + lib/arm/ltsf2vfp.S | 28 + lib/arm/modsi3.S | 36 + lib/arm/muldf3vfp.S | 24 + lib/arm/mulsf3vfp.S | 24 + lib/arm/nedf2vfp.S | 27 + lib/arm/negdf2vfp.S | 21 + lib/arm/negsf2vfp.S | 21 + lib/arm/nesf2vfp.S | 28 + lib/arm/restore_vfp_d8_d15_regs.S | 37 + lib/arm/save_vfp_d8_d15_regs.S | 35 + lib/arm/subdf3vfp.S | 24 + lib/arm/subsf3vfp.S | 25 + lib/arm/switch16.S | 44 + lib/arm/switch32.S | 46 + lib/arm/switch8.S | 43 + lib/arm/switchu8.S | 43 + lib/arm/sync_synchronize.S | 34 + lib/arm/truncdfsf2vfp.S | 24 + lib/arm/unorddf2vfp.S | 27 + lib/arm/unordsf2vfp.S | 28 + lib/ashldi3.c | 41 + lib/ashlti3.c | 45 + lib/ashrdi3.c | 42 + lib/ashrti3.c | 46 + lib/assembly.h | 54 + lib/clear_cache.c | 40 + lib/clzdi2.c | 29 + lib/clzsi2.c | 53 + lib/clzti2.c | 33 + lib/cmpdi2.c | 38 + lib/cmpti2.c | 42 + lib/comparedf2.c | 132 + lib/comparesf2.c | 131 + lib/ctzdi2.c | 29 + lib/ctzsi2.c | 57 + lib/ctzti2.c | 33 + lib/divdc3.c | 59 + lib/divdf3.c | 182 + lib/divdi3.c | 31 + lib/divsc3.c | 59 + lib/divsf3.c | 166 + lib/divsi3.c | 31 + lib/divti3.c | 35 + lib/divxc3.c | 62 + lib/enable_execute_stack.c | 58 + lib/endianness.h | 94 + lib/eprintf.c | 33 + lib/extendsfdf2.c | 136 + lib/ffsdi2.c | 33 + lib/ffsti2.c | 37 + lib/fixdfdi.c | 43 + lib/fixdfsi.c | 45 + lib/fixdfti.c | 45 + lib/fixsfdi.c | 41 + lib/fixsfsi.c | 45 + lib/fixsfti.c | 45 + lib/fixunsdfdi.c | 45 + lib/fixunsdfsi.c | 42 + lib/fixunsdfti.c | 47 + lib/fixunssfdi.c | 43 + lib/fixunssfsi.c | 43 + lib/fixunssfti.c | 47 + lib/fixunsxfdi.c | 44 + lib/fixunsxfsi.c | 44 + lib/fixunsxfti.c | 49 + lib/fixxfdi.c | 44 + lib/fixxfti.c | 47 + lib/floatdidf.c | 107 + lib/floatdisf.c | 79 + lib/floatdixf.c | 46 + lib/floatsidf.c | 48 + lib/floatsisf.c | 54 + lib/floattidf.c | 86 + lib/floattisf.c | 85 + lib/floattixf.c | 87 + lib/floatundidf.c | 107 + lib/floatundisf.c | 76 + lib/floatundixf.c | 42 + lib/floatunsidf.c | 37 + lib/floatunsisf.c | 45 + lib/floatuntidf.c | 83 + lib/floatuntisf.c | 82 + lib/floatuntixf.c | 84 + lib/fp_lib.h | 143 + lib/gcc_personality_v0.c | 251 + lib/i386/CMakeLists.txt | 3 + lib/i386/Makefile.mk | 19 + lib/i386/ashldi3.S | 56 + lib/i386/ashrdi3.S | 67 + lib/i386/divdi3.S | 161 + lib/i386/floatdidf.S | 35 + lib/i386/floatdisf.S | 31 + lib/i386/floatdixf.S | 29 + lib/i386/floatundidf.S | 46 + lib/i386/floatundisf.S | 99 + lib/i386/floatundixf.S | 37 + lib/i386/lshrdi3.S | 57 + lib/i386/moddi3.S | 166 + lib/i386/muldi3.S | 29 + lib/i386/udivdi3.S | 114 + lib/i386/umoddi3.S | 125 + lib/int_lib.h | 155 + lib/lshrdi3.c | 41 + lib/lshrti3.c | 45 + lib/moddi3.c | 32 + lib/modsi3.c | 23 + lib/modti3.c | 36 + lib/muldc3.c | 74 + lib/muldf3.c | 119 + lib/muldi3.c | 54 + lib/mulsc3.c | 74 + lib/mulsf3.c | 109 + lib/multi3.c | 58 + lib/mulvdi3.c | 57 + lib/mulvsi3.c | 57 + lib/mulvti3.c | 61 + lib/mulxc3.c | 78 + lib/negdf2.c | 19 + lib/negdi2.c | 26 + lib/negsf2.c | 19 + lib/negti2.c | 30 + lib/negvdi2.c | 29 + lib/negvsi2.c | 29 + lib/negvti2.c | 33 + lib/paritydi2.c | 27 + lib/paritysi2.c | 27 + lib/parityti2.c | 31 + lib/popcountdi2.c | 36 + lib/popcountsi2.c | 33 + lib/popcountti2.c | 44 + lib/powidf2.c | 34 + lib/powisf2.c | 34 + lib/powitf2.c | 38 + lib/powixf2.c | 38 + lib/ppc/CMakeLists.txt | 12 + lib/ppc/DD.h | 46 + lib/ppc/Makefile.mk | 19 + lib/ppc/divtc3.c | 93 + lib/ppc/fixtfdi.c | 104 + lib/ppc/fixunstfdi.c | 60 + lib/ppc/floatditf.c | 37 + lib/ppc/floatunditf.c | 42 + lib/ppc/gcc_qadd.c | 76 + lib/ppc/gcc_qdiv.c | 55 + lib/ppc/gcc_qmul.c | 53 + lib/ppc/gcc_qsub.c | 76 + lib/ppc/multc3.c | 97 + lib/ppc/restFP.S | 43 + lib/ppc/saveFP.S | 40 + lib/subvdi3.c | 37 + lib/subvsi3.c | 37 + lib/subvti3.c | 41 + lib/trampoline_setup.c | 50 + lib/truncdfsf2.c | 167 + lib/ucmpdi2.c | 38 + lib/ucmpti2.c | 42 + lib/udivdi3.c | 25 + lib/udivmoddi4.c | 251 + lib/udivmodti4.c | 256 + lib/udivsi3.c | 63 + lib/udivti3.c | 29 + lib/umoddi3.c | 27 + lib/umodsi3.c | 25 + lib/umodti3.c | 31 + lib/x86_64/CMakeLists.txt | 5 + lib/x86_64/Makefile.mk | 19 + lib/x86_64/floatdidf.c | 16 + lib/x86_64/floatdisf.c | 14 + lib/x86_64/floatdixf.c | 16 + lib/x86_64/floatundidf.S | 43 + lib/x86_64/floatundisf.S | 33 + lib/x86_64/floatundixf.S | 62 + make/AppleBI.mk | 84 + make/config.mk | 36 + make/filter-inputs | 25 + make/lib_info.mk | 51 + make/lib_platforms.mk | 82 + make/lib_util.mk | 65 + make/options.mk | 33 + make/platform/clang_darwin.mk | 253 + make/platform/darwin_bni.mk | 95 + make/platform/darwin_fat.mk | 56 + make/platform/multi_arch.mk | 16 + make/subdir.mk | 90 + make/test/test-util.mk | 66 + make/util.mk | 114 + test/CMakeLists.txt | 122 + test/Unit/absvdi2_test.c | 65 + test/Unit/absvsi2_test.c | 65 + test/Unit/absvti2_test.c | 82 + test/Unit/adddf3vfp_test.c | 46 + test/Unit/addsf3vfp_test.c | 46 + test/Unit/addvdi3_test.c | 58 + test/Unit/addvsi3_test.c | 58 + test/Unit/addvti3_test.c | 92 + test/Unit/ashldi3_test.c | 77 + test/Unit/ashlti3_test.c | 173 + test/Unit/ashrdi3_test.c | 118 + test/Unit/ashrti3_test.c | 171 + test/Unit/bswapdi2_test.c | 42 + test/Unit/bswapsi2_test.c | 42 + test/Unit/clear_cache_test.c | 59 + test/Unit/clzdi2_test.c | 68 + test/Unit/clzsi2_test.c | 599 + test/Unit/clzti2_test.c | 88 + test/Unit/cmpdi2_test.c | 77 + test/Unit/cmpti2_test.c | 110 + test/Unit/comparedf2_test.c | 479 + test/Unit/comparesf2_test.c | 479 + test/Unit/ctzdi2_test.c | 67 + test/Unit/ctzsi2_test.c | 569 + test/Unit/ctzti2_test.c | 82 + test/Unit/divdc3_test.c | 370 + test/Unit/divdf3vfp_test.c | 46 + test/Unit/divdi3_test.c | 58 + test/Unit/divsc3_test.c | 370 + test/Unit/divsf3vfp_test.c | 46 + test/Unit/divsi3_test.c | 56 + test/Unit/divtc3_test.c | 380 + test/Unit/divti3_test.c | 76 + test/Unit/divxc3_test.c | 377 + test/Unit/enable_execute_stack_test.c | 57 + test/Unit/endianness.h | 94 + test/Unit/eqdf2vfp_test.c | 53 + test/Unit/eqsf2vfp_test.c | 49 + test/Unit/extebdsfdf2vfp_test.c | 46 + test/Unit/ffsdi2_test.c | 66 + test/Unit/ffsti2_test.c | 81 + test/Unit/fixdfdi_test.c | 94 + test/Unit/fixdfsivfp_test.c | 48 + test/Unit/fixdfti_test.c | 121 + test/Unit/fixsfdi_test.c | 84 + test/Unit/fixsfsivfp_test.c | 50 + test/Unit/fixsfti_test.c | 109 + test/Unit/fixunsdfdi_test.c | 106 + test/Unit/fixunsdfsi_test.c | 100 + test/Unit/fixunsdfsivfp_test.c | 48 + test/Unit/fixunsdfti_test.c | 128 + test/Unit/fixunssfdi_test.c | 95 + test/Unit/fixunssfsi_test.c | 93 + test/Unit/fixunssfsivfp_test.c | 48 + test/Unit/fixunssfti_test.c | 120 + test/Unit/fixunstfdi_test.c | 119 + test/Unit/fixunsxfdi_test.c | 122 + test/Unit/fixunsxfsi_test.c | 105 + test/Unit/fixunsxfti_test.c | 139 + test/Unit/fixxfdi_test.c | 113 + test/Unit/fixxfti_test.c | 144 + test/Unit/floatdidf_test.c | 137 + test/Unit/floatdisf_test.c | 95 + test/Unit/floatdixf_test.c | 142 + test/Unit/floatsidfvfp_test.c | 48 + test/Unit/floatsisfvfp_test.c | 48 + test/Unit/floattidf_test.c | 178 + test/Unit/floattisf_test.c | 134 + test/Unit/floattixf_test.c | 210 + test/Unit/floatundidf_test.c | 132 + test/Unit/floatundisf_test.c | 96 + test/Unit/floatundixf_test.c | 143 + test/Unit/floatunssidfvfp_test.c | 48 + test/Unit/floatunssisfvfp_test.c | 48 + test/Unit/floatuntidf_test.c | 172 + test/Unit/floatuntisf_test.c | 163 + test/Unit/floatuntixf_test.c | 217 + test/Unit/gcc_personality_test.c | 42 + test/Unit/gcc_personality_test_helper.cxx | 85 + test/Unit/gedf2vfp_test.c | 51 + test/Unit/gesf2vfp_test.c | 51 + test/Unit/gtdf2vfp_test.c | 51 + test/Unit/gtsf2vfp_test.c | 51 + test/Unit/ledf2vfp_test.c | 51 + test/Unit/lesf2vfp_test.c | 51 + test/Unit/lshrdi3_test.c | 118 + test/Unit/lshrti3_test.c | 171 + test/Unit/ltdf2vfp_test.c | 49 + test/Unit/ltsf2vfp_test.c | 51 + test/Unit/moddi3_test.c | 62 + test/Unit/modsi3_test.c | 57 + test/Unit/modti3_test.c | 93 + test/Unit/muldc3_test.c | 366 + test/Unit/muldf3vfp_test.c | 48 + test/Unit/muldi3_test.c | 110 + test/Unit/mulsc3_test.c | 370 + test/Unit/mulsf3vfp_test.c | 48 + test/Unit/multc3_test.c | 373 + test/Unit/multi3_test.c | 132 + test/Unit/mulvdi3_test.c | 175 + test/Unit/mulvsi3_test.c | 148 + test/Unit/mulvti3_test.c | 258 + test/Unit/mulxc3_test.c | 373 + test/Unit/nedf2vfp_test.c | 49 + test/Unit/negdf2vfp_test.c | 46 + test/Unit/negdi2_test.c | 84 + test/Unit/negsf2vfp_test.c | 46 + test/Unit/negti2_test.c | 125 + test/Unit/negvdi2_test.c | 57 + test/Unit/negvsi2_test.c | 56 + test/Unit/negvti2_test.c | 107 + test/Unit/nesf2vfp_test.c | 49 + test/Unit/paritydi2_test.c | 51 + test/Unit/paritysi2_test.c | 50 + test/Unit/parityti2_test.c | 62 + test/Unit/popcountdi2_test.c | 63 + test/Unit/popcountsi2_test.c | 62 + test/Unit/popcountti2_test.c | 80 + test/Unit/powidf2_test.c | 224 + test/Unit/powisf2_test.c | 224 + test/Unit/powitf2_test.c | 230 + test/Unit/powixf2_test.c | 230 + test/Unit/ppc/CMakeLists.txt | 9 + test/Unit/ppc/DD.h | 14 + test/Unit/ppc/fixtfdi_test.c | 477 + test/Unit/ppc/floatditf_test.c | 30 + test/Unit/ppc/floatditf_test.h | 38018 +++++++++ test/Unit/ppc/floatunditf_test.c | 30 + test/Unit/ppc/floatunditf_test.h | 19014 +++++ test/Unit/ppc/qadd_test.c | 1872 + test/Unit/ppc/qdiv_test.c | 795 + test/Unit/ppc/qmul_test.c | 793 + test/Unit/ppc/qsub_test.c | 1874 + test/Unit/ppc/test | 18 + test/Unit/subdf3vfp_test.c | 46 + test/Unit/subsf3vfp_test.c | 46 + test/Unit/subvdi3_test.c | 60 + test/Unit/subvsi3_test.c | 60 + test/Unit/subvti3_test.c | 78 + test/Unit/test | 68 + test/Unit/trampoline_setup_test.c | 63 + test/Unit/truncdfsf2vfp_test.c | 48 + test/Unit/ucmpdi2_test.c | 75 + test/Unit/ucmpti2_test.c | 114 + test/Unit/udivdi3_test.c | 44 + test/Unit/udivmoddi4_test.c | 20639 +++++ test/Unit/udivmodti4_test.c | 65351 ++++++++++++++++ test/Unit/udivsi3_test.c | 175 + test/Unit/udivti3_test.c | 65 + test/Unit/umoddi3_test.c | 44 + test/Unit/umodsi3_test.c | 175 + test/Unit/umodti3_test.c | 63 + test/Unit/unorddf2vfp_test.c | 47 + test/Unit/unordsf2vfp_test.c | 47 + test/timing/CMakeLists.txt | 17 + test/timing/ashldi3.c | 49 + test/timing/ashrdi3.c | 49 + test/timing/divdi3.c | 52 + test/timing/floatdidf.c | 47 + test/timing/floatdisf.c | 47 + test/timing/floatdixf.c | 47 + test/timing/floatundidf.c | 44 + test/timing/floatundisf.c | 47 + test/timing/floatundixf.c | 47 + test/timing/lshrdi3.c | 49 + test/timing/moddi3.c | 52 + test/timing/muldi3.c | 52 + test/timing/negdi2.c | 50 + test/timing/time | 39 + test/timing/timing.h | 28 + test/timing/udivdi3.c | 52 + test/timing/umoddi3.c | 52 + www/content.css | 25 + www/index.html | 156 + www/menu.css | 39 + www/menu.html.incl | 19 + 471 files changed, 184040 insertions(+) create mode 100644 .gitignore create mode 100644 BlocksRuntime/Block.h create mode 100644 BlocksRuntime/Block_private.h create mode 100644 BlocksRuntime/CMakeLists.txt create mode 100644 BlocksRuntime/data.c create mode 100644 BlocksRuntime/runtime.c create mode 100644 BlocksRuntime/tests/block-static.c create mode 100644 BlocksRuntime/tests/blockimport.c create mode 100644 BlocksRuntime/tests/byrefaccess.c create mode 100644 BlocksRuntime/tests/byrefcopy.c create mode 100644 BlocksRuntime/tests/byrefcopycopy.c create mode 100644 BlocksRuntime/tests/byrefcopyinner.c create mode 100644 BlocksRuntime/tests/byrefcopyint.c create mode 100644 BlocksRuntime/tests/byrefcopystack.c create mode 100644 BlocksRuntime/tests/byrefsanity.c create mode 100644 BlocksRuntime/tests/byrefstruct.c create mode 100644 BlocksRuntime/tests/c99.c create mode 100644 BlocksRuntime/tests/cast.c create mode 100644 BlocksRuntime/tests/constassign.c create mode 100644 BlocksRuntime/tests/copy-block-literal-rdar6439600.c create mode 100644 BlocksRuntime/tests/copyconstructor.C create mode 100644 BlocksRuntime/tests/copynull.c create mode 100644 BlocksRuntime/tests/dispatch_async.c create mode 100644 BlocksRuntime/tests/dispatch_call_Block_with_release.c create mode 100644 BlocksRuntime/tests/fail.c create mode 100644 BlocksRuntime/tests/flagsisa.c create mode 100644 BlocksRuntime/tests/globalexpression.c create mode 100644 BlocksRuntime/tests/goto.c create mode 100644 BlocksRuntime/tests/hasdescriptor.c create mode 100644 BlocksRuntime/tests/josh.C create mode 100644 BlocksRuntime/tests/k-and-r.c create mode 100644 BlocksRuntime/tests/large-struct.c create mode 100644 BlocksRuntime/tests/localisglobal.c create mode 100644 BlocksRuntime/tests/macro.c create mode 100644 BlocksRuntime/tests/makefile create mode 100644 BlocksRuntime/tests/modglobal.c create mode 100644 BlocksRuntime/tests/nestedimport.c create mode 100644 BlocksRuntime/tests/nullblockisa.c create mode 100644 BlocksRuntime/tests/objectRRGC.c create mode 100644 BlocksRuntime/tests/objectassign.c create mode 100644 BlocksRuntime/tests/orbars.c create mode 100644 BlocksRuntime/tests/rdar6396238.c create mode 100644 BlocksRuntime/tests/rdar6405500.c create mode 100644 BlocksRuntime/tests/rdar6414583.c create mode 100644 BlocksRuntime/tests/recursive-block.c create mode 100644 BlocksRuntime/tests/recursive-test.c create mode 100644 BlocksRuntime/tests/recursiveassign.c create mode 100644 BlocksRuntime/tests/reference.C create mode 100644 BlocksRuntime/tests/rettypepromotion.c create mode 100644 BlocksRuntime/tests/returnfunctionptr.c create mode 100644 BlocksRuntime/tests/shorthandexpression.c create mode 100644 BlocksRuntime/tests/sizeof.c create mode 100644 BlocksRuntime/tests/small-struct.c create mode 100644 BlocksRuntime/tests/structmember.c create mode 100644 BlocksRuntime/tests/testfilerunner.h create mode 100644 BlocksRuntime/tests/testfilerunner.m create mode 100644 BlocksRuntime/tests/varargs-bad-assign.c create mode 100644 BlocksRuntime/tests/varargs.c create mode 100644 BlocksRuntime/tests/variadic.c create mode 100644 BlocksRuntime/tests/voidarg.c create mode 100644 CMakeLists.txt create mode 100644 CREDITS.TXT create mode 100644 LICENSE.TXT create mode 100644 Makefile create mode 100644 README.txt create mode 100644 cmake/ConfigureChecks.cmake create mode 100644 cmake/Modules/DefineCompilerFlags.cmake create mode 100644 cmake/Modules/MacroAddCheckTest.cmake create mode 100644 cmake/Modules/MacroEnsureOutOfSourceBuild.cmake create mode 100644 cmake/config.h.cmake create mode 100644 lib/CMakeLists.txt create mode 100644 lib/Makefile.mk create mode 100644 lib/absvdi2.c create mode 100644 lib/absvsi2.c create mode 100644 lib/absvti2.c create mode 100644 lib/adddf3.c create mode 100644 lib/addsf3.c create mode 100644 lib/addvdi3.c create mode 100644 lib/addvsi3.c create mode 100644 lib/addvti3.c create mode 100644 lib/apple_versioning.c create mode 100644 lib/arm/CMakeLists.txt create mode 100644 lib/arm/Makefile.mk create mode 100644 lib/arm/adddf3vfp.S create mode 100644 lib/arm/addsf3vfp.S create mode 100644 lib/arm/bswapdi2.S create mode 100644 lib/arm/bswapsi2.S create mode 100644 lib/arm/comparesf2.S create mode 100644 lib/arm/divdf3vfp.S create mode 100644 lib/arm/divsf3vfp.S create mode 100644 lib/arm/eqdf2vfp.S create mode 100644 lib/arm/eqsf2vfp.S create mode 100644 lib/arm/extendsfdf2vfp.S create mode 100644 lib/arm/fixdfsivfp.S create mode 100644 lib/arm/fixsfsivfp.S create mode 100644 lib/arm/fixunsdfsivfp.S create mode 100644 lib/arm/fixunssfsivfp.S create mode 100644 lib/arm/floatsidfvfp.S create mode 100644 lib/arm/floatsisfvfp.S create mode 100644 lib/arm/floatunssidfvfp.S create mode 100644 lib/arm/floatunssisfvfp.S create mode 100644 lib/arm/gedf2vfp.S create mode 100644 lib/arm/gesf2vfp.S create mode 100644 lib/arm/gtdf2vfp.S create mode 100644 lib/arm/gtsf2vfp.S create mode 100644 lib/arm/ledf2vfp.S create mode 100644 lib/arm/lesf2vfp.S create mode 100644 lib/arm/ltdf2vfp.S create mode 100644 lib/arm/ltsf2vfp.S create mode 100644 lib/arm/modsi3.S create mode 100644 lib/arm/muldf3vfp.S create mode 100644 lib/arm/mulsf3vfp.S create mode 100644 lib/arm/nedf2vfp.S create mode 100644 lib/arm/negdf2vfp.S create mode 100644 lib/arm/negsf2vfp.S create mode 100644 lib/arm/nesf2vfp.S create mode 100644 lib/arm/restore_vfp_d8_d15_regs.S create mode 100644 lib/arm/save_vfp_d8_d15_regs.S create mode 100644 lib/arm/subdf3vfp.S create mode 100644 lib/arm/subsf3vfp.S create mode 100644 lib/arm/switch16.S create mode 100644 lib/arm/switch32.S create mode 100644 lib/arm/switch8.S create mode 100644 lib/arm/switchu8.S create mode 100644 lib/arm/sync_synchronize.S create mode 100644 lib/arm/truncdfsf2vfp.S create mode 100644 lib/arm/unorddf2vfp.S create mode 100644 lib/arm/unordsf2vfp.S create mode 100644 lib/ashldi3.c create mode 100644 lib/ashlti3.c create mode 100644 lib/ashrdi3.c create mode 100644 lib/ashrti3.c create mode 100644 lib/assembly.h create mode 100644 lib/clear_cache.c create mode 100644 lib/clzdi2.c create mode 100644 lib/clzsi2.c create mode 100644 lib/clzti2.c create mode 100644 lib/cmpdi2.c create mode 100644 lib/cmpti2.c create mode 100644 lib/comparedf2.c create mode 100644 lib/comparesf2.c create mode 100644 lib/ctzdi2.c create mode 100644 lib/ctzsi2.c create mode 100644 lib/ctzti2.c create mode 100644 lib/divdc3.c create mode 100644 lib/divdf3.c create mode 100644 lib/divdi3.c create mode 100644 lib/divsc3.c create mode 100644 lib/divsf3.c create mode 100644 lib/divsi3.c create mode 100644 lib/divti3.c create mode 100644 lib/divxc3.c create mode 100644 lib/enable_execute_stack.c create mode 100644 lib/endianness.h create mode 100644 lib/eprintf.c create mode 100644 lib/extendsfdf2.c create mode 100644 lib/ffsdi2.c create mode 100644 lib/ffsti2.c create mode 100644 lib/fixdfdi.c create mode 100644 lib/fixdfsi.c create mode 100644 lib/fixdfti.c create mode 100644 lib/fixsfdi.c create mode 100644 lib/fixsfsi.c create mode 100644 lib/fixsfti.c create mode 100644 lib/fixunsdfdi.c create mode 100644 lib/fixunsdfsi.c create mode 100644 lib/fixunsdfti.c create mode 100644 lib/fixunssfdi.c create mode 100644 lib/fixunssfsi.c create mode 100644 lib/fixunssfti.c create mode 100644 lib/fixunsxfdi.c create mode 100644 lib/fixunsxfsi.c create mode 100644 lib/fixunsxfti.c create mode 100644 lib/fixxfdi.c create mode 100644 lib/fixxfti.c create mode 100644 lib/floatdidf.c create mode 100644 lib/floatdisf.c create mode 100644 lib/floatdixf.c create mode 100644 lib/floatsidf.c create mode 100644 lib/floatsisf.c create mode 100644 lib/floattidf.c create mode 100644 lib/floattisf.c create mode 100644 lib/floattixf.c create mode 100644 lib/floatundidf.c create mode 100644 lib/floatundisf.c create mode 100644 lib/floatundixf.c create mode 100644 lib/floatunsidf.c create mode 100644 lib/floatunsisf.c create mode 100644 lib/floatuntidf.c create mode 100644 lib/floatuntisf.c create mode 100644 lib/floatuntixf.c create mode 100644 lib/fp_lib.h create mode 100644 lib/gcc_personality_v0.c create mode 100644 lib/i386/CMakeLists.txt create mode 100644 lib/i386/Makefile.mk create mode 100644 lib/i386/ashldi3.S create mode 100644 lib/i386/ashrdi3.S create mode 100644 lib/i386/divdi3.S create mode 100644 lib/i386/floatdidf.S create mode 100644 lib/i386/floatdisf.S create mode 100644 lib/i386/floatdixf.S create mode 100644 lib/i386/floatundidf.S create mode 100644 lib/i386/floatundisf.S create mode 100644 lib/i386/floatundixf.S create mode 100644 lib/i386/lshrdi3.S create mode 100644 lib/i386/moddi3.S create mode 100644 lib/i386/muldi3.S create mode 100644 lib/i386/udivdi3.S create mode 100644 lib/i386/umoddi3.S create mode 100644 lib/int_lib.h create mode 100644 lib/lshrdi3.c create mode 100644 lib/lshrti3.c create mode 100644 lib/moddi3.c create mode 100644 lib/modsi3.c create mode 100644 lib/modti3.c create mode 100644 lib/muldc3.c create mode 100644 lib/muldf3.c create mode 100644 lib/muldi3.c create mode 100644 lib/mulsc3.c create mode 100644 lib/mulsf3.c create mode 100644 lib/multi3.c create mode 100644 lib/mulvdi3.c create mode 100644 lib/mulvsi3.c create mode 100644 lib/mulvti3.c create mode 100644 lib/mulxc3.c create mode 100644 lib/negdf2.c create mode 100644 lib/negdi2.c create mode 100644 lib/negsf2.c create mode 100644 lib/negti2.c create mode 100644 lib/negvdi2.c create mode 100644 lib/negvsi2.c create mode 100644 lib/negvti2.c create mode 100644 lib/paritydi2.c create mode 100644 lib/paritysi2.c create mode 100644 lib/parityti2.c create mode 100644 lib/popcountdi2.c create mode 100644 lib/popcountsi2.c create mode 100644 lib/popcountti2.c create mode 100644 lib/powidf2.c create mode 100644 lib/powisf2.c create mode 100644 lib/powitf2.c create mode 100644 lib/powixf2.c create mode 100644 lib/ppc/CMakeLists.txt create mode 100644 lib/ppc/DD.h create mode 100644 lib/ppc/Makefile.mk create mode 100644 lib/ppc/divtc3.c create mode 100644 lib/ppc/fixtfdi.c create mode 100644 lib/ppc/fixunstfdi.c create mode 100644 lib/ppc/floatditf.c create mode 100644 lib/ppc/floatunditf.c create mode 100644 lib/ppc/gcc_qadd.c create mode 100644 lib/ppc/gcc_qdiv.c create mode 100644 lib/ppc/gcc_qmul.c create mode 100644 lib/ppc/gcc_qsub.c create mode 100644 lib/ppc/multc3.c create mode 100644 lib/ppc/restFP.S create mode 100644 lib/ppc/saveFP.S create mode 100644 lib/subvdi3.c create mode 100644 lib/subvsi3.c create mode 100644 lib/subvti3.c create mode 100644 lib/trampoline_setup.c create mode 100644 lib/truncdfsf2.c create mode 100644 lib/ucmpdi2.c create mode 100644 lib/ucmpti2.c create mode 100644 lib/udivdi3.c create mode 100644 lib/udivmoddi4.c create mode 100644 lib/udivmodti4.c create mode 100644 lib/udivsi3.c create mode 100644 lib/udivti3.c create mode 100644 lib/umoddi3.c create mode 100644 lib/umodsi3.c create mode 100644 lib/umodti3.c create mode 100644 lib/x86_64/CMakeLists.txt create mode 100644 lib/x86_64/Makefile.mk create mode 100644 lib/x86_64/floatdidf.c create mode 100644 lib/x86_64/floatdisf.c create mode 100644 lib/x86_64/floatdixf.c create mode 100644 lib/x86_64/floatundidf.S create mode 100644 lib/x86_64/floatundisf.S create mode 100644 lib/x86_64/floatundixf.S create mode 100644 make/AppleBI.mk create mode 100644 make/config.mk create mode 100755 make/filter-inputs create mode 100644 make/lib_info.mk create mode 100644 make/lib_platforms.mk create mode 100644 make/lib_util.mk create mode 100644 make/options.mk create mode 100644 make/platform/clang_darwin.mk create mode 100644 make/platform/darwin_bni.mk create mode 100644 make/platform/darwin_fat.mk create mode 100644 make/platform/multi_arch.mk create mode 100644 make/subdir.mk create mode 100644 make/test/test-util.mk create mode 100644 make/util.mk create mode 100644 test/CMakeLists.txt create mode 100644 test/Unit/absvdi2_test.c create mode 100644 test/Unit/absvsi2_test.c create mode 100644 test/Unit/absvti2_test.c create mode 100644 test/Unit/adddf3vfp_test.c create mode 100644 test/Unit/addsf3vfp_test.c create mode 100644 test/Unit/addvdi3_test.c create mode 100644 test/Unit/addvsi3_test.c create mode 100644 test/Unit/addvti3_test.c create mode 100644 test/Unit/ashldi3_test.c create mode 100644 test/Unit/ashlti3_test.c create mode 100644 test/Unit/ashrdi3_test.c create mode 100644 test/Unit/ashrti3_test.c create mode 100644 test/Unit/bswapdi2_test.c create mode 100644 test/Unit/bswapsi2_test.c create mode 100644 test/Unit/clear_cache_test.c create mode 100644 test/Unit/clzdi2_test.c create mode 100644 test/Unit/clzsi2_test.c create mode 100644 test/Unit/clzti2_test.c create mode 100644 test/Unit/cmpdi2_test.c create mode 100644 test/Unit/cmpti2_test.c create mode 100644 test/Unit/comparedf2_test.c create mode 100644 test/Unit/comparesf2_test.c create mode 100644 test/Unit/ctzdi2_test.c create mode 100644 test/Unit/ctzsi2_test.c create mode 100644 test/Unit/ctzti2_test.c create mode 100644 test/Unit/divdc3_test.c create mode 100644 test/Unit/divdf3vfp_test.c create mode 100644 test/Unit/divdi3_test.c create mode 100644 test/Unit/divsc3_test.c create mode 100644 test/Unit/divsf3vfp_test.c create mode 100644 test/Unit/divsi3_test.c create mode 100644 test/Unit/divtc3_test.c create mode 100644 test/Unit/divti3_test.c create mode 100644 test/Unit/divxc3_test.c create mode 100644 test/Unit/enable_execute_stack_test.c create mode 100644 test/Unit/endianness.h create mode 100644 test/Unit/eqdf2vfp_test.c create mode 100644 test/Unit/eqsf2vfp_test.c create mode 100644 test/Unit/extebdsfdf2vfp_test.c create mode 100644 test/Unit/ffsdi2_test.c create mode 100644 test/Unit/ffsti2_test.c create mode 100644 test/Unit/fixdfdi_test.c create mode 100644 test/Unit/fixdfsivfp_test.c create mode 100644 test/Unit/fixdfti_test.c create mode 100644 test/Unit/fixsfdi_test.c create mode 100644 test/Unit/fixsfsivfp_test.c create mode 100644 test/Unit/fixsfti_test.c create mode 100644 test/Unit/fixunsdfdi_test.c create mode 100644 test/Unit/fixunsdfsi_test.c create mode 100644 test/Unit/fixunsdfsivfp_test.c create mode 100644 test/Unit/fixunsdfti_test.c create mode 100644 test/Unit/fixunssfdi_test.c create mode 100644 test/Unit/fixunssfsi_test.c create mode 100644 test/Unit/fixunssfsivfp_test.c create mode 100644 test/Unit/fixunssfti_test.c create mode 100644 test/Unit/fixunstfdi_test.c create mode 100644 test/Unit/fixunsxfdi_test.c create mode 100644 test/Unit/fixunsxfsi_test.c create mode 100644 test/Unit/fixunsxfti_test.c create mode 100644 test/Unit/fixxfdi_test.c create mode 100644 test/Unit/fixxfti_test.c create mode 100644 test/Unit/floatdidf_test.c create mode 100644 test/Unit/floatdisf_test.c create mode 100644 test/Unit/floatdixf_test.c create mode 100644 test/Unit/floatsidfvfp_test.c create mode 100644 test/Unit/floatsisfvfp_test.c create mode 100644 test/Unit/floattidf_test.c create mode 100644 test/Unit/floattisf_test.c create mode 100644 test/Unit/floattixf_test.c create mode 100644 test/Unit/floatundidf_test.c create mode 100644 test/Unit/floatundisf_test.c create mode 100644 test/Unit/floatundixf_test.c create mode 100644 test/Unit/floatunssidfvfp_test.c create mode 100644 test/Unit/floatunssisfvfp_test.c create mode 100644 test/Unit/floatuntidf_test.c create mode 100644 test/Unit/floatuntisf_test.c create mode 100644 test/Unit/floatuntixf_test.c create mode 100644 test/Unit/gcc_personality_test.c create mode 100644 test/Unit/gcc_personality_test_helper.cxx create mode 100644 test/Unit/gedf2vfp_test.c create mode 100644 test/Unit/gesf2vfp_test.c create mode 100644 test/Unit/gtdf2vfp_test.c create mode 100644 test/Unit/gtsf2vfp_test.c create mode 100644 test/Unit/ledf2vfp_test.c create mode 100644 test/Unit/lesf2vfp_test.c create mode 100644 test/Unit/lshrdi3_test.c create mode 100644 test/Unit/lshrti3_test.c create mode 100644 test/Unit/ltdf2vfp_test.c create mode 100644 test/Unit/ltsf2vfp_test.c create mode 100644 test/Unit/moddi3_test.c create mode 100644 test/Unit/modsi3_test.c create mode 100644 test/Unit/modti3_test.c create mode 100644 test/Unit/muldc3_test.c create mode 100644 test/Unit/muldf3vfp_test.c create mode 100644 test/Unit/muldi3_test.c create mode 100644 test/Unit/mulsc3_test.c create mode 100644 test/Unit/mulsf3vfp_test.c create mode 100644 test/Unit/multc3_test.c create mode 100644 test/Unit/multi3_test.c create mode 100644 test/Unit/mulvdi3_test.c create mode 100644 test/Unit/mulvsi3_test.c create mode 100644 test/Unit/mulvti3_test.c create mode 100644 test/Unit/mulxc3_test.c create mode 100644 test/Unit/nedf2vfp_test.c create mode 100644 test/Unit/negdf2vfp_test.c create mode 100644 test/Unit/negdi2_test.c create mode 100644 test/Unit/negsf2vfp_test.c create mode 100644 test/Unit/negti2_test.c create mode 100644 test/Unit/negvdi2_test.c create mode 100644 test/Unit/negvsi2_test.c create mode 100644 test/Unit/negvti2_test.c create mode 100644 test/Unit/nesf2vfp_test.c create mode 100644 test/Unit/paritydi2_test.c create mode 100644 test/Unit/paritysi2_test.c create mode 100644 test/Unit/parityti2_test.c create mode 100644 test/Unit/popcountdi2_test.c create mode 100644 test/Unit/popcountsi2_test.c create mode 100644 test/Unit/popcountti2_test.c create mode 100644 test/Unit/powidf2_test.c create mode 100644 test/Unit/powisf2_test.c create mode 100644 test/Unit/powitf2_test.c create mode 100644 test/Unit/powixf2_test.c create mode 100644 test/Unit/ppc/CMakeLists.txt create mode 100644 test/Unit/ppc/DD.h create mode 100644 test/Unit/ppc/fixtfdi_test.c create mode 100644 test/Unit/ppc/floatditf_test.c create mode 100644 test/Unit/ppc/floatditf_test.h create mode 100644 test/Unit/ppc/floatunditf_test.c create mode 100644 test/Unit/ppc/floatunditf_test.h create mode 100644 test/Unit/ppc/qadd_test.c create mode 100644 test/Unit/ppc/qdiv_test.c create mode 100644 test/Unit/ppc/qmul_test.c create mode 100644 test/Unit/ppc/qsub_test.c create mode 100755 test/Unit/ppc/test create mode 100644 test/Unit/subdf3vfp_test.c create mode 100644 test/Unit/subsf3vfp_test.c create mode 100644 test/Unit/subvdi3_test.c create mode 100644 test/Unit/subvsi3_test.c create mode 100644 test/Unit/subvti3_test.c create mode 100755 test/Unit/test create mode 100644 test/Unit/trampoline_setup_test.c create mode 100644 test/Unit/truncdfsf2vfp_test.c create mode 100644 test/Unit/ucmpdi2_test.c create mode 100644 test/Unit/ucmpti2_test.c create mode 100644 test/Unit/udivdi3_test.c create mode 100644 test/Unit/udivmoddi4_test.c create mode 100644 test/Unit/udivmodti4_test.c create mode 100644 test/Unit/udivsi3_test.c create mode 100644 test/Unit/udivti3_test.c create mode 100644 test/Unit/umoddi3_test.c create mode 100644 test/Unit/umodsi3_test.c create mode 100644 test/Unit/umodti3_test.c create mode 100644 test/Unit/unorddf2vfp_test.c create mode 100644 test/Unit/unordsf2vfp_test.c create mode 100644 test/timing/CMakeLists.txt create mode 100644 test/timing/ashldi3.c create mode 100644 test/timing/ashrdi3.c create mode 100644 test/timing/divdi3.c create mode 100644 test/timing/floatdidf.c create mode 100644 test/timing/floatdisf.c create mode 100644 test/timing/floatdixf.c create mode 100644 test/timing/floatundidf.c create mode 100644 test/timing/floatundisf.c create mode 100644 test/timing/floatundixf.c create mode 100644 test/timing/lshrdi3.c create mode 100644 test/timing/moddi3.c create mode 100644 test/timing/muldi3.c create mode 100644 test/timing/negdi2.c create mode 100755 test/timing/time create mode 100644 test/timing/timing.h create mode 100644 test/timing/udivdi3.c create mode 100644 test/timing/umoddi3.c create mode 100644 www/content.css create mode 100644 www/index.html create mode 100644 www/menu.css create mode 100644 www/menu.html.incl diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..8f9995985548 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +Debug +Release +Profile diff --git a/BlocksRuntime/Block.h b/BlocksRuntime/Block.h new file mode 100644 index 000000000000..55cdd01a9123 --- /dev/null +++ b/BlocksRuntime/Block.h @@ -0,0 +1,59 @@ +/* + * Block.h + * + * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _BLOCK_H_ +#define _BLOCK_H_ + +#if !defined(BLOCK_EXPORT) +# if defined(__cplusplus) +# define BLOCK_EXPORT extern "C" +# else +# define BLOCK_EXPORT extern +# endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Create a heap based copy of a Block or simply add a reference to an existing one. + * This must be paired with Block_release to recover memory, even when running + * under Objective-C Garbage Collection. + */ +BLOCK_EXPORT void *_Block_copy(const void *aBlock); + +/* Lose the reference, and if heap based and last reference, recover the memory. */ +BLOCK_EXPORT void _Block_release(const void *aBlock); + +#if defined(__cplusplus) +} +#endif + +/* Type correct macros. */ + +#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__))) +#define Block_release(...) _Block_release((const void *)(__VA_ARGS__)) + + +#endif diff --git a/BlocksRuntime/Block_private.h b/BlocksRuntime/Block_private.h new file mode 100644 index 000000000000..8ae821815ebe --- /dev/null +++ b/BlocksRuntime/Block_private.h @@ -0,0 +1,179 @@ +/* + * Block_private.h + * + * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _BLOCK_PRIVATE_H_ +#define _BLOCK_PRIVATE_H_ + +#if !defined(BLOCK_EXPORT) +# if defined(__cplusplus) +# define BLOCK_EXPORT extern "C" +# else +# define BLOCK_EXPORT extern +# endif +#endif + +#ifndef _MSC_VER +#include +#else +/* MSVC doesn't have . Compensate. */ +typedef char bool; +#define true (bool)1 +#define false (bool)0 +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +enum { + BLOCK_REFCOUNT_MASK = (0xffff), + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */ + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) +}; + + +/* Revised new layout. */ +struct Block_descriptor { + unsigned long int reserved; + unsigned long int size; + void (*copy)(void *dst, void *src); + void (*dispose)(void *); +}; + + +struct Block_layout { + void *isa; + int flags; + int reserved; + void (*invoke)(void *, ...); + struct Block_descriptor *descriptor; + /* Imported variables. */ +}; + + +struct Block_byref { + void *isa; + struct Block_byref *forwarding; + int flags; /* refcount; */ + int size; + void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src); + void (*byref_destroy)(struct Block_byref *); + /* long shared[0]; */ +}; + + +struct Block_byref_header { + void *isa; + struct Block_byref *forwarding; + int flags; + int size; +}; + + +/* Runtime support functions used by compiler when generating copy/dispose helpers. */ + +enum { + /* See function implementation for a more complete description of these fields and combinations */ + BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), block, ... */ + BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ + BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block variable */ + BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */ + BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose support routines. */ +}; + +/* Runtime entry point called by compiler when assigning objects inside copy helper routines */ +BLOCK_EXPORT void _Block_object_assign(void *destAddr, const void *object, const int flags); + /* BLOCK_FIELD_IS_BYREF is only used from within block copy helpers */ + + +/* runtime entry point called by the compiler when disposing of objects inside dispose helper routine */ +BLOCK_EXPORT void _Block_object_dispose(const void *object, const int flags); + + + +/* Other support functions */ + +/* Runtime entry to get total size of a closure */ +BLOCK_EXPORT unsigned long int Block_size(void *block_basic); + + + +/* the raw data space for runtime classes for blocks */ +/* class+meta used for stack, malloc, and collectable based blocks */ +BLOCK_EXPORT void * _NSConcreteStackBlock[32]; +BLOCK_EXPORT void * _NSConcreteMallocBlock[32]; +BLOCK_EXPORT void * _NSConcreteAutoBlock[32]; +BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32]; +BLOCK_EXPORT void * _NSConcreteGlobalBlock[32]; +BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32]; + + +/* the intercept routines that must be used under GC */ +BLOCK_EXPORT void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject), + void (*setHasRefcount)(const void *, const bool), + void (*gc_assign_strong)(void *, void **), + void (*gc_assign_weak)(const void *, void *), + void (*gc_memmove)(void *, void *, unsigned long)); + +/* earlier version, now simply transitional */ +BLOCK_EXPORT void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject), + void (*setHasRefcount)(const void *, const bool), + void (*gc_assign_strong)(void *, void **), + void (*gc_assign_weak)(const void *, void *)); + +BLOCK_EXPORT void _Block_use_RR( void (*retain)(const void *), + void (*release)(const void *)); + +/* make a collectable GC heap based Block. Not useful under non-GC. */ +BLOCK_EXPORT void *_Block_copy_collectable(const void *aBlock); + +/* thread-unsafe diagnostic */ +BLOCK_EXPORT const char *_Block_dump(const void *block); + + +/* Obsolete */ + +/* first layout */ +struct Block_basic { + void *isa; + int Block_flags; /* int32_t */ + int Block_size; /* XXX should be packed into Block_flags */ + void (*Block_invoke)(void *); + void (*Block_copy)(void *dst, void *src); /* iff BLOCK_HAS_COPY_DISPOSE */ + void (*Block_dispose)(void *); /* iff BLOCK_HAS_COPY_DISPOSE */ + /* long params[0]; // where const imports, __block storage references, etc. get laid down */ +}; + + +#if defined(__cplusplus) +} +#endif + + +#endif /* _BLOCK_PRIVATE_H_ */ diff --git a/BlocksRuntime/CMakeLists.txt b/BlocksRuntime/CMakeLists.txt new file mode 100644 index 000000000000..5b4686b83a69 --- /dev/null +++ b/BlocksRuntime/CMakeLists.txt @@ -0,0 +1,13 @@ +PROJECT( BlocksRuntime C ) + +SET( SRCS + runtime.c + data.c + ) + +ADD_LIBRARY( ${PROJECT_NAME} SHARED ${SRCS}) +SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES + INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib ) + +INSTALL( TARGETS ${PROJECT_NAME} DESTINATION lib ) +INSTALL( FILES Block.h Block_private.h DESTINATION include ) diff --git a/BlocksRuntime/data.c b/BlocksRuntime/data.c new file mode 100644 index 000000000000..b4eb02e0b01e --- /dev/null +++ b/BlocksRuntime/data.c @@ -0,0 +1,41 @@ +/* + * data.c + * + * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/******************** +NSBlock support + +We allocate space and export a symbol to be used as the Class for the on-stack and malloc'ed copies until ObjC arrives on the scene. These data areas are set up by Foundation to link in as real classes post facto. + +We keep these in a separate file so that we can include the runtime code in test subprojects but not include the data so that compiled code that sees the data in libSystem doesn't get confused by a second copy. Somehow these don't get unified in a common block. +**********************/ + +void * _NSConcreteStackBlock[32] = { 0 }; +void * _NSConcreteMallocBlock[32] = { 0 }; +void * _NSConcreteAutoBlock[32] = { 0 }; +void * _NSConcreteFinalizingBlock[32] = { 0 }; +void * _NSConcreteGlobalBlock[32] = { 0 }; +void * _NSConcreteWeakBlockVariable[32] = { 0 }; + +void _Block_copy_error(void) { +} diff --git a/BlocksRuntime/runtime.c b/BlocksRuntime/runtime.c new file mode 100644 index 000000000000..a059c2234df1 --- /dev/null +++ b/BlocksRuntime/runtime.c @@ -0,0 +1,700 @@ +/* + * runtime.c + * + * Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "Block_private.h" +#include +#include +#include +#include + +#include "config.h" + +#ifdef HAVE_AVAILABILITY_MACROS_H +#include +#endif /* HAVE_AVAILABILITY_MACROS_H */ + +#ifdef HAVE_TARGET_CONDITIONALS_H +#include +#endif /* HAVE_TARGET_CONDITIONALS_H */ + +#if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG) + +#ifdef HAVE_LIBKERN_OSATOMIC_H +#include +#endif /* HAVE_LIBKERN_OSATOMIC_H */ + +#elif defined(__WIN32__) || defined(_WIN32) +#define _CRT_SECURE_NO_WARNINGS 1 +#include + +static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) { + /* fixme barrier is overkill -- see objc-os.h */ + long original = InterlockedCompareExchange(dst, newl, oldl); + return (original == oldl); +} + +static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) { + /* fixme barrier is overkill -- see objc-os.h */ + int original = InterlockedCompareExchange(dst, newi, oldi); + return (original == oldi); +} + +/* + * Check to see if the GCC atomic built-ins are available. If we're on + * a 64-bit system, make sure we have an 8-byte atomic function + * available. + * + */ + +#elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG) + +static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) { + return __sync_bool_compare_and_swap(dst, oldl, newl); +} + +static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) { + return __sync_bool_compare_and_swap(dst, oldi, newi); +} + +#else +#error unknown atomic compare-and-swap primitive +#endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */ + + +/* + * Globals: + */ + +static void *_Block_copy_class = _NSConcreteMallocBlock; +static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock; +static int _Block_copy_flag = BLOCK_NEEDS_FREE; +static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2; + +static const int WANTS_ONE = (1 << 16); + +static bool isGC = false; + +/* + * Internal Utilities: + */ + +#if 0 +static unsigned long int latching_incr_long(unsigned long int *where) { + while (1) { + unsigned long int old_value = *(volatile unsigned long int *)where; + if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) { + return BLOCK_REFCOUNT_MASK; + } + if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) { + return old_value+1; + } + } +} +#endif /* if 0 */ + +static int latching_incr_int(int *where) { + while (1) { + int old_value = *(volatile int *)where; + if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) { + return BLOCK_REFCOUNT_MASK; + } + if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) { + return old_value+1; + } + } +} + +#if 0 +static int latching_decr_long(unsigned long int *where) { + while (1) { + unsigned long int old_value = *(volatile int *)where; + if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) { + return BLOCK_REFCOUNT_MASK; + } + if ((old_value & BLOCK_REFCOUNT_MASK) == 0) { + return 0; + } + if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) { + return old_value-1; + } + } +} +#endif /* if 0 */ + +static int latching_decr_int(int *where) { + while (1) { + int old_value = *(volatile int *)where; + if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) { + return BLOCK_REFCOUNT_MASK; + } + if ((old_value & BLOCK_REFCOUNT_MASK) == 0) { + return 0; + } + if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) { + return old_value-1; + } + } +} + + +/* + * GC support stub routines: + */ +#if 0 +#pragma mark GC Support Routines +#endif /* if 0 */ + + +static void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) { + return malloc(size); +} + +static void _Block_assign_default(void *value, void **destptr) { + *destptr = value; +} + +static void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) { +} + +static void _Block_do_nothing(const void *aBlock) { } + +static void _Block_retain_object_default(const void *ptr) { + if (!ptr) return; +} + +static void _Block_release_object_default(const void *ptr) { + if (!ptr) return; +} + +static void _Block_assign_weak_default(const void *ptr, void *dest) { + *(void **)dest = (void *)ptr; +} + +static void _Block_memmove_default(void *dst, void *src, unsigned long size) { + memmove(dst, src, (size_t)size); +} + +static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) { + void **destp = (void **)dest; + void **srcp = (void **)src; + while (size) { + _Block_assign_default(*srcp, destp); + destp++; + srcp++; + size -= sizeof(void *); + } +} + +/* + * GC support callout functions - initially set to stub routines: + */ + +static void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default; +static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free; +static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default; +static void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default; +static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default; +static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default; +static void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default; +static void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default; + + +/* + * GC support SPI functions - called from ObjC runtime and CoreFoundation: + */ + +/* Public SPI + * Called from objc-auto to turn on GC. + * version 3, 4 arg, but changed 1st arg + */ +void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject), + void (*setHasRefcount)(const void *, const bool), + void (*gc_assign)(void *, void **), + void (*gc_assign_weak)(const void *, void *), + void (*gc_memmove)(void *, void *, unsigned long)) { + + isGC = true; + _Block_allocator = alloc; + _Block_deallocator = _Block_do_nothing; + _Block_assign = gc_assign; + _Block_copy_flag = BLOCK_IS_GC; + _Block_copy_class = _NSConcreteAutoBlock; + /* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */ + _Block_copy_finalizing_class = _NSConcreteFinalizingBlock; + _Block_setHasRefcount = setHasRefcount; + _Byref_flag_initial_value = BLOCK_IS_GC; // no refcount + _Block_retain_object = _Block_do_nothing; + _Block_release_object = _Block_do_nothing; + _Block_assign_weak = gc_assign_weak; + _Block_memmove = gc_memmove; +} + +/* transitional */ +void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject), + void (*setHasRefcount)(const void *, const bool), + void (*gc_assign)(void *, void **), + void (*gc_assign_weak)(const void *, void *)) { + /* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */ + _Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken); +} + + +/* + * Called from objc-auto to alternatively turn on retain/release. + * Prior to this the only "object" support we can provide is for those + * super special objects that live in libSystem, namely dispatch queues. + * Blocks and Block_byrefs have their own special entry points. + * + */ +void _Block_use_RR( void (*retain)(const void *), + void (*release)(const void *)) { + _Block_retain_object = retain; + _Block_release_object = release; +} + +/* + * Internal Support routines for copying: + */ + +#if 0 +#pragma mark Copy/Release support +#endif /* if 0 */ + +/* Copy, or bump refcount, of a block. If really copying, call the copy helper if present. */ +static void *_Block_copy_internal(const void *arg, const int flags) { + struct Block_layout *aBlock; + const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE; + + //printf("_Block_copy_internal(%p, %x)\n", arg, flags); + if (!arg) return NULL; + + + // The following would be better done as a switch statement + aBlock = (struct Block_layout *)arg; + if (aBlock->flags & BLOCK_NEEDS_FREE) { + // latches on high + latching_incr_int(&aBlock->flags); + return aBlock; + } + else if (aBlock->flags & BLOCK_IS_GC) { + // GC refcounting is expensive so do most refcounting here. + if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) { + // Tell collector to hang on this - it will bump the GC refcount version + _Block_setHasRefcount(aBlock, true); + } + return aBlock; + } + else if (aBlock->flags & BLOCK_IS_GLOBAL) { + return aBlock; + } + + // Its a stack block. Make a copy. + if (!isGC) { + struct Block_layout *result = malloc(aBlock->descriptor->size); + if (!result) return (void *)0; + memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first + // reset refcount + result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed + result->flags |= BLOCK_NEEDS_FREE | 1; + result->isa = _NSConcreteMallocBlock; + if (result->flags & BLOCK_HAS_COPY_DISPOSE) { + //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock); + (*aBlock->descriptor->copy)(result, aBlock); // do fixup + } + return result; + } + else { + // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne + // This allows the copy helper routines to make non-refcounted block copies under GC + unsigned long int flags = aBlock->flags; + bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0; + struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR); + if (!result) return (void *)0; + memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first + // reset refcount + // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE. + flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK); // XXX not needed + if (wantsOne) + flags |= BLOCK_IS_GC | 1; + else + flags |= BLOCK_IS_GC; + result->flags = flags; + if (flags & BLOCK_HAS_COPY_DISPOSE) { + //printf("calling block copy helper...\n"); + (*aBlock->descriptor->copy)(result, aBlock); // do fixup + } + if (hasCTOR) { + result->isa = _NSConcreteFinalizingBlock; + } + else { + result->isa = _NSConcreteAutoBlock; + } + return result; + } +} + + +/* + * Runtime entry points for maintaining the sharing knowledge of byref data blocks. + * + * A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data + * Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr. + * We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it. + * Otherwise we need to copy it and update the stack forwarding pointer + * XXX We need to account for weak/nonretained read-write barriers. + */ + +static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) { + struct Block_byref **destp = (struct Block_byref **)dest; + struct Block_byref *src = (struct Block_byref *)arg; + + //printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags); + //printf("src dump: %s\n", _Block_byref_dump(src)); + if (src->forwarding->flags & BLOCK_IS_GC) { + ; // don't need to do any more work + } + else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) { + //printf("making copy\n"); + // src points to stack + bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)); + // if its weak ask for an object (only matters under GC) + struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak); + copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack + copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier) + src->forwarding = copy; // patch stack to point to heap copy + copy->size = src->size; + if (isWeak) { + copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning + } + if (src->flags & BLOCK_HAS_COPY_DISPOSE) { + // Trust copy helper to copy everything of interest + // If more than one field shows up in a byref block this is wrong XXX + copy->byref_keep = src->byref_keep; + copy->byref_destroy = src->byref_destroy; + (*src->byref_keep)(copy, src); + } + else { + // just bits. Blast 'em using _Block_memmove in case they're __strong + _Block_memmove( + (void *)©->byref_keep, + (void *)&src->byref_keep, + src->size - sizeof(struct Block_byref_header)); + } + } + // already copied to heap + else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) { + latching_incr_int(&src->forwarding->flags); + } + // assign byref data block pointer into new Block + _Block_assign(src->forwarding, (void **)destp); +} + +// Old compiler SPI +static void _Block_byref_release(const void *arg) { + struct Block_byref *shared_struct = (struct Block_byref *)arg; + int refcount; + + // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?) + shared_struct = shared_struct->forwarding; + + //printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags); + // To support C++ destructors under GC we arrange for there to be a finalizer for this + // by using an isa that directs the code to a finalizer that calls the byref_destroy method. + if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) { + return; // stack or GC or global + } + refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK; + if (refcount <= 0) { + printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg); + } + else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) { + //printf("disposing of heap based byref block\n"); + if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) { + //printf("calling out to helper\n"); + (*shared_struct->byref_destroy)(shared_struct); + } + _Block_deallocator((struct Block_layout *)shared_struct); + } +} + + +/* + * + * API supporting SPI + * _Block_copy, _Block_release, and (old) _Block_destroy + * + */ + +#if 0 +#pragma mark SPI/API +#endif /* if 0 */ + +void *_Block_copy(const void *arg) { + return _Block_copy_internal(arg, WANTS_ONE); +} + + +// API entry point to release a copied Block +void _Block_release(void *arg) { + struct Block_layout *aBlock = (struct Block_layout *)arg; + int32_t newCount; + if (!aBlock) return; + newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK; + if (newCount > 0) return; + // Hit zero + if (aBlock->flags & BLOCK_IS_GC) { + // Tell GC we no longer have our own refcounts. GC will decr its refcount + // and unless someone has done a CFRetain or marked it uncollectable it will + // now be subject to GC reclamation. + _Block_setHasRefcount(aBlock, false); + } + else if (aBlock->flags & BLOCK_NEEDS_FREE) { + if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock); + _Block_deallocator(aBlock); + } + else if (aBlock->flags & BLOCK_IS_GLOBAL) { + ; + } + else { + printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock); + } +} + + + +// Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers +static void _Block_destroy(const void *arg) { + struct Block_layout *aBlock; + if (!arg) return; + aBlock = (struct Block_layout *)arg; + if (aBlock->flags & BLOCK_IS_GC) { + // assert(aBlock->Block_flags & BLOCK_HAS_CTOR); + return; // ignore, we are being called because of a DTOR + } + _Block_release(aBlock); +} + + + +/* + * + * SPI used by other layers + * + */ + +// SPI, also internal. Called from NSAutoBlock only under GC +void *_Block_copy_collectable(const void *aBlock) { + return _Block_copy_internal(aBlock, 0); +} + + +// SPI +unsigned long int Block_size(void *arg) { + return ((struct Block_layout *)arg)->descriptor->size; +} + + +#if 0 +#pragma mark Compiler SPI entry points +#endif /* if 0 */ + + +/******************************************************* + +Entry points used by the compiler - the real API! + + +A Block can reference four different kinds of things that require help when the Block is copied to the heap. +1) C++ stack based objects +2) References to Objective-C objects +3) Other Blocks +4) __block variables + +In these cases helper functions are synthesized by the compiler for use in Block_copy and Block_release, called the copy and dispose helpers. The copy helper emits a call to the C++ const copy constructor for C++ stack based objects and for the rest calls into the runtime support function _Block_object_assign. The dispose helper has a call to the C++ destructor for case 1 and a call into _Block_object_dispose for the rest. + +The flags parameter of _Block_object_assign and _Block_object_dispose is set to + * BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object, + * BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and + * BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable. +If the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16). + +So the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24. + +When a __block variable is either a C++ object, an Objective-C object, or another Block then the compiler also generates copy/dispose helper functions. Similarly to the Block copy helper, the "__block" copy helper (formerly and still a.k.a. "byref" copy helper) will do a C++ copy constructor (not a const one though!) and the dispose helper will do the destructor. And similarly the helpers will call into the same two support functions with the same values for objects and Blocks with the additional BLOCK_BYREF_CALLER (128) bit of information supplied. + +So the __block copy/dispose helpers will generate flag values of 3 or 7 for objects and Blocks respectively, with BLOCK_FIELD_IS_WEAK (16) or'ed as appropriate and always 128 or'd in, for the following set of possibilities: + __block id 128+3 + __weak block id 128+3+16 + __block (^Block) 128+7 + __weak __block (^Block) 128+7+16 + +The implementation of the two routines would be improved by switch statements enumerating the eight cases. + +********************************************************/ + +/* + * When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point + * to do the assignment. + */ +void _Block_object_assign(void *destAddr, const void *object, const int flags) { + //printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags); + if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) { + if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) { + _Block_assign_weak(object, destAddr); + } + else { + // do *not* retain or *copy* __block variables whatever they are + _Block_assign((void *)object, destAddr); + } + } + else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) { + // copying a __block reference from the stack Block to the heap + // flags will indicate if it holds a __weak reference and needs a special isa + _Block_byref_assign_copy(destAddr, object, flags); + } + // (this test must be before next one) + else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { + // copying a Block declared variable from the stack Block to the heap + _Block_assign(_Block_copy_internal(object, flags), destAddr); + } + // (this test must be after previous one) + else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) { + //printf("retaining object at %p\n", object); + _Block_retain_object(object); + //printf("done retaining object at %p\n", object); + _Block_assign((void *)object, destAddr); + } +} + +// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point +// to help dispose of the contents +// Used initially only for __attribute__((NSObject)) marked pointers. +void _Block_object_dispose(const void *object, const int flags) { + //printf("_Block_object_dispose(%p, %x)\n", object, flags); + if (flags & BLOCK_FIELD_IS_BYREF) { + // get rid of the __block data structure held in a Block + _Block_byref_release(object); + } + else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) { + // get rid of a referenced Block held by this Block + // (ignore __block Block variables, compiler doesn't need to call us) + _Block_destroy(object); + } + else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) { + // get rid of a referenced object held by this Block + // (ignore __block object variables, compiler doesn't need to call us) + _Block_release_object(object); + } +} + + +/* + * Debugging support: + */ +#if 0 +#pragma mark Debugging +#endif /* if 0 */ + + +const char *_Block_dump(const void *block) { + struct Block_layout *closure = (struct Block_layout *)block; + static char buffer[512]; + char *cp = buffer; + if (closure == NULL) { + sprintf(cp, "NULL passed to _Block_dump\n"); + return buffer; + } + if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) { + printf("Block compiled by obsolete compiler, please recompile source for this Block\n"); + exit(1); + } + cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure); + if (closure->isa == NULL) { + cp += sprintf(cp, "isa: NULL\n"); + } + else if (closure->isa == _NSConcreteStackBlock) { + cp += sprintf(cp, "isa: stack Block\n"); + } + else if (closure->isa == _NSConcreteMallocBlock) { + cp += sprintf(cp, "isa: malloc heap Block\n"); + } + else if (closure->isa == _NSConcreteAutoBlock) { + cp += sprintf(cp, "isa: GC heap Block\n"); + } + else if (closure->isa == _NSConcreteGlobalBlock) { + cp += sprintf(cp, "isa: global Block\n"); + } + else if (closure->isa == _NSConcreteFinalizingBlock) { + cp += sprintf(cp, "isa: finalizing Block\n"); + } + else { + cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa); + } + cp += sprintf(cp, "flags:"); + if (closure->flags & BLOCK_HAS_DESCRIPTOR) { + cp += sprintf(cp, " HASDESCRIPTOR"); + } + if (closure->flags & BLOCK_NEEDS_FREE) { + cp += sprintf(cp, " FREEME"); + } + if (closure->flags & BLOCK_IS_GC) { + cp += sprintf(cp, " ISGC"); + } + if (closure->flags & BLOCK_HAS_COPY_DISPOSE) { + cp += sprintf(cp, " HASHELP"); + } + if (closure->flags & BLOCK_HAS_CTOR) { + cp += sprintf(cp, " HASCTOR"); + } + cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK); + cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke); + { + struct Block_descriptor *dp = closure->descriptor; + cp += sprintf(cp, "descriptor: %p\n", (void *)dp); + cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved); + cp += sprintf(cp, "descriptor->size: %lu\n", dp->size); + + if (closure->flags & BLOCK_HAS_COPY_DISPOSE) { + cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy); + cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose); + } + } + return buffer; +} + + +const char *_Block_byref_dump(struct Block_byref *src) { + static char buffer[256]; + char *cp = buffer; + cp += sprintf(cp, "byref data block %p contents:\n", (void *)src); + cp += sprintf(cp, " forwarding: %p\n", (void *)src->forwarding); + cp += sprintf(cp, " flags: 0x%x\n", src->flags); + cp += sprintf(cp, " size: %d\n", src->size); + if (src->flags & BLOCK_HAS_COPY_DISPOSE) { + cp += sprintf(cp, " copy helper: %p\n", (void *)(uintptr_t)src->byref_keep); + cp += sprintf(cp, " dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy); + } + return buffer; +} + diff --git a/BlocksRuntime/tests/block-static.c b/BlocksRuntime/tests/block-static.c new file mode 100644 index 000000000000..d38c816cf015 --- /dev/null +++ b/BlocksRuntime/tests/block-static.c @@ -0,0 +1,25 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// testfilerunner CONFIG + +#include + + +int main(int argc, char **argv) { + static int numberOfSquesals = 5; + + ^{ numberOfSquesals = 6; }(); + + if (numberOfSquesals == 6) { + printf("%s: success\n", argv[0]); + return 0; + } + printf("**** did not update static local, rdar://6177162\n"); + return 1; + +} + diff --git a/BlocksRuntime/tests/blockimport.c b/BlocksRuntime/tests/blockimport.c new file mode 100644 index 000000000000..178fce4395e5 --- /dev/null +++ b/BlocksRuntime/tests/blockimport.c @@ -0,0 +1,51 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * blockimport.c + * testObjects + * + * Created by Blaine Garst on 10/13/08. + * + */ + + +// +// pure C nothing more needed +// CONFIG rdar://6289344 + +#include +#include +#include + + + + +int main(int argc, char *argv[]) { + int i = 1; + int (^intblock)(void) = ^{ return i*10; }; + + void (^vv)(void) = ^{ + if (argc > 0) { + printf("intblock returns %d\n", intblock()); + } + }; + +#if 0 + //printf("Block dump %s\n", _Block_dump(vv)); + { + struct Block_layout *layout = (struct Block_layout *)(void *)vv; + printf("isa %p\n", layout->isa); + printf("flags %x\n", layout->flags); + printf("descriptor %p\n", layout->descriptor); + printf("descriptor->size %d\n", layout->descriptor->size); + } +#endif + void (^vvcopy)(void) = Block_copy(vv); + Block_release(vvcopy); + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/byrefaccess.c b/BlocksRuntime/tests/byrefaccess.c new file mode 100644 index 000000000000..4565553338ac --- /dev/null +++ b/BlocksRuntime/tests/byrefaccess.c @@ -0,0 +1,34 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// byrefaccess.m +// test that byref access to locals is accurate +// testObjects +// +// Created by Blaine Garst on 5/13/08. +// +// CONFIG + +#include + + +void callVoidVoid(void (^closure)(void)) { + closure(); +} + +int main(int argc, char *argv[]) { + __block int i = 10; + + callVoidVoid(^{ ++i; }); + + if (i != 11) { + printf("*** %s didn't update i\n", argv[0]); + return 1; + } + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/byrefcopy.c b/BlocksRuntime/tests/byrefcopy.c new file mode 100644 index 000000000000..513b63c2725d --- /dev/null +++ b/BlocksRuntime/tests/byrefcopy.c @@ -0,0 +1,41 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// byrefcopy.m +// testObjects +// +// Created by Blaine Garst on 5/13/08. +// + +#include +#include +#include + +// CONFIG + +void callVoidVoid(void (^closure)(void)) { + closure(); +} + +int main(int argc, char *argv[]) { + int __block i = 10; + + void (^block)(void) = ^{ ++i; }; + //printf("original (old style) is %s\n", _Block_dump_old(block)); + //printf("original (new style) is %s\n", _Block_dump(block)); + void (^blockcopy)(void) = Block_copy(block); + //printf("copy is %s\n", _Block_dump(blockcopy)); + // use a copy & see that it updates i + callVoidVoid(block); + + if (i != 11) { + printf("*** %s didn't update i\n", argv[0]); + return 1; + } + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/byrefcopycopy.c b/BlocksRuntime/tests/byrefcopycopy.c new file mode 100644 index 000000000000..d6fafc152e1d --- /dev/null +++ b/BlocksRuntime/tests/byrefcopycopy.c @@ -0,0 +1,46 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG rdar://6255170 + +#include +#include +#include +#include +#include +#include + + +int +main(int argc, char *argv[]) +{ + __block int var = 0; + int shouldbe = 0; + void (^b)(void) = ^{ var++; /*printf("var is at %p with value %d\n", &var, var);*/ }; + __typeof(b) _b; + //printf("before copy...\n"); + b(); ++shouldbe; + size_t i; + + for (i = 0; i < 10; i++) { + _b = Block_copy(b); // make a new copy each time + assert(_b); + ++shouldbe; + _b(); // should still update the stack + Block_release(_b); + } + + //printf("after...\n"); + b(); ++shouldbe; + + if (var != shouldbe) { + printf("Hmm, var is %d but should be %d\n", var, shouldbe); + return 1; + } + printf("%s: Success!!\n", argv[0]); + + return 0; +} diff --git a/BlocksRuntime/tests/byrefcopyinner.c b/BlocksRuntime/tests/byrefcopyinner.c new file mode 100644 index 000000000000..07770933afe3 --- /dev/null +++ b/BlocksRuntime/tests/byrefcopyinner.c @@ -0,0 +1,32 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include +#include + +// CONFIG rdar://6225809 +// fixed in 5623 + +int main(int argc, char *argv[]) { + __block int a = 42; + int* ap = &a; // just to keep the address on the stack. + + void (^b)(void) = ^{ + //a; // workaround, a should be implicitly imported + Block_copy(^{ + a = 2; + }); + }; + + Block_copy(b); + + if(&a == ap) { + printf("**** __block heap storage should have been created at this point\n"); + return 1; + } + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/byrefcopyint.c b/BlocksRuntime/tests/byrefcopyint.c new file mode 100644 index 000000000000..d632f88a0bc5 --- /dev/null +++ b/BlocksRuntime/tests/byrefcopyint.c @@ -0,0 +1,69 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * byrefcopyint.c + * testObjects + * + * Created by Blaine Garst on 12/1/08. + * + */ + +// +// byrefcopyid.m +// testObjects +// +// Created by Blaine Garst on 5/13/08. +// + +// Tests copying of blocks with byref ints +// CONFIG rdar://6414583 -C99 + +#include +#include +#include +#include + + + + +typedef void (^voidVoid)(void); + +voidVoid dummy; + +void callVoidVoid(voidVoid closure) { + closure(); +} + + +voidVoid testRoutine(const char *whoami) { + __block int dumbo = strlen(whoami); + dummy = ^{ + //printf("incring dumbo from %d\n", dumbo); + ++dumbo; + }; + + + voidVoid copy = Block_copy(dummy); + + + return copy; +} + +int main(int argc, char *argv[]) { + voidVoid array[100]; + for (int i = 0; i < 100; ++i) { + array[i] = testRoutine(argv[0]); + array[i](); + } + for (int i = 0; i < 100; ++i) { + Block_release(array[i]); + } + + + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/byrefcopystack.c b/BlocksRuntime/tests/byrefcopystack.c new file mode 100644 index 000000000000..d119afa3668f --- /dev/null +++ b/BlocksRuntime/tests/byrefcopystack.c @@ -0,0 +1,41 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// byrefcopystack.m +// testObjects +// +// Created by Blaine Garst on 5/13/08. +// + + + +#include +#include + +// CONFIG rdar://6255170 + +void (^bumpi)(void); +int (^geti)(void); + +void setClosures() { + int __block i = 10; + bumpi = Block_copy(^{ ++i; }); + geti = Block_copy(^{ return i; }); +} + +int main(int argc, char *argv[]) { + setClosures(); + bumpi(); + int i = geti(); + + if (i != 11) { + printf("*** %s didn't update i\n", argv[0]); + return 1; + } + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/byrefsanity.c b/BlocksRuntime/tests/byrefsanity.c new file mode 100644 index 000000000000..dfa16b0ddd6a --- /dev/null +++ b/BlocksRuntime/tests/byrefsanity.c @@ -0,0 +1,73 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG + + +#include +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + __block int var = 0; + void (^b)(void) = ^{ var++; }; + + //sanity(b); + b(); + printf("%s: success!\n", argv[0]); + return 0; +} + + +#if 1 +/* replicated internal data structures: BEWARE, MAY CHANGE!!! */ + +enum { + BLOCK_REFCOUNT_MASK = (0xffff), + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_NO_COPY = (1 << 26), // interim byref: no copies allowed + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), +}; + +struct byref_id { + struct byref_id *forwarding; + int flags;//refcount; + int size; + void (*byref_keep)(struct byref_id *dst, struct byref_id *src); + void (*byref_destroy)(struct byref_id *); + int var; +}; +struct Block_basic2 { + void *isa; + int Block_flags; // int32_t + int Block_size; // XXX should be packed into Block_flags + void (*Block_invoke)(void *); + void (*Block_copy)(void *dst, void *src); + void (*Block_dispose)(void *); + struct byref_id *ref; +}; + +void sanity(void *arg) { + struct Block_basic2 *bb = (struct Block_basic2 *)arg; + if ( ! (bb->Block_flags & BLOCK_HAS_COPY_DISPOSE)) { + printf("missing copy/dispose helpers for byref data\n"); + exit(1); + } + struct byref_id *ref = bb->ref; + if (ref->forwarding != ref) { + printf("forwarding pointer should be %p but is %p\n", ref, ref->forwarding); + exit(1); + } +} +#endif + + + diff --git a/BlocksRuntime/tests/byrefstruct.c b/BlocksRuntime/tests/byrefstruct.c new file mode 100644 index 000000000000..a3dc44e2c36e --- /dev/null +++ b/BlocksRuntime/tests/byrefstruct.c @@ -0,0 +1,57 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*- +// CONFIG + +#import +#import +#import + +typedef struct { + unsigned long ps[30]; + int qs[30]; +} BobTheStruct; + +int main (int argc, const char * argv[]) { + __block BobTheStruct fiddly; + BobTheStruct copy; + + void (^incrementFiddly)() = ^{ + int i; + for(i=0; i<30; i++) { + fiddly.ps[i]++; + fiddly.qs[i]++; + } + }; + + memset(&fiddly, 0xA5, sizeof(fiddly)); + memset(©, 0x2A, sizeof(copy)); + + int i; + for(i=0; i<30; i++) { + fiddly.ps[i] = i * i * i; + fiddly.qs[i] = -i * i * i; + } + + copy = fiddly; + incrementFiddly(); + + if ( © == &fiddly ) { + printf("%s: struct wasn't copied.", argv[0]); + exit(1); + } + for(i=0; i<30; i++) { + //printf("[%d]: fiddly.ps: %lu, copy.ps: %lu, fiddly.qs: %d, copy.qs: %d\n", i, fiddly.ps[i], copy.ps[i], fiddly.qs[i], copy.qs[i]); + if ( (fiddly.ps[i] != copy.ps[i] + 1) || (fiddly.qs[i] != copy.qs[i] + 1) ) { + printf("%s: struct contents were not incremented.", argv[0]); + exit(1); + } + } + + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/c99.c b/BlocksRuntime/tests/c99.c new file mode 100644 index 000000000000..8f31ab3fdfb8 --- /dev/null +++ b/BlocksRuntime/tests/c99.c @@ -0,0 +1,20 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// c99.m +// +// CONFIG C99 rdar://problem/6399225 + +#import +#import + +int main(int argc, char *argv[]) { + void (^blockA)(void) = ^ { ; }; + blockA(); + printf("%s: success\n", argv[0]); + exit(0); +} diff --git a/BlocksRuntime/tests/cast.c b/BlocksRuntime/tests/cast.c new file mode 100644 index 000000000000..5bef2c19def5 --- /dev/null +++ b/BlocksRuntime/tests/cast.c @@ -0,0 +1,37 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * cast.c + * testObjects + * + * Created by Blaine Garst on 2/17/09. + * + */ + +// PURPOSE should allow casting of a Block reference to an arbitrary pointer and back +// CONFIG open + +#include + + + +int main(int argc, char *argv[]) { + + void (^aBlock)(void); + int *ip; + char *cp; + double *dp; + + ip = (int *)aBlock; + cp = (char *)aBlock; + dp = (double *)aBlock; + aBlock = (void (^)(void))ip; + aBlock = (void (^)(void))cp; + aBlock = (void (^)(void))dp; + printf("%s: success", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/constassign.c b/BlocksRuntime/tests/constassign.c new file mode 100644 index 000000000000..537cb2df0597 --- /dev/null +++ b/BlocksRuntime/tests/constassign.c @@ -0,0 +1,28 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// constassign.c +// bocktest +// +// Created by Blaine Garst on 3/21/08. +// +// shouldn't be able to assign to a const pointer +// CONFIG error: assignment of read-only + +#import + +void foo(void) { printf("I'm in foo\n"); } +void bar(void) { printf("I'm in bar\n"); } + +int main(int argc, char *argv[]) { + void (*const fptr)(void) = foo; + void (^const blockA)(void) = ^ { printf("hello\n"); }; + blockA = ^ { printf("world\n"); } ; + fptr = bar; + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/copy-block-literal-rdar6439600.c b/BlocksRuntime/tests/copy-block-literal-rdar6439600.c new file mode 100644 index 000000000000..6fa488eee4ff --- /dev/null +++ b/BlocksRuntime/tests/copy-block-literal-rdar6439600.c @@ -0,0 +1,29 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG open rdar://6439600 + +#import +#import + +#define NUMBER_OF_BLOCKS 100 +int main (int argc, const char * argv[]) { + int (^x[NUMBER_OF_BLOCKS])(); + int i; + + for(i=0; i +#include + +// CONFIG C++ rdar://6243400,rdar://6289367 + + +int constructors = 0; +int destructors = 0; + + +#define CONST const + +class TestObject +{ +public: + TestObject(CONST TestObject& inObj); + TestObject(); + ~TestObject(); + + TestObject& operator=(CONST TestObject& inObj); + + int version() CONST { return _version; } +private: + mutable int _version; +}; + +TestObject::TestObject(CONST TestObject& inObj) + +{ + ++constructors; + _version = inObj._version; + //printf("%p (%d) -- TestObject(const TestObject&) called\n", this, _version); +} + + +TestObject::TestObject() +{ + _version = ++constructors; + //printf("%p (%d) -- TestObject() called\n", this, _version); +} + + +TestObject::~TestObject() +{ + //printf("%p -- ~TestObject() called\n", this); + ++destructors; +} + + +TestObject& TestObject::operator=(CONST TestObject& inObj) +{ + //printf("%p -- operator= called\n", this); + _version = inObj._version; + return *this; +} + + + +void testRoutine() { + TestObject one; + + void (^b)(void) = ^{ printf("my const copy of one is %d\n", one.version()); }; +} + + + +int main(int argc, char *argv[]) { + testRoutine(); + if (constructors == 0) { + printf("No copy constructors!!!\n"); + return 1; + } + if (constructors != destructors) { + printf("%d constructors but only %d destructors\n", constructors, destructors); + return 1; + } + printf("%s:success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/copynull.c b/BlocksRuntime/tests/copynull.c new file mode 100644 index 000000000000..c49e499f3ab6 --- /dev/null +++ b/BlocksRuntime/tests/copynull.c @@ -0,0 +1,37 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * copynull.c + * testObjects + * + * Created by Blaine Garst on 10/15/08. + * + */ + +#import +#import +#import + +// CONFIG rdar://6295848 + +int main(int argc, char *argv[]) { + + void (^block)(void) = (void (^)(void))0; + void (^blockcopy)(void) = Block_copy(block); + + if (blockcopy != (void (^)(void))0) { + printf("whoops, somehow we copied NULL!\n"); + return 1; + } + // make sure we can also + Block_release(blockcopy); + // and more secretly + //_Block_destroy(blockcopy); + + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/dispatch_async.c b/BlocksRuntime/tests/dispatch_async.c new file mode 100644 index 000000000000..e3e517c54650 --- /dev/null +++ b/BlocksRuntime/tests/dispatch_async.c @@ -0,0 +1,57 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include + +#include +#include +//#import +#include + +// CONFIG rdar://problem/6371811 + +const char *whoami = "nobody"; + +void EnqueueStuff(dispatch_queue_t q) +{ + __block CFIndex counter; + + // above call has a side effect: it works around: + // __block variables not implicitly imported into intermediate scopes + dispatch_async(q, ^{ + counter = 0; + }); + + + dispatch_async(q, ^{ + //printf("outer block.\n"); + counter++; + dispatch_async(q, ^{ + //printf("inner block.\n"); + counter--; + if(counter == 0) { + printf("%s: success\n", whoami); + exit(0); + } + }); + if(counter == 0) { + printf("already done? inconceivable!\n"); + exit(1); + } + }); +} + +int main (int argc, const char * argv[]) { + dispatch_queue_t q = dispatch_queue_create("queue", NULL); + + whoami = argv[0]; + + EnqueueStuff(q); + + dispatch_main(); + printf("shouldn't get here\n"); + return 1; +} diff --git a/BlocksRuntime/tests/dispatch_call_Block_with_release.c b/BlocksRuntime/tests/dispatch_call_Block_with_release.c new file mode 100644 index 000000000000..9e06f69ba762 --- /dev/null +++ b/BlocksRuntime/tests/dispatch_call_Block_with_release.c @@ -0,0 +1,31 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include +#include + +// CONFIG + +void callsomething(const char *format, int argument) { +} + +void +dispatch_call_Block_with_release2(void *block) +{ + void (^b)(void) = (void (^)(void))block; + b(); + Block_release(b); +} + +int main(int argc, char *argv[]) { + void (^b1)(void) = ^{ callsomething("argc is %d\n", argc); }; + void (^b2)(void) = ^{ callsomething("hellow world\n", 0); }; // global block now + + dispatch_call_Block_with_release2(Block_copy(b1)); + dispatch_call_Block_with_release2(Block_copy(b2)); + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/fail.c b/BlocksRuntime/tests/fail.c new file mode 100644 index 000000000000..28dbc2d1521f --- /dev/null +++ b/BlocksRuntime/tests/fail.c @@ -0,0 +1,107 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * fail.c + * testObjects + * + * Created by Blaine Garst on 9/16/08. + * + */ +#include +#include +#include +#include +#include +#include + + +bool readfile(char *buffer, const char *from) { + int fd = open(from, 0); + if (fd < 0) return false; + int count = read(fd, buffer, 512); + if (count < 0) return false; + buffer[count] = 0; // zap newline + return true; +} + +// basic idea, take compiler args, run compiler, and verify that expected failure matches any existing one + +int main(int argc, char *argv[]) { + if (argc == 1) return 0; + char *copy[argc+1]; // make a copy + // find and strip off -e "errorfile" + char *errorfile = NULL; + int counter = 0, i = 0; + for (i = 1; i < argc; ++i) { // skip 0 arg which is "fail" + if (!strncmp(argv[i], "-e", 2)) { + errorfile = argv[++i]; + } + else { + copy[counter++] = argv[i]; + } + } + copy[counter] = NULL; + pid_t child = fork(); + char buffer[512]; + if (child == 0) { + // in child + sprintf(buffer, "/tmp/errorfile_%d", getpid()); + close(1); + int fd = creat(buffer, 0777); + if (fd != 1) { + fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd); + exit(1); + } + close(2); + dup(1); + int result = execv(copy[0], copy); + exit(10); + } + if (child < 0) { + printf("fork failed\n"); + exit(1); + } + int status = 0; + pid_t deadchild = wait(&status); + if (deadchild != child) { + printf("wait got %d instead of %d\n", deadchild, child); + exit(1); + } + if (WEXITSTATUS(status) == 0) { + printf("compiler exited normally, not good under these circumstances\n"); + exit(1); + } + //printf("exit status of child %d was %d\n", child, WEXITSTATUS(status)); + sprintf(buffer, "/tmp/errorfile_%d", child); + if (errorfile) { + //printf("ignoring error file: %s\n", errorfile); + char desired[512]; + char got[512]; + bool gotErrorFile = readfile(desired, errorfile); + bool gotOutput = readfile(got, buffer); + if (!gotErrorFile && gotOutput) { + printf("didn't read errorfile %s, it should have something from\n*****\n%s\n*****\nin it.\n", + errorfile, got); + exit(1); + } + else if (gotErrorFile && gotOutput) { + char *where = strstr(got, desired); + if (!where) { + printf("didn't find contents of %s in %s\n", errorfile, buffer); + exit(1); + } + } + else { + printf("errorfile %s and output %s inconsistent\n", errorfile, buffer); + exit(1); + } + } + unlink(buffer); + printf("success\n"); + exit(0); +} + diff --git a/BlocksRuntime/tests/flagsisa.c b/BlocksRuntime/tests/flagsisa.c new file mode 100644 index 000000000000..5d4b2dcb4030 --- /dev/null +++ b/BlocksRuntime/tests/flagsisa.c @@ -0,0 +1,21 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include + +/* CONFIG rdar://6310599 + */ + +int main(int argc, char *argv[]) +{ + __block int flags; + __block void *isa; + + ^{ flags=1; isa = (void *)isa; }; + printf("%s: success\n", argv[0]); + return 0; +} + diff --git a/BlocksRuntime/tests/globalexpression.c b/BlocksRuntime/tests/globalexpression.c new file mode 100644 index 000000000000..eeedd75e7078 --- /dev/null +++ b/BlocksRuntime/tests/globalexpression.c @@ -0,0 +1,42 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// testfilerunner CONFIG + +#import +#import + +int global; + +void (^gblock)(int) = ^(int x){ global = x; }; + +int main(int argc, char *argv[]) { + gblock(1); + if (global != 1) { + printf("%s: *** did not set global to 1\n", argv[0]); + return 1; + } + void (^gblockcopy)(int) = Block_copy(gblock); + if (gblockcopy != gblock) { + printf("global copy %p not a no-op %p\n", (void *)gblockcopy, (void *)gblock); + return 1; + } + Block_release(gblockcopy); + gblock(3); + if (global != 3) { + printf("%s: *** did not set global to 3\n", argv[0]); + return 1; + } + gblockcopy = Block_copy(gblock); + gblockcopy(5); + if (global != 5) { + printf("%s: *** did not set global to 5\n", argv[0]); + return 1; + } + printf("%s: Success!\n", argv[0]); + return 0; +} + diff --git a/BlocksRuntime/tests/goto.c b/BlocksRuntime/tests/goto.c new file mode 100644 index 000000000000..7e5b08adbe8e --- /dev/null +++ b/BlocksRuntime/tests/goto.c @@ -0,0 +1,34 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * goto.c + * testObjects + * + * Created by Blaine Garst on 10/17/08. + * + */ + +// CONFIG rdar://6289031 + +#include + +int main(int argc, char *argv[]) +{ + __block int val = 0; + + ^{ val = 1; }(); + + if (val == 0) { + goto out_bad; // error: local byref variable val is in the scope of this goto + } + + printf("%s: Success!\n", argv[0]); + return 0; +out_bad: + printf("%s: val not updated!\n", argv[0]); + return 1; +} diff --git a/BlocksRuntime/tests/hasdescriptor.c b/BlocksRuntime/tests/hasdescriptor.c new file mode 100644 index 000000000000..429adb9bdb14 --- /dev/null +++ b/BlocksRuntime/tests/hasdescriptor.c @@ -0,0 +1,29 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + + + +// CONFIG C + +#include +#include + + +int main(int argc, char *argv[]) { + void (^inner)(void) = ^ { printf("argc was %d\n", argc); }; + void (^outer)(void) = ^{ + inner(); + inner(); + }; + //printf("size of inner is %ld\n", Block_size(inner)); + //printf("size of outer is %ld\n", Block_size(outer)); + if (Block_size(inner) != Block_size(outer)) { + printf("not the same size, using old compiler??\n"); + return 1; + } + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/josh.C b/BlocksRuntime/tests/josh.C new file mode 100644 index 000000000000..dbc7369e8c39 --- /dev/null +++ b/BlocksRuntime/tests/josh.C @@ -0,0 +1,32 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG C++ GC RR open rdar://6347910 + + + +struct MyStruct { + int something; +}; + +struct TestObject { + + void test(void){ + { + MyStruct first; // works + } + void (^b)(void) = ^{ + MyStruct inner; // fails to compile! + }; + } +}; + + + +int main(int argc, char *argv[]) { + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/k-and-r.c b/BlocksRuntime/tests/k-and-r.c new file mode 100644 index 000000000000..16b9cc643b50 --- /dev/null +++ b/BlocksRuntime/tests/k-and-r.c @@ -0,0 +1,33 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*- +// CONFIG error: incompatible block pointer types assigning + +#import +#import + +int main(int argc, char *argv[]) { +#ifndef __cplusplus + char (^rot13)(); + rot13 = ^(char c) { return (char)(((c - 'a' + 13) % 26) + 'a'); }; + char n = rot13('a'); + char c = rot13('p'); + if ( n != 'n' || c != 'c' ) { + printf("%s: rot13('a') returned %c, rot13('p') returns %c\n", argv[0], n, c); + exit(1); + } +#else +// yield characteristic error message for C++ +#error incompatible block pointer types assigning +#endif +#ifndef __clang__ +// yield characteristic error message for C++ +#error incompatible block pointer types assigning +#endif + printf("%s: success\n", argv[0]); + exit(0); +} diff --git a/BlocksRuntime/tests/large-struct.c b/BlocksRuntime/tests/large-struct.c new file mode 100644 index 000000000000..1867bd02dfab --- /dev/null +++ b/BlocksRuntime/tests/large-struct.c @@ -0,0 +1,51 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*- +// CONFIG + +#import +#import +#import + +typedef struct { + unsigned long ps[30]; + int qs[30]; +} BobTheStruct; + +int main (int argc, const char * argv[]) { + BobTheStruct inny; + BobTheStruct outty; + BobTheStruct (^copyStruct)(BobTheStruct); + int i; + + memset(&inny, 0xA5, sizeof(inny)); + memset(&outty, 0x2A, sizeof(outty)); + + for(i=0; i<30; i++) { + inny.ps[i] = i * i * i; + inny.qs[i] = -i * i * i; + } + + copyStruct = ^(BobTheStruct aBigStruct){ return aBigStruct; }; // pass-by-value intrinsically copies the argument + + outty = copyStruct(inny); + + if ( &inny == &outty ) { + printf("%s: struct wasn't copied.", argv[0]); + exit(1); + } + for(i=0; i<30; i++) { + if ( (inny.ps[i] != outty.ps[i]) || (inny.qs[i] != outty.qs[i]) ) { + printf("%s: struct contents did not match.", argv[0]); + exit(1); + } + } + + printf("%s: success\n", argv[0]); + + return 0; +} diff --git a/BlocksRuntime/tests/localisglobal.c b/BlocksRuntime/tests/localisglobal.c new file mode 100644 index 000000000000..75a79dff48ee --- /dev/null +++ b/BlocksRuntime/tests/localisglobal.c @@ -0,0 +1,42 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * localisglobal.c + * testObjects + * + * Created by Blaine Garst on 9/29/08. + * + * works in all configurations + * CONFIG rdar://6230297 + */ + +#include + +void (^global)(void) = ^{ printf("hello world\n"); }; + +int aresame(void *first, void *second) { + long *f = (long *)first; + long *s = (long *)second; + return *f == *s; +} +int main(int argc, char *argv[]) { + int i = 10; + void (^local)(void) = ^ { printf("hi %d\n", i); }; + void (^localisglobal)(void) = ^ { printf("hi\n"); }; + + if (aresame(local, localisglobal)) { + printf("local block could be global, but isn't\n"); + return 1; + } + if (!aresame(global, localisglobal)) { + printf("local block is not global, not stack, what is it??\n"); + return 1; + } + printf("%s: success\n", argv[0]); + return 0; + +} diff --git a/BlocksRuntime/tests/macro.c b/BlocksRuntime/tests/macro.c new file mode 100644 index 000000000000..988c0689b8f8 --- /dev/null +++ b/BlocksRuntime/tests/macro.c @@ -0,0 +1,14 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG open rdar://6718399 +#include + +void foo() { + void (^bbb)(void) = Block_copy(^ { + int j, cnt; + }); +} diff --git a/BlocksRuntime/tests/makefile b/BlocksRuntime/tests/makefile new file mode 100644 index 000000000000..2734bcae35f5 --- /dev/null +++ b/BlocksRuntime/tests/makefile @@ -0,0 +1,70 @@ +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +CCDIR=/usr/bin +#CCDIR=/Volumes/Keep/gcc/usr/bin + +all: std + +clean: + rm -fr *.dSYM *.o *-bin testfilerunner + +TFR = ~public/bin/testfilerunner + +testfilerunner: testfilerunner.h testfilerunner.m + gcc -fobjc-gc-only -g -arch x86_64 -arch i386 -std=gnu99 testfilerunner.m -o testfilerunner -framework Foundation + +tests: + grep CONFIG *.[cmCM] | $(TFR) $(CCDIR) -- + +open: + grep CONFIG *.[cmCM] | $(TFR) $(CCDIR) -open -- + +fast: + grep CONFIG *.[cmCM] | $(TFR) -fast $(CCDIR) -- + +std: + grep CONFIG *.[cmCM] | $(TFR) -- + +clang: + grep CONFIG *.[cmCM] | $(TFR) -clang -fast -- + +fastd: + grep CONFIG *.[cmCM] | $(TFR) -fast -- + + +# Hack Alert: arguably most of the following belongs in libclosure's Makefile; sticking it here until I get around to grokking what goes on in that file. +sudid: + @echo Enabling sudo: # Hack Alert: enable sudo first thing so we don't hang at the password prompt later + @sudo echo Thanks + + +RootsDirectory ?= /tmp/ +# Note: the libsystem project (built by the libsystemroot target below) uses the ALTUSRLOCALLIBSYSTEM variable, so we use it here to maintain parity +ALTUSRLOCALLIBSYSTEM ?= $(RootsDirectory)/alt-usr-local-lib-system/ +altusrlocallibsystem: + ditto /usr/local/lib/system $(ALTUSRLOCALLIBSYSTEM) # FIXME: conditionalize this copy + + +# ER: option to not require extra privileges (-nosudo or somesuch) +Buildit ?= ~rc/bin/buildit -rootsDirectory $(RootsDirectory) -arch i386 -arch ppc -arch x86_64 +blocksroot: sudid clean altusrlocallibsystem + sudo $(Buildit) .. + ditto $(RootsDirectory)/libclosure.roots/libclosure~dst/usr/local/lib/system $(ALTUSRLOCALLIBSYSTEM) + + +LibsystemVersion ?= 121 +LibsystemPath ?= ~rc/Software/SnowLeopard/Projects/Libsystem/Libsystem-$(LibsystemVersion) +LibsystemTmpPath ?= $(RootsDirectory)/Libsystem-$(LibsystemVersion) +libsystemroot: blocksroot + ditto $(LibsystemPath) $(LibsystemTmpPath) # FIXME: conditionalize this copy + sudo ALTUSRLOCALLIBSYSTEM=$(ALTUSRLOCALLIBSYSTEM) $(Buildit) $(LibsystemTmpPath) + + +# Defaults to product of the libsystemroot target but does not automatically rebuild that, make both targets if you want a fresh root +LibsystemRootPath ?= $(RootsDirectory)/Libsystem-$(LibsystemVersion).roots/Libsystem-$(LibsystemVersion)~dst/usr/lib/ +roottests: + grep CONFIG *.[cmCM] | $(TFR) -dyld $(LibsystemRootPath) -- # FIXME: figure out if I can "call" the std target instead of duplicating it + diff --git a/BlocksRuntime/tests/modglobal.c b/BlocksRuntime/tests/modglobal.c new file mode 100644 index 000000000000..562d5a5cc418 --- /dev/null +++ b/BlocksRuntime/tests/modglobal.c @@ -0,0 +1,18 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +#include + +// CONFIG + +int AGlobal; + +int main(int argc, char *argv[]) { + void (^f)(void) = ^ { AGlobal++; }; + + printf("%s: success\n", argv[0]); + return 0; + +} diff --git a/BlocksRuntime/tests/nestedimport.c b/BlocksRuntime/tests/nestedimport.c new file mode 100644 index 000000000000..e8066922fbba --- /dev/null +++ b/BlocksRuntime/tests/nestedimport.c @@ -0,0 +1,44 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// nestedimport.m +// testObjects +// +// Created by Blaine Garst on 6/24/08. +// +// pure C nothing more needed +// CONFIG + + +#include +#include + + +int Global = 0; + +void callVoidVoid(void (^closure)(void)) { + closure(); +} + +int main(int argc, char *argv[]) { + int i = 1; + + void (^vv)(void) = ^{ + if (argc > 0) { + callVoidVoid(^{ Global = i; }); + } + }; + + i = 2; + vv(); + if (Global != 1) { + printf("%s: error, Global not set to captured value\n", argv[0]); + exit(1); + } + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/nullblockisa.c b/BlocksRuntime/tests/nullblockisa.c new file mode 100644 index 000000000000..ba0282e82084 --- /dev/null +++ b/BlocksRuntime/tests/nullblockisa.c @@ -0,0 +1,43 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// nullblockisa.m +// testObjects +// +// Created by Blaine Garst on 9/24/08. +// +// CONFIG rdar://6244520 + + + +#include +#include +#include + + +void check(void (^b)(void)) { + struct _custom { + struct Block_layout layout; + struct Block_byref *innerp; + } *custom = (struct _custom *)(void *)(b); + //printf("block is at %p, size is %lx, inner is %p\n", (void *)b, Block_size(b), innerp); + if (custom->innerp->isa != (void *)NULL) { + printf("not a NULL __block isa\n"); + exit(1); + } + return; +} + +int main(int argc, char *argv[]) { + + __block int i; + + check(^{ printf("%d\n", ++i); }); + printf("%s: success\n", argv[0]); + return 0; +} + diff --git a/BlocksRuntime/tests/objectRRGC.c b/BlocksRuntime/tests/objectRRGC.c new file mode 100644 index 000000000000..2cefea2afd3a --- /dev/null +++ b/BlocksRuntime/tests/objectRRGC.c @@ -0,0 +1,77 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * objectRRGC.c + * testObjects + * + * Created by Blaine Garst on 10/31/08. + * + * Test that the runtime honors the new callouts properly for retain/release and GC + * CON FIG C rdar://6175959 + */ + + + +#include +#include + + +int AssignCalled = 0; +int DisposeCalled = 0; + +// local copy instead of libSystem.B.dylib copy +void _Block_object_assign(void *destAddr, const void *object, const int isWeak) { + //printf("_Block_object_assign(%p, %p, %d) called\n", destAddr, object, isWeak); + AssignCalled = 1; +} + +void _Block_object_dispose(const void *object, const int isWeak) { + //printf("_Block_object_dispose(%p, %d) called\n", object, isWeak); + DisposeCalled = 1; +} + +struct MyStruct { + long isa; + long field; +}; + +typedef struct MyStruct *__attribute__((NSObject)) MyStruct_t; + +int main(int argc, char *argv[]) { + // create a block + struct MyStruct X; + MyStruct_t xp = (MyStruct_t)&X; + xp->field = 10; + void (^myBlock)(void) = ^{ printf("field is %ld\n", xp->field); }; + // should be a copy helper generated with a calls to above routines + // Lets find out! + struct Block_layout *bl = (struct Block_layout *)(void *)myBlock; + if ((bl->flags & BLOCK_HAS_DESCRIPTOR) != BLOCK_HAS_DESCRIPTOR) { + printf("using old runtime layout!\n"); + return 1; + } + if ((bl->flags & BLOCK_HAS_COPY_DISPOSE) != BLOCK_HAS_COPY_DISPOSE) { + printf("no copy dispose!!!!\n"); + return 1; + } + // call helper routines directly. These will, in turn, we hope, call the stubs above + long destBuffer[256]; + //printf("destbuffer is at %p, block at %p\n", destBuffer, (void *)bl); + //printf("dump is %s\n", _Block_dump(myBlock)); + bl->descriptor->copy(destBuffer, bl); + bl->descriptor->dispose(bl); + if (AssignCalled == 0) { + printf("did not call assign helper!\n"); + return 1; + } + if (DisposeCalled == 0) { + printf("did not call dispose helper\n"); + return 1; + } + printf("%s: Success!\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/objectassign.c b/BlocksRuntime/tests/objectassign.c new file mode 100644 index 000000000000..1c4f4841419e --- /dev/null +++ b/BlocksRuntime/tests/objectassign.c @@ -0,0 +1,76 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * objectassign.c + * testObjects + * + * Created by Blaine Garst on 10/28/08. + * + * This just tests that the compiler is issuing the proper helper routines + * CONFIG C rdar://6175959 + */ + + +#include +#include + + +int AssignCalled = 0; +int DisposeCalled = 0; + +// local copy instead of libSystem.B.dylib copy +void _Block_object_assign(void *destAddr, const void *object, const int isWeak) { + //printf("_Block_object_assign(%p, %p, %d) called\n", destAddr, object, isWeak); + AssignCalled = 1; +} + +void _Block_object_dispose(const void *object, const int isWeak) { + //printf("_Block_object_dispose(%p, %d) called\n", object, isWeak); + DisposeCalled = 1; +} + +struct MyStruct { + long isa; + long field; +}; + +typedef struct MyStruct *__attribute__((NSObject)) MyStruct_t; + +int main(int argc, char *argv[]) { + if (__APPLE_CC__ < 5627) { + printf("need compiler version %d, have %d\n", 5627, __APPLE_CC__); + return 0; + } + // create a block + struct MyStruct X; + MyStruct_t xp = (MyStruct_t)&X; + xp->field = 10; + void (^myBlock)(void) = ^{ printf("field is %ld\n", xp->field); }; + // should be a copy helper generated with a calls to above routines + // Lets find out! + struct Block_layout *bl = (struct Block_layout *)(void *)myBlock; + if ((bl->flags & BLOCK_HAS_COPY_DISPOSE) != BLOCK_HAS_COPY_DISPOSE) { + printf("no copy dispose!!!!\n"); + return 1; + } + // call helper routines directly. These will, in turn, we hope, call the stubs above + long destBuffer[256]; + //printf("destbuffer is at %p, block at %p\n", destBuffer, (void *)bl); + //printf("dump is %s\n", _Block_dump(myBlock)); + bl->descriptor->copy(destBuffer, bl); + bl->descriptor->dispose(bl); + if (AssignCalled == 0) { + printf("did not call assign helper!\n"); + return 1; + } + if (DisposeCalled == 0) { + printf("did not call dispose helper\n"); + return 1; + } + printf("%s: Success!\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/orbars.c b/BlocksRuntime/tests/orbars.c new file mode 100644 index 000000000000..18a9244452f1 --- /dev/null +++ b/BlocksRuntime/tests/orbars.c @@ -0,0 +1,23 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * orbars.c + * testObjects + * + * Created by Blaine Garst on 9/17/08. + * + * CONFIG rdar://6276695 error: before ‘|’ token + */ + +#include + +int main(int argc, char *argv[]) { + int i = 10; + void (^b)(void) = ^(void){ | i | printf("hello world, %d\n", ++i); }; + printf("%s: success :-(\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/rdar6396238.c b/BlocksRuntime/tests/rdar6396238.c new file mode 100644 index 000000000000..280415643a1a --- /dev/null +++ b/BlocksRuntime/tests/rdar6396238.c @@ -0,0 +1,32 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG rdar://6396238 + +#include +#include + +static int count = 0; + +void (^mkblock(void))(void) +{ + count++; + return ^{ + count++; + }; +} + +int main (int argc, const char * argv[]) { + mkblock()(); + if (count != 2) { + printf("%s: failure, 2 != %d\n", argv[0], count); + exit(1); + } else { + printf("%s: success\n", argv[0]); + exit(0); + } + return 0; +} diff --git a/BlocksRuntime/tests/rdar6405500.c b/BlocksRuntime/tests/rdar6405500.c new file mode 100644 index 000000000000..1ab4624bcfce --- /dev/null +++ b/BlocksRuntime/tests/rdar6405500.c @@ -0,0 +1,29 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG rdar://6405500 + +#include +#include +#import +#import + +int main (int argc, const char * argv[]) { + __block void (^blockFu)(size_t t); + blockFu = ^(size_t t){ + if (t == 20) { + printf("%s: success\n", argv[0]); + exit(0); + } else + dispatch_async(dispatch_get_main_queue(), ^{ blockFu(20); }); + }; + + dispatch_apply(10, dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT), blockFu); + + dispatch_main(); + printf("shouldn't get here\n"); + return 1; +} diff --git a/BlocksRuntime/tests/rdar6414583.c b/BlocksRuntime/tests/rdar6414583.c new file mode 100644 index 000000000000..2ada04d3ddcc --- /dev/null +++ b/BlocksRuntime/tests/rdar6414583.c @@ -0,0 +1,31 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG rdar://6414583 + +// a smaller case of byrefcopyint + +#include +#include +#include + +int main(int argc, char *argv[]) { + __block int c = 1; + + //printf("&c = %p - c = %i\n", &c, c); + + int i; + for(i =0; i < 2; i++) { + dispatch_block_t block = Block_copy(^{ c = i; }); + + block(); +// printf("%i: &c = %p - c = %i\n", i, &c, c); + + Block_release(block); + } + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/recursive-block.c b/BlocksRuntime/tests/recursive-block.c new file mode 100644 index 000000000000..454ad48267df --- /dev/null +++ b/BlocksRuntime/tests/recursive-block.c @@ -0,0 +1,55 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include +#include +#include +#include + +// CONFIG + + +int cumulation = 0; + +int doSomething(int i) { + cumulation += i; + return cumulation; +} + +void dirtyStack() { + int i = random(); + int j = doSomething(i); + int k = doSomething(j); + doSomething(i + j + k); +} + +typedef void (^voidVoid)(void); + +voidVoid testFunction() { + int i = random(); + __block voidVoid inner = ^{ doSomething(i); }; + //printf("inner, on stack, is %p\n", (void*)inner); + /*__block*/ voidVoid outer = ^{ + //printf("will call inner block %p\n", (void *)inner); + inner(); + }; + //printf("outer looks like: %s\n", _Block_dump(outer)); + voidVoid result = Block_copy(outer); + //Block_release(inner); + return result; +} + + +int main(int argc, char **argv) { + voidVoid block = testFunction(); + dirtyStack(); + block(); + Block_release(block); + + printf("%s: success\n", argv[0]); + + return 0; +} diff --git a/BlocksRuntime/tests/recursive-test.c b/BlocksRuntime/tests/recursive-test.c new file mode 100644 index 000000000000..f79914863121 --- /dev/null +++ b/BlocksRuntime/tests/recursive-test.c @@ -0,0 +1,74 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// CONFIG open rdar://6416474 +// was rdar://5847976 +// was rdar://6348320 + +#include +#include + +int verbose = 0; + +int main(int argc, char* argv[]) { + + if (argc > 1) verbose = 1; + + __block void (^recursive_local_block)(int); + + if (verbose) printf("recursive_local_block is a local recursive block\n"); + recursive_local_block = ^(int i) { + if (verbose) printf("%d\n", i); + if (i > 0) { + recursive_local_block(i - 1); + } + }; + + if (verbose) printf("recursive_local_block's address is %p, running it:\n", (void*)recursive_local_block); + recursive_local_block(5); + + if (verbose) printf("Creating other_local_block: a local block that calls recursive_local_block\n"); + + void (^other_local_block)(int) = ^(int i) { + if (verbose) printf("other_local_block running\n"); + recursive_local_block(i); + }; + + if (verbose) printf("other_local_block's address is %p, running it:\n", (void*)other_local_block); + + other_local_block(5); + +#if __APPLE_CC__ >= 5627 + if (verbose) printf("Creating other_copied_block: a Block_copy of a block that will call recursive_local_block\n"); + + void (^other_copied_block)(int) = Block_copy(^(int i) { + if (verbose) printf("other_copied_block running\n"); + recursive_local_block(i); + }); + + if (verbose) printf("other_copied_block's address is %p, running it:\n", (void*)other_copied_block); + + other_copied_block(5); +#endif + + __block void (^recursive_copy_block)(int); + + if (verbose) printf("Creating recursive_copy_block: a Block_copy of a block that will call recursive_copy_block recursively\n"); + + recursive_copy_block = Block_copy(^(int i) { + if (verbose) printf("%d\n", i); + if (i > 0) { + recursive_copy_block(i - 1); + } + }); + + if (verbose) printf("recursive_copy_block's address is %p, running it:\n", (void*)recursive_copy_block); + + recursive_copy_block(5); + + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/recursiveassign.c b/BlocksRuntime/tests/recursiveassign.c new file mode 100644 index 000000000000..f0070cbe5c93 --- /dev/null +++ b/BlocksRuntime/tests/recursiveassign.c @@ -0,0 +1,44 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * recursiveassign.c + * testObjects + * + * Created by Blaine Garst on 12/3/08. + * + */ + +// CONFIG rdar://6639533 + +// The compiler is prefetching x->forwarding before evaluting code that recomputes forwarding and so the value goes to a place that is never seen again. + +#include +#include +#include + + +int main(int argc, char* argv[]) { + + __block void (^recursive_copy_block)(int) = ^(int arg) { printf("got wrong Block\n"); exit(1); }; + + + recursive_copy_block = Block_copy(^(int i) { + if (i > 0) { + recursive_copy_block(i - 1); + } + else { + printf("done!\n"); + } + }); + + + recursive_copy_block(5); + + printf("%s: Success\n", argv[0]); + return 0; +} + diff --git a/BlocksRuntime/tests/reference.C b/BlocksRuntime/tests/reference.C new file mode 100644 index 000000000000..f86f11e86ce1 --- /dev/null +++ b/BlocksRuntime/tests/reference.C @@ -0,0 +1,95 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#import +#import +#import + +// CONFIG C++ + +int recovered = 0; + + + +int constructors = 0; +int destructors = 0; + +#define CONST const + +class TestObject +{ +public: + TestObject(CONST TestObject& inObj); + TestObject(); + ~TestObject(); + + TestObject& operator=(CONST TestObject& inObj); + + void test(void); + + int version() CONST { return _version; } +private: + mutable int _version; +}; + +TestObject::TestObject(CONST TestObject& inObj) + +{ + ++constructors; + _version = inObj._version; + //printf("%p (%d) -- TestObject(const TestObject&) called", this, _version); +} + + +TestObject::TestObject() +{ + _version = ++constructors; + //printf("%p (%d) -- TestObject() called\n", this, _version); +} + + +TestObject::~TestObject() +{ + //printf("%p -- ~TestObject() called\n", this); + ++destructors; +} + +#if 1 +TestObject& TestObject::operator=(CONST TestObject& inObj) +{ + //printf("%p -- operator= called", this); + _version = inObj._version; + return *this; +} +#endif + +void TestObject::test(void) { + void (^b)(void) = ^{ recovered = _version; }; + void (^b2)(void) = Block_copy(b); + b2(); + Block_release(b2); +} + + + +void testRoutine() { + TestObject one; + + + one.test(); +} + + + +int main(int argc, char *argv[]) { + testRoutine(); + if (recovered == 1) { + printf("%s: success\n", argv[0]); + exit(0); + } + printf("%s: *** didn't recover byref block variable\n", argv[0]); + exit(1); +} diff --git a/BlocksRuntime/tests/rettypepromotion.c b/BlocksRuntime/tests/rettypepromotion.c new file mode 100644 index 000000000000..597eafe8b858 --- /dev/null +++ b/BlocksRuntime/tests/rettypepromotion.c @@ -0,0 +1,36 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * rettypepromotion.c + * testObjects + * + * Created by Blaine Garst on 11/3/08. + * + */ + +// CONFIG error: +// C++ and C give different errors so we don't check for an exact match. +// The error is that enum's are defined to be ints, always, even if defined with explicit long values + + +#include +#include + +enum { LESS = -1, EQUAL, GREATER }; + +void sortWithBlock(long (^comp)(void *arg1, void *arg2)) { +} + +int main(int argc, char *argv[]) { + sortWithBlock(^(void *arg1, void *arg2) { + if (random()) return LESS; + if (random()) return EQUAL; + if (random()) return GREATER; + }); + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/returnfunctionptr.c b/BlocksRuntime/tests/returnfunctionptr.c new file mode 100644 index 000000000000..6c7df631f8db --- /dev/null +++ b/BlocksRuntime/tests/returnfunctionptr.c @@ -0,0 +1,23 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + + +// CONFIG rdar://6339747 but wasn't + +#include + +int (*funcptr)(long); + +int (*(^b)(char))(long); + +int main(int argc, char *argv[]) { + // implicit is fine + b = ^(char x) { return funcptr; }; + // explicit never parses + b = ^int (*(char x))(long) { return funcptr; }; + printf("%s: Success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/shorthandexpression.c b/BlocksRuntime/tests/shorthandexpression.c new file mode 100644 index 000000000000..bf4582072b48 --- /dev/null +++ b/BlocksRuntime/tests/shorthandexpression.c @@ -0,0 +1,24 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * shorthandexpression.c + * testObjects + * + * Created by Blaine Garst on 9/16/08. + * + * CONFIG error: + */ + + +void foo() { + void (^b)(void) = ^(void)printf("hello world\n"); +} + +int main(int argc, char *argv[]) { + printf("%s: this shouldn't compile\n", argv[0]); + return 1; +} diff --git a/BlocksRuntime/tests/sizeof.c b/BlocksRuntime/tests/sizeof.c new file mode 100644 index 000000000000..1f84fc16f38f --- /dev/null +++ b/BlocksRuntime/tests/sizeof.c @@ -0,0 +1,26 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * sizeof.c + * testObjects + * + * Created by Blaine Garst on 2/17/09. + * + */ + +#include + +// CONFIG error: + +int main(int argc, char *argv[]) { + + void (^aBlock)(void) = ^{ printf("hellow world\n"); }; + + printf("the size of a block is %ld\n", sizeof(*aBlock)); + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/small-struct.c b/BlocksRuntime/tests/small-struct.c new file mode 100644 index 000000000000..434f3c179f7e --- /dev/null +++ b/BlocksRuntime/tests/small-struct.c @@ -0,0 +1,45 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*- +// CONFIG + +#import +#import +#import + +typedef struct { + int a; + int b; +} MiniStruct; + +int main (int argc, const char * argv[]) { + MiniStruct inny; + MiniStruct outty; + MiniStruct (^copyStruct)(MiniStruct); + + memset(&inny, 0xA5, sizeof(inny)); + memset(&outty, 0x2A, sizeof(outty)); + + inny.a = 12; + inny.b = 42; + + copyStruct = ^(MiniStruct aTinyStruct){ return aTinyStruct; }; // pass-by-value intrinsically copies the argument + + outty = copyStruct(inny); + + if ( &inny == &outty ) { + printf("%s: struct wasn't copied.", argv[0]); + exit(1); + } + if ( (inny.a != outty.a) || (inny.b != outty.b) ) { + printf("%s: struct contents did not match.", argv[0]); + exit(1); + } + + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/structmember.c b/BlocksRuntime/tests/structmember.c new file mode 100644 index 000000000000..c451d3f348c9 --- /dev/null +++ b/BlocksRuntime/tests/structmember.c @@ -0,0 +1,45 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * structmember.c + * testObjects + * + * Created by Blaine Garst on 9/30/08. + * CONFIG + */ +#include +#include +#include + +// CONFIG + +int main(int argc, char *argv[]) { + struct stuff { + long int a; + long int b; + long int c; + } localStuff = { 10, 20, 30 }; + int d; + + void (^a)(void) = ^ { printf("d is %d", d); }; + void (^b)(void) = ^ { printf("d is %d, localStuff.a is %lu", d, localStuff.a); }; + + unsigned nominalsize = Block_size(b) - Block_size(a); +#if __cplusplus__ + // need copy+dispose helper for C++ structures + nominalsize += 2*sizeof(void*); +#endif + if ((Block_size(b) - Block_size(a)) != nominalsize) { + printf("sizeof a is %ld, sizeof b is %ld, expected %d\n", Block_size(a), Block_size(b), nominalsize); + printf("dump of b is %s\n", _Block_dump(b)); + return 1; + } + printf("%s: Success\n", argv[0]); + return 0; +} + + diff --git a/BlocksRuntime/tests/testfilerunner.h b/BlocksRuntime/tests/testfilerunner.h new file mode 100644 index 000000000000..d4e54f029047 --- /dev/null +++ b/BlocksRuntime/tests/testfilerunner.h @@ -0,0 +1,110 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// testfilerunner.h +// testObjects +// +// Created by Blaine Garst on 9/24/08. +// + +#import + +/* + variations: + four source types: C, ObjC, C++, ObjC++, + and for ObjC or ObjC++ we have + RR and GC capabilities + we assume C++ friendly includes for C/ObjC even if C++ isn't used + + + four compilers: C, ObjC, C++, ObjC++ + and for ObjC or ObjC++ we can compile + RR, RR+GC, GC+RR, GC + although to test RR+GC we need to build a shell "main" in both modes + and/or run with GC disabled if possible. + + To maximize coverage we mark files with capabilities and then ask them to be + compiled with each variation of compiler and option. + If the file doesn't have the capability it politely refuses. +*/ + +enum options { + Do64 = (1 << 0), + DoCPP = (1 << 1), + DoOBJC = (1 << 3), + DoGC = (1 << 4), + DoRR = (1 << 5), + DoRRGC = (1 << 6), // -fobjc-gc but main w/o so it runs in RR mode + DoGCRR = (1 << 7), // -fobjc-gc & run GC mode + + //DoDashG = (1 << 8), + DoDashO = (1 << 9), + DoDashOs = (1 << 10), + DoDashO2 = (1 << 11), + + DoC99 = (1 << 12), // -std=c99 +}; + + +@class TestFileExeGenerator; + +// this class will actually compile and/or run a target binary +// XXX we don't track which dynamic libraries requested/used nor set them up +@interface TestFileExe : NSObject { + NSPointerArray *compileLine; + int options; + bool shouldFail; + TestFileExeGenerator *generator; + __strong char *binaryName; + __strong char *sourceName; + __strong char *libraryPath; + __strong char *frameworkPath; +} +@property int options; +@property(assign) NSPointerArray *compileLine; +@property(assign) TestFileExeGenerator *generator; +@property bool shouldFail; +@property __strong char *binaryName; +@property __strong char *sourceName; +@property __strong char *libraryPath; +@property __strong char *frameworkPath; +- (bool) compileUnlessExists:(bool)skip; +- (bool) run; +@property(readonly) __strong char *radar; +@end + +// this class generates an appropriate set of configurations to compile +// we don't track which gcc we use but we should XXX +@interface TestFileExeGenerator : NSObject { + bool hasObjC; + bool hasRR; + bool hasGC; + bool hasCPlusPlus; + bool wantsC99; + bool wants64; + bool wants32; + bool supposedToNotCompile; + bool open; // this problem is still open - e.g. unresolved + __strong char *radar; // for things already known to go wrong + __strong char *filename; + __strong char *compilerPath; + __strong char *errorString; + __strong char *warningString; + NSPointerArray *extraLibraries; +} +@property bool hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64; +@property(assign) __strong char *radar; +@property __strong char *filename; +@property __strong char *compilerPath; +@property __strong char *errorString; +@property __strong char *warningString; +- (TestFileExe *)lineForOptions:(int)options; // nil if no can do ++ (NSArray *)generatorsFromFILE:(FILE *)fd; ++ (NSArray *)generatorsFromPath:(NSString *)path; +@end + + diff --git a/BlocksRuntime/tests/testfilerunner.m b/BlocksRuntime/tests/testfilerunner.m new file mode 100644 index 000000000000..459adf889f6e --- /dev/null +++ b/BlocksRuntime/tests/testfilerunner.m @@ -0,0 +1,805 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// +// testfilerunner.m +// testObjects +// +// Created by Blaine Garst on 9/24/08. +// + +#import "testfilerunner.h" +#import +#include +#include +#include +#include +#include +#include + +bool Everything = false; // do it also with 3 levels of optimization +bool DoClang = false; + +static bool isDirectory(char *path); +static bool isExecutable(char *path); +static bool isYounger(char *source, char *binary); +static bool readErrorFile(char *buffer, const char *from); + +__strong char *gcstrcpy2(__strong const char *arg, char *endp) { + unsigned size = endp - arg + 1; + __strong char *result = NSAllocateCollectable(size, 0); + strncpy(result, arg, size); + result[size-1] = 0; + return result; +} +__strong char *gcstrcpy1(__strong char *arg) { + unsigned size = strlen(arg) + 1; + __strong char *result = NSAllocateCollectable(size, 0); + strncpy(result, arg, size); + result[size-1] = 0; + return result; +} + +@implementation TestFileExe + +@synthesize options, compileLine, shouldFail, binaryName, sourceName; +@synthesize generator; +@synthesize libraryPath, frameworkPath; + +- (NSString *)description { + NSMutableString *result = [NSMutableString new]; + if (shouldFail) [result appendString:@"fail"]; + for (id x in compileLine) { + [result appendString:[NSString stringWithFormat:@" %s", (char *)x]]; + } + return result; +} + +- (__strong char *)radar { + return generator.radar; +} + +- (bool) compileUnlessExists:(bool)skip { + if (shouldFail) { + printf("don't use this to compile anymore!\n"); + return false; + } + if (skip && isExecutable(binaryName) && !isYounger(sourceName, binaryName)) return true; + int argc = [compileLine count]; + char *argv[argc+1]; + for (int i = 0; i < argc; ++i) + argv[i] = (char *)[compileLine pointerAtIndex:i]; + argv[argc] = NULL; + pid_t child = fork(); + if (child == 0) { + execv(argv[0], argv); + exit(10); // shouldn't happen + } + if (child < 0) { + printf("fork failed\n"); + return false; + } + int status = 0; + pid_t deadchild = wait(&status); + if (deadchild != child) { + printf("wait got %d instead of %d\n", deadchild, child); + exit(1); + } + if (WEXITSTATUS(status) == 0) { + return true; + } + printf("run failed\n"); + return false; +} + +bool lookforIn(char *lookfor, const char *format, pid_t child) { + char buffer[512]; + char got[512]; + sprintf(buffer, format, child); + bool gotOutput = readErrorFile(got, buffer); + if (!gotOutput) { + printf("**** didn't get an output file %s to analyze!!??\n", buffer); + return false; + } + char *where = strstr(got, lookfor); + if (!where) { + printf("didn't find '%s' in output file %s\n", lookfor, buffer); + return false; + } + unlink(buffer); + return true; +} + +- (bool) compileWithExpectedFailure { + if (!shouldFail) { + printf("Why am I being called?\n"); + return false; + } + int argc = [compileLine count]; + char *argv[argc+1]; + for (int i = 0; i < argc; ++i) + argv[i] = (char *)[compileLine pointerAtIndex:i]; + argv[argc] = NULL; + pid_t child = fork(); + char buffer[512]; + if (child == 0) { + // in child + sprintf(buffer, "/tmp/errorfile_%d", getpid()); + close(1); + int fd = creat(buffer, 0777); + if (fd != 1) { + fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd); + exit(1); + } + close(2); + dup(1); + int result = execv(argv[0], argv); + exit(10); + } + if (child < 0) { + printf("fork failed\n"); + return false; + } + int status = 0; + pid_t deadchild = wait(&status); + if (deadchild != child) { + printf("wait got %d instead of %d\n", deadchild, child); + exit(11); + } + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) { + return false; + } + } + else { + printf("***** compiler borked/ICEd/died unexpectedly (status %x)\n", status); + return false; + } + char *error = generator.errorString; + + if (!error) return true; +#if 0 + char got[512]; + sprintf(buffer, "/tmp/errorfile_%d", child); + bool gotOutput = readErrorFile(got, buffer); + if (!gotOutput) { + printf("**** didn't get an error file %s to analyze!!??\n", buffer); + return false; + } + char *where = strstr(got, error); + if (!where) { + printf("didn't find '%s' in error file %s\n", error, buffer); + return false; + } + unlink(buffer); +#else + if (!lookforIn(error, "/tmp/errorfile_%d", child)) return false; +#endif + return true; +} + +- (bool) run { + if (shouldFail) return true; + if (sizeof(long) == 4 && options & Do64) { + return true; // skip 64-bit tests + } + int argc = 1; + char *argv[argc+1]; + argv[0] = binaryName; + argv[argc] = NULL; + pid_t child = fork(); + if (child == 0) { + // set up environment + char lpath[1024]; + char fpath[1024]; + char *myenv[3]; + int counter = 0; + if (libraryPath) { + sprintf(lpath, "DYLD_LIBRARY_PATH=%s", libraryPath); + myenv[counter++] = lpath; + } + if (frameworkPath) { + sprintf(fpath, "DYLD_FRAMEWORK_PATH=%s", frameworkPath); + myenv[counter++] = fpath; + } + myenv[counter] = NULL; + if (generator.warningString) { + // set up stdout/stderr + char outfile[1024]; + sprintf(outfile, "/tmp/stdout_%d", getpid()); + close(2); + close(1); + creat(outfile, 0700); + dup(1); + } + execve(argv[0], argv, myenv); + exit(10); // shouldn't happen + } + if (child < 0) { + printf("fork failed\n"); + return false; + } + int status = 0; + pid_t deadchild = wait(&status); + if (deadchild != child) { + printf("wait got %d instead of %d\n", deadchild, child); + exit(1); + } + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + if (generator.warningString) { + if (!lookforIn(generator.warningString, "/tmp/stdout_%d", child)) return false; + } + return true; + } + printf("**** run failed for %s\n", binaryName); + return false; +} + +@end + +@implementation TestFileExeGenerator +@synthesize filename, compilerPath, errorString; +@synthesize hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64; +@synthesize radar; +@synthesize warningString; + +- (void)setFilename:(__strong char *)name { + filename = gcstrcpy1(name); +} +- (void)setCompilerPath:(__strong char *)name { + compilerPath = gcstrcpy1(name); +} + +- (void)forMostThings:(NSMutableArray *)lines options:(int)options { + TestFileExe *item = nil; + item = [self lineForOptions:options]; + if (item) [lines addObject:item]; + item = [self lineForOptions:options|Do64]; + if (item) [lines addObject:item]; + item = [self lineForOptions:options|DoCPP]; + if (item) [lines addObject:item]; + item = [self lineForOptions:options|Do64|DoCPP]; + if (item) [lines addObject:item]; +} + +/* + DoDashG = (1 << 8), + DoDashO = (1 << 9), + DoDashOs = (1 << 10), + DoDashO2 = (1 << 11), +*/ + +- (void)forAllThings:(NSMutableArray *)lines options:(int)options { + [self forMostThings:lines options:options]; + if (!Everything) { + return; + } + // now do it with three explicit optimization flags + [self forMostThings:lines options:options | DoDashO]; + [self forMostThings:lines options:options | DoDashOs]; + [self forMostThings:lines options:options | DoDashO2]; +} + +- (NSArray *)allLines { + NSMutableArray *result = [NSMutableArray new]; + TestFileExe *item = nil; + + int options = 0; + [self forAllThings:result options:0]; + [self forAllThings:result options:DoOBJC | DoRR]; + [self forAllThings:result options:DoOBJC | DoGC]; + [self forAllThings:result options:DoOBJC | DoGCRR]; + //[self forAllThings:result options:DoOBJC | DoRRGC]; + + return result; +} + +- (void)addLibrary:(const char *)dashLSomething { + if (!extraLibraries) { + extraLibraries = [NSPointerArray pointerArrayWithOptions: + NSPointerFunctionsStrongMemory | + NSPointerFunctionsCStringPersonality]; + } + [extraLibraries addPointer:(void *)dashLSomething]; +} + +- (TestFileExe *)lineForOptions:(int)options { // nil if no can do + if (hasObjC && !(options & DoOBJC)) return nil; + if (hasCPlusPlus && !(options & DoCPP)) return nil; + if (hasObjC) { + if (!hasGC && (options & (DoGC|DoGCRR))) return nil; // not smart enough + if (!hasRR && (options & (DoRR|DoRRGC))) return nil; + } + NSPointerArray *pa = [NSPointerArray pointerArrayWithOptions: + NSPointerFunctionsStrongMemory | + NSPointerFunctionsCStringPersonality]; + // construct path + char path[512]; + path[0] = 0; + if (!compilerPath) compilerPath = "/usr/bin"; + if (compilerPath) { + strcat(path, compilerPath); + strcat(path, "/"); + } + if (options & DoCPP) { + strcat(path, DoClang ? "clang++" : "g++-4.2"); + } + else { + strcat(path, DoClang ? "clang" : "gcc-4.2"); + } + [pa addPointer:gcstrcpy1(path)]; + if (options & DoOBJC) { + if (options & DoCPP) { + [pa addPointer:"-ObjC++"]; + } + else { + [pa addPointer:"-ObjC"]; + } + } + [pa addPointer:"-g"]; + if (options & DoDashO) [pa addPointer:"-O"]; + else if (options & DoDashO2) [pa addPointer:"-O2"]; + else if (options & DoDashOs) [pa addPointer:"-Os"]; + if (wantsC99 && (! (options & DoCPP))) { + [pa addPointer:"-std=c99"]; + [pa addPointer:"-fblocks"]; + } + [pa addPointer:"-arch"]; + [pa addPointer: (options & Do64) ? "x86_64" : "i386"]; + + if (options & DoOBJC) { + switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) { + case DoRR: + break; + case DoGC: + [pa addPointer:"-fobjc-gc-only"]; + break; + case DoGCRR: + [pa addPointer:"-fobjc-gc"]; + break; + case DoRRGC: + printf("DoRRGC unsupported right now\n"); + [pa addPointer:"-c"]; + return nil; + } + [pa addPointer:"-framework"]; + [pa addPointer:"Foundation"]; + } + [pa addPointer:gcstrcpy1(filename)]; + [pa addPointer:"-o"]; + + path[0] = 0; + strcat(path, filename); + strcat(path, "."); + strcat(path, (options & Do64) ? "64" : "32"); + if (options & DoOBJC) { + switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) { + case DoRR: strcat(path, "-rr"); break; + case DoGC: strcat(path, "-gconly"); break; + case DoGCRR: strcat(path, "-gcrr"); break; + case DoRRGC: strcat(path, "-rrgc"); break; + } + } + if (options & DoCPP) strcat(path, "++"); + if (options & DoDashO) strcat(path, "-O"); + else if (options & DoDashO2) strcat(path, "-O2"); + else if (options & DoDashOs) strcat(path, "-Os"); + if (wantsC99) strcat(path, "-C99"); + strcat(path, DoClang ? "-clang" : "-gcc"); + strcat(path, "-bin"); + TestFileExe *result = [TestFileExe new]; + result.binaryName = gcstrcpy1(path); // could snarf copy in pa + [pa addPointer:result.binaryName]; + for (id cString in extraLibraries) { + [pa addPointer:cString]; + } + + result.sourceName = gcstrcpy1(filename); // could snarf copy in pa + result.compileLine = pa; + result.options = options; + result.shouldFail = supposedToNotCompile; + result.generator = self; + return result; +} + ++ (NSArray *)generatorsFromPath:(NSString *)path { + FILE *fp = fopen([path fileSystemRepresentation], "r"); + if (fp == NULL) return nil; + NSArray *result = [self generatorsFromFILE:fp]; + fclose(fp); + return result; +} + +#define LOOKFOR "CON" "FIG" + +char *__strong parseRadar(char *line) { + line = strstr(line, "rdar:"); // returns beginning + char *endp = line + strlen("rdar:"); + while (*endp && *endp != ' ' && *endp != '\n') + ++endp; + return gcstrcpy2(line, endp); +} + +- (void)parseLibraries:(const char *)line { + start: + line = strstr(line, "-l"); + char *endp = (char *)line + 2; + while (*endp && *endp != ' ' && *endp != '\n') + ++endp; + [self addLibrary:gcstrcpy2(line, endp)]; + if (strstr(endp, "-l")) { + line = endp; + goto start; + } +} + ++ (TestFileExeGenerator *)generatorFromLine:(char *)line filename:(char *)filename { + TestFileExeGenerator *item = [TestFileExeGenerator new]; + item.filename = gcstrcpy1(filename); + if (strstr(line, "GC")) item.hasGC = true; + if (strstr(line, "RR")) item.hasRR = true; + if (strstr(line, "C++")) item.hasCPlusPlus = true; + if (strstr(line, "-C99")) { + item.wantsC99 = true; + } + if (strstr(line, "64")) item.wants64 = true; + if (strstr(line, "32")) item.wants32 = true; + if (strstr(line, "-l")) [item parseLibraries:line]; + if (strstr(line, "open")) item.open = true; + if (strstr(line, "FAIL")) item.supposedToNotCompile = true; // old + // compile time error + if (strstr(line, "error:")) { + item.supposedToNotCompile = true; + // zap newline + char *error = strstr(line, "error:") + strlen("error:"); + // make sure we have something before the newline + char *newline = strstr(error, "\n"); + if (newline && ((newline-error) > 1)) { + *newline = 0; + item.errorString = gcstrcpy1(strstr(line, "error:") + strlen("error: ")); + } + } + // run time warning + if (strstr(line, "runtime:")) { + // zap newline + char *error = strstr(line, "runtime:") + strlen("runtime:"); + // make sure we have something before the newline + char *newline = strstr(error, "\n"); + if (newline && ((newline-error) > 1)) { + *newline = 0; + item.warningString = gcstrcpy1(strstr(line, "runtime:") + strlen("runtime:")); + } + } + if (strstr(line, "rdar:")) item.radar = parseRadar(line); + if (item.hasGC || item.hasRR) item.hasObjC = true; + if (!item.wants32 && !item.wants64) { // give them both if they ask for neither + item.wants32 = item.wants64 = true; + } + return item; +} + ++ (NSArray *)generatorsFromFILE:(FILE *)fp { + NSMutableArray *result = [NSMutableArray new]; + // pretend this is a grep LOOKFOR *.[cmCM][cmCM] input + // look for + // filename: ... LOOKFOR [GC] [RR] [C++] [FAIL ...] + char buf[512]; + while (fgets(buf, 512, fp)) { + char *config = strstr(buf, LOOKFOR); + if (!config) continue; + char *filename = buf; + char *end = strchr(buf, ':'); + *end = 0; + [result addObject:[self generatorFromLine:config filename:filename]]; + } + return result; +} + ++ (TestFileExeGenerator *)generatorFromFilename:(char *)filename { + FILE *fp = fopen(filename, "r"); + if (!fp) { + printf("didn't open %s!!\n", filename); + return nil; + } + char buf[512]; + while (fgets(buf, 512, fp)) { + char *config = strstr(buf, LOOKFOR); + if (!config) continue; + fclose(fp); + return [self generatorFromLine:config filename:filename]; + } + fclose(fp); + // guess from filename + char *ext = strrchr(filename, '.'); + if (!ext) return nil; + TestFileExeGenerator *result = [TestFileExeGenerator new]; + result.filename = gcstrcpy1(filename); + if (!strncmp(ext, ".m", 2)) { + result.hasObjC = true; + result.hasRR = true; + result.hasGC = true; + } + else if (!strcmp(ext, ".c")) { + ; + } + else if (!strcmp(ext, ".M") || !strcmp(ext, ".mm")) { + result.hasObjC = true; + result.hasRR = true; + result.hasGC = true; + result.hasCPlusPlus = true; + } + else if (!strcmp(ext, ".cc") + || !strcmp(ext, ".cp") + || !strcmp(ext, ".cxx") + || !strcmp(ext, ".cpp") + || !strcmp(ext, ".CPP") + || !strcmp(ext, ".c++") + || !strcmp(ext, ".C")) { + result.hasCPlusPlus = true; + } + else { + printf("unknown extension, file %s ignored\n", filename); + result = nil; + } + return result; + +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%s: %s%s%s%s%s%s", + filename, + LOOKFOR, + hasGC ? " GC" : "", + hasRR ? " RR" : "", + hasCPlusPlus ? " C++" : "", + wantsC99 ? "C99" : "", + supposedToNotCompile ? " FAIL" : ""]; +} + +@end + +void printDetails(NSArray *failures, const char *whatAreThey) { + if ([failures count]) { + NSMutableString *output = [NSMutableString new]; + printf("%s:\n", whatAreThey); + for (TestFileExe *line in failures) { + printf("%s", line.binaryName); + char *radar = line.generator.radar; + if (radar) + printf(" (due to %s?),", radar); + printf(" recompile via:\n%s\n\n", line.description.UTF8String); + } + printf("\n"); + } +} + +void help(const char *whoami) { + printf("Usage: %s [-fast] [-e] [-dyld librarypath] [gcc4.2dir] [-- | source1 ...]\n", whoami); + printf(" -fast don't recompile if binary younger than source\n"); + printf(" -open only run tests that are thought to still be unresolved\n"); + printf(" -clang use the clang and clang++ compilers\n"); + printf(" -e compile all variations also with -Os, -O2, -O3\n"); + printf(" -dyld p override DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH to p when running tests\n"); + printf(" directory containing gcc-4.2 (or clang) that you wish to use to compile the tests\n"); + printf(" -- assume stdin is a grep CON" "FIG across the test sources\n"); + printf(" otherwise treat each remaining argument as a single test file source\n"); + printf("%s will compile and run individual test files under a variety of compilers, c, obj-c, c++, and objc++\n", whoami); + printf(" .c files are compiled with all four compilers\n"); + printf(" .m files are compiled with objc and objc++ compilers\n"); + printf(" .C files are compiled with c++ and objc++ compilers\n"); + printf(" .M files are compiled only with the objc++ compiler\n"); + printf("(actually all forms of extensions recognized by the compilers are honored, .cc, .c++ etc.)\n"); + printf("\nTest files should run to completion with no output and exit (return) 0 on success.\n"); + printf("Further they should be able to be compiled and run with GC on or off and by the C++ compilers\n"); + printf("A line containing the string CON" "FIG within the source enables restrictions to the above assumptions\n"); + printf("and other options.\n"); + printf("Following CON" "FIG the string\n"); + printf(" C++ restricts the test to only be run by c++ and objc++ compilers\n"); + printf(" GC restricts the test to only be compiled and run with GC on\n"); + printf(" RR (retain/release) restricts the test to only be compiled and run with GC off\n"); + printf("Additionally,\n"); + printf(" -C99 restricts the C versions of the test to -fstd=c99 -fblocks\n"); + printf(" -O adds the -O optimization level\n"); + printf(" -O2 adds the -O2 optimization level\n"); + printf(" -Os adds the -Os optimization level\n"); + printf("Files that are known to exhibit unresolved problems can provide the term \"open\" and this can"); + printf("in turn allow highlighting of fixes that have regressed as well as identify that fixes are now available.\n"); + printf("Files that exhibit known bugs may provide\n"); + printf(" rdar://whatever such that if they fail the rdar will get cited\n"); + printf("Files that are expected to fail to compile should provide, as their last token sequence,\n"); + printf(" error:\n"); + printf(" or error: substring to match.\n"); + printf("Files that are expected to produce a runtime error message should provide, as their last token sequence,\n"); + printf(" warning: string to match\n"); + printf("\n%s will compile and run all configurations of the test files and report a summary at the end. Good luck.\n", whoami); + printf(" Blaine Garst blaine@apple.com\n"); +} + +int main(int argc, char *argv[]) { + printf("running on %s-bit architecture\n", sizeof(long) == 4 ? "32" : "64"); + char *compilerDir = "/usr/bin"; + NSMutableArray *generators = [NSMutableArray new]; + bool doFast = false; + bool doStdin = false; + bool onlyOpen = false; + char *libraryPath = getenv("DYLD_LIBRARY_PATH"); + char *frameworkPath = getenv("DYLD_FRAMEWORK_PATH"); + // process options + while (argc > 1) { + if (!strcmp(argv[1], "-fast")) { + doFast = true; + --argc; + ++argv; + } + else if (!strcmp(argv[1], "-dyld")) { + doFast = true; + --argc; + ++argv; + frameworkPath = argv[1]; + libraryPath = argv[1]; + --argc; + ++argv; + } + else if (!strcmp(argv[1], "-open")) { + onlyOpen = true; + --argc; + ++argv; + } + else if (!strcmp(argv[1], "-clang")) { + DoClang = true; + --argc; + ++argv; + } + else if (!strcmp(argv[1], "-e")) { + Everything = true; + --argc; + ++argv; + } + else if (!strcmp(argv[1], "--")) { + doStdin = true; + --argc; + ++argv; + } + else if (!strcmp(argv[1], "-")) { + help(argv[0]); + return 1; + } + else if (argc > 1 && isDirectory(argv[1])) { + compilerDir = argv[1]; + ++argv; + --argc; + } + else + break; + } + // process remaining arguments, or stdin + if (argc == 1) { + if (doStdin) + generators = (NSMutableArray *)[TestFileExeGenerator generatorsFromFILE:stdin]; + else { + help(argv[0]); + return 1; + } + } + else while (argc > 1) { + TestFileExeGenerator *generator = [TestFileExeGenerator generatorFromFilename:argv[1]]; + if (generator) [generators addObject:generator]; + ++argv; + --argc; + } + // see if we can generate all possibilities + NSMutableArray *failureToCompile = [NSMutableArray new]; + NSMutableArray *failureToFailToCompile = [NSMutableArray new]; + NSMutableArray *failureToRun = [NSMutableArray new]; + NSMutableArray *successes = [NSMutableArray new]; + for (TestFileExeGenerator *generator in generators) { + //NSLog(@"got %@", generator); + if (onlyOpen && !generator.open) { + //printf("skipping resolved test %s\n", generator.filename); + continue; // skip closed if onlyOpen + } + if (!onlyOpen && generator.open) { + //printf("skipping open test %s\n", generator.filename); + continue; // skip open if not asked for onlyOpen + } + generator.compilerPath = compilerDir; + NSArray *tests = [generator allLines]; + for (TestFileExe *line in tests) { + line.frameworkPath = frameworkPath; // tell generators about it instead XXX + line.libraryPath = libraryPath; // tell generators about it instead XXX + if ([line shouldFail]) { + if (doFast) continue; // don't recompile & don't count as success + if ([line compileWithExpectedFailure]) { + [successes addObject:line]; + } + else + [failureToFailToCompile addObject:line]; + } + else if ([line compileUnlessExists:doFast]) { + if ([line run]) { + printf("%s ran successfully\n", line.binaryName); + [successes addObject:line]; + } + else { + [failureToRun addObject:line]; + } + } + else { + [failureToCompile addObject:line]; + } + } + } + printf("\n--- results ---\n\n%lu successes\n%lu unexpected compile failures\n%lu failure to fail to compile errors\n%lu run failures\n", + [successes count], [failureToCompile count], [failureToFailToCompile count], [failureToRun count]); + printDetails(failureToCompile, "unexpected compile failures"); + printDetails(failureToFailToCompile, "should have failed to compile but didn't failures"); + printDetails(failureToRun, "run failures"); + + if (onlyOpen && [successes count]) { + NSMutableSet *radars = [NSMutableSet new]; + printf("The following tests ran successfully suggesting that they are now resolved:\n"); + for (TestFileExe *line in successes) { + printf("%s\n", line.binaryName); + if (line.radar) [radars addObject:line.generator]; + } + if ([radars count]) { + printf("The following radars may be resolved:\n"); + for (TestFileExeGenerator *line in radars) { + printf("%s\n", line.radar); + } + } + } + + return [failureToCompile count] + [failureToRun count]; +} + +#include + +static bool isDirectory(char *path) { + struct stat statb; + int retval = stat(path, &statb); + if (retval != 0) return false; + if (statb.st_mode & S_IFDIR) return true; + return false; +} + +static bool isExecutable(char *path) { + struct stat statb; + int retval = stat(path, &statb); + if (retval != 0) return false; + if (!(statb.st_mode & S_IFREG)) return false; + if (statb.st_mode & S_IXUSR) return true; + return false; +} + +static bool isYounger(char *source, char *binary) { + struct stat statb; + int retval = stat(binary, &statb); + if (retval != 0) return true; // if doesn't exit, lie + + struct stat stata; + retval = stat(source, &stata); + if (retval != 0) return true; // we're hosed + // the greater the timeval the younger it is + if (stata.st_mtimespec.tv_sec > statb.st_mtimespec.tv_sec) return true; + if (stata.st_mtimespec.tv_nsec > statb.st_mtimespec.tv_nsec) return true; + return false; +} + +static bool readErrorFile(char *buffer, const char *from) { + int fd = open(from, 0); + if (fd < 0) { + printf("didn't open %s, (might not have been created?)\n", buffer); + return false; + } + int count = read(fd, buffer, 512); + if (count < 1) { + printf("read error on %s\n", buffer); + return false; + } + buffer[count-1] = 0; // zap newline + return true; +} diff --git a/BlocksRuntime/tests/varargs-bad-assign.c b/BlocksRuntime/tests/varargs-bad-assign.c new file mode 100644 index 000000000000..b978668b95c0 --- /dev/null +++ b/BlocksRuntime/tests/varargs-bad-assign.c @@ -0,0 +1,44 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*- +// HACK ALERT: gcc and g++ give different errors, referencing the line number to ensure that it checks for the right error; MUST KEEP IN SYNC WITH THE TEST +// CONFIG 27: error: + +#import +#import +#import +#import + + +int main (int argc, const char * argv[]) { + int (^sumn)(int n, ...); + int six = 0; + + sumn = ^(int a, int b, int n, ...){ + int result = 0; + va_list numbers; + int i; + + va_start(numbers, n); + for (i = 0 ; i < n ; i++) { + result += va_arg(numbers, int); + } + va_end(numbers); + + return result; + }; + + six = sumn(3, 1, 2, 3); + + if ( six != 6 ) { + printf("%s: Expected 6 but got %d\n", argv[0], six); + exit(1); + } + + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/varargs.c b/BlocksRuntime/tests/varargs.c new file mode 100644 index 000000000000..01affc76e68c --- /dev/null +++ b/BlocksRuntime/tests/varargs.c @@ -0,0 +1,39 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*- +// CONFIG + +#import +#import +#import +#import + + +int main (int argc, const char * argv[]) { + int (^sumn)(int n, ...) = ^(int n, ...){ + int result = 0; + va_list numbers; + int i; + + va_start(numbers, n); + for (i = 0 ; i < n ; i++) { + result += va_arg(numbers, int); + } + va_end(numbers); + + return result; + }; + int six = sumn(3, 1, 2, 3); + + if ( six != 6 ) { + printf("%s: Expected 6 but got %d\n", argv[0], six); + exit(1); + } + + printf("%s: success\n", argv[0]); + return 0; +} diff --git a/BlocksRuntime/tests/variadic.c b/BlocksRuntime/tests/variadic.c new file mode 100644 index 000000000000..1d80657e9886 --- /dev/null +++ b/BlocksRuntime/tests/variadic.c @@ -0,0 +1,66 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * variadic.c + * testObjects + * + * Created by Blaine Garst on 2/17/09. + * + */ + +// PURPOSE Test that variadic arguments compile and work for Blocks +// CONFIG + +#include +#include + +int main(int argc, char *argv[]) { + + long (^addthem)(const char *, ...) = ^long (const char *format, ...){ + va_list argp; + const char *p; + int i; + char c; + double d; + long result = 0; + va_start(argp, format); + //printf("starting...\n"); + for (p = format; *p; p++) switch (*p) { + case 'i': + i = va_arg(argp, int); + //printf("i: %d\n", i); + result += i; + break; + case 'd': + d = va_arg(argp, double); + //printf("d: %g\n", d); + result += (int)d; + break; + case 'c': + c = va_arg(argp, int); + //printf("c: '%c'\n", c); + result += c; + break; + } + //printf("...done\n\n"); + return result; + }; + long testresult = addthem("ii", 10, 20); + if (testresult != 30) { + printf("got wrong result: %ld\n", testresult); + return 1; + } + testresult = addthem("idc", 30, 40.0, 'a'); + if (testresult != (70+'a')) { + printf("got different wrong result: %ld\n", testresult); + return 1; + } + printf("%s: Success\n", argv[0]); + return 0; +} + + diff --git a/BlocksRuntime/tests/voidarg.c b/BlocksRuntime/tests/voidarg.c new file mode 100644 index 000000000000..a8f034b47c10 --- /dev/null +++ b/BlocksRuntime/tests/voidarg.c @@ -0,0 +1,27 @@ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +/* + * voidarg.c + * testObjects + * + * Created by Blaine Garst on 2/17/09. + * + */ + +// PURPOSE should complain about missing 'void' but both GCC and clang are supporting K&R instead +// CONFIG open error: + +#include + +int Global; + +void (^globalBlock)() = ^{ ++Global; }; // should be void (^gb)(void) = ... + +int main(int argc, char *argv[]) { + printf("%s: success", argv[0]); + return 0; +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000000..483b673773a7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,55 @@ +# See docs/CMake.html for instructions about how to build Compiler-RT with CMake. + +PROJECT( CompilerRT C ) +CMAKE_MINIMUM_REQUIRED( VERSION 2.6 ) + +set(PACKAGE_NAME compiler-rt) +set(PACKAGE_VERSION 1.0svn) +set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") +set(PACKAGE_BUGREPORT "llvmbugs@cs.uiuc.edu") + +SET( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules ) + +# add definitions +include(DefineCompilerFlags) + +# Disallow in-source build +INCLUDE( MacroEnsureOutOfSourceBuild ) +MACRO_ENSURE_OUT_OF_SOURCE_BUILD( + "${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there." + ) + +INCLUDE( ${CMAKE_SOURCE_DIR}/cmake/ConfigureChecks.cmake ) +CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/cmake/config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/config.h ) + +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} +) + +SET( Achitectures + i386 x86_64 ppc arm + ) + +SET( Configurations + Debug Release Profile + ) + +# Only build Blocks Runtime if the compiler has enough support +IF( WIN32 OR MSVC OR HAVE_OSATOMIC_COMPARE_AND_SWAP_INT OR HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT ) + SET(BUILD_BLOCKS_RUNTIME TRUE) +ELSE( WIN32 OR MSVC OR HAVE_OSATOMIC_COMPARE_AND_SWAP_INT OR HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT ) + SET(BUILD_BLOCKS_RUNTIME FALSE) +ENDIF( WIN32 OR MSVC OR HAVE_OSATOMIC_COMPARE_AND_SWAP_INT OR HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT ) + +IF( BUILD_BLOCKS_RUNTIME ) + ADD_SUBDIRECTORY( BlocksRuntime ) +ELSE( BUILD_BLOCKS_RUNTIME ) + MESSAGE(STATUS "No suitable atomic operation routines detected, skipping Blocks Runtime") +ENDIF( BUILD_BLOCKS_RUNTIME ) + +ADD_SUBDIRECTORY( lib ) + +# Enable Test Suit: +INCLUDE( MacroAddCheckTest ) +ADD_SUBDIRECTORY( test ) diff --git a/CREDITS.TXT b/CREDITS.TXT new file mode 100644 index 000000000000..8b07b82bf87b --- /dev/null +++ b/CREDITS.TXT @@ -0,0 +1,21 @@ +This file is a partial list of people who have contributed to the LLVM/CompilerRT +project. If you have contributed a patch or made some other contribution to +LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be +done! + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). + +N: Craig van Vliet +E: cvanvliet@auroraux.org +W: http://www.auroraux.org +D: Code style and Readability fixes. + +N: Edward O'Callaghan +E: eocallaghan@auroraux.org +W: http://www.auroraux.org +D: CMake'ify Compiler-RT build system +D: Maintain Solaris & AuroraUX ports of Compiler-RT + diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 000000000000..a5e1345f673f --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,63 @@ +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2009 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- diff --git a/Makefile b/Makefile new file mode 100644 index 000000000000..530590618c62 --- /dev/null +++ b/Makefile @@ -0,0 +1,243 @@ +SubDirs := lib + +# Set default rule before anything else. +all: help + +include make/config.mk +include make/util.mk +# If SRCROOT is defined, assume we are doing an Apple style build. We should be +# able to use RC_XBS for this but that is unused during "make installsrc". +ifdef SRCROOT + include make/AppleBI.mk +endif + +# Make sure we don't build with a missing ProjObjRoot. +ifeq ($(ProjObjRoot),) +$(error Refusing to build with empty ProjObjRoot variable) +endif + +############## + +### +# Rules + +### +# Top level targets + +# FIXME: Document the available subtargets. +help: + @echo "usage: make [{VARIABLE=VALUE}*] target" + @echo + @echo "User variables:" + @echo " VERBOSE=1: Use to show all commands [default=0]" + @echo + @echo "Available targets:" + @echo " : build the libraries for 'platform'" + @echo " clean: clean all configurations" + @echo " test: run unit tests" + @echo + @echo " info-platforms: list available platforms" + @echo " help-devel: print additional help for developers" + @echo + +help-devel: help + @echo "Development targets:" + @echo " -:" + @echo " build the libraries for a single platform config" + @echo " --:" + @echo " build the libraries for a single config and arch" + @echo " info-functions: list available compiler-rt functions" + @echo " help-hidden: print help for Makefile debugging" + @echo + +help-hidden: help-devel + @echo "Debugging variables:" + @echo " DEBUGMAKE=1: enable some Makefile logging [default=]" + @echo " =2: enable more Makefile logging" + @echo + @echo "Debugging targets:" + @echo " make-print-FOO: print information on the variable 'FOO'" + @echo + +info-functions: + @echo "compiler-rt Available Functions" + @echo + @echo "All Functions: $(AvailableFunctions)" + @$(foreach fn,$(AvailableFunctions),\ + printf " %-20s - available in (%s)\n" $(fn)\ + "$(foreach key,$(AvailableIn.$(fn)),$($(key).Dir))";) + +info-platforms: + @echo "compiler-rt Available Platforms" + @echo + @echo "Platforms:" + @$(foreach key,$(PlatformKeys),\ + printf " %s - from '%s'\n" $($(key).Name) $($(key).Path);\ + printf " %s\n" "$($(key).Description)";\ + printf " Configurations: %s\n\n" "$($(key).Configs)";) + +# Provide default clean target which is extended by other templates. +.PHONY: clean +clean:: + +# Test +.PHONY: test +test: + cd test/Unit && ./test + +### +# Directory handling magic. + +# Create directories as needed, and timestamp their creation. +%/.dir: + $(Summary) " MKDIR: $*" + $(Verb) $(MKDIR) $* > /dev/null + $(Verb) $(DATE) > $@ + +# Remove directories +%/.remove: + $(Verb) $(RM) -r $* + +### +# Include child makefile fragments + +Dir := . +include make/subdir.mk +include make/lib_info.mk +include make/lib_util.mk +include make/lib_platforms.mk + +### +# Define Platform Rules + +define PerPlatform_template +$(call Set,Tmp.Key,$(1)) +$(call Set,Tmp.Name,$($(Tmp.Key).Name)) +$(call Set,Tmp.Configs,$($(Tmp.Key).Configs)) +$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)) + +# Top-Level Platform Target +$(Tmp.Name):: $(Tmp.Configs:%=$(Tmp.ObjPath)/%/libcompiler_rt.a) +.PHONY: $(Tmp.Name) + +clean:: + $(Verb) rm -rf $(Tmp.ObjPath) + +# Per-Config Libraries +$(foreach config,$(Tmp.Configs),\ + $(call PerPlatformConfig_template,$(config))) +endef + +define PerPlatformConfig_template +$(call Set,Tmp.Config,$(1)) +$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)) + +# Compute the archs to build, depending on whether this is a universal build or +# not. +$(call Set,Tmp.ArchsToBuild,\ + $(if $(call IsDefined,$(Tmp.Key).UniversalArchs),\ + $(strip \ + $(or $($(Tmp.Key).UniversalArchs.$(Tmp.Config)),\ + $($(Tmp.Key).UniversalArchs))),\ + $(call VarOrDefault,$(Tmp.Key).Arch.$(Tmp.Config),$($(Tmp.Key).Arch)))) + +# Copy or lipo to create the per-config library. +$(call Set,Tmp.Inputs,$(Tmp.ArchsToBuild:%=$(Tmp.ObjPath)/%/libcompiler_rt.a)) +$(Tmp.ObjPath)/libcompiler_rt.a: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir + $(Summary) " FINAL-ARCHIVE: $(Tmp.Name)/$(Tmp.Config): $$@" + -$(Verb) $(RM) $$@ + $(if $(call streq,1,$(words $(Tmp.ArchsToBuild))), \ + $(Verb) $(CP) $(Tmp.Inputs) $$@, \ + $(Verb) $(LIPO) -create -output $$@ $(Tmp.Inputs)) +.PRECIOUS: $(Tmp.ObjPath)/.dir + +# Per-Config Targets +$(Tmp.Name)-$(Tmp.Config):: $(Tmp.ObjPath)/libcompiler_rt.a +.PHONY: $(Tmp.Name)-$(Tmp.Config) + +# Per-Config-Arch Libraries +$(foreach arch,$(Tmp.ArchsToBuild),\ + $(call PerPlatformConfigArch_template,$(arch))) +endef + +define PerPlatformConfigArch_template +$(call Set,Tmp.Arch,$(1)) +$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch)) +$(call Set,Tmp.Functions,$(strip \ + $(call GetCNAVar,FUNCTIONS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.Optimized,$(strip \ + $(call GetCNAVar,OPTIMIZED,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.AR,$(strip \ + $(call GetCNAVar,AR,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.ARFLAGS,$(strip \ + $(call GetCNAVar,ARFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.RANLIB,$(strip \ + $(call GetCNAVar,RANLIB,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.RANLIBFLAGS,$(strip \ + $(call GetCNAVar,RANLIBFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) + +# Compute the object inputs for this library. +$(call Set,Tmp.Inputs,\ + $(foreach fn,$(sort $(Tmp.Functions)),\ + $(call Set,Tmp.FnDir,\ + $(call SelectFunctionDir,$(Tmp.Config),$(Tmp.Arch),$(fn),$(Tmp.Optimized)))\ + $(Tmp.ObjPath)/$(Tmp.FnDir)/$(fn).o)) +$(Tmp.ObjPath)/libcompiler_rt.a: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir + $(Summary) " ARCHIVE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$@" + -$(Verb) $(RM) $$@ + $(Verb) $(Tmp.AR) $(Tmp.ARFLAGS) $$@ $(Tmp.Inputs) + $(Verb) $(Tmp.RANLIB) $(Tmp.RANLIBFLAGS) $$@ +.PRECIOUS: $(Tmp.ObjPath)/.dir + +# Per-Config-Arch Targets +$(Tmp.Name)-$(Tmp.Config)-$(Tmp.Arch):: $(Tmp.ObjPath)/libcompiler_rt.a +.PHONY: $(Tmp.Name)-$(Tmp.Config)-$(Tmp.Arch) + +# Per-Config-Arch-SubDir Objects +$(foreach key,$(SubDirKeys),\ + $(call PerPlatformConfigArchSubDir_template,$(key))) +endef + +define PerPlatformConfigArchSubDir_template +$(call Set,Tmp.SubDirKey,$(1)) +$(call Set,Tmp.SubDir,$($(Tmp.SubDirKey).Dir)) +$(call Set,Tmp.SrcPath,$(ProjSrcRoot)/$(Tmp.SubDir)) +$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch)/$(Tmp.SubDirKey)) +$(call Set,Tmp.Dependencies,$($(Tmp.SubDirKey).Dependencies)) +$(call Set,Tmp.CC,$(strip \ + $(call GetCNAVar,CC,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.KERNEL_USE,$(strip \ + $(call GetCNAVar,KERNEL_USE,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.VISIBILITY_HIDDEN,$(strip \ + $(call GetCNAVar,VISIBILITY_HIDDEN,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) +$(call Set,Tmp.CFLAGS,$(strip \ + $(if $(call IsDefined,$(Tmp.Key).UniversalArchs),-arch $(Tmp.Arch),)\ + $(if $(call streq,$(Tmp.VISIBILITY_HIDDEN),1),\ + -fvisibility=hidden -DVISIBILITY_HIDDEN,)\ + $(if $(call streq,$(Tmp.KERNEL_USE),1),\ + -mkernel -DKERNEL_USE,)\ + $(call GetCNAVar,CFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch)))) + +$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.s $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir + $(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<" + $(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$< +$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.S $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir + $(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<" + $(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$< +$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.c $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir + $(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<" + $(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$< +.PRECIOUS: $(Tmp.ObjPath)/.dir + +endef + +# Run templates. +$(foreach key,$(PlatformKeys),\ + $(eval $(call PerPlatform_template,$(key)))) + +### + +ifneq ($(DEBUGMAKE),) + $(info MAKE: Done processing Makefile) + $(info ) +endif diff --git a/README.txt b/README.txt new file mode 100644 index 000000000000..ab389d2129ba --- /dev/null +++ b/README.txt @@ -0,0 +1,330 @@ +Compiler-RT +================================ + +This directory and its subdirectories contain source code for the compiler +support routines. + +Compiler-RT is open source software. You may freely distribute it under the +terms of the license agreement found in LICENSE.txt. + +================================ + +This is a replacement library for libgcc. Each function is contained +in its own file. Each function has a corresponding unit test under +test/Unit. + +A rudimentary script to test each file is in the file called +test/Unit/test. + +Here is the specification for this library: + +http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc + +Here is a synopsis of the contents of this library: + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +// Integral bit manipulation + +di_int __ashldi3(di_int a, si_int b); // a << b +ti_int __ashlti3(ti_int a, si_int b); // a << b + +di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill) +ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill) +di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill) +ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill) + +si_int __clzsi2(si_int a); // count leading zeros +si_int __clzdi2(di_int a); // count leading zeros +si_int __clzti2(ti_int a); // count leading zeros +si_int __ctzsi2(si_int a); // count trailing zeros +si_int __ctzdi2(di_int a); // count trailing zeros +si_int __ctzti2(ti_int a); // count trailing zeros + +si_int __ffsdi2(di_int a); // find least significant 1 bit +si_int __ffsti2(ti_int a); // find least significant 1 bit + +si_int __paritysi2(si_int a); // bit parity +si_int __paritydi2(di_int a); // bit parity +si_int __parityti2(ti_int a); // bit parity + +si_int __popcountsi2(si_int a); // bit population +si_int __popcountdi2(di_int a); // bit population +si_int __popcountti2(ti_int a); // bit population + +uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only +uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only + +// Integral arithmetic + +di_int __negdi2 (di_int a); // -a +ti_int __negti2 (ti_int a); // -a +di_int __muldi3 (di_int a, di_int b); // a * b +ti_int __multi3 (ti_int a, ti_int b); // a * b +si_int __divsi3 (si_int a, si_int b); // a / b signed +di_int __divdi3 (di_int a, di_int b); // a / b signed +ti_int __divti3 (ti_int a, ti_int b); // a / b signed +su_int __udivsi3 (su_int n, su_int d); // a / b unsigned +du_int __udivdi3 (du_int a, du_int b); // a / b unsigned +tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned +si_int __modsi3 (si_int a, si_int b); // a % b signed +di_int __moddi3 (di_int a, di_int b); // a % b signed +ti_int __modti3 (ti_int a, ti_int b); // a % b signed +su_int __umodsi3 (su_int a, su_int b); // a % b unsigned +du_int __umoddi3 (du_int a, du_int b); // a % b unsigned +tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b + +// Integral arithmetic with trapping overflow + +si_int __absvsi2(si_int a); // abs(a) +di_int __absvdi2(di_int a); // abs(a) +ti_int __absvti2(ti_int a); // abs(a) + +si_int __negvsi2(si_int a); // -a +di_int __negvdi2(di_int a); // -a +ti_int __negvti2(ti_int a); // -a + +si_int __addvsi3(si_int a, si_int b); // a + b +di_int __addvdi3(di_int a, di_int b); // a + b +ti_int __addvti3(ti_int a, ti_int b); // a + b + +si_int __subvsi3(si_int a, si_int b); // a - b +di_int __subvdi3(di_int a, di_int b); // a - b +ti_int __subvti3(ti_int a, ti_int b); // a - b + +si_int __mulvsi3(si_int a, si_int b); // a * b +di_int __mulvdi3(di_int a, di_int b); // a * b +ti_int __mulvti3(ti_int a, ti_int b); // a * b + +// Integral comparison: a < b -> 0 +// a == b -> 1 +// a > b -> 2 + +si_int __cmpdi2 (di_int a, di_int b); +si_int __cmpti2 (ti_int a, ti_int b); +si_int __ucmpdi2(du_int a, du_int b); +si_int __ucmpti2(tu_int a, tu_int b); + +// Integral / floating point conversion + +di_int __fixsfdi( float a); +di_int __fixdfdi( double a); +di_int __fixxfdi(long double a); + +ti_int __fixsfti( float a); +ti_int __fixdfti( double a); +ti_int __fixxfti(long double a); +uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation + +su_int __fixunssfsi( float a); +su_int __fixunsdfsi( double a); +su_int __fixunsxfsi(long double a); + +du_int __fixunssfdi( float a); +du_int __fixunsdfdi( double a); +du_int __fixunsxfdi(long double a); + +tu_int __fixunssfti( float a); +tu_int __fixunsdfti( double a); +tu_int __fixunsxfti(long double a); +uint64_t __fixunstfdi(long double input); // ppc only + +float __floatdisf(di_int a); +double __floatdidf(di_int a); +long double __floatdixf(di_int a); +long double __floatditf(int64_t a); // ppc only + +float __floattisf(ti_int a); +double __floattidf(ti_int a); +long double __floattixf(ti_int a); + +float __floatundisf(du_int a); +double __floatundidf(du_int a); +long double __floatundixf(du_int a); +long double __floatunditf(uint64_t a); // ppc only + +float __floatuntisf(tu_int a); +double __floatuntidf(tu_int a); +long double __floatuntixf(tu_int a); + +// Floating point raised to integer power + +float __powisf2( float a, si_int b); // a ^ b +double __powidf2( double a, si_int b); // a ^ b +long double __powixf2(long double a, si_int b); // a ^ b +long double __powitf2(long double a, si_int b); // ppc only, a ^ b + +// Complex arithmetic + +// (a + ib) * (c + id) + + float _Complex __mulsc3( float a, float b, float c, float d); + double _Complex __muldc3(double a, double b, double c, double d); +long double _Complex __mulxc3(long double a, long double b, + long double c, long double d); +long double _Complex __multc3(long double a, long double b, + long double c, long double d); // ppc only + +// (a + ib) / (c + id) + + float _Complex __divsc3( float a, float b, float c, float d); + double _Complex __divdc3(double a, double b, double c, double d); +long double _Complex __divxc3(long double a, long double b, + long double c, long double d); +long double _Complex __divtc3(long double a, long double b, + long double c, long double d); // ppc only + + +// Runtime support + +// __clear_cache() is used to tell process that new instructions have been +// written to an address range. Necessary on processors that do not have +// a unified instuction and data cache. +void __clear_cache(void* start, void* end); + +// __enable_execute_stack() is used with nested functions when a trampoline +// function is written onto the stack and that page range needs to be made +// executable. +void __enable_execute_stack(void* addr); + +// __gcc_personality_v0() is normally only called by the system unwinder. +// C code (as opposed to C++) normally does not need a personality function +// because there are no catch clauses or destructors to be run. But there +// is a C language extension __attribute__((cleanup(func))) which marks local +// variables as needing the cleanup function "func" to be run when the +// variable goes out of scope. That includes when an exception is thrown, +// so a personality handler is needed. +_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + _Unwind_Context_t context); + +// for use with some implementations of assert() in +void __eprintf(const char* format, const char* assertion_expression, + const char* line, const char* file); + + + +// Power PC specific functions + +// There is no C interface to the saveFP/restFP functions. They are helper +// functions called by the prolog and epilog of functions that need to save +// a number of non-volatile float point registers. +saveFP +restFP + +// PowerPC has a standard template for trampoline functions. This function +// generates a custom trampoline function with the specific realFunc +// and localsPtr values. +void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated, + const void* realFunc, void* localsPtr); + +// adds two 128-bit double-double precision values ( x + y ) +long double __gcc_qadd(long double x, long double y); + +// subtracts two 128-bit double-double precision values ( x - y ) +long double __gcc_qsub(long double x, long double y); + +// multiples two 128-bit double-double precision values ( x * y ) +long double __gcc_qmul(long double x, long double y); + +// divides two 128-bit double-double precision values ( x / y ) +long double __gcc_qdiv(long double a, long double b); + + +// ARM specific functions + +// There is no C interface to the switch* functions. These helper functions +// are only needed by Thumb1 code for efficient switch table generation. +switch16 +switch32 +switch8 +switchu8 + +// There is no C interface to the *_vfp_d8_d15_regs functions. There are +// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use +// SJLJ for exceptions, each function with a catch clause or destuctors needs +// to save and restore all registers in it prolog and epliog. But there is +// no way to access vector and high float registers from thumb1 code, so the +// compiler must add call outs to these helper functions in the prolog and +// epilog. +restore_vfp_d8_d15_regs +save_vfp_d8_d15_regs + + +// Note: long ago ARM processors did not have floating point hardware support. +// Floating point was done in software and floating point parameters were +// passed in integer registers. When hardware support was added for floating +// point, new *vfp functions were added to do the same operations but with +// floating point parameters in floating point registers. + +// Undocumented functions + +float __addsf3vfp(float a, float b); // Appears to return a + b +double __adddf3vfp(double a, double b); // Appears to return a + b +float __divsf3vfp(float a, float b); // Appears to return a / b +double __divdf3vfp(double a, double b); // Appears to return a / b +int __eqsf2vfp(float a, float b); // Appears to return one + // iff a == b and neither is NaN. +int __eqdf2vfp(double a, double b); // Appears to return one + // iff a == b and neither is NaN. +double __extendsfdf2vfp(float a); // Appears to convert from + // float to double. +int __fixdfsivfp(double a); // Appears to convert from + // double to int. +int __fixsfsivfp(float a); // Appears to convert from + // float to int. +unsigned int __fixunssfsivfp(float a); // Appears to convert from + // float to unsigned int. +unsigned int __fixunsdfsivfp(double a); // Appears to convert from + // double to unsigned int. +double __floatsidfvfp(int a); // Appears to convert from + // int to double. +float __floatsisfvfp(int a); // Appears to convert from + // int to float. +double __floatunssidfvfp(unsigned int a); // Appears to convert from + // unisgned int to double. +float __floatunssisfvfp(unsigned int a); // Appears to convert from + // unisgned int to float. +int __gedf2vfp(double a, double b); // Appears to return __gedf2 + // (a >= b) +int __gesf2vfp(float a, float b); // Appears to return __gesf2 + // (a >= b) +int __gtdf2vfp(double a, double b); // Appears to return __gtdf2 + // (a > b) +int __gtsf2vfp(float a, float b); // Appears to return __gtsf2 + // (a > b) +int __ledf2vfp(double a, double b); // Appears to return __ledf2 + // (a <= b) +int __lesf2vfp(float a, float b); // Appears to return __lesf2 + // (a <= b) +int __ltdf2vfp(double a, double b); // Appears to return __ltdf2 + // (a < b) +int __ltsf2vfp(float a, float b); // Appears to return __ltsf2 + // (a < b) +double __muldf3vfp(double a, double b); // Appears to return a * b +float __mulsf3vfp(float a, float b); // Appears to return a * b +int __nedf2vfp(double a, double b); // Appears to return __nedf2 + // (a != b) +double __negdf2vfp(double a); // Appears to return -a +float __negsf2vfp(float a); // Appears to return -a +float __negsf2vfp(float a); // Appears to return -a +double __subdf3vfp(double a, double b); // Appears to return a - b +float __subsf3vfp(float a, float b); // Appears to return a - b +float __truncdfsf2vfp(double a); // Appears to convert from + // double to float. +int __unorddf2vfp(double a, double b); // Appears to return __unorddf2 +int __unordsf2vfp(float a, float b); // Appears to return __unordsf2 + + +Preconditions are listed for each function at the definition when there are any. +Any preconditions reflect the specification at +http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc. + +Assumptions are listed in "int_lib.h", and in individual files. Where possible +assumptions are checked at compile time. diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake new file mode 100644 index 000000000000..b72a390af8cf --- /dev/null +++ b/cmake/ConfigureChecks.cmake @@ -0,0 +1,38 @@ +INCLUDE( CheckIncludeFile ) +INCLUDE( CheckFunctionExists ) +INCLUDE( CheckSymbolExists ) +INCLUDE( CheckCSourceCompiles ) + +SET( PACKAGE ${PACKAGE_NAME} ) +SET( VERSION ${PACKAGE_VERSION} ) + +SET( BINARYDIR ${CMAKE_BINARY_DIR} ) +SET( SOURCEDIR ${CMAKE_SOURCE_DIR} ) + +# HEADER FILES +CHECK_INCLUDE_FILE( sys/byteorder.h HAVE_SYS_BYTEORDER_H ) +CHECK_INCLUDE_FILE( AvailabilityMacros.h HAVE_AVAILABILITY_MACROS_H ) +CHECK_INCLUDE_FILE( TargetConditionals.h HAVE_TARGET_CONDITIONALS_H ) +CHECK_INCLUDE_FILE( libkern/OSAtomic.h HAVE_LIBKERN_OSATOMIC_H ) + +# FUNCTIONS +CHECK_FUNCTION_EXISTS( sysconf HAVE_SYSCONF ) +CHECK_SYMBOL_EXISTS( OSAtomicCompareAndSwapInt libkern/OSAtomic.h HAVE_OSATOMIC_COMPARE_AND_SWAP_INT ) +CHECK_SYMBOL_EXISTS( OSAtomicCompareAndSwapLong libkern/OSAtomic.h HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG ) + +# BUILTIN +CHECK_C_SOURCE_COMPILES( " +volatile int a; +int main(int argc, char *argv[]) { + (void)__sync_bool_compare_and_swap(&a, 1, 2); + return 0; +} +" HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT ) + +CHECK_C_SOURCE_COMPILES( " +volatile long a; +int main(int argc, char *argv[]) { + (void)__sync_bool_compare_and_swap(&a, 1, 2); + return 0; +} +" HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG ) diff --git a/cmake/Modules/DefineCompilerFlags.cmake b/cmake/Modules/DefineCompilerFlags.cmake new file mode 100644 index 000000000000..9e262b94bc4b --- /dev/null +++ b/cmake/Modules/DefineCompilerFlags.cmake @@ -0,0 +1,6 @@ +# Define compiler flags + +if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) + #ADD_DEFINITIONS( -Wall -W -Werror -pedantic ) + ADD_DEFINITIONS( -std=c99 -Wall -Wextra -W -pedantic -Wno-unused-parameter ) +endif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) diff --git a/cmake/Modules/MacroAddCheckTest.cmake b/cmake/Modules/MacroAddCheckTest.cmake new file mode 100644 index 000000000000..a13912188716 --- /dev/null +++ b/cmake/Modules/MacroAddCheckTest.cmake @@ -0,0 +1,12 @@ +# - macro_add_check_test(test_name test_source linklib1 ... linklibN) + +ENABLE_TESTING() +include(CTest) +set(CMAKE_C_FLAGS_PROFILING "-g -pg") + +macro (MACRO_ADD_CHECK_TEST _testName _testSource) + add_executable(${_testName} ${_testSource}) + target_link_libraries(${_testName} ${ARGN}) + get_target_property(_targetLocation ${_testName} LOCATION) + add_test(${_testName} ${_targetLocation}) +endmacro (MACRO_ADD_CHECK_TEST) diff --git a/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake new file mode 100644 index 000000000000..a0669365bf99 --- /dev/null +++ b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,18 @@ +# MACRO_ENSURE_OUT_OF_SOURCE_BUILD() + +macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage ) + +string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource ) +if( _insource ) + message( SEND_ERROR "${_errorMessage}" ) + message( FATAL_ERROR + "In-source builds are not allowed. + CMake would overwrite the makefiles distributed with Compiler-RT. + Please create a directory and run cmake from there, passing the path + to this source directory as the last argument. + This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. + Please delete them." + ) +endif( _insource ) + +endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD ) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake new file mode 100644 index 000000000000..307e277872ac --- /dev/null +++ b/cmake/config.h.cmake @@ -0,0 +1,12 @@ +#cmakedefine HAVE_SYS_BYTEORDER_H ${HAVE_SYS_BYTEORDER} +#cmakedefine HAVE_AVAILABILITY_MACROS_H ${HAVE_AVAILABILITY_MACROS_H} +#cmakedefine HAVE_TARGET_CONDITIONALS_H ${HAVE_TARGET_CONDITIONALS_H} +#cmakedefine HAVE_LIBKERN_OSATOMIC_H ${HAVE_LIBKERN_OSATOMIC_H} + +#cmakedefine HAVE_SYSCONF ${HAVE_SYSCONF} + +#cmakedefine HAVE_OSATOMIC_COMPARE_AND_SWAP_INT ${HAVE_OSATOMIC_COMPARE_AND_SWAP_INT} +#cmakedefine HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG ${HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG} + +#cmakedefine HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT ${HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT} +#cmakedefine HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG ${HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 000000000000..e29474a1da6d --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,81 @@ +# +# Create a library called "CompilerRT" which includes the source files. + +#INCLUDE_DIRECTORIES( +# ${CMAKE_CURRENT_BINARY_DIR} +#) + +# Generic functions needed for each architecture +# libcompiler_rt.Generic.a libcompiler_rt.Optimized.a + +# Generic +SET( Generic_SRCS + absvdi2.c absvsi2.c addvdi3.c addvsi3.c ashldi3.c ashrdi3.c + clzdi2.c clzsi2.c cmpdi2.c ctzdi2.c ctzsi2.c + divdc3.c divdi3.c divsc3.c ffsdi2.c + fixdfdi.c fixsfdi.c fixunsdfdi.c fixunsdfsi.c fixunssfdi.c + fixunssfsi.c floatdidf.c floatdisf.c floatundidf.c floatundisf.c + gcc_personality_v0.c lshrdi3.c moddi3.c muldc3.c muldi3.c + mulsc3.c mulvdi3.c mulvsi3.c negdi2.c negvdi2.c negvsi2.c + paritydi2.c paritysi2.c popcountdi2.c popcountsi2.c powidf2.c + powisf2.c subvdi3.c subvsi3.c ucmpdi2.c udivdi3.c + udivmoddi4.c umoddi3.c apple_versioning.c eprintf.c + ) + +# Optimized functions for each architecture + +# Commenting out for the min until the basics are working first. +# ADD_SUBDIRECTORY( ppc ) +# ADD_SUBDIRECTORY( x86_64 ) +# ADD_SUBDIRECTORY( i386 ) +# ADD_SUBDIRECTORY( arm ) + +# List of functions needed for each architecture. +SET( i386_Functions + divxc3.c fixunsxfdi.c fixunsxfsi.c fixxfdi.c floatdixf.c + floatundixf.c mulxc3.c powixf2.c clear_cache.c enable_execute_stack.c + ) + +SET( x86_64_Functions + absvti2.c addvti3.c ashlti3.c ashrti3.c clzti2.c cmpti2.c + ctzti2.c divti3.c divxc3.c ffsti2.c fixdfti.c fixsfti.c + fixunsdfti.c fixunssfti.c fixunsxfdi.c fixunsxfsi.c + fixunsxfti.c fixxfdi.c fixxfti.c floatdixf.c floattidf.c + floattisf.c floattixf.c floatundixf.c floatuntidf.c + floatuntisf.c floatuntixf.c lshrti3.c modti3.c multi3.c + mulvti3.c mulxc3.c negti2.c negvti2.c parityti2.c + popcountti2.c powixf2.c subvti3.c ucmpti2.c udivmodti4.c + udivti3.c umodti3.c clear_cache.c enable_execute_stack.c + ) + +SET( PPC_Functions + divtc3.c fixtfdi.c fixunstfdi.c floatditf.c floatunditf.c + gcc_qadd.c gcc_qdiv.c gcc_qmul.c gcc_qsub.c multc3.c + powitf2.c restFP.c saveFP.c trampoline_setup.c + clear_cache.c enable_execute_stack.c + ) + +SET( ARM_Functions + adddf3vfp.c addsf3vfp.c bswapdi2.c bswapsi2.c divdf3vfp.c + divsf3vfp.c eqdf2vfp.c eqsf2vfp.c extendsfdf2vfp.c + fixdfsivfp.c fixsfsivfp.c fixunsdfsivfp.c fixunssfsivfp.c + floatsidfvfp.c floatsisfvfp.c floatunssidfvfp.c floatunssisfvfp.c + gedf2vfp.c gesf2vfp.c gtdf2vfp.c gtsf2vfp.c + ledf2vfp.c lesf2vfp.c ltdf2vfp.c ltsf2vfp.c + muldf3vfp.c mulsf3vfp.c + nedf2vfp.c negdf2vfp.c negsf2vfp.c nesf2vfp.c + subdf3vfp.c subsf3vfp.c truncdfsf2vfp.c unorddf2vfp.c unordsf2vfp.c + modsi3.c umodsi3.c udivsi3.c divsi3.c switch.c + ) + +#FOREACH( LOOP_VAR ${Achitectures} ) +# See ARCHIVE_OUTPUT_DIRECTORY docs. +#${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${LOOP_VAR} +#ENDFOREACH + +ADD_LIBRARY( ${PROJECT_NAME}-Generic STATIC ${Generic_SRCS} ) +#ADD_LIBRARY( ${PROJECT_NAME}-i386 STATIC ${i386_Functions} ) + +# [[debug|optimized|general] +#TARGET_LINK_LIBRARIES( ${PROJECT_NAME} ${PROJECT_NAME}-Common optimized ${PROJECT_NAME}-i386 ) + diff --git a/lib/Makefile.mk b/lib/Makefile.mk new file mode 100644 index 000000000000..1ed8c11a08ba --- /dev/null +++ b/lib/Makefile.mk @@ -0,0 +1,17 @@ +#===- lib/Makefile.mk --------------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +SubDirs := i386 ppc x86_64 arm + +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) +Implementation := Generic + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard $(Dir)/*.h) diff --git a/lib/absvdi2.c b/lib/absvdi2.c new file mode 100644 index 000000000000..919afd1351d3 --- /dev/null +++ b/lib/absvdi2.c @@ -0,0 +1,30 @@ +/*===-- absvdi2.c - Implement __absvdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * This file implements __absvdi2 for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: absolute value */ + +/* Effects: aborts if abs(x) < 0 */ + +di_int +__absvdi2(di_int a) +{ + const int N = (int)(sizeof(di_int) * CHAR_BIT); + if (a == ((di_int)1 << (N-1))) + compilerrt_abort(); + const di_int t = a >> (N - 1); + return (a ^ t) - t; +} diff --git a/lib/absvsi2.c b/lib/absvsi2.c new file mode 100644 index 000000000000..a2c8e3f19052 --- /dev/null +++ b/lib/absvsi2.c @@ -0,0 +1,30 @@ +/* ===-- absvsi2.c - Implement __absvsi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __absvsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: absolute value */ + +/* Effects: aborts if abs(x) < 0 */ + +si_int +__absvsi2(si_int a) +{ + const int N = (int)(sizeof(si_int) * CHAR_BIT); + if (a == (1 << (N-1))) + compilerrt_abort(); + const si_int t = a >> (N - 1); + return (a ^ t) - t; +} diff --git a/lib/absvti2.c b/lib/absvti2.c new file mode 100644 index 000000000000..0978122dceef --- /dev/null +++ b/lib/absvti2.c @@ -0,0 +1,34 @@ +/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __absvti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: absolute value */ + +/* Effects: aborts if abs(x) < 0 */ + +ti_int +__absvti2(ti_int a) +{ + const int N = (int)(sizeof(ti_int) * CHAR_BIT); + if (a == ((ti_int)1 << (N-1))) + compilerrt_abort(); + const ti_int s = a >> (N - 1); + return (a ^ s) - s; +} + +#endif diff --git a/lib/adddf3.c b/lib/adddf3.c new file mode 100644 index 000000000000..1ec43dcf58e2 --- /dev/null +++ b/lib/adddf3.c @@ -0,0 +1,154 @@ +//===-- lib/adddf3.c - Double-precision addition and subtraction --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float addition and subtraction +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t __adddf3(fp_t a, fp_t b) { + + rep_t aRep = toRep(a); + rep_t bRep = toRep(b); + const rep_t aAbs = aRep & absMask; + const rep_t bAbs = bRep & absMask; + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) { + + // NaN + anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep); + // +/-infinity + anything remaining = +/- infinity + else return a; + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (!aAbs) { + // but we need to get the sign right for zero + zero + if (!bAbs) return fromRep(toRep(a) & toRep(b)); + else return b; + } + + // anything + zero = anything + if (!bAbs) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const rep_t temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + int aExponent = aRep >> significandBits & maxExponent; + int bExponent = bRep >> significandBits & maxExponent; + rep_t aSignificand = aRep & significandMask; + rep_t bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(&aSignificand); + if (bExponent == 0) bExponent = normalize(&bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const rep_t resultSign = aRep & signBit; + const bool subtraction = (aRep ^ bRep) & signBit; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | implicitBit) << 3; + bSignificand = (bSignificand | implicitBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const int align = aExponent - bExponent; + if (align) { + if (align < typeWidth) { + const bool sticky = bSignificand << (typeWidth - align); + bSignificand = bSignificand >> align | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + + if (subtraction) { + aSignificand -= bSignificand; + + // If a == -b, return +zero. + if (aSignificand == 0) return fromRep(0); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < implicitBit << 3) { + const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); + aSignificand <<= shift; + aExponent -= shift; + } + } + + else /* addition */ { + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & implicitBit << 4) { + const bool sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return fromRep(infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + const int shift = 1 - aExponent; + const bool sticky = aSignificand << (typeWidth - shift); + aSignificand = aSignificand >> shift | sticky; + aExponent = 0; + } + + // Low three bits are round, guard, and sticky. + const int roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + rep_t result = aSignificand >> 3 & significandMask; + + // Insert the exponent and sign. + result |= (rep_t)aExponent << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result++; + if (roundGuardSticky == 0x4) result += result & 1; + return fromRep(result); +} + +// Subtraction; flip the sign bit of b and add. +fp_t __subdf3(fp_t a, fp_t b) { + return __adddf3(a, fromRep(toRep(b) ^ signBit)); +} diff --git a/lib/addsf3.c b/lib/addsf3.c new file mode 100644 index 000000000000..fec14e838518 --- /dev/null +++ b/lib/addsf3.c @@ -0,0 +1,164 @@ +//===-- lib/addsf3.c - Single-precision addition and subtraction --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float addition and subtraction +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __addsf3(fp_t a, fp_t b) { + + rep_t aRep = toRep(a); + rep_t bRep = toRep(b); + const rep_t aAbs = aRep & absMask; + const rep_t bAbs = bRep & absMask; + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) { + + // NaN + anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep); + // +/-infinity + anything remaining = +/- infinity + else return a; + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (!aAbs) { + // but we need to get the sign right for zero + zero + if (!bAbs) return fromRep(toRep(a) & toRep(b)); + else return b; + } + + // anything + zero = anything + if (!bAbs) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const rep_t temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + int aExponent = aRep >> significandBits & maxExponent; + int bExponent = bRep >> significandBits & maxExponent; + rep_t aSignificand = aRep & significandMask; + rep_t bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(&aSignificand); + if (bExponent == 0) bExponent = normalize(&bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const rep_t resultSign = aRep & signBit; + const bool subtraction = (aRep ^ bRep) & signBit; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | implicitBit) << 3; + bSignificand = (bSignificand | implicitBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const int align = aExponent - bExponent; + if (align) { + if (align < typeWidth) { + const bool sticky = bSignificand << (typeWidth - align); + bSignificand = bSignificand >> align | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + + if (subtraction) { + aSignificand -= bSignificand; + + // If a == -b, return +zero. + if (aSignificand == 0) return fromRep(0); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < implicitBit << 3) { + const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); + aSignificand <<= shift; + aExponent -= shift; + } + } + + else /* addition */ { + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & implicitBit << 4) { + const bool sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return fromRep(infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + const int shift = 1 - aExponent; + const bool sticky = aSignificand << (typeWidth - shift); + aSignificand = aSignificand >> shift | sticky; + aExponent = 0; + } + + // Low three bits are round, guard, and sticky. + const int roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + rep_t result = aSignificand >> 3 & significandMask; + + // Insert the exponent and sign. + result |= (rep_t)aExponent << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result++; + if (roundGuardSticky == 0x4) result += result & 1; + return fromRep(result); +} + +// Subtraction; flip the sign bit of b and add. +fp_t __subsf3(fp_t a, fp_t b) { + return __addsf3(a, fromRep(toRep(b) ^ signBit)); +} + + + + + + + + + + diff --git a/lib/addvdi3.c b/lib/addvdi3.c new file mode 100644 index 000000000000..53ab1024bd6f --- /dev/null +++ b/lib/addvdi3.c @@ -0,0 +1,37 @@ +/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __addvdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: a + b */ + +/* Effects: aborts if a + b overflows */ + +di_int +__addvdi3(di_int a, di_int b) +{ + di_int s = a + b; + if (b >= 0) + { + if (s < a) + compilerrt_abort(); + } + else + { + if (s >= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/addvsi3.c b/lib/addvsi3.c new file mode 100644 index 000000000000..22cd3154ce6c --- /dev/null +++ b/lib/addvsi3.c @@ -0,0 +1,37 @@ +/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __addvsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: a + b */ + +/* Effects: aborts if a + b overflows */ + +si_int +__addvsi3(si_int a, si_int b) +{ + si_int s = a + b; + if (b >= 0) + { + if (s < a) + compilerrt_abort(); + } + else + { + if (s >= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/addvti3.c b/lib/addvti3.c new file mode 100644 index 000000000000..3df1a742ce33 --- /dev/null +++ b/lib/addvti3.c @@ -0,0 +1,41 @@ +/* ===-- addvti3.c - Implement __addvti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __addvti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: a + b */ + +/* Effects: aborts if a + b overflows */ + +ti_int +__addvti3(ti_int a, ti_int b) +{ + ti_int s = a + b; + if (b >= 0) + { + if (s < a) + compilerrt_abort(); + } + else + { + if (s >= a) + compilerrt_abort(); + } + return s; +} + +#endif diff --git a/lib/apple_versioning.c b/lib/apple_versioning.c new file mode 100644 index 000000000000..0360026bceed --- /dev/null +++ b/lib/apple_versioning.c @@ -0,0 +1,150 @@ +/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + + + +#if __APPLE__ + #if __arm__ + #define NOT_HERE_BEFORE_10_6(sym) + #elif __ppc__ + #define NOT_HERE_BEFORE_10_6(sym) \ + extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; + #else + #define NOT_HERE_BEFORE_10_6(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; + #endif /* __ppc__ */ + + +/* Symbols in libSystem.dylib in 10.6 and later, + * but are in libgcc_s.dylib in earlier versions + */ + +NOT_HERE_BEFORE_10_6(__absvdi2) +NOT_HERE_BEFORE_10_6(__absvsi2) +NOT_HERE_BEFORE_10_6(__absvti2) +NOT_HERE_BEFORE_10_6(__addvdi3) +NOT_HERE_BEFORE_10_6(__addvsi3) +NOT_HERE_BEFORE_10_6(__addvti3) +NOT_HERE_BEFORE_10_6(__ashldi3) +NOT_HERE_BEFORE_10_6(__ashlti3) +NOT_HERE_BEFORE_10_6(__ashrdi3) +NOT_HERE_BEFORE_10_6(__ashrti3) +NOT_HERE_BEFORE_10_6(__clear_cache) +NOT_HERE_BEFORE_10_6(__clzdi2) +NOT_HERE_BEFORE_10_6(__clzsi2) +NOT_HERE_BEFORE_10_6(__clzti2) +NOT_HERE_BEFORE_10_6(__cmpdi2) +NOT_HERE_BEFORE_10_6(__cmpti2) +NOT_HERE_BEFORE_10_6(__ctzdi2) +NOT_HERE_BEFORE_10_6(__ctzsi2) +NOT_HERE_BEFORE_10_6(__ctzti2) +NOT_HERE_BEFORE_10_6(__divdc3) +NOT_HERE_BEFORE_10_6(__divdi3) +NOT_HERE_BEFORE_10_6(__divsc3) +NOT_HERE_BEFORE_10_6(__divtc3) +NOT_HERE_BEFORE_10_6(__divti3) +NOT_HERE_BEFORE_10_6(__divxc3) +NOT_HERE_BEFORE_10_6(__enable_execute_stack) +NOT_HERE_BEFORE_10_6(__ffsdi2) +NOT_HERE_BEFORE_10_6(__ffsti2) +NOT_HERE_BEFORE_10_6(__fixdfdi) +NOT_HERE_BEFORE_10_6(__fixdfti) +NOT_HERE_BEFORE_10_6(__fixsfdi) +NOT_HERE_BEFORE_10_6(__fixsfti) +NOT_HERE_BEFORE_10_6(__fixtfdi) +NOT_HERE_BEFORE_10_6(__fixunsdfdi) +NOT_HERE_BEFORE_10_6(__fixunsdfsi) +NOT_HERE_BEFORE_10_6(__fixunsdfti) +NOT_HERE_BEFORE_10_6(__fixunssfdi) +NOT_HERE_BEFORE_10_6(__fixunssfsi) +NOT_HERE_BEFORE_10_6(__fixunssfti) +NOT_HERE_BEFORE_10_6(__fixunstfdi) +NOT_HERE_BEFORE_10_6(__fixunsxfdi) +NOT_HERE_BEFORE_10_6(__fixunsxfsi) +NOT_HERE_BEFORE_10_6(__fixunsxfti) +NOT_HERE_BEFORE_10_6(__fixxfdi) +NOT_HERE_BEFORE_10_6(__fixxfti) +NOT_HERE_BEFORE_10_6(__floatdidf) +NOT_HERE_BEFORE_10_6(__floatdisf) +NOT_HERE_BEFORE_10_6(__floatditf) +NOT_HERE_BEFORE_10_6(__floatdixf) +NOT_HERE_BEFORE_10_6(__floattidf) +NOT_HERE_BEFORE_10_6(__floattisf) +NOT_HERE_BEFORE_10_6(__floattixf) +NOT_HERE_BEFORE_10_6(__floatundidf) +NOT_HERE_BEFORE_10_6(__floatundisf) +NOT_HERE_BEFORE_10_6(__floatunditf) +NOT_HERE_BEFORE_10_6(__floatundixf) +NOT_HERE_BEFORE_10_6(__floatuntidf) +NOT_HERE_BEFORE_10_6(__floatuntisf) +NOT_HERE_BEFORE_10_6(__floatuntixf) +NOT_HERE_BEFORE_10_6(__gcc_personality_v0) +NOT_HERE_BEFORE_10_6(__lshrdi3) +NOT_HERE_BEFORE_10_6(__lshrti3) +NOT_HERE_BEFORE_10_6(__moddi3) +NOT_HERE_BEFORE_10_6(__modti3) +NOT_HERE_BEFORE_10_6(__muldc3) +NOT_HERE_BEFORE_10_6(__muldi3) +NOT_HERE_BEFORE_10_6(__mulsc3) +NOT_HERE_BEFORE_10_6(__multc3) +NOT_HERE_BEFORE_10_6(__multi3) +NOT_HERE_BEFORE_10_6(__mulvdi3) +NOT_HERE_BEFORE_10_6(__mulvsi3) +NOT_HERE_BEFORE_10_6(__mulvti3) +NOT_HERE_BEFORE_10_6(__mulxc3) +NOT_HERE_BEFORE_10_6(__negdi2) +NOT_HERE_BEFORE_10_6(__negti2) +NOT_HERE_BEFORE_10_6(__negvdi2) +NOT_HERE_BEFORE_10_6(__negvsi2) +NOT_HERE_BEFORE_10_6(__negvti2) +NOT_HERE_BEFORE_10_6(__paritydi2) +NOT_HERE_BEFORE_10_6(__paritysi2) +NOT_HERE_BEFORE_10_6(__parityti2) +NOT_HERE_BEFORE_10_6(__popcountdi2) +NOT_HERE_BEFORE_10_6(__popcountsi2) +NOT_HERE_BEFORE_10_6(__popcountti2) +NOT_HERE_BEFORE_10_6(__powidf2) +NOT_HERE_BEFORE_10_6(__powisf2) +NOT_HERE_BEFORE_10_6(__powitf2) +NOT_HERE_BEFORE_10_6(__powixf2) +NOT_HERE_BEFORE_10_6(__subvdi3) +NOT_HERE_BEFORE_10_6(__subvsi3) +NOT_HERE_BEFORE_10_6(__subvti3) +NOT_HERE_BEFORE_10_6(__ucmpdi2) +NOT_HERE_BEFORE_10_6(__ucmpti2) +NOT_HERE_BEFORE_10_6(__udivdi3) +NOT_HERE_BEFORE_10_6(__udivmoddi4) +NOT_HERE_BEFORE_10_6(__udivmodti4) +NOT_HERE_BEFORE_10_6(__udivti3) +NOT_HERE_BEFORE_10_6(__umoddi3) +NOT_HERE_BEFORE_10_6(__umodti3) + + +#if __ppc__ +NOT_HERE_BEFORE_10_6(__gcc_qadd) +NOT_HERE_BEFORE_10_6(__gcc_qdiv) +NOT_HERE_BEFORE_10_6(__gcc_qmul) +NOT_HERE_BEFORE_10_6(__gcc_qsub) +NOT_HERE_BEFORE_10_6(__trampoline_setup) +#endif /* __ppc__ */ + +#else /* !__APPLE__ */ + +extern int avoid_empty_file; + +#endif /* !__APPLE__*/ diff --git a/lib/arm/CMakeLists.txt b/lib/arm/CMakeLists.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/arm/Makefile.mk b/lib/arm/Makefile.mk new file mode 100644 index 000000000000..cde97c3f99ae --- /dev/null +++ b/lib/arm/Makefile.mk @@ -0,0 +1,19 @@ +#===- lib/arm/Makefile.mk ----------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +SubDirs := +OnlyArchs := armv5 armv6 armv7 + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/arm/adddf3vfp.S b/lib/arm/adddf3vfp.S new file mode 100644 index 000000000000..5e705e3c5796 --- /dev/null +++ b/lib/arm/adddf3vfp.S @@ -0,0 +1,24 @@ +//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// double __adddf3vfp(double a, double b) { return a + b; } +// +// Adds two double precision floating point numbers using the Darwin +// calling convention where double arguments are passsed in GPR pairs +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__adddf3vfp) + fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6 + fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7 + faddd d6, d6, d7 + fmrrd r0, r1, d6 // move result back to r0/r1 pair + bx lr diff --git a/lib/arm/addsf3vfp.S b/lib/arm/addsf3vfp.S new file mode 100644 index 000000000000..36d509c1f52b --- /dev/null +++ b/lib/arm/addsf3vfp.S @@ -0,0 +1,24 @@ +//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __addsf3vfp(float a, float b); +// +// Adds two single precision floating point numbers using the Darwin +// calling convention where single arguments are passsed in GPRs +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__addsf3vfp) + fmsr s14, r0 // move first param from r0 into float register + fmsr s15, r1 // move second param from r1 into float register + fadds s14, s14, s15 + fmrs r0, s14 // move result back to r0 + bx lr diff --git a/lib/arm/bswapdi2.S b/lib/arm/bswapdi2.S new file mode 100644 index 000000000000..d3ca33a341c7 --- /dev/null +++ b/lib/arm/bswapdi2.S @@ -0,0 +1,36 @@ +//===------- bswapdi2 - Implement bswapdi2 --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern uint64_t __bswapdi2(uint64_t); +// +// Reverse all the bytes in a 64-bit integer. +// +.align 2 +DEFINE_COMPILERRT_FUNCTION(__bswapdi2) +#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__ + // before armv6 does not have "rev" instruction + // r2 = rev(r0) + eor r2, r0, r0, ror #16 + bic r2, r2, #0xff0000 + mov r2, r2, lsr #8 + eor r2, r2, r0, ror #8 + // r0 = rev(r1) + eor r0, r1, r1, ror #16 + bic r0, r0, #0xff0000 + mov r0, r0, lsr #8 + eor r0, r0, r1, ror #8 +#else + rev r2, r0 // r2 = rev(r0) + rev r0, r1 // r0 = rev(r1) +#endif + mov r1, r2 // r1 = r2 = rev(r0) + bx lr diff --git a/lib/arm/bswapsi2.S b/lib/arm/bswapsi2.S new file mode 100644 index 000000000000..0a0c073706ce --- /dev/null +++ b/lib/arm/bswapsi2.S @@ -0,0 +1,28 @@ +//===------- bswapsi2 - Implement bswapsi2 --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern uint32_t __bswapsi2(uint32_t); +// +// Reverse all the bytes in a 32-bit integer. +// +.align 2 +DEFINE_COMPILERRT_FUNCTION(__bswapsi2) +#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__ + // before armv6 does not have "rev" instruction + eor r1, r0, r0, ror #16 + bic r1, r1, #0xff0000 + mov r1, r1, lsr #8 + eor r0, r1, r0, ror #8 +#else + rev r0, r0 +#endif + bx lr diff --git a/lib/arm/comparesf2.S b/lib/arm/comparesf2.S new file mode 100644 index 000000000000..f21e0bcd13f6 --- /dev/null +++ b/lib/arm/comparesf2.S @@ -0,0 +1,130 @@ +//===-- comparesf2.S - Implement single-precision soft-float comparisons --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the following soft-fp_t comparison routines: +// +// __eqsf2 __gesf2 __unordsf2 +// __lesf2 __gtsf2 +// __ltsf2 +// __nesf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, with multiple names. +// +// The routines behave as follows: +// +// __lesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unordsf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +.syntax unified + +.align 2 +DEFINE_COMPILERRT_FUNCTION(__eqsf2) +DEFINE_COMPILERRT_FUNCTION(__lesf2) +DEFINE_COMPILERRT_FUNCTION(__ltsf2) +DEFINE_COMPILERRT_FUNCTION(__nesf2) + // Make copies of a and b with the sign bit shifted off the top. These will + // be used to detect zeros and NaNs. + mov r2, r0, lsl #1 + mov r3, r1, lsl #1 + + // We do the comparison in three stages (ignoring NaN values for the time + // being). First, we orr the absolute values of a and b; this sets the Z + // flag if both a and b are zero (of either sign). The shift of r3 doesn't + // effect this at all, but it *does* make sure that the C flag is clear for + // the subsequent operations. + orrs r12, r2, r3, lsr #1 + + // Next, we check if a and b have the same or different signs. If they have + // opposite signs, this eor will set the N flag. + eorsne r12, r0, r1 + + // If a and b are equal (either both zeros or bit identical; again, we're + // ignoring NaNs for now), this subtract will zero out r0. If they have the + // same sign, the flags are updated as they would be for a comparison of the + // absolute values of a and b. + subspl r0, r2, r3 + + // If a is smaller in magnitude than b and both have the same sign, place + // the negation of the sign of b in r0. Thus, if both are negative and + // a > b, this sets r0 to 0; if both are positive and a < b, this sets + // r0 to -1. + // + // This is also done if a and b have opposite signs and are not both zero, + // because in that case the subtract was not performed and the C flag is + // still clear from the shift argument in orrs; if a is positive and b + // negative, this places 0 in r0; if a is negative and b positive, -1 is + // placed in r0. + mvnlo r0, r1, asr #31 + + // If a is greater in magnitude than b and both have the same sign, place + // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed + // in r0, which is the desired result. Conversely, if both are positive + // and a > b, zero is placed in r0. + movhi r0, r1, asr #31 + + // If you've been keeping track, at this point r0 contains -1 if a < b and + // 0 if a >= b. All that remains to be done is to set it to 1 if a > b. + // If a == b, then the Z flag is set, so we can get the correct final value + // into r0 by simply or'ing with 1 if Z is clear. + orrne r0, r0, #1 + + // Finally, we need to deal with NaNs. If either argument is NaN, replace + // the value in r0 with 1. + cmp r2, #0xff000000 + cmpls r3, #0xff000000 + movhi r0, #1 + bx lr + +.align 2 +DEFINE_COMPILERRT_FUNCTION(__gesf2) +DEFINE_COMPILERRT_FUNCTION(__gtsf2) + // Identical to the preceeding except in that we return -1 for NaN values. + // Given that the two paths share so much code, one might be tempted to + // unify them; however, the extra code needed to do so makes the code size + // to performance tradeoff very hard to justify for such small functions. + mov r2, r0, lsl #1 + mov r3, r1, lsl #1 + orrs r12, r2, r3, lsr #1 + eorsne r12, r0, r1 + subspl r0, r2, r3 + mvnlo r0, r1, asr #31 + movhi r0, r1, asr #31 + orrne r0, r0, #1 + cmp r2, #0xff000000 + cmpls r3, #0xff000000 + movhi r0, #-1 + bx lr + +.align 2 +DEFINE_COMPILERRT_FUNCTION(__unordsf2) + // Return 1 for NaN values, 0 otherwise. + mov r2, r0, lsl #1 + mov r3, r1, lsl #1 + mov r0, #0 + cmp r2, #0xff000000 + cmpls r3, #0xff000000 + movhi r0, #1 + bx lr diff --git a/lib/arm/divdf3vfp.S b/lib/arm/divdf3vfp.S new file mode 100644 index 000000000000..e43baa373274 --- /dev/null +++ b/lib/arm/divdf3vfp.S @@ -0,0 +1,24 @@ +//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __divdf3vfp(double a, double b); +// +// Divides two double precision floating point numbers using the Darwin +// calling convention where double arguments are passsed in GPR pairs +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__divdf3vfp) + fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6 + fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7 + fdivd d5, d6, d7 + fmrrd r0, r1, d5 // move result back to r0/r1 pair + bx lr diff --git a/lib/arm/divsf3vfp.S b/lib/arm/divsf3vfp.S new file mode 100644 index 000000000000..d96c930f8352 --- /dev/null +++ b/lib/arm/divsf3vfp.S @@ -0,0 +1,24 @@ +//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __divsf3vfp(float a, float b); +// +// Divides two single precision floating point numbers using the Darwin +// calling convention where single arguments are passsed like 32-bit ints. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__divsf3vfp) + fmsr s14, r0 // move first param from r0 into float register + fmsr s15, r1 // move second param from r1 into float register + fdivs s13, s14, s15 + fmrs r0, s13 // move result back to r0 + bx lr diff --git a/lib/arm/eqdf2vfp.S b/lib/arm/eqdf2vfp.S new file mode 100644 index 000000000000..d4384ec0e5ea --- /dev/null +++ b/lib/arm/eqdf2vfp.S @@ -0,0 +1,27 @@ +//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __eqdf2vfp(double a, double b); +// +// Returns one iff a == b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + moveq r0, #1 // set result register to 1 if equal + movne r0, #0 + bx lr diff --git a/lib/arm/eqsf2vfp.S b/lib/arm/eqsf2vfp.S new file mode 100644 index 000000000000..07355a3c2239 --- /dev/null +++ b/lib/arm/eqsf2vfp.S @@ -0,0 +1,28 @@ +//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __eqsf2vfp(float a, float b); +// +// Returns one iff a == b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + moveq r0, #1 // set result register to 1 if equal + movne r0, #0 + bx lr + diff --git a/lib/arm/extendsfdf2vfp.S b/lib/arm/extendsfdf2vfp.S new file mode 100644 index 000000000000..4343a7ef1ed4 --- /dev/null +++ b/lib/arm/extendsfdf2vfp.S @@ -0,0 +1,24 @@ +//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __extendsfdf2vfp(float a); +// +// Converts single precision float to double precision result. +// Uses Darwin calling convention where a single precision parameter is +// passed in a GPR and a double precision result is returned in R0/R1 pair. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp) + fmsr s15, r0 // load float register from R0 + fcvtds d7, s15 // convert single to double + fmrrd r0, r1, d7 // return result in r0/r1 pair + bx lr diff --git a/lib/arm/fixdfsivfp.S b/lib/arm/fixdfsivfp.S new file mode 100644 index 000000000000..30458ccd59b3 --- /dev/null +++ b/lib/arm/fixdfsivfp.S @@ -0,0 +1,24 @@ +//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __fixdfsivfp(double a); +// +// Converts double precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a double precision parameter is +// passed in GPR register pair. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp) + fmdrr d7, r0, r1 // load double register from R0/R1 + ftosizd s15, d7 // convert double to 32-bit int into s15 + fmrs r0, s15 // move s15 to result register + bx lr diff --git a/lib/arm/fixsfsivfp.S b/lib/arm/fixsfsivfp.S new file mode 100644 index 000000000000..ce6f18e1b90c --- /dev/null +++ b/lib/arm/fixsfsivfp.S @@ -0,0 +1,24 @@ +//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __fixsfsivfp(float a); +// +// Converts single precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a single precision parameter is +// passed in a GPR.. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp) + fmsr s15, r0 // load float register from R0 + ftosizs s15, s15 // convert single to 32-bit int into s15 + fmrs r0, s15 // move s15 to result register + bx lr diff --git a/lib/arm/fixunsdfsivfp.S b/lib/arm/fixunsdfsivfp.S new file mode 100644 index 000000000000..7e766c02a5e8 --- /dev/null +++ b/lib/arm/fixunsdfsivfp.S @@ -0,0 +1,25 @@ +//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern unsigned int __fixunsdfsivfp(double a); +// +// Converts double precision float to a 32-bit unsigned int rounding towards +// zero. All negative values become zero. +// Uses Darwin calling convention where a double precision parameter is +// passed in GPR register pair. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp) + fmdrr d7, r0, r1 // load double register from R0/R1 + ftouizd s15, d7 // convert double to 32-bit int into s15 + fmrs r0, s15 // move s15 to result register + bx lr diff --git a/lib/arm/fixunssfsivfp.S b/lib/arm/fixunssfsivfp.S new file mode 100644 index 000000000000..ba2344f587e7 --- /dev/null +++ b/lib/arm/fixunssfsivfp.S @@ -0,0 +1,25 @@ +//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern unsigned int __fixunssfsivfp(float a); +// +// Converts single precision float to a 32-bit unsigned int rounding towards +// zero. All negative values become zero. +// Uses Darwin calling convention where a single precision parameter is +// passed in a GPR.. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp) + fmsr s15, r0 // load float register from R0 + ftouizs s15, s15 // convert single to 32-bit unsigned into s15 + fmrs r0, s15 // move s15 to result register + bx lr diff --git a/lib/arm/floatsidfvfp.S b/lib/arm/floatsidfvfp.S new file mode 100644 index 000000000000..5ed4ace9b2c0 --- /dev/null +++ b/lib/arm/floatsidfvfp.S @@ -0,0 +1,24 @@ +//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __floatsidfvfp(int a); +// +// Converts a 32-bit int to a double precision float. +// Uses Darwin calling convention where a double precision result is +// return in GPR register pair. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp) + fmsr s15, r0 // move int to float register s15 + fsitod d7, s15 // convert 32-bit int in s15 to double in d7 + fmrrd r0, r1, d7 // move d7 to result register pair r0/r1 + bx lr diff --git a/lib/arm/floatsisfvfp.S b/lib/arm/floatsisfvfp.S new file mode 100644 index 000000000000..0114c789358a --- /dev/null +++ b/lib/arm/floatsisfvfp.S @@ -0,0 +1,24 @@ +//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __floatsisfvfp(int a); +// +// Converts single precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a single precision result is +// return in a GPR.. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp) + fmsr s15, r0 // move int to float register s15 + fsitos s15, s15 // convert 32-bit int in s15 to float in s15 + fmrs r0, s15 // move s15 to result register + bx lr diff --git a/lib/arm/floatunssidfvfp.S b/lib/arm/floatunssidfvfp.S new file mode 100644 index 000000000000..d1bfe3af5841 --- /dev/null +++ b/lib/arm/floatunssidfvfp.S @@ -0,0 +1,24 @@ +//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __floatunssidfvfp(unsigned int a); +// +// Converts a 32-bit int to a double precision float. +// Uses Darwin calling convention where a double precision result is +// return in GPR register pair. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp) + fmsr s15, r0 // move int to float register s15 + fuitod d7, s15 // convert 32-bit int in s15 to double in d7 + fmrrd r0, r1, d7 // move d7 to result register pair r0/r1 + bx lr diff --git a/lib/arm/floatunssisfvfp.S b/lib/arm/floatunssisfvfp.S new file mode 100644 index 000000000000..0b73577b1067 --- /dev/null +++ b/lib/arm/floatunssisfvfp.S @@ -0,0 +1,24 @@ +//===-- floatunssisfvfp.S - Implement floatunssisfvfp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __floatunssisfvfp(unsigned int a); +// +// Converts single precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a single precision result is +// return in a GPR.. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp) + fmsr s15, r0 // move int to float register s15 + fuitos s15, s15 // convert 32-bit int in s15 to float in s15 + fmrs r0, s15 // move s15 to result register + bx lr diff --git a/lib/arm/gedf2vfp.S b/lib/arm/gedf2vfp.S new file mode 100644 index 000000000000..6ab856fe6f34 --- /dev/null +++ b/lib/arm/gedf2vfp.S @@ -0,0 +1,27 @@ +//===-- gedf2vfp.S - Implement gedf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __gedf2vfp(double a, double b); +// +// Returns one iff a >= b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gedf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + movge r0, #1 // set result register to 1 if greater than or equal + movlt r0, #0 + bx lr diff --git a/lib/arm/gesf2vfp.S b/lib/arm/gesf2vfp.S new file mode 100644 index 000000000000..b00d82107dc3 --- /dev/null +++ b/lib/arm/gesf2vfp.S @@ -0,0 +1,28 @@ +//===-- gesf2vfp.S - Implement gesf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __gesf2vfp(float a, float b); +// +// Returns one iff a >= b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gesf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + movge r0, #1 // set result register to 1 if greater than or equal + movlt r0, #0 + bx lr + diff --git a/lib/arm/gtdf2vfp.S b/lib/arm/gtdf2vfp.S new file mode 100644 index 000000000000..65594c7d3f92 --- /dev/null +++ b/lib/arm/gtdf2vfp.S @@ -0,0 +1,27 @@ +//===-- gtdf2vfp.S - Implement gtdf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __gtdf2vfp(double a, double b); +// +// Returns one iff a > b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + movgt r0, #1 // set result register to 1 if equal + movle r0, #0 + bx lr diff --git a/lib/arm/gtsf2vfp.S b/lib/arm/gtsf2vfp.S new file mode 100644 index 000000000000..53ef2a00f804 --- /dev/null +++ b/lib/arm/gtsf2vfp.S @@ -0,0 +1,28 @@ +//===-- gtsf2vfp.S - Implement gtsf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __gtsf2vfp(float a, float b); +// +// Returns one iff a > b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + movgt r0, #1 // set result register to 1 if equal + movle r0, #0 + bx lr + diff --git a/lib/arm/ledf2vfp.S b/lib/arm/ledf2vfp.S new file mode 100644 index 000000000000..327a7d5159f7 --- /dev/null +++ b/lib/arm/ledf2vfp.S @@ -0,0 +1,27 @@ +//===-- ledf2vfp.S - Implement ledf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __ledf2vfp(double a, double b); +// +// Returns one iff a <= b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__ledf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + movls r0, #1 // set result register to 1 if equal + movhi r0, #0 + bx lr diff --git a/lib/arm/lesf2vfp.S b/lib/arm/lesf2vfp.S new file mode 100644 index 000000000000..b7e05da9b42b --- /dev/null +++ b/lib/arm/lesf2vfp.S @@ -0,0 +1,28 @@ +//===-- lesf2vfp.S - Implement lesf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __lesf2vfp(float a, float b); +// +// Returns one iff a <= b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__lesf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + movls r0, #1 // set result register to 1 if equal + movhi r0, #0 + bx lr + diff --git a/lib/arm/ltdf2vfp.S b/lib/arm/ltdf2vfp.S new file mode 100644 index 000000000000..55dfd808a3b8 --- /dev/null +++ b/lib/arm/ltdf2vfp.S @@ -0,0 +1,27 @@ +//===-- ltdf2vfp.S - Implement ltdf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __ltdf2vfp(double a, double b); +// +// Returns one iff a < b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + movmi r0, #1 // set result register to 1 if equal + movpl r0, #0 + bx lr diff --git a/lib/arm/ltsf2vfp.S b/lib/arm/ltsf2vfp.S new file mode 100644 index 000000000000..3816a7123a64 --- /dev/null +++ b/lib/arm/ltsf2vfp.S @@ -0,0 +1,28 @@ +//===-- ltsf2vfp.S - Implement ltsf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __ltsf2vfp(float a, float b); +// +// Returns one iff a < b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + movmi r0, #1 // set result register to 1 if equal + movpl r0, #0 + bx lr + diff --git a/lib/arm/modsi3.S b/lib/arm/modsi3.S new file mode 100644 index 000000000000..64a3afd9aa06 --- /dev/null +++ b/lib/arm/modsi3.S @@ -0,0 +1,36 @@ +//===-------- modsi3.S - Implement modsi3 ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int32_t __modsi3(int32_t a, int32_t b); +// +// Returns the remainder when dividing two 32-bit signed integers. +// Conceptually, the function is: { return a - (a / b) * b; } +// But if you write that in C, llvm compiles it to a call to __modsi3... +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__modsi3) + push {r4, r5, r7, lr} + add r7, sp, #8 // set stack frame + mov r5, r0 // save a + mov r4, r1 // save b + bl ___divsi3 // compute a/b +#if __ARM_ARCH_7A__ + mls r0, r4, r0, r5 // mulitple result * b and subtract from a +#else + // before armv7, does not have "mls" instruction + mul r3, r0, r4 // multiple result * b + sub r0, r5, r3 // a - result +#endif + pop {r4, r5, r7, pc} + + + diff --git a/lib/arm/muldf3vfp.S b/lib/arm/muldf3vfp.S new file mode 100644 index 000000000000..cb503d309121 --- /dev/null +++ b/lib/arm/muldf3vfp.S @@ -0,0 +1,24 @@ +//===-- muldf3vfp.S - Implement muldf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __muldf3vfp(double a, double b); +// +// Multiplies two double precision floating point numbers using the Darwin +// calling convention where double arguments are passsed in GPR pairs +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__muldf3vfp) + fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6 + fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7 + fmuld d6, d6, d7 + fmrrd r0, r1, d6 // move result back to r0/r1 pair + bx lr diff --git a/lib/arm/mulsf3vfp.S b/lib/arm/mulsf3vfp.S new file mode 100644 index 000000000000..49b4d1df9468 --- /dev/null +++ b/lib/arm/mulsf3vfp.S @@ -0,0 +1,24 @@ +//===-- mulsf3vfp.S - Implement mulsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __mulsf3vfp(float a, float b); +// +// Multiplies two single precision floating point numbers using the Darwin +// calling convention where single arguments are passsed like 32-bit ints. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp) + fmsr s14, r0 // move first param from r0 into float register + fmsr s15, r1 // move second param from r1 into float register + fmuls s13, s14, s15 + fmrs r0, s13 // move result back to r0 + bx lr diff --git a/lib/arm/nedf2vfp.S b/lib/arm/nedf2vfp.S new file mode 100644 index 000000000000..813864e88302 --- /dev/null +++ b/lib/arm/nedf2vfp.S @@ -0,0 +1,27 @@ +//===-- nedf2vfp.S - Implement nedf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __nedf2vfp(double a, double b); +// +// Returns zero if a and b are unequal and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__nedf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + movne r0, #1 // set result register to 0 if unequal + moveq r0, #0 + bx lr diff --git a/lib/arm/negdf2vfp.S b/lib/arm/negdf2vfp.S new file mode 100644 index 000000000000..8013975445ad --- /dev/null +++ b/lib/arm/negdf2vfp.S @@ -0,0 +1,21 @@ +//===-- negdf2vfp.S - Implement negdf2vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __negdf2vfp(double a, double b); +// +// Returns the negation a double precision floating point numbers using the +// Darwin calling convention where double arguments are passsed in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__negdf2vfp) + eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair + bx lr diff --git a/lib/arm/negsf2vfp.S b/lib/arm/negsf2vfp.S new file mode 100644 index 000000000000..243c0865c8cc --- /dev/null +++ b/lib/arm/negsf2vfp.S @@ -0,0 +1,21 @@ +//===-- negsf2vfp.S - Implement negsf2vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __negsf2vfp(float a); +// +// Returns the negation of a single precision floating point numbers using the +// Darwin calling convention where single arguments are passsed like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__negsf2vfp) + eor r0, r0, #-2147483648 // flip sign bit on float in r0 + bx lr diff --git a/lib/arm/nesf2vfp.S b/lib/arm/nesf2vfp.S new file mode 100644 index 000000000000..d470afa0ef7e --- /dev/null +++ b/lib/arm/nesf2vfp.S @@ -0,0 +1,28 @@ +//===-- nesf2vfp.S - Implement nesf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __nesf2vfp(float a, float b); +// +// Returns one iff a != b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__nesf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + movne r0, #1 // set result register to 1 if unequal + moveq r0, #0 + bx lr + diff --git a/lib/arm/restore_vfp_d8_d15_regs.S b/lib/arm/restore_vfp_d8_d15_regs.S new file mode 100644 index 000000000000..25404cd25076 --- /dev/null +++ b/lib/arm/restore_vfp_d8_d15_regs.S @@ -0,0 +1,37 @@ +//===-- save_restore_regs.S - Implement save/restore* ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling C++ functions that need to handle thrown exceptions the +// compiler is required to save all registers and call __Unwind_SjLj_Register +// in the function prolog. But when compiling for thumb1, there are +// no instructions to access the floating point registers, so the +// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs +// written in ARM to save the float registers. In the epilog, the compiler +// must also add a call to __restore_vfp_d8_d15_regs to restore those registers. +// + + .text + .syntax unified + +// +// Restore registers d8-d15 from stack +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs) + vldmia sp!, {d8-d15} // pop registers d8-d15 off stack + bx lr // return to prolog + + + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/arm/save_vfp_d8_d15_regs.S b/lib/arm/save_vfp_d8_d15_regs.S new file mode 100644 index 000000000000..92de61bc6e8f --- /dev/null +++ b/lib/arm/save_vfp_d8_d15_regs.S @@ -0,0 +1,35 @@ +//===-- save_restore_regs.S - Implement save/restore* ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling C++ functions that need to handle thrown exceptions the +// compiler is required to save all registers and call __Unwind_SjLj_Register +// in the function prolog. But when compiling for thumb1, there are +// no instructions to access the floating point registers, so the +// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs +// written in ARM to save the float registers. In the epilog, the compiler +// must also add a call to __restore_vfp_d8_d15_regs to restore those registers. +// + + .text + .syntax unified + +// +// Save registers d8-d15 onto stack +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs) + vstmdb sp!, {d8-d15} // push registers d8-d15 onto stack + bx lr // return to prolog + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/arm/subdf3vfp.S b/lib/arm/subdf3vfp.S new file mode 100644 index 000000000000..88416006a061 --- /dev/null +++ b/lib/arm/subdf3vfp.S @@ -0,0 +1,24 @@ +//===-- subdf3vfp.S - Implement subdf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __subdf3vfp(double a, double b); +// +// Returns difference between two double precision floating point numbers using +// the Darwin calling convention where double arguments are passsed in GPR pairs +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__subdf3vfp) + fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6 + fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7 + fsubd d6, d6, d7 + fmrrd r0, r1, d6 // move result back to r0/r1 pair + bx lr diff --git a/lib/arm/subsf3vfp.S b/lib/arm/subsf3vfp.S new file mode 100644 index 000000000000..4ead9c23e712 --- /dev/null +++ b/lib/arm/subsf3vfp.S @@ -0,0 +1,25 @@ +//===-- subsf3vfp.S - Implement subsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __subsf3vfp(float a, float b); +// +// Returns the difference between two single precision floating point numbers +// using the Darwin calling convention where single arguments are passsed +// like 32-bit ints. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__subsf3vfp) + fmsr s14, r0 // move first param from r0 into float register + fmsr s15, r1 // move second param from r1 into float register + fsubs s14, s14, s15 + fmrs r0, s14 // move result back to r0 + bx lr diff --git a/lib/arm/switch16.S b/lib/arm/switch16.S new file mode 100644 index 000000000000..05c7b98b01ab --- /dev/null +++ b/lib/arm/switch16.S @@ -0,0 +1,44 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains signed 2-byte sized elements which are 1/2 the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16) + ldrh ip, [lr, #-1] // get first 16-bit word in table + cmp r0, ip // compare with index + add r0, lr, r0, lsl #1 // compute address of element in table + ldrshcc r0, [r0, #1] // load 16-bit element if r0 is in range + add ip, lr, ip, lsl #1 // compute address of last element in table + ldrshhs r0, [ip, #1] // load 16-bit element if r0 out of range + add ip, lr, r0, lsl #1 // compute label = lr + element*2 + bx ip // jump to computed label + + // tell linker it can break up file at label boundaries + .subsections_via_symbols diff --git a/lib/arm/switch32.S b/lib/arm/switch32.S new file mode 100644 index 000000000000..a127cb79f534 --- /dev/null +++ b/lib/arm/switch32.S @@ -0,0 +1,46 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains signed 4-byte sized elements which are the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32) + ldr ip, [lr, #-1] // get first 32-bit word in table + cmp r0, ip // compare with index + add r0, lr, r0, lsl #2 // compute address of element in table + ldrcc r0, [r0, #3] // load 32-bit element if r0 is in range + add ip, lr, ip, lsl #2 // compute address of last element in table + ldrcs r0, [ip, #3] // load 32-bit element if r0 out of range + add ip, lr, r0 // compute label = lr + element + bx ip // jump to computed label + + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/arm/switch8.S b/lib/arm/switch8.S new file mode 100644 index 000000000000..d05f6ac7f068 --- /dev/null +++ b/lib/arm/switch8.S @@ -0,0 +1,43 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains signed byte sized elements which are 1/2 the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8) + ldrb ip, [lr, #-1] // get first byte in table + cmp r0, ip // signed compare with index + ldrsbcc r0, [lr, r0] // get indexed byte out of table + ldrsbhs r0, [lr, ip] // if out of range, use last entry in table + add ip, lr, r0, lsl #1 // compute label = lr + element*2 + bx ip // jump to computed label + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/arm/switchu8.S b/lib/arm/switchu8.S new file mode 100644 index 000000000000..faffddb50c1e --- /dev/null +++ b/lib/arm/switchu8.S @@ -0,0 +1,43 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains unsigned byte sized elements which are 1/2 the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8) + ldrb ip, [lr, #-1] // get first byte in table + cmp r0, ip // compare with index + ldrbcc r0, [lr, r0] // get indexed byte out of table + ldrbhs r0, [lr, ip] // if out of range, use last entry in table + add ip, lr, r0, lsl #1 // compute label = lr + element*2 + bx ip // jump to computed label + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/arm/sync_synchronize.S b/lib/arm/sync_synchronize.S new file mode 100644 index 000000000000..76fdab1fbdb2 --- /dev/null +++ b/lib/arm/sync_synchronize.S @@ -0,0 +1,34 @@ +//===-- sync_synchronize - Implement memory barrier * ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling a use of the gcc built-in __sync_synchronize() in thumb1 mode +// the compiler may emit a call to __sync_synchronize. +// On Darwin the implementation jumps to an OS supplied function named +// OSMemoryBarrier +// + + .text + .syntax unified + +#if __APPLE__ + + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__sync_synchronize) + stmfd sp!, {r7, lr} + add r7, sp, #0 + bl _OSMemoryBarrier + ldmfd sp!, {r7, pc} + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + +#endif diff --git a/lib/arm/truncdfsf2vfp.S b/lib/arm/truncdfsf2vfp.S new file mode 100644 index 000000000000..5725e25c76a7 --- /dev/null +++ b/lib/arm/truncdfsf2vfp.S @@ -0,0 +1,24 @@ +//===-- truncdfsf2vfp.S - Implement truncdfsf2vfp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __truncdfsf2vfp(double a); +// +// Converts double precision float to signle precision result. +// Uses Darwin calling convention where a double precision parameter is +// passed in a R0/R1 pair and a signle precision result is returned in R0. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp) + fmdrr d7, r0, r1 // load double from r0/r1 pair + fcvtsd s15, d7 // convert double to single (trucate precision) + fmrs r0, s15 // return result in r0 + bx lr diff --git a/lib/arm/unorddf2vfp.S b/lib/arm/unorddf2vfp.S new file mode 100644 index 000000000000..de00b07feef9 --- /dev/null +++ b/lib/arm/unorddf2vfp.S @@ -0,0 +1,27 @@ +//===-- unorddf2vfp.S - Implement unorddf2vfp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __unorddf2vfp(double a, double b); +// +// Returns one iff a or b is NaN +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp) + fmdrr d6, r0, r1 // load r0/r1 pair in double register + fmdrr d7, r2, r3 // load r2/r3 pair in double register + fcmpd d6, d7 + fmstat + movvs r0, #1 // set result register to 1 if "overflow" (any NaNs) + movvc r0, #0 + bx lr diff --git a/lib/arm/unordsf2vfp.S b/lib/arm/unordsf2vfp.S new file mode 100644 index 000000000000..ab291a858dab --- /dev/null +++ b/lib/arm/unordsf2vfp.S @@ -0,0 +1,28 @@ +//===-- unordsf2vfp.S - Implement unordsf2vfp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __unordsf2vfp(float a, float b); +// +// Returns one iff a or b is NaN +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .align 2 +DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp) + fmsr s14, r0 // move from GPR 0 to float register + fmsr s15, r1 // move from GPR 1 to float register + fcmps s14, s15 + fmstat + movvs r0, #1 // set result register to 1 if "overflow" (any NaNs) + movvc r0, #0 + bx lr + diff --git a/lib/ashldi3.c b/lib/ashldi3.c new file mode 100644 index 000000000000..993f71ca9724 --- /dev/null +++ b/lib/ashldi3.c @@ -0,0 +1,41 @@ +/* ====-- ashldi3.c - Implement __ashldi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a << b */ + +/* Precondition: 0 <= b < bits_in_dword */ + +di_int +__ashldi3(di_int a, si_int b) +{ + const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); + dwords input; + dwords result; + input.all = a; + if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ + { + result.s.low = 0; + result.s.high = input.s.low << (b - bits_in_word); + } + else /* 0 <= b < bits_in_word */ + { + if (b == 0) + return a; + result.s.low = input.s.low << b; + result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_word - b)); + } + return result.all; +} diff --git a/lib/ashlti3.c b/lib/ashlti3.c new file mode 100644 index 000000000000..317de6655956 --- /dev/null +++ b/lib/ashlti3.c @@ -0,0 +1,45 @@ +/* ===-- ashlti3.c - Implement __ashlti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashlti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: a << b */ + +/* Precondition: 0 <= b < bits_in_tword */ + +ti_int +__ashlti3(ti_int a, si_int b) +{ + const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT); + twords input; + twords result; + input.all = a; + if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ + { + result.s.low = 0; + result.s.high = input.s.low << (b - bits_in_dword); + } + else /* 0 <= b < bits_in_dword */ + { + if (b == 0) + return a; + result.s.low = input.s.low << b; + result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b)); + } + return result.all; +} + +#endif /* __x86_64 */ diff --git a/lib/ashrdi3.c b/lib/ashrdi3.c new file mode 100644 index 000000000000..8e27a11a7523 --- /dev/null +++ b/lib/ashrdi3.c @@ -0,0 +1,42 @@ +/*===-- ashrdi3.c - Implement __ashrdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashrdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: arithmetic a >> b */ + +/* Precondition: 0 <= b < bits_in_dword */ + +di_int +__ashrdi3(di_int a, si_int b) +{ + const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); + dwords input; + dwords result; + input.all = a; + if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ + { + /* result.s.high = input.s.high < 0 ? -1 : 0 */ + result.s.high = input.s.high >> (bits_in_word - 1); + result.s.low = input.s.high >> (b - bits_in_word); + } + else /* 0 <= b < bits_in_word */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b); + } + return result.all; +} diff --git a/lib/ashrti3.c b/lib/ashrti3.c new file mode 100644 index 000000000000..4eab2475c133 --- /dev/null +++ b/lib/ashrti3.c @@ -0,0 +1,46 @@ +/* ===-- ashrti3.c - Implement __ashrti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashrti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: arithmetic a >> b */ + +/* Precondition: 0 <= b < bits_in_tword */ + +ti_int +__ashrti3(ti_int a, si_int b) +{ + const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT); + twords input; + twords result; + input.all = a; + if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ + { + /* result.s.high = input.s.high < 0 ? -1 : 0 */ + result.s.high = input.s.high >> (bits_in_dword - 1); + result.s.low = input.s.high >> (b - bits_in_dword); + } + else /* 0 <= b < bits_in_dword */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b); + } + return result.all; +} + +#endif /* __x86_64 */ diff --git a/lib/assembly.h b/lib/assembly.h new file mode 100644 index 000000000000..c2d5a34fffb0 --- /dev/null +++ b/lib/assembly.h @@ -0,0 +1,54 @@ +/* ===-- assembly.h - compiler-rt assembler support macros -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file defines macros for use in compiler-rt assembler source. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef COMPILERRT_ASSEMBLY_H +#define COMPILERRT_ASSEMBLY_H + +#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) +#define SEPARATOR @ +#else +#define SEPARATOR ; +#endif + +/* We can't use __USER_LABEL_PREFIX__ here, it isn't possible to concatenate the + *values* of two macros. This is quite brittle, though. */ +#if defined(__APPLE__) +#define SYMBOL_NAME(name) _##name +#else +#define SYMBOL_NAME(name) name +#endif + +#ifdef VISIBILITY_HIDDEN +#define DEFINE_COMPILERRT_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + .private_extern SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_NAME(name): +#else +#define DEFINE_COMPILERRT_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_NAME(name): +#endif + +#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + .private_extern SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_NAME(name): + +#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ + .globl name SEPARATOR \ + .private_extern name SEPARATOR \ + name: + +#endif /* COMPILERRT_ASSEMBLY_H */ diff --git a/lib/clear_cache.c b/lib/clear_cache.c new file mode 100644 index 000000000000..ddc48bcc56e3 --- /dev/null +++ b/lib/clear_cache.c @@ -0,0 +1,40 @@ +/* ===-- clear_cache.c - Implement __clear_cache ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include + +#if __APPLE__ + #include +#endif + +/* + * The compiler generates calls to __clear_cache() when creating + * trampoline functions on the stack for use with nested functions. + * It is expected to invalidate the instruction cache for the + * specified range. + */ + +void __clear_cache(void* start, void* end) +{ +#if __i386__ || __x86_64__ +/* + * Intel processors have a unified instruction and data cache + * so there is nothing to do + */ +#else + #if __APPLE__ + /* On Darwin, sys_icache_invalidate() provides this functionality */ + sys_icache_invalidate(start, end-start); + #else + compilerrt_abort(); + #endif +#endif +} + diff --git a/lib/clzdi2.c b/lib/clzdi2.c new file mode 100644 index 000000000000..ea953961de09 --- /dev/null +++ b/lib/clzdi2.c @@ -0,0 +1,29 @@ +/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __clzdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of leading 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__clzdi2(di_int a) +{ + dwords x; + x.all = a; + const si_int f = -(x.s.high == 0); + return __builtin_clz((x.s.high & ~f) | (x.s.low & f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} diff --git a/lib/clzsi2.c b/lib/clzsi2.c new file mode 100644 index 000000000000..7e14af293701 --- /dev/null +++ b/lib/clzsi2.c @@ -0,0 +1,53 @@ +/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __clzsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of leading 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__clzsi2(si_int a) +{ + su_int x = (su_int)a; + si_int t = ((x & 0xFFFF0000) == 0) << 4; /* if (x is small) t = 16 else 0 */ + x >>= 16 - t; /* x = [0 - 0xFFFF] */ + su_int r = t; /* r = [0, 16] */ + /* return r + clz(x) */ + t = ((x & 0xFF00) == 0) << 3; + x >>= 8 - t; /* x = [0 - 0xFF] */ + r += t; /* r = [0, 8, 16, 24] */ + /* return r + clz(x) */ + t = ((x & 0xF0) == 0) << 2; + x >>= 4 - t; /* x = [0 - 0xF] */ + r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */ + /* return r + clz(x) */ + t = ((x & 0xC) == 0) << 1; + x >>= 2 - t; /* x = [0 - 3] */ + r += t; /* r = [0 - 30] and is even */ + /* return r + clz(x) */ +/* switch (x) + * { + * case 0: + * return r + 2; + * case 1: + * return r + 1; + * case 2: + * case 3: + * return r; + * } + */ + return r + ((2 - x) & -((x & 2) == 0)); +} diff --git a/lib/clzti2.c b/lib/clzti2.c new file mode 100644 index 000000000000..805688fbe223 --- /dev/null +++ b/lib/clzti2.c @@ -0,0 +1,33 @@ +/* ===-- clzti2.c - Implement __clzti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __clzti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: the number of leading 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__clzti2(ti_int a) +{ + twords x; + x.all = a; + const di_int f = -(x.s.high == 0); + return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) + + ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT))); +} + +#endif /* __x86_64 */ diff --git a/lib/cmpdi2.c b/lib/cmpdi2.c new file mode 100644 index 000000000000..0b8735244ca6 --- /dev/null +++ b/lib/cmpdi2.c @@ -0,0 +1,38 @@ +/* ===-- cmpdi2.c - Implement __cmpdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __cmpdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: if (a < b) returns 0 +* if (a == b) returns 1 +* if (a > b) returns 2 +*/ + +si_int +__cmpdi2(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} diff --git a/lib/cmpti2.c b/lib/cmpti2.c new file mode 100644 index 000000000000..90b3b75638b7 --- /dev/null +++ b/lib/cmpti2.c @@ -0,0 +1,42 @@ +/* ===-- cmpti2.c - Implement __cmpti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __cmpti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: if (a < b) returns 0 + * if (a == b) returns 1 + * if (a > b) returns 2 + */ + +si_int +__cmpti2(ti_int a, ti_int b) +{ + twords x; + x.all = a; + twords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} + +#endif diff --git a/lib/comparedf2.c b/lib/comparedf2.c new file mode 100644 index 000000000000..5c5ee9d65bf2 --- /dev/null +++ b/lib/comparedf2.c @@ -0,0 +1,132 @@ +//===-- lib/comparedf2.c - Double-precision comparisons -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// // This file implements the following soft-float comparison routines: +// +// __eqdf2 __gedf2 __unorddf2 +// __ledf2 __gtdf2 +// __ltdf2 +// __nedf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, and wrappers to provide the other names. +// +// The main routines behave as follows: +// +// __ledf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gedf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unorddf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __ledf2( ) and __gedf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +enum LE_RESULT { + LE_LESS = -1, + LE_EQUAL = 0, + LE_GREATER = 1, + LE_UNORDERED = 1 +}; + +enum LE_RESULT __ledf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a floating-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } +} + +enum GE_RESULT { + GE_LESS = -1, + GE_EQUAL = 0, + GE_GREATER = 1, + GE_UNORDERED = -1 // Note: different from LE_UNORDERED +}; + +enum GE_RESULT __gedf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } else { + if (aInt > bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } +} + +int __unorddf2(fp_t a, fp_t b) { + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; +} + +// The following are alternative names for the preceeding routines. + +enum LE_RESULT __eqdf2(fp_t a, fp_t b) { + return __ledf2(a, b); +} + +enum LE_RESULT __ltdf2(fp_t a, fp_t b) { + return __ledf2(a, b); +} + +enum LE_RESULT __nedf2(fp_t a, fp_t b) { + return __ledf2(a, b); +} + +enum GE_RESULT __gtdf2(fp_t a, fp_t b) { + return __gedf2(a, b); +} + diff --git a/lib/comparesf2.c b/lib/comparesf2.c new file mode 100644 index 000000000000..fd0572401117 --- /dev/null +++ b/lib/comparesf2.c @@ -0,0 +1,131 @@ +//===-- lib/comparesf2.c - Single-precision comparisons -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the following soft-fp_t comparison routines: +// +// __eqsf2 __gesf2 __unordsf2 +// __lesf2 __gtsf2 +// __ltsf2 +// __nesf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, and wrappers to provide the other names. +// +// The main routines behave as follows: +// +// __lesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unordsf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +enum LE_RESULT { + LE_LESS = -1, + LE_EQUAL = 0, + LE_GREATER = 1, + LE_UNORDERED = 1 +}; + +enum LE_RESULT __lesf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } +} + +enum GE_RESULT { + GE_LESS = -1, + GE_EQUAL = 0, + GE_GREATER = 1, + GE_UNORDERED = -1 // Note: different from LE_UNORDERED +}; + +enum GE_RESULT __gesf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } else { + if (aInt > bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } +} + +int __unordsf2(fp_t a, fp_t b) { + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; +} + +// The following are alternative names for the preceeding routines. + +enum LE_RESULT __eqsf2(fp_t a, fp_t b) { + return __lesf2(a, b); +} + +enum LE_RESULT __ltsf2(fp_t a, fp_t b) { + return __lesf2(a, b); +} + +enum LE_RESULT __nesf2(fp_t a, fp_t b) { + return __lesf2(a, b); +} + +enum GE_RESULT __gtsf2(fp_t a, fp_t b) { + return __gesf2(a, b); +} diff --git a/lib/ctzdi2.c b/lib/ctzdi2.c new file mode 100644 index 000000000000..b49f2c713534 --- /dev/null +++ b/lib/ctzdi2.c @@ -0,0 +1,29 @@ +/* ===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__ctzdi2(di_int a) +{ + dwords x; + x.all = a; + const si_int f = -(x.s.low == 0); + return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} diff --git a/lib/ctzsi2.c b/lib/ctzsi2.c new file mode 100644 index 000000000000..30d34c862509 --- /dev/null +++ b/lib/ctzsi2.c @@ -0,0 +1,57 @@ +/* ===-- ctzsi2.c - Implement __ctzsi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__ctzsi2(si_int a) +{ + su_int x = (su_int)a; + si_int t = ((x & 0x0000FFFF) == 0) << 4; /* if (x has no small bits) t = 16 else 0 */ + x >>= t; /* x = [0 - 0xFFFF] + higher garbage bits */ + su_int r = t; /* r = [0, 16] */ + /* return r + ctz(x) */ + t = ((x & 0x00FF) == 0) << 3; + x >>= t; /* x = [0 - 0xFF] + higher garbage bits */ + r += t; /* r = [0, 8, 16, 24] */ + /* return r + ctz(x) */ + t = ((x & 0x0F) == 0) << 2; + x >>= t; /* x = [0 - 0xF] + higher garbage bits */ + r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */ + /* return r + ctz(x) */ + t = ((x & 0x3) == 0) << 1; + x >>= t; + x &= 3; /* x = [0 - 3] */ + r += t; /* r = [0 - 30] and is even */ + /* return r + ctz(x) */ + +/* The branch-less return statement below is equivalent + * to the following switch statement: + * switch (x) + * { + * case 0: + * return r + 2; + * case 2: + * return r + 1; + * case 1: + * case 3: + * return r; + * } + */ + return r + ((2 - (x >> 1)) & -((x & 1) == 0)); +} diff --git a/lib/ctzti2.c b/lib/ctzti2.c new file mode 100644 index 000000000000..f2d41fee1cb8 --- /dev/null +++ b/lib/ctzti2.c @@ -0,0 +1,33 @@ +/* ===-- ctzti2.c - Implement __ctzti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__ctzti2(ti_int a) +{ + twords x; + x.all = a; + const di_int f = -(x.s.low == 0); + return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) + + ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT))); +} + +#endif diff --git a/lib/divdc3.c b/lib/divdc3.c new file mode 100644 index 000000000000..c96aefd0e49d --- /dev/null +++ b/lib/divdc3.c @@ -0,0 +1,59 @@ +/* ===-- divdc3.c - Implement __divdc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include +#include + +/* Returns: the quotient of (a + ib) / (c + id) */ + +double _Complex +__divdc3(double __a, double __b, double __c, double __d) +{ + int __ilogbw = 0; + double __logbw = logb(fmax(fabs(__c), fabs(__d))); + if (isfinite(__logbw)) + { + __ilogbw = (int)__logbw; + __c = scalbn(__c, -__ilogbw); + __d = scalbn(__d, -__ilogbw); + } + double __denom = __c * __c + __d * __d; + double _Complex z; + __real__ z = scalbn((__a * __c + __b * __d) / __denom, -__ilogbw); + __imag__ z = scalbn((__b * __c - __a * __d) / __denom, -__ilogbw); + if (isnan(__real__ z) && isnan(__imag__ z)) + { + if ((__denom == 0.0) && (!isnan(__a) || !isnan(__b))) + { + __real__ z = copysign(INFINITY, __c) * __a; + __imag__ z = copysign(INFINITY, __c) * __b; + } + else if ((isinf(__a) || isinf(__b)) && isfinite(__c) && isfinite(__d)) + { + __a = copysign(isinf(__a) ? 1.0 : 0.0, __a); + __b = copysign(isinf(__b) ? 1.0 : 0.0, __b); + __real__ z = INFINITY * (__a * __c + __b * __d); + __imag__ z = INFINITY * (__b * __c - __a * __d); + } + else if (isinf(__logbw) && __logbw > 0.0 && isfinite(__a) && isfinite(__b)) + { + __c = copysign(isinf(__c) ? 1.0 : 0.0, __c); + __d = copysign(isinf(__d) ? 1.0 : 0.0, __d); + __real__ z = 0.0 * (__a * __c + __b * __d); + __imag__ z = 0.0 * (__b * __c - __a * __d); + } + } + return z; +} diff --git a/lib/divdf3.c b/lib/divdf3.c new file mode 100644 index 000000000000..21b8f09bacb0 --- /dev/null +++ b/lib/divdf3.c @@ -0,0 +1,182 @@ +//===-- lib/divdf3.c - Double-precision division ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float division +// with the IEEE-754 default rounding (to nearest, ties to even). +// +// For simplicity, this implementation currently flushes denormals to zero. +// It should be a fairly straightforward exercise to implement gradual +// underflow with correct rounding. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t __divdf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN / anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything / NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity / infinity = NaN + if (bAbs == infRep) return fromRep(qnanRep); + // infinity / anything else = +/- infinity + else return fromRep(aAbs | quotientSign); + } + + // anything else / infinity = +/- 0 + if (bAbs == infRep) return fromRep(quotientSign); + + if (!aAbs) { + // zero / zero = NaN + if (!bAbs) return fromRep(qnanRep); + // zero / anything else = +/- zero + else return fromRep(quotientSign); + } + // anything else / zero = +/- infinity + if (!bAbs) return fromRep(infRep | quotientSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale -= normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + int quotientExponent = aExponent - bExponent + scale; + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + const uint32_t q31b = bSignificand >> 21; + uint32_t recip32 = UINT32_C(0x7504f333) - q31b; + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + uint32_t correction32; + correction32 = -((uint64_t)recip32 * q31b >> 32); + recip32 = (uint64_t)recip32 * correction32 >> 31; + correction32 = -((uint64_t)recip32 * q31b >> 32); + recip32 = (uint64_t)recip32 * correction32 >> 31; + correction32 = -((uint64_t)recip32 * q31b >> 32); + recip32 = (uint64_t)recip32 * correction32 >> 31; + + // recip32 might have overflowed to exactly zero in the preceeding + // computation if the high word of b is exactly 1.0. This would sabotage + // the full-width final stage of the computation that follows, so we adjust + // recip32 downward by one bit. + recip32--; + + // We need to perform one more iteration to get us to 56 binary digits; + // The last iteration needs to happen with extra precision. + const uint32_t q63blo = bSignificand << 11; + uint64_t correction, reciprocal; + correction = -((uint64_t)recip32*q31b + ((uint64_t)recip32*q63blo >> 32)); + uint32_t cHi = correction >> 32; + uint32_t cLo = correction; + reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32); + + // We already adjusted the 32-bit estimate, now we need to adjust the final + // 64-bit reciprocal estimate downward to ensure that it is strictly smaller + // than the infinitely precise exact reciprocal. Because the computation + // of the Newton-Raphson step is truncating at every step, this adjustment + // is small; most of the work is already done. + reciprocal -= 2; + + // The numerical reciprocal is accurate to within 2^-56, lies in the + // interval [0.5, 1.0), and is strictly smaller than the true reciprocal + // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b + // in Q53 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0.5, 2.0) + // 3. the error in q is bounded away from 2^-53 (actually, we have a + // couple of bits to spare, but this is all we need). + + // We need a 64 x 64 multiply high to compute q, which isn't a basic + // operation in C, so we need to be a little bit fussy. + rep_t quotient, quotientLo; + wideMultiply(aSignificand << 2, reciprocal, "ient, "ientLo); + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + rep_t residual; + if (quotient < (implicitBit << 1)) { + residual = (aSignificand << 53) - quotient * bSignificand; + quotientExponent--; + } else { + quotient >>= 1; + residual = (aSignificand << 52) - quotient * bSignificand; + } + + const int writtenExponent = quotientExponent + exponentBias; + + if (writtenExponent >= maxExponent) { + // If we have overflowed the exponent, return infinity. + return fromRep(infRep | quotientSign); + } + + else if (writtenExponent < 1) { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return fromRep(quotientSign); + } + + else { + const bool round = (residual << 1) > bSignificand; + // Clear the implicit bit + rep_t absResult = quotient & significandMask; + // Insert the exponent + absResult |= (rep_t)writtenExponent << significandBits; + // Round + absResult += round; + // Insert the sign and return + const double result = fromRep(absResult | quotientSign); + return result; + } +} diff --git a/lib/divdi3.c b/lib/divdi3.c new file mode 100644 index 000000000000..fccfb8b09a09 --- /dev/null +++ b/lib/divdi3.c @@ -0,0 +1,31 @@ +/* ===-- divdi3.c - Implement __divdi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +di_int +__divdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /*sign of quotient */ + return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} diff --git a/lib/divsc3.c b/lib/divsc3.c new file mode 100644 index 000000000000..c38c8638efb0 --- /dev/null +++ b/lib/divsc3.c @@ -0,0 +1,59 @@ +/*===-- divsc3.c - Implement __divsc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divsc3 for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include +#include + +/* Returns: the quotient of (a + ib) / (c + id) */ + +float _Complex +__divsc3(float __a, float __b, float __c, float __d) +{ + int __ilogbw = 0; + float __logbw = logbf(fmaxf(fabsf(__c), fabsf(__d))); + if (isfinite(__logbw)) + { + __ilogbw = (int)__logbw; + __c = scalbnf(__c, -__ilogbw); + __d = scalbnf(__d, -__ilogbw); + } + float __denom = __c * __c + __d * __d; + float _Complex z; + __real__ z = scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw); + __imag__ z = scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw); + if (isnan(__real__ z) && isnan(__imag__ z)) + { + if ((__denom == 0) && (!isnan(__a) || !isnan(__b))) + { + __real__ z = copysignf(INFINITY, __c) * __a; + __imag__ z = copysignf(INFINITY, __c) * __b; + } + else if ((isinf(__a) || isinf(__b)) && isfinite(__c) && isfinite(__d)) + { + __a = copysignf(isinf(__a) ? 1 : 0, __a); + __b = copysignf(isinf(__b) ? 1 : 0, __b); + __real__ z = INFINITY * (__a * __c + __b * __d); + __imag__ z = INFINITY * (__b * __c - __a * __d); + } + else if (isinf(__logbw) && __logbw > 0 && isfinite(__a) && isfinite(__b)) + { + __c = copysignf(isinf(__c) ? 1 : 0, __c); + __d = copysignf(isinf(__d) ? 1 : 0, __d); + __real__ z = 0 * (__a * __c + __b * __d); + __imag__ z = 0 * (__b * __c - __a * __d); + } + } + return z; +} diff --git a/lib/divsf3.c b/lib/divsf3.c new file mode 100644 index 000000000000..03b7311788bc --- /dev/null +++ b/lib/divsf3.c @@ -0,0 +1,166 @@ +//===-- lib/divsf3.c - Single-precision division ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float division +// with the IEEE-754 default rounding (to nearest, ties to even). +// +// For simplicity, this implementation currently flushes denormals to zero. +// It should be a fairly straightforward exercise to implement gradual +// underflow with correct rounding. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __divsf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN / anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything / NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity / infinity = NaN + if (bAbs == infRep) return fromRep(qnanRep); + // infinity / anything else = +/- infinity + else return fromRep(aAbs | quotientSign); + } + + // anything else / infinity = +/- 0 + if (bAbs == infRep) return fromRep(quotientSign); + + if (!aAbs) { + // zero / zero = NaN + if (!bAbs) return fromRep(qnanRep); + // zero / anything else = +/- zero + else return fromRep(quotientSign); + } + // anything else / zero = +/- infinity + if (!bAbs) return fromRep(infRep | quotientSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale -= normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + int quotientExponent = aExponent - bExponent + scale; + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + uint32_t q31b = bSignificand << 8; + uint32_t reciprocal = UINT32_C(0x7504f333) - q31b; + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + uint32_t correction; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + + // Exhaustive testing shows that the error in reciprocal after three steps + // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our + // expectations. We bump the reciprocal by a tiny value to force the error + // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to + // be specific). This also causes 1/1 to give a sensible approximation + // instead of zero (due to overflow). + reciprocal -= 2; + + // The numerical reciprocal is accurate to within 2^-28, lies in the + // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller + // than the true reciprocal of b. Multiplying a by this reciprocal thus + // gives a numerical q = a/b in Q24 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) + // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes + // from the fact that we truncate the product, and the 2^27 term + // is the error in the reciprocal of b scaled by the maximum + // possible value of a. As a consequence of this error bound, + // either q or nextafter(q) is the correctly rounded + rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32; + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + rep_t residual; + if (quotient < (implicitBit << 1)) { + residual = (aSignificand << 24) - quotient * bSignificand; + quotientExponent--; + } else { + quotient >>= 1; + residual = (aSignificand << 23) - quotient * bSignificand; + } + + const int writtenExponent = quotientExponent + exponentBias; + + if (writtenExponent >= maxExponent) { + // If we have overflowed the exponent, return infinity. + return fromRep(infRep | quotientSign); + } + + else if (writtenExponent < 1) { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return fromRep(quotientSign); + } + + else { + const bool round = (residual << 1) > bSignificand; + // Clear the implicit bit + rep_t absResult = quotient & significandMask; + // Insert the exponent + absResult |= (rep_t)writtenExponent << significandBits; + // Round + absResult += round; + // Insert the sign and return + return fromRep(absResult | quotientSign); + } +} diff --git a/lib/divsi3.c b/lib/divsi3.c new file mode 100644 index 000000000000..0eff6ef0d735 --- /dev/null +++ b/lib/divsi3.c @@ -0,0 +1,31 @@ +/* ===-- divsi3.c - Implement __divsi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +su_int __udivsi3(su_int n, su_int d); + +/* Returns: a / b */ + +si_int +__divsi3(si_int a, si_int b) +{ + const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1; + si_int s_a = a >> bits_in_word_m1; /* s_a = a < 0 ? -1 : 0 */ + si_int s_b = b >> bits_in_word_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /* sign of quotient */ + return (__udivsi3(a, b) ^ s_a) - s_a; /* negate if s_a == -1 */ +} diff --git a/lib/divti3.c b/lib/divti3.c new file mode 100644 index 000000000000..c752f6cfbe9d --- /dev/null +++ b/lib/divti3.c @@ -0,0 +1,35 @@ +/* ===-- divti3.c - Implement __divti3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/* Returns: a / b */ + +ti_int +__divti3(ti_int a, ti_int b) +{ + const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; + ti_int s_a = a >> bits_in_tword_m1; /* s_a = a < 0 ? -1 : 0 */ + ti_int s_b = b >> bits_in_tword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /* sign of quotient */ + return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} + +#endif diff --git a/lib/divxc3.c b/lib/divxc3.c new file mode 100644 index 000000000000..03357ae552c3 --- /dev/null +++ b/lib/divxc3.c @@ -0,0 +1,62 @@ +/* ===-- divxc3.c - Implement __divxc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divxc3 for the compiler_rt library. + * + */ + +#if !_ARCH_PPC + +#include "int_lib.h" +#include +#include + +/* Returns: the quotient of (a + ib) / (c + id) */ + +long double _Complex +__divxc3(long double __a, long double __b, long double __c, long double __d) +{ + int __ilogbw = 0; + long double __logbw = logbl(fmaxl(fabsl(__c), fabsl(__d))); + if (isfinite(__logbw)) + { + __ilogbw = (int)__logbw; + __c = scalbnl(__c, -__ilogbw); + __d = scalbnl(__d, -__ilogbw); + } + long double __denom = __c * __c + __d * __d; + long double _Complex z; + __real__ z = scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); + __imag__ z = scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); + if (isnan(__real__ z) && isnan(__imag__ z)) + { + if ((__denom == 0) && (!isnan(__a) || !isnan(__b))) + { + __real__ z = copysignl(INFINITY, __c) * __a; + __imag__ z = copysignl(INFINITY, __c) * __b; + } + else if ((isinf(__a) || isinf(__b)) && isfinite(__c) && isfinite(__d)) + { + __a = copysignl(isinf(__a) ? 1 : 0, __a); + __b = copysignl(isinf(__b) ? 1 : 0, __b); + __real__ z = INFINITY * (__a * __c + __b * __d); + __imag__ z = INFINITY * (__b * __c - __a * __d); + } + else if (isinf(__logbw) && __logbw > 0 && isfinite(__a) && isfinite(__b)) + { + __c = copysignl(isinf(__c) ? 1 : 0, __c); + __d = copysignl(isinf(__d) ? 1 : 0, __d); + __real__ z = 0 * (__a * __c + __b * __d); + __imag__ z = 0 * (__b * __c - __a * __d); + } + } + return z; +} + +#endif diff --git a/lib/enable_execute_stack.c b/lib/enable_execute_stack.c new file mode 100644 index 000000000000..193e7dbc23bc --- /dev/null +++ b/lib/enable_execute_stack.c @@ -0,0 +1,58 @@ +/* ===-- enable_execute_stack.c - Implement __enable_execute_stack ---------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include +#include + +/* #include "config.h" + * FIXME: CMake - include when cmake system is ready. + * Remove #define HAVE_SYSCONF 1 line. + */ +#define HAVE_SYSCONF 1 + +#ifndef __APPLE__ +#include +#endif /* __APPLE__ */ + +#if __LP64__ + #define TRAMPOLINE_SIZE 48 +#else + #define TRAMPOLINE_SIZE 40 +#endif + +/* + * The compiler generates calls to __enable_execute_stack() when creating + * trampoline functions on the stack for use with nested functions. + * It is expected to mark the page(s) containing the address + * and the next 48 bytes as executable. Since the stack is normally rw- + * that means changing the protection on those page(s) to rwx. + */ + +void __enable_execute_stack(void* addr) +{ + +#if __APPLE__ + /* On Darwin, pagesize is always 4096 bytes */ + const uintptr_t pageSize = 4096; +#elif !defined(HAVE_SYSCONF) +#error "HAVE_SYSCONF not defined! See enable_execute_stack.c" +#else + const uintptr_t pageSize = sysconf(_SC_PAGESIZE); +#endif /* __APPLE__ */ + + const uintptr_t pageAlignMask = ~(pageSize-1); + uintptr_t p = (uintptr_t)addr; + unsigned char* startPage = (unsigned char*)(p & pageAlignMask); + unsigned char* endPage = (unsigned char*)((p+TRAMPOLINE_SIZE+pageSize) & pageAlignMask); + size_t length = endPage - startPage; + (void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC); +} + + diff --git a/lib/endianness.h b/lib/endianness.h new file mode 100644 index 000000000000..6d2587d022e3 --- /dev/null +++ b/lib/endianness.h @@ -0,0 +1,94 @@ +/* ===-- endianness.h - configuration header for compiler-rt ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef ENDIANNESS_H +#define ENDIANNESS_H + +/* + * Known limitations: + * Middle endian systems are not handled currently. + */ + +#if defined(__SVR4) && defined(__sun) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* Solaris and AuroraUX. */ + +/* .. */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* *BSD */ + +/* .. */ + +/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */ +#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ ) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#endif +#endif /* __BIG_ENDIAN__ */ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif +#endif /* __LITTLE_ENDIAN__ */ + +#endif /* Mac OSX */ + +/* .. */ + +#if defined(__linux__) +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* __BYTE_ORDER */ + +#endif /* GNU/Linux */ + +/* . */ + +#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) +#error Unable to determine endian +#endif /* Check we found an endianness correctly. */ + +#endif /* ENDIANNESS_H */ diff --git a/lib/eprintf.c b/lib/eprintf.c new file mode 100644 index 000000000000..786fe6aaa672 --- /dev/null +++ b/lib/eprintf.c @@ -0,0 +1,33 @@ +/* ===---------- eprintf.c - Implements __eprintf --------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + + + +#include "int_lib.h" +#include +#include + + +/* + * __eprintf() was used in an old version of . + * It can eventually go away, but it is needed when linking + * .o files built with the old . + * + * It should never be exported from a dylib, so it is marked + * visibility hidden. + */ +__attribute__((visibility("hidden"))) +void __eprintf(const char* format, const char* assertion_expression, + const char* line, const char* file) +{ + fprintf(stderr, format, assertion_expression, line, file); + fflush(stderr); + compilerrt_abort(); +} diff --git a/lib/extendsfdf2.c b/lib/extendsfdf2.c new file mode 100644 index 000000000000..025eb9572446 --- /dev/null +++ b/lib/extendsfdf2.c @@ -0,0 +1,136 @@ +//===-- lib/extendsfdf2.c - single -> double conversion -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a fairly generic conversion from a narrower to a wider +// IEEE-754 floating-point type. The constants and types defined following the +// includes below parameterize the conversion. +// +// This routine can be trivially adapted to support conversions from +// half-precision or to quad-precision. It does not support types that don't +// use the usual IEEE-754 interchange formats; specifically, some work would be +// needed to adapt it to (for example) the Intel 80-bit format or PowerPC +// double-double format. +// +// Note please, however, that this implementation is only intended to support +// *widening* operations; if you need to convert to a *narrower* floating-point +// type (e.g. double -> float), then this routine will not do what you want it +// to. +// +// It also requires that integer types at least as large as both formats +// are available on the target platform; this may pose a problem when trying +// to add support for quad on some 32-bit systems, for example. You also may +// run into trouble finding an appropriate CLZ function for wide source types; +// you will likely need to roll your own on some platforms. +// +// Finally, the following assumptions are made: +// +// 1. floating-point types and integer types have the same endianness on the +// target platform +// +// 2. quiet NaNs, if supported, are indicated by the leading bit of the +// significand field being set +// +//===----------------------------------------------------------------------===// + +#include +#include + +typedef float src_t; +typedef uint32_t src_rep_t; +#define SRC_REP_C UINT32_C +static const int srcSigBits = 23; +#define src_rep_t_clz __builtin_clz + +typedef double dst_t; +typedef uint64_t dst_rep_t; +#define DST_REP_C UINT64_C +static const int dstSigBits = 52; + +// End of specialization parameters. Two helper routines for conversion to and +// from the representation of floating-point data as integer values follow. + +static inline src_rep_t srcToRep(src_t x) { + const union { src_t f; src_rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline dst_t dstFromRep(dst_rep_t x) { + const union { dst_t f; dst_rep_t i; } rep = {.i = x}; + return rep.f; +} + +// End helper routines. Conversion implementation follows. + +dst_t __extendsfdf2(src_t a) { + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const int srcBits = sizeof(src_t)*CHAR_BIT; + const int srcExpBits = srcBits - srcSigBits - 1; + const int srcInfExp = (1 << srcExpBits) - 1; + const int srcExpBias = srcInfExp >> 1; + + const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits; + const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits; + const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits); + const src_rep_t srcAbsMask = srcSignMask - 1; + const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1); + const src_rep_t srcNaNCode = srcQNaN - 1; + + const int dstBits = sizeof(dst_t)*CHAR_BIT; + const int dstExpBits = dstBits - dstSigBits - 1; + const int dstInfExp = (1 << dstExpBits) - 1; + const int dstExpBias = dstInfExp >> 1; + + const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits; + + // Break a into a sign and representation of the absolute value + const src_rep_t aRep = srcToRep(a); + const src_rep_t aAbs = aRep & srcAbsMask; + const src_rep_t sign = aRep & srcSignMask; + dst_rep_t absResult; + + if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits); + absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits; + } + + else if (aAbs >= srcInfinity) { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + absResult = (dst_rep_t)dstInfExp << dstSigBits; + absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits); + absResult |= aAbs & srcNaNCode; + } + + else if (aAbs) { + // a is denormal. + // renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal); + absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale); + absResult ^= dstMinNormal; + const int resultExponent = dstExpBias - srcExpBias - scale + 1; + absResult |= (dst_rep_t)resultExponent << dstSigBits; + } + + else { + // a is zero. + absResult = 0; + } + + // Apply the signbit to (dst_t)abs(a). + const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits); + return dstFromRep(result); +} diff --git a/lib/ffsdi2.c b/lib/ffsdi2.c new file mode 100644 index 000000000000..8c03d19afcc6 --- /dev/null +++ b/lib/ffsdi2.c @@ -0,0 +1,33 @@ +/* ===-- ffsdi2.c - Implement __ffsdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ffsdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the index of the least significant 1-bit in a, or + * the value zero if a is zero. The least significant bit is index one. + */ + +si_int +__ffsdi2(di_int a) +{ + dwords x; + x.all = a; + if (x.s.low == 0) + { + if (x.s.high == 0) + return 0; + return __builtin_ctz(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT); + } + return __builtin_ctz(x.s.low) + 1; +} diff --git a/lib/ffsti2.c b/lib/ffsti2.c new file mode 100644 index 000000000000..0139eb1f7576 --- /dev/null +++ b/lib/ffsti2.c @@ -0,0 +1,37 @@ +/* ===-- ffsti2.c - Implement __ffsti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ffsti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: the index of the least significant 1-bit in a, or + * the value zero if a is zero. The least significant bit is index one. + */ + +si_int +__ffsti2(ti_int a) +{ + twords x; + x.all = a; + if (x.s.low == 0) + { + if (x.s.high == 0) + return 0; + return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT); + } + return __builtin_ctzll(x.s.low) + 1; +} + +#endif /* __x86_64 */ diff --git a/lib/fixdfdi.c b/lib/fixdfdi.c new file mode 100644 index 000000000000..3d3116c1811b --- /dev/null +++ b/lib/fixdfdi.c @@ -0,0 +1,43 @@ +/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixdfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * su_int is a 32 bit integral type + * value in double is representable in di_int (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +di_int +__fixdfdi(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0) + return 0; + di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31; + dwords r; + r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000; + r.s.low = fb.u.s.low; + if (e > 52) + r.all <<= (e - 52); + else + r.all >>= (52 - e); + return (r.all ^ s) - s; +} diff --git a/lib/fixdfsi.c b/lib/fixdfsi.c new file mode 100644 index 000000000000..7d17aeddeb48 --- /dev/null +++ b/lib/fixdfsi.c @@ -0,0 +1,45 @@ +//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision to integer conversion for the +// compiler-rt library. No range checking is performed; the behavior of this +// conversion is undefined for out of range values in the C standard. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +int __fixdfsi(fp_t a) { + + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If 0 < exponent < significandBits, right shift to get the result. + if ((unsigned int)exponent < significandBits) { + return sign * (significand >> (significandBits - exponent)); + } + + // If exponent is negative, the result is zero. + else if (exponent < 0) { + return 0; + } + + // If significandBits < exponent, left shift to get the result. This shift + // may end up being larger than the type width, which incurs undefined + // behavior, but the conversion itself is undefined in that case, so + // whatever the compiler decides to do is fine. + else { + return sign * (significand << (exponent - significandBits)); + } +} diff --git a/lib/fixdfti.c b/lib/fixdfti.c new file mode 100644 index 000000000000..359b84eaecef --- /dev/null +++ b/lib/fixdfti.c @@ -0,0 +1,45 @@ +/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixdfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * su_int is a 32 bit integral type + * value in double is representable in ti_int (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +ti_int +__fixdfti(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0) + return 0; + ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31; + ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all); + if (e > 52) + r <<= (e - 52); + else + r >>= (52 - e); + return (r ^ s) - s; +} + +#endif diff --git a/lib/fixsfdi.c b/lib/fixsfdi.c new file mode 100644 index 000000000000..08f1524e152a --- /dev/null +++ b/lib/fixsfdi.c @@ -0,0 +1,41 @@ +/* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixsfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * su_int is a 32 bit integral type + * value in float is representable in di_int (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +di_int +__fixsfdi(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0) + return 0; + di_int s = (si_int)(fb.u & 0x80000000) >> 31; + di_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return (r ^ s) - s; +} diff --git a/lib/fixsfsi.c b/lib/fixsfsi.c new file mode 100644 index 000000000000..ff79377198f4 --- /dev/null +++ b/lib/fixsfsi.c @@ -0,0 +1,45 @@ +//===-- lib/fixsfsi.c - Single-precision -> integer conversion ----*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision to integer conversion for the +// compiler-rt library. No range checking is performed; the behavior of this +// conversion is undefined for out of range values in the C standard. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +int __fixsfsi(fp_t a) { + + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If 0 < exponent < significandBits, right shift to get the result. + if ((unsigned int)exponent < significandBits) { + return sign * (significand >> (significandBits - exponent)); + } + + // If exponent is negative, the result is zero. + else if (exponent < 0) { + return 0; + } + + // If significandBits < exponent, left shift to get the result. This shift + // may end up being larger than the type width, which incurs undefined + // behavior, but the conversion itself is undefined in that case, so + // whatever the compiler decides to do is fine. + else { + return sign * (significand << (exponent - significandBits)); + } +} diff --git a/lib/fixsfti.c b/lib/fixsfti.c new file mode 100644 index 000000000000..95992fe3f48e --- /dev/null +++ b/lib/fixsfti.c @@ -0,0 +1,45 @@ +/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixsfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * su_int is a 32 bit integral type + * value in float is representable in ti_int (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +ti_int +__fixsfti(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0) + return 0; + ti_int s = (si_int)(fb.u & 0x80000000) >> 31; + ti_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return (r ^ s) - s; +} + +#endif diff --git a/lib/fixunsdfdi.c b/lib/fixunsdfdi.c new file mode 100644 index 000000000000..bdcee13e80ba --- /dev/null +++ b/lib/fixunsdfdi.c @@ -0,0 +1,45 @@ +/* ===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsdfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: double is a IEEE 64 bit floating point type + * du_int is a 64 bit integral type + * value in double is representable in du_int or is negative + * (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +du_int +__fixunsdfdi(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0 || (fb.u.s.high & 0x80000000)) + return 0; + udwords r; + r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000; + r.s.low = fb.u.s.low; + if (e > 52) + r.all <<= (e - 52); + else + r.all >>= (52 - e); + return r.all; +} diff --git a/lib/fixunsdfsi.c b/lib/fixunsdfsi.c new file mode 100644 index 000000000000..a0cba79aabb9 --- /dev/null +++ b/lib/fixunsdfsi.c @@ -0,0 +1,42 @@ +/* ===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsdfsi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned int, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: double is a IEEE 64 bit floating point type + * su_int is a 32 bit integral type + * value in double is representable in su_int or is negative + * (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +su_int +__fixunsdfsi(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0 || (fb.u.s.high & 0x80000000)) + return 0; + return ( + 0x80000000u | + ((fb.u.s.high & 0x000FFFFF) << 11) | + (fb.u.s.low >> 21) + ) >> (31 - e); +} diff --git a/lib/fixunsdfti.c b/lib/fixunsdfti.c new file mode 100644 index 000000000000..c1cd72deca2f --- /dev/null +++ b/lib/fixunsdfti.c @@ -0,0 +1,47 @@ +/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsdfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: double is a IEEE 64 bit floating point type + * tu_int is a 64 bit integral type + * value in double is representable in tu_int or is negative + * (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +tu_int +__fixunsdfti(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0 || (fb.u.s.high & 0x80000000)) + return 0; + tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL); + if (e > 52) + r <<= (e - 52); + else + r >>= (52 - e); + return r; +} + +#endif diff --git a/lib/fixunssfdi.c b/lib/fixunssfdi.c new file mode 100644 index 000000000000..3837bd890e69 --- /dev/null +++ b/lib/fixunssfdi.c @@ -0,0 +1,43 @@ +/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunssfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: float is a IEEE 32 bit floating point type + * du_int is a 64 bit integral type + * value in float is representable in du_int or is negative + * (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +du_int +__fixunssfdi(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0 || (fb.u & 0x80000000)) + return 0; + du_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return r; +} diff --git a/lib/fixunssfsi.c b/lib/fixunssfsi.c new file mode 100644 index 000000000000..a001cd48196b --- /dev/null +++ b/lib/fixunssfsi.c @@ -0,0 +1,43 @@ +/* ===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunssfsi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned int, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: float is a IEEE 32 bit floating point type + * su_int is a 32 bit integral type + * value in float is representable in su_int or is negative + * (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +su_int +__fixunssfsi(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0 || (fb.u & 0x80000000)) + return 0; + su_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return r; +} diff --git a/lib/fixunssfti.c b/lib/fixunssfti.c new file mode 100644 index 000000000000..20b7e760547a --- /dev/null +++ b/lib/fixunssfti.c @@ -0,0 +1,47 @@ +/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunssfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: float is a IEEE 32 bit floating point type + * tu_int is a 64 bit integral type + * value in float is representable in tu_int or is negative + * (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +tu_int +__fixunssfti(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0 || (fb.u & 0x80000000)) + return 0; + tu_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return r; +} + +#endif diff --git a/lib/fixunsxfdi.c b/lib/fixunsxfdi.c new file mode 100644 index 000000000000..872727bcd3df --- /dev/null +++ b/lib/fixunsxfdi.c @@ -0,0 +1,44 @@ +/* ===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsxfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * du_int is a 64 bit integral type + * value in long double is representable in du_int or is negative + * (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +du_int +__fixunsxfdi(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0 || (fb.u.high.s.low & 0x00008000)) + return 0; + return fb.u.low.all >> (63 - e); +} + +#endif diff --git a/lib/fixunsxfsi.c b/lib/fixunsxfsi.c new file mode 100644 index 000000000000..c9a607ace6d0 --- /dev/null +++ b/lib/fixunsxfsi.c @@ -0,0 +1,44 @@ +/* ===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsxfsi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a unsigned int, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * su_int is a 32 bit integral type + * value in long double is representable in su_int or is negative + * (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +su_int +__fixunsxfsi(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0 || (fb.u.high.s.low & 0x00008000)) + return 0; + return fb.u.low.s.high >> (31 - e); +} + +#endif /* !_ARCH_PPC */ diff --git a/lib/fixunsxfti.c b/lib/fixunsxfti.c new file mode 100644 index 000000000000..d0bd512c4d41 --- /dev/null +++ b/lib/fixunsxfti.c @@ -0,0 +1,49 @@ +/* ===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsxfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * tu_int is a 64 bit integral type + * value in long double is representable in tu_int or is negative + * (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +tu_int +__fixunsxfti(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0 || (fb.u.high.s.low & 0x00008000)) + return 0; + tu_int r = fb.u.low.all; + if (e > 63) + r <<= (e - 63); + else + r >>= (63 - e); + return r; +} + +#endif diff --git a/lib/fixxfdi.c b/lib/fixxfdi.c new file mode 100644 index 000000000000..de6f818b8cda --- /dev/null +++ b/lib/fixxfdi.c @@ -0,0 +1,44 @@ +/* ===-- fixxfdi.c - Implement __fixxfdi -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixxfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * su_int is a 32 bit integral type + * value in long double is representable in di_int (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +di_int +__fixxfdi(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0) + return 0; + di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15); + di_int r = fb.u.low.all; + r = (du_int)r >> (63 - e); + return (r ^ s) - s; +} + +#endif /* !_ARCH_PPC */ diff --git a/lib/fixxfti.c b/lib/fixxfti.c new file mode 100644 index 000000000000..c2248016c85c --- /dev/null +++ b/lib/fixxfti.c @@ -0,0 +1,47 @@ +/* ===-- fixxfti.c - Implement __fixxfti -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixxfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * su_int is a 32 bit integral type + * value in long double is representable in ti_int (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +ti_int +__fixxfti(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0) + return 0; + ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15); + ti_int r = fb.u.low.all; + if (e > 63) + r <<= (e - 63); + else + r >>= (63 - e); + return (r ^ s) - s; +} + +#endif /* __x86_64 */ diff --git a/lib/floatdidf.c b/lib/floatdidf.c new file mode 100644 index 000000000000..a0f501b60fff --- /dev/null +++ b/lib/floatdidf.c @@ -0,0 +1,107 @@ +/*===-- floatdidf.c - Implement __floatdidf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * This file implements __floatdidf for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: convert a to a double, rounding toward even. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * di_int is a 64 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +#ifndef __SOFT_FP__ +/* Support for systems that have hardware floating-point; we'll set the inexact flag + * as a side-effect of this computation. + */ +#include + +double +__floatdidf(di_int a) +{ + static const double twop52 = 0x1.0p52; + static const double twop32 = 0x1.0p32; + + union { int64_t x; double d; } low = { .d = twop52 }; + + const double high = (int32_t)(a >> 32) * twop32; + low.x |= a & INT64_C(0x00000000ffffffff); + + const double result = (high - twop52) + low.d; + return result; +} + +#else +/* Support for systems that don't have hardware floating-point; there are no flags to + * set, and we don't want to code-gen to an unknown soft-float implementation. + */ + +double +__floatdidf(di_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = ((du_int)a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((du_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.high = ((su_int)s & 0x80000000) | /* sign */ + ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.low = (su_int)a; /* mantissa-low */ + return fb.f; +} +#endif diff --git a/lib/floatdisf.c b/lib/floatdisf.c new file mode 100644 index 000000000000..1925f1588c5d --- /dev/null +++ b/lib/floatdisf.c @@ -0,0 +1,79 @@ +/*===-- floatdisf.c - Implement __floatdisf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * This file implements __floatdisf for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: convert a to a float, rounding toward even.*/ + +/* Assumption: float is a IEEE 32 bit floating point type + * di_int is a 64 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +float +__floatdisf(di_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = ((du_int)a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((du_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((su_int)s & 0x80000000) | /* sign */ + ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} diff --git a/lib/floatdixf.c b/lib/floatdixf.c new file mode 100644 index 000000000000..bfda367dfeca --- /dev/null +++ b/lib/floatdixf.c @@ -0,0 +1,46 @@ +/* ===-- floatdixf.c - Implement __floatdixf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatdixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * di_int is a 64 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +long double +__floatdixf(di_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N-1); + a = (a ^ s) - s; + int clz = __builtin_clzll(a); + int e = (N - 1) - clz ; /* exponent */ + long_double_bits fb; + fb.u.high.s.low = ((su_int)s & 0x00008000) | /* sign */ + (e + 16383); /* exponent */ + fb.u.low.all = a << clz; /* mantissa */ + return fb.f; +} + +#endif /* !_ARCH_PPC */ diff --git a/lib/floatsidf.c b/lib/floatsidf.c new file mode 100644 index 000000000000..a13ab8fbcfb5 --- /dev/null +++ b/lib/floatsidf.c @@ -0,0 +1,48 @@ +//===-- lib/floatsidf.c - integer -> double-precision conversion --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to double-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t __floatsidf(int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + + // All other cases begin by extracting the sign and absolute value of a + rep_t sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field and clear the implicit bit. Extra + // cast to unsigned int is necessary to get the correct behavior for + // the input INT_MIN. + const int shift = significandBits - exponent; + result = (rep_t)(unsigned int)a << shift ^ implicitBit; + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} diff --git a/lib/floatsisf.c b/lib/floatsisf.c new file mode 100644 index 000000000000..4a629755e783 --- /dev/null +++ b/lib/floatsisf.c @@ -0,0 +1,54 @@ +//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __floatsisf(int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + + // All other cases begin by extracting the sign and absolute value of a + rep_t sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + } else { + const int shift = exponent - significandBits; + result = (rep_t)a >> shift ^ implicitBit; + rep_t round = (rep_t)a << (typeWidth - shift); + if (round > signBit) result++; + if (round == signBit) result += result & 1; + } + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} diff --git a/lib/floattidf.c b/lib/floattidf.c new file mode 100644 index 000000000000..274f58517c4e --- /dev/null +++ b/lib/floattidf.c @@ -0,0 +1,86 @@ +/* ===-- floattidf.c - Implement __floattidf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floattidf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: convert a to a double, rounding toward even.*/ + +/* Assumption: double is a IEEE 64 bit floating point type + * ti_int is a 128 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +double +__floattidf(ti_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */ + ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.s.low = (su_int)a; /* mantissa-low */ + return fb.f; +} + +#endif diff --git a/lib/floattisf.c b/lib/floattisf.c new file mode 100644 index 000000000000..72f37481b3a2 --- /dev/null +++ b/lib/floattisf.c @@ -0,0 +1,85 @@ +/* ===-- floattisf.c - Implement __floattisf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floattisf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: convert a to a float, rounding toward even. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * ti_int is a 128 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +float +__floattisf(ti_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((su_int)s & 0x80000000) | /* sign */ + ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/floattixf.c b/lib/floattixf.c new file mode 100644 index 000000000000..77d906049be6 --- /dev/null +++ b/lib/floattixf.c @@ -0,0 +1,87 @@ +/* ===-- floattixf.c - Implement __floattixf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floattixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * ti_int is a 128 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +si_int __clzti2(ti_int a); + +long double +__floattixf(ti_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > LDBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit LDBL_MANT_DIG-1 bits to the right of 1 + * Q = bit LDBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case LDBL_MANT_DIG + 1: + a <<= 1; + break; + case LDBL_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << LDBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to LDBL_MANT_DIG bits */ + } + else + { + a <<= (LDBL_MANT_DIG - sd); + /* a is now rounded to LDBL_MANT_DIG bits */ + } + long_double_bits fb; + fb.u.high.s.low = ((su_int)s & 0x8000) | /* sign */ + (e + 16383); /* exponent */ + fb.u.low.all = (du_int)a; /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/floatundidf.c b/lib/floatundidf.c new file mode 100644 index 000000000000..1f304c5c3535 --- /dev/null +++ b/lib/floatundidf.c @@ -0,0 +1,107 @@ +/* ===-- floatundidf.c - Implement __floatundidf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatundidf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: convert a to a double, rounding toward even. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * du_int is a 64 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +#ifndef __SOFT_FP__ +/* Support for systems that have hardware floating-point; we'll set the inexact flag + * as a side-effect of this computation. + */ + +#include + +double +__floatundidf(du_int a) +{ + static const double twop52 = 0x1.0p52; + static const double twop84 = 0x1.0p84; + static const double twop84_plus_twop52 = 0x1.00000001p84; + + union { uint64_t x; double d; } high = { .d = twop84 }; + union { uint64_t x; double d; } low = { .d = twop52 }; + + high.x |= a >> 32; + low.x |= a & UINT64_C(0x00000000ffffffff); + + const double result = (high.d - twop84_plus_twop52) + low.d; + return result; +} + +#else +/* Support for systems that don't have hardware floating-point; there are no flags to + * set, and we don't want to code-gen to an unknown soft-float implementation. + */ + +double +__floatundidf(du_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((du_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.high = ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.low = (su_int)a; /* mantissa-low */ + return fb.f; +} +#endif diff --git a/lib/floatundisf.c b/lib/floatundisf.c new file mode 100644 index 000000000000..79b4b82e3a03 --- /dev/null +++ b/lib/floatundisf.c @@ -0,0 +1,76 @@ +/*===-- floatundisf.c - Implement __floatundisf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatundisf for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: convert a to a float, rounding toward even. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * du_int is a 64 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +float +__floatundisf(du_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* 8 exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((du_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} diff --git a/lib/floatundixf.c b/lib/floatundixf.c new file mode 100644 index 000000000000..bc9582f7604f --- /dev/null +++ b/lib/floatundixf.c @@ -0,0 +1,42 @@ +/* ===-- floatundixf.c - Implement __floatundixf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatundixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * du_int is a 64 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ +long double +__floatundixf(du_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int clz = __builtin_clzll(a); + int e = (N - 1) - clz ; /* exponent */ + long_double_bits fb; + fb.u.high.s.low = (e + 16383); /* exponent */ + fb.u.low.all = a << clz; /* mantissa */ + return fb.f; +} + +#endif /* _ARCH_PPC */ diff --git a/lib/floatunsidf.c b/lib/floatunsidf.c new file mode 100644 index 000000000000..05242c18ab37 --- /dev/null +++ b/lib/floatunsidf.c @@ -0,0 +1,37 @@ +//===-- lib/floatunsidf.c - uint -> double-precision conversion ---*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements unsigned integer to double-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t __floatunsidf(unsigned int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) return fromRep(0); + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field and clear the implicit bit. + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + return fromRep(result); +} diff --git a/lib/floatunsisf.c b/lib/floatunsisf.c new file mode 100644 index 000000000000..31c064432908 --- /dev/null +++ b/lib/floatunsisf.c @@ -0,0 +1,45 @@ +//===-- lib/floatunsisf.c - uint -> single-precision conversion ---*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements unsigned integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __floatunsisf(unsigned int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) return fromRep(0); + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + } else { + const int shift = exponent - significandBits; + result = (rep_t)a >> shift ^ implicitBit; + rep_t round = (rep_t)a << (typeWidth - shift); + if (round > signBit) result++; + if (round == signBit) result += result & 1; + } + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + return fromRep(result); +} diff --git a/lib/floatuntidf.c b/lib/floatuntidf.c new file mode 100644 index 000000000000..51d8b2827a36 --- /dev/null +++ b/lib/floatuntidf.c @@ -0,0 +1,83 @@ +/* ===-- floatuntidf.c - Implement __floatuntidf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatuntidf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: convert a to a double, rounding toward even. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * tu_int is a 128 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +double +__floatuntidf(tu_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.s.high = ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.s.low = (su_int)a; /* mantissa-low */ + return fb.f; +} + +#endif diff --git a/lib/floatuntisf.c b/lib/floatuntisf.c new file mode 100644 index 000000000000..328f39bbef78 --- /dev/null +++ b/lib/floatuntisf.c @@ -0,0 +1,82 @@ +/* ===-- floatuntisf.c - Implement __floatuntisf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatuntisf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: convert a to a float, rounding toward even. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * tu_int is a 128 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +float +__floatuntisf(tu_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/floatuntixf.c b/lib/floatuntixf.c new file mode 100644 index 000000000000..e82d0c1e6ff4 --- /dev/null +++ b/lib/floatuntixf.c @@ -0,0 +1,84 @@ +/* ===-- floatuntixf.c - Implement __floatuntixf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatuntixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * tu_int is a 128 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +si_int __clzti2(ti_int a); + +long double +__floatuntixf(tu_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > LDBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit LDBL_MANT_DIG-1 bits to the right of 1 + * Q = bit LDBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case LDBL_MANT_DIG + 1: + a <<= 1; + break; + case LDBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (LDBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << LDBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to LDBL_MANT_DIG bits */ + } + else + { + a <<= (LDBL_MANT_DIG - sd); + /* a is now rounded to LDBL_MANT_DIG bits */ + } + long_double_bits fb; + fb.u.high.s.low = (e + 16383); /* exponent */ + fb.u.low.all = (du_int)a; /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/fp_lib.h b/lib/fp_lib.h new file mode 100644 index 000000000000..eac670d7f236 --- /dev/null +++ b/lib/fp_lib.h @@ -0,0 +1,143 @@ +//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a configuration header for soft-float routines in compiler-rt. +// This file does not provide any part of the compiler-rt interface, but defines +// many useful constants and utility routines that are used in the +// implementation of the soft-float routines in compiler-rt. +// +// Assumes that float and double correspond to the IEEE-754 binary32 and +// binary64 types, respectively, and that integer endianness matches floating +// point endianness on the target platform. +// +//===----------------------------------------------------------------------===// + +#ifndef FP_LIB_HEADER +#define FP_LIB_HEADER + +#include +#include +#include + +#if defined SINGLE_PRECISION + +typedef uint32_t rep_t; +typedef int32_t srep_t; +typedef float fp_t; +#define REP_C UINT32_C +#define significandBits 23 + +static inline int rep_clz(rep_t a) { + return __builtin_clz(a); +} + +// 32x32 --> 64 bit multiply +static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + const uint64_t product = (uint64_t)a*b; + *hi = product >> 32; + *lo = product; +} + +#elif defined DOUBLE_PRECISION + +typedef uint64_t rep_t; +typedef int64_t srep_t; +typedef double fp_t; +#define REP_C UINT64_C +#define significandBits 52 + +static inline int rep_clz(rep_t a) { +#if defined __LP64__ + return __builtin_clzl(a); +#else + if (a & REP_C(0xffffffff00000000)) + return __builtin_clz(a >> 32); + else + return 32 + __builtin_clz(a & REP_C(0xffffffff)); +#endif +} + +#define loWord(a) (a & 0xffffffffU) +#define hiWord(a) (a >> 32) + +// 64x64 -> 128 wide multiply for platforms that don't have such an operation; +// many 64-bit platforms have this operation, but they tend to have hardware +// floating-point, so we don't bother with a special case for them here. +static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + // Each of the component 32x32 -> 64 products + const uint64_t plolo = loWord(a) * loWord(b); + const uint64_t plohi = loWord(a) * hiWord(b); + const uint64_t philo = hiWord(a) * loWord(b); + const uint64_t phihi = hiWord(a) * hiWord(b); + // Sum terms that contribute to lo in a way that allows us to get the carry + const uint64_t r0 = loWord(plolo); + const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo); + *lo = r0 + (r1 << 32); + // Sum terms contributing to hi with the carry from lo + *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi; +} + +#else +#error Either SINGLE_PRECISION or DOUBLE_PRECISION must be defined. +#endif + +#define typeWidth (sizeof(rep_t)*CHAR_BIT) +#define exponentBits (typeWidth - significandBits - 1) +#define maxExponent ((1 << exponentBits) - 1) +#define exponentBias (maxExponent >> 1) + +#define implicitBit (REP_C(1) << significandBits) +#define significandMask (implicitBit - 1U) +#define signBit (REP_C(1) << (significandBits + exponentBits)) +#define absMask (signBit - 1U) +#define exponentMask (absMask ^ significandMask) +#define oneRep ((rep_t)exponentBias << significandBits) +#define infRep exponentMask +#define quietBit (implicitBit >> 1) +#define qnanRep (exponentMask | quietBit) + +static inline rep_t toRep(fp_t x) { + const union { fp_t f; rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline fp_t fromRep(rep_t x) { + const union { fp_t f; rep_t i; } rep = {.i = x}; + return rep.f; +} + +static inline int normalize(rep_t *significand) { + const int shift = rep_clz(*significand) - rep_clz(implicitBit); + *significand <<= shift; + return 1 - shift; +} + +static inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) { + *hi = *hi << count | *lo >> (typeWidth - count); + *lo = *lo << count; +} + +static inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, int count) { + if (count < typeWidth) { + const bool sticky = *lo << (typeWidth - count); + *lo = *hi << (typeWidth - count) | *lo >> count | sticky; + *hi = *hi >> count; + } + else if (count < 2*typeWidth) { + const bool sticky = *hi << (2*typeWidth - count) | *lo; + *lo = *hi >> (count - typeWidth) | sticky; + *hi = 0; + } else { + const bool sticky = *hi | *lo; + *lo = sticky; + *hi = 0; + } +} + +#endif // FP_LIB_HEADER diff --git a/lib/gcc_personality_v0.c b/lib/gcc_personality_v0.c new file mode 100644 index 000000000000..59401900ef85 --- /dev/null +++ b/lib/gcc_personality_v0.c @@ -0,0 +1,251 @@ +/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + */ + +#include +#include +#include + +#include "int_lib.h" + +/* + * _Unwind_* stuff based on C++ ABI public documentation + * http://refspecs.freestandards.org/abi-eh-1.21.html + */ + +typedef enum { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 +} _Unwind_Reason_Code; + +typedef enum { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16 +} _Unwind_Action; + +typedef struct _Unwind_Context* _Unwind_Context_t; + +struct _Unwind_Exception { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code reason, + struct _Unwind_Exception* exc); + uintptr_t private_1; + uintptr_t private_2; +}; + +extern const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c); +extern void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n); +extern void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value); +extern uintptr_t _Unwind_GetIP(_Unwind_Context_t context); +extern uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context); + + +/* + * Pointer encodings documented at: + * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html + */ + +#define DW_EH_PE_omit 0xff /* no data follows */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 +#define DW_EH_PE_indirect 0x80 /* gcc extension */ + + + +/* read a uleb128 encoded value and advance pointer */ +static uintptr_t readULEB128(const uint8_t** data) +{ + uintptr_t result = 0; + uintptr_t shift = 0; + unsigned char byte; + const uint8_t* p = *data; + do { + byte = *p++; + result |= (byte & 0x7f) << shift; + shift += 7; + } while (byte & 0x80); + *data = p; + return result; +} + +/* read a pointer encoded value and advance pointer */ +static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) +{ + const uint8_t* p = *data; + uintptr_t result = 0; + + if ( encoding == DW_EH_PE_omit ) + return 0; + + /* first get value */ + switch (encoding & 0x0F) { + case DW_EH_PE_absptr: + result = *((uintptr_t*)p); + p += sizeof(uintptr_t); + break; + case DW_EH_PE_uleb128: + result = readULEB128(&p); + break; + case DW_EH_PE_udata2: + result = *((uint16_t*)p); + p += sizeof(uint16_t); + break; + case DW_EH_PE_udata4: + result = *((uint32_t*)p); + p += sizeof(uint32_t); + break; + case DW_EH_PE_udata8: + result = *((uint64_t*)p); + p += sizeof(uint64_t); + break; + case DW_EH_PE_sdata2: + result = *((int16_t*)p); + p += sizeof(int16_t); + break; + case DW_EH_PE_sdata4: + result = *((int32_t*)p); + p += sizeof(int32_t); + break; + case DW_EH_PE_sdata8: + result = *((int64_t*)p); + p += sizeof(int64_t); + break; + case DW_EH_PE_sleb128: + default: + /* not supported */ + compilerrt_abort(); + break; + } + + /* then add relative offset */ + switch ( encoding & 0x70 ) { + case DW_EH_PE_absptr: + /* do nothing */ + break; + case DW_EH_PE_pcrel: + result += (uintptr_t)(*data); + break; + case DW_EH_PE_textrel: + case DW_EH_PE_datarel: + case DW_EH_PE_funcrel: + case DW_EH_PE_aligned: + default: + /* not supported */ + compilerrt_abort(); + break; + } + + /* then apply indirection */ + if (encoding & DW_EH_PE_indirect) { + result = *((uintptr_t*)result); + } + + *data = p; + return result; +} + + +/* + * The C compiler makes references to __gcc_personality_v0 in + * the dwarf unwind information for translation units that use + * __attribute__((cleanup(xx))) on local variables. + * This personality routine is called by the system unwinder + * on each frame as the stack is unwound during a C++ exception + * throw through a C function compiled with -fexceptions. + */ +#if __arm__ +// the setjump-longjump based exceptions personality routine has a different name +_Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions, + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + _Unwind_Context_t context) +#else +_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + _Unwind_Context_t context) +#endif +{ + /* Since C does not have catch clauses, there is nothing to do during */ + /* phase 1 (the search phase). */ + if ( actions & _UA_SEARCH_PHASE ) + return _URC_CONTINUE_UNWIND; + + /* There is nothing to do if there is no LSDA for this frame. */ + const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context); + if ( lsda == NULL ) + return _URC_CONTINUE_UNWIND; + + uintptr_t pc = _Unwind_GetIP(context)-1; + uintptr_t funcStart = _Unwind_GetRegionStart(context); + uintptr_t pcOffset = pc - funcStart; + + /* Parse LSDA header. */ + uint8_t lpStartEncoding = *lsda++; + if (lpStartEncoding != DW_EH_PE_omit) { + readEncodedPointer(&lsda, lpStartEncoding); + } + uint8_t ttypeEncoding = *lsda++; + if (ttypeEncoding != DW_EH_PE_omit) { + readULEB128(&lsda); + } + /* Walk call-site table looking for range that includes current PC. */ + uint8_t callSiteEncoding = *lsda++; + uint32_t callSiteTableLength = readULEB128(&lsda); + const uint8_t* callSiteTableStart = lsda; + const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; + const uint8_t* p=callSiteTableStart; + while (p < callSiteTableEnd) { + uintptr_t start = readEncodedPointer(&p, callSiteEncoding); + uintptr_t length = readEncodedPointer(&p, callSiteEncoding); + uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding); + readULEB128(&p); /* action value not used for C code */ + if ( landingPad == 0 ) + continue; /* no landing pad for this entry */ + if ( (start <= pcOffset) && (pcOffset < (start+length)) ) { + /* Found landing pad for the PC. + * Set Instruction Pointer to so we re-enter function + * at landing pad. The landing pad is created by the compiler + * to take two parameters in registers. + */ + _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), + (uintptr_t)exceptionObject); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0); + _Unwind_SetIP(context, funcStart+landingPad); + return _URC_INSTALL_CONTEXT; + } + } + + /* No landing pad found, continue unwinding. */ + return _URC_CONTINUE_UNWIND; +} + diff --git a/lib/i386/CMakeLists.txt b/lib/i386/CMakeLists.txt new file mode 100644 index 000000000000..1c2861afb06e --- /dev/null +++ b/lib/i386/CMakeLists.txt @@ -0,0 +1,3 @@ +SET( SRCS + + ) diff --git a/lib/i386/Makefile.mk b/lib/i386/Makefile.mk new file mode 100644 index 000000000000..20f95e651481 --- /dev/null +++ b/lib/i386/Makefile.mk @@ -0,0 +1,19 @@ +#===- lib/i386/Makefile.mk ---------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +SubDirs := +OnlyArchs := i386 + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/i386/ashldi3.S b/lib/i386/ashldi3.S new file mode 100644 index 000000000000..af6f98bc7cf8 --- /dev/null +++ b/lib/i386/ashldi3.S @@ -0,0 +1,56 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __ashldi3(di_int input, int count); + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +#ifdef __i386__ +#ifdef __SSE2__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashldi3) + movd 12(%esp), %xmm2 // Load count +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 // Load input +#else + movq 4(%esp), %xmm0 // Load input +#endif + psllq %xmm2, %xmm0 // shift input by count + movd %xmm0, %eax + psrlq $32, %xmm0 + movd %xmm0, %edx + ret + +#else // Use GPRs instead of SSE2 instructions, if they aren't available. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashldi3) + movl 12(%esp), %ecx // Load count + movl 8(%esp), %edx // Load high + movl 4(%esp), %eax // Load low + + testl $0x20, %ecx // If count >= 32 + jnz 1f // goto 1 + shldl %cl, %eax, %edx // left shift high by count + shll %cl, %eax // left shift low by count + ret + +1: movl %eax, %edx // Move low to high + xorl %eax, %eax // clear low + shll %cl, %edx // shift high by count - 32 + ret + +#endif // __SSE2__ +#endif // __i386__ diff --git a/lib/i386/ashrdi3.S b/lib/i386/ashrdi3.S new file mode 100644 index 000000000000..346f9b1adc16 --- /dev/null +++ b/lib/i386/ashrdi3.S @@ -0,0 +1,67 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __ashrdi3(di_int input, int count); + +#ifdef __i386__ +#ifdef __SSE2__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashrdi3) + movd 12(%esp), %xmm2 // Load count + movl 8(%esp), %eax +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 // Load input +#else + movq 4(%esp), %xmm0 // Load input +#endif + + psrlq %xmm2, %xmm0 // unsigned shift input by count + + testl %eax, %eax // check the sign-bit of the input + jns 1f // early out for positive inputs + + // If the input is negative, we need to construct the shifted sign bit + // to or into the result, as xmm does not have a signed right shift. + pcmpeqb %xmm1, %xmm1 // -1ULL + psrlq $58, %xmm1 // 0x3f + pandn %xmm1, %xmm2 // 63 - count + pcmpeqb %xmm1, %xmm1 // -1ULL + psubq %xmm1, %xmm2 // 64 - count + psllq %xmm2, %xmm1 // -1 << (64 - count) = leading sign bits + por %xmm1, %xmm0 + + // Move the result back to the general purpose registers and return +1: movd %xmm0, %eax + psrlq $32, %xmm0 + movd %xmm0, %edx + ret + +#else // Use GPRs instead of SSE2 instructions, if they aren't available. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashrdi3) + movl 12(%esp), %ecx // Load count + movl 8(%esp), %edx // Load high + movl 4(%esp), %eax // Load low + + testl $0x20, %ecx // If count >= 32 + jnz 1f // goto 1 + + shrdl %cl, %edx, %eax // right shift low by count + sarl %cl, %edx // right shift high by count + ret + +1: movl %edx, %eax // Move high to low + sarl $31, %edx // clear high + sarl %cl, %eax // shift low by count - 32 + ret + +#endif // __SSE2__ +#endif // __i386__ diff --git a/lib/i386/divdi3.S b/lib/i386/divdi3.S new file mode 100644 index 000000000000..5ad530c34a4f --- /dev/null +++ b/lib/i386/divdi3.S @@ -0,0 +1,161 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __divdi3(di_int a, di_int b); + +// result = a / b. +// both inputs and the output are 64-bit signed integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__divdi3) + +/* This is currently implemented by wrapping the unsigned divide up in an absolute + value, then restoring the correct sign at the end of the computation. This could + certainly be improved upon. */ + + pushl %esi + movl 20(%esp), %edx // high word of b + movl 16(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (b < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(b) + movl %edx, 20(%esp) + movl %eax, 16(%esp) // store abs(b) back to stack + movl %ecx, %esi // set aside sign of b + + movl 12(%esp), %edx // high word of b + movl 8(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (a < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(a) + movl %edx, 12(%esp) + movl %eax, 8(%esp) // store abs(a) back to stack + xorl %ecx, %esi // sign of result = (sign of a) ^ (sign of b) + + pushl %ebx + movl 24(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 16(%esp), %edx // Load the high and low words of a, and jump + movl 12(%esp), %eax // to [1] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 1f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + + +1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + + +9: /* High word of b is zero on this branch */ + + movl 16(%esp), %eax // Find qhi and rhi such that + movl 20(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 12(%esp), %eax // Find qlo such that + divl %ecx // + movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %ebx // Restore callee-save registers + popl %esi + retl // Return + +#endif // __i386__ diff --git a/lib/i386/floatdidf.S b/lib/i386/floatdidf.S new file mode 100644 index 000000000000..3a526eab9f96 --- /dev/null +++ b/lib/i386/floatdidf.S @@ -0,0 +1,35 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// double __floatundidf(du_int a); + +#ifdef __i386__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop32: .quad 0x41f0000000000000 + +#define REL_ADDR(_a) (_a)-0b(%eax) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatdidf) + cvtsi2sd 8(%esp), %xmm1 + movss 4(%esp), %xmm0 // low 32 bits of a + calll 0f +0: popl %eax + mulsd REL_ADDR(twop32), %xmm1 // a_hi as a double (without rounding) + movsd REL_ADDR(twop52), %xmm2 // 0x1.0p52 + subsd %xmm2, %xmm1 // a_hi - 0x1p52 (no rounding occurs) + orpd %xmm2, %xmm0 // 0x1p52 + a_lo (no rounding occurs) + addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here) + movsd %xmm0, 4(%esp) + fldl 4(%esp) + ret + +#endif // __i386__ diff --git a/lib/i386/floatdisf.S b/lib/i386/floatdisf.S new file mode 100644 index 000000000000..741e4a6607fc --- /dev/null +++ b/lib/i386/floatdisf.S @@ -0,0 +1,31 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatdisf(di_int a); + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatdisf) +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 + movq %xmm0, 4(%esp) +#endif + fildll 4(%esp) + fstps 4(%esp) + flds 4(%esp) + ret + +#endif // __i386__ diff --git a/lib/i386/floatdixf.S b/lib/i386/floatdixf.S new file mode 100644 index 000000000000..f0271abcbdc2 --- /dev/null +++ b/lib/i386/floatdixf.S @@ -0,0 +1,29 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatdixf(di_int a); + +#ifdef __i386__ + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatdixf) +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 + movq %xmm0, 4(%esp) +#endif + fildll 4(%esp) + ret + +#endif // __i386__ diff --git a/lib/i386/floatundidf.S b/lib/i386/floatundidf.S new file mode 100644 index 000000000000..7186a355d96c --- /dev/null +++ b/lib/i386/floatundidf.S @@ -0,0 +1,46 @@ +//===-- floatundidf.S - Implement __floatundidf for i386 ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements __floatundidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// double __floatundidf(du_int a); + +#ifdef __i386__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52: + .quad 0x4530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)-0b(%eax) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundidf) + movss 8(%esp), %xmm1 // high 32 bits of a + movss 4(%esp), %xmm0 // low 32 bits of a + calll 0f +0: popl %eax + orpd REL_ADDR(twop84), %xmm1 // 0x1p84 + a_hi (no rounding occurs) + subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs) + orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs) + addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here) + movsd %xmm0, 4(%esp) + fldl 4(%esp) + ret + +#endif // __i386__ diff --git a/lib/i386/floatundisf.S b/lib/i386/floatundisf.S new file mode 100644 index 000000000000..070820c9d4d2 --- /dev/null +++ b/lib/i386/floatundisf.S @@ -0,0 +1,99 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatundisf(du_int a); + +// Note that there is a hardware instruction, fildll, that does most of what +// this function needs to do. However, because of our ia32 ABI, it will take +// a write-small read-large stall, so the software implementation here is +// actually several cycles faster. + +// This is a branch-free implementation. A branchy implementation might be +// faster for the common case if you know something a priori about the input +// distribution. + +/* branch-free x87 implementation - one cycle slower than without x87. + +#ifdef __i386__ + +.const +.align 3 + + .quad 0x43f0000000000000 +twop64: .quad 0x0000000000000000 + +#define TWOp64 twop64-0b(%ecx,%eax,8) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundisf) + movl 8(%esp), %eax + movd 8(%esp), %xmm1 + movd 4(%esp), %xmm0 + punpckldq %xmm1, %xmm0 + calll 0f +0: popl %ecx + sarl $31, %eax + movq %xmm0, 4(%esp) + fildll 4(%esp) + faddl TWOp64 + fstps 4(%esp) + flds 4(%esp) + ret + +#endif // __i386__ + +*/ + +/* branch-free, x87-free implementation - faster at the expense of code size */ + +#ifdef __i386__ + +#ifndef __ELF__ +.const +.align 3 +#else +.align 8 +#endif +twop52: .quad 0x4330000000000000 + .quad 0x0000000000000fff +sticky: .quad 0x0000000000000000 + .long 0x00000012 +twelve: .long 0x00000000 + +#define TWOp52 twop52-0b(%ecx) +#define STICKY sticky-0b(%ecx,%eax,8) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundisf) + movl 8(%esp), %eax + movd 8(%esp), %xmm1 + movd 4(%esp), %xmm0 + punpckldq %xmm1, %xmm0 + + calll 0f +0: popl %ecx + shrl %eax // high 31 bits of input as sint32 + addl $0x7ff80000, %eax + sarl $31, %eax // (big input) ? -1 : 0 + movsd STICKY, %xmm1 // (big input) ? 0xfff : 0 + movl $12, %edx + andl %eax, %edx // (big input) ? 12 : 0 + movd %edx, %xmm3 + andpd %xmm0, %xmm1 // (big input) ? input & 0xfff : 0 + movsd TWOp52, %xmm2 // 0x1.0p52 + psrlq %xmm3, %xmm0 // (big input) ? input >> 12 : input + orpd %xmm2, %xmm1 // 0x1.0p52 + ((big input) ? input & 0xfff : input) + orpd %xmm1, %xmm0 // 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input) + subsd %xmm2, %xmm0 // (double)((big input) ? (input >> 12 | input & 0xfff) : input) + cvtsd2ss %xmm0, %xmm0 // (float)((big input) ? (input >> 12 | input & 0xfff) : input) + pslld $23, %xmm3 + paddd %xmm3, %xmm0 // (float)input + movd %xmm0, 4(%esp) + flds 4(%esp) + ret + +#endif // __i386__ diff --git a/lib/i386/floatundixf.S b/lib/i386/floatundixf.S new file mode 100644 index 000000000000..2cf6d5c2a6ee --- /dev/null +++ b/lib/i386/floatundixf.S @@ -0,0 +1,37 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// long double __floatundixf(du_int a);16 + +#ifdef __i386__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52_neg: + .quad 0xc530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)-0b(%eax) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundixf) + calll 0f +0: popl %eax + movss 8(%esp), %xmm0 // hi 32 bits of input + movss 4(%esp), %xmm1 // lo 32 bits of input + orpd REL_ADDR(twop84), %xmm0 // 2^84 + hi (as a double) + orpd REL_ADDR(twop52), %xmm1 // 2^52 + lo (as a double) + addsd REL_ADDR(twop84_plus_twop52_neg), %xmm0 // hi - 2^52 (no rounding occurs) + movsd %xmm1, 4(%esp) + fldl 4(%esp) + movsd %xmm0, 4(%esp) + faddl 4(%esp) + ret + +#endif // __i386__ diff --git a/lib/i386/lshrdi3.S b/lib/i386/lshrdi3.S new file mode 100644 index 000000000000..74937d2d8c16 --- /dev/null +++ b/lib/i386/lshrdi3.S @@ -0,0 +1,57 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __lshrdi3(di_int input, int count); + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +#ifdef __i386__ +#ifdef __SSE2__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__lshrdi3) + movd 12(%esp), %xmm2 // Load count +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 // Load input +#else + movq 4(%esp), %xmm0 // Load input +#endif + psrlq %xmm2, %xmm0 // shift input by count + movd %xmm0, %eax + psrlq $32, %xmm0 + movd %xmm0, %edx + ret + +#else // Use GPRs instead of SSE2 instructions, if they aren't available. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__lshrdi3) + movl 12(%esp), %ecx // Load count + movl 8(%esp), %edx // Load high + movl 4(%esp), %eax // Load low + + testl $0x20, %ecx // If count >= 32 + jnz 1f // goto 1 + + shrdl %cl, %edx, %eax // right shift low by count + shrl %cl, %edx // right shift high by count + ret + +1: movl %edx, %eax // Move high to low + xorl %edx, %edx // clear high + shrl %cl, %eax // shift low by count - 32 + ret + +#endif // __SSE2__ +#endif // __i386__ diff --git a/lib/i386/moddi3.S b/lib/i386/moddi3.S new file mode 100644 index 000000000000..85f5b3811d5c --- /dev/null +++ b/lib/i386/moddi3.S @@ -0,0 +1,166 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __moddi3(di_int a, di_int b); + +// result = remainder of a / b. +// both inputs and the output are 64-bit signed integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// + +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__moddi3) + +/* This is currently implemented by wrapping the unsigned modulus up in an absolute + value. This could certainly be improved upon. */ + + pushl %esi + movl 20(%esp), %edx // high word of b + movl 16(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (b < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(b) + movl %edx, 20(%esp) + movl %eax, 16(%esp) // store abs(b) back to stack + + movl 12(%esp), %edx // high word of b + movl 8(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (a < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(a) + movl %edx, 12(%esp) + movl %eax, 8(%esp) // store abs(a) back to stack + movl %ecx, %esi // set aside sign of a + + pushl %ebx + movl 24(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 16(%esp), %edx // Load the high and low words of a, and jump + movl 12(%esp), %eax // to [2] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 2f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 1f // if positive, this is the result. + addl 24(%esp), %ebx // otherwise + adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +1: movl %ebx, %eax + movl %ecx, %edx + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + +2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 3f // if positive, this is the result. + addl 24(%esp), %ebx // otherwise + adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +3: movl %ebx, %eax + movl %ecx, %edx + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + +9: /* High word of b is zero on this branch */ + + movl 16(%esp), %eax // Find qhi and rhi such that + movl 20(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 12(%esp), %eax // Find rlo such that + divl %ecx // + movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + popl %ebx // + xorl %edx, %edx // and return 0:rlo + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %esi + retl // Return + + +#endif // __i386__ diff --git a/lib/i386/muldi3.S b/lib/i386/muldi3.S new file mode 100644 index 000000000000..5f99f6a9ea82 --- /dev/null +++ b/lib/i386/muldi3.S @@ -0,0 +1,29 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __muldi3(di_int a, di_int b); + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__muldi3) + pushl %ebx + movl 16(%esp), %eax // b.lo + movl 12(%esp), %ecx // a.hi + imull %eax, %ecx // b.lo * a.hi + + movl 8(%esp), %edx // a.lo + movl 20(%esp), %ebx // b.hi + imull %edx, %ebx // a.lo * b.hi + + mull %edx // EDX:EAX = a.lo * b.lo + addl %ecx, %ebx // EBX = (a.lo*b.hi + a.hi*b.lo) + addl %ebx, %edx + + popl %ebx + retl + +#endif // __i386__ diff --git a/lib/i386/udivdi3.S b/lib/i386/udivdi3.S new file mode 100644 index 000000000000..77936f858ac6 --- /dev/null +++ b/lib/i386/udivdi3.S @@ -0,0 +1,114 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// du_int __udivdi3(du_int a, du_int b); + +// result = a / b. +// both inputs and the output are 64-bit unsigned integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__udivdi3) + + pushl %ebx + movl 20(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 12(%esp), %edx // Load the high and low words of a, and jump + movl 8(%esp), %eax // to [1] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 1f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + popl %edi + popl %ebx + retl + + +1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + popl %edi + popl %ebx + retl + + +9: /* High word of b is zero on this branch */ + + movl 12(%esp), %eax // Find qhi and rhi such that + movl 16(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 8(%esp), %eax // Find qlo such that + divl %ecx // + movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + popl %ebx // + retl // and return qhi:qlo + +#endif // __i386__ diff --git a/lib/i386/umoddi3.S b/lib/i386/umoddi3.S new file mode 100644 index 000000000000..3cf8aeb62b28 --- /dev/null +++ b/lib/i386/umoddi3.S @@ -0,0 +1,125 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// du_int __umoddi3(du_int a, du_int b); + +// result = remainder of a / b. +// both inputs and the output are 64-bit unsigned integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// + +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__umoddi3) + + pushl %ebx + movl 20(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 12(%esp), %edx // Load the high and low words of a, and jump + movl 8(%esp), %eax // to [2] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 2f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 1f // if positive, this is the result. + addl 20(%esp), %ebx // otherwise + adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +1: movl %ebx, %eax + movl %ecx, %edx + + popl %edi + popl %ebx + retl + + +2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 3f // if positive, this is the result. + addl 20(%esp), %ebx // otherwise + adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +3: movl %ebx, %eax + movl %ecx, %edx + + popl %edi + popl %ebx + retl + + + +9: /* High word of b is zero on this branch */ + + movl 12(%esp), %eax // Find qhi and rhi such that + movl 16(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 8(%esp), %eax // Find rlo such that + divl %ecx // + movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + popl %ebx // + xorl %edx, %edx // and return 0:rlo + retl // + +#endif // __i386__ diff --git a/lib/int_lib.h b/lib/int_lib.h new file mode 100644 index 000000000000..912a12f5937c --- /dev/null +++ b/lib/int_lib.h @@ -0,0 +1,155 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_LIB_H +#define INT_LIB_H + +/* Assumption: signed integral is 2's complement */ +/* Assumption: right shift of signed negative is arithmetic shift */ + +#include +#include "endianness.h" +#include + +/* If compiling for kernel use, call panic() instead of abort(). */ +#ifdef KERNEL_USE +extern void panic (const char *, ...); +#define compilerrt_abort() \ + panic("%s:%d: abort in %s", __FILE__, __LINE__, __FUNCTION__) +#else +#define compilerrt_abort() abort() +#endif + +#if !defined(INFINITY) && defined(HUGE_VAL) +#define INFINITY HUGE_VAL +#endif /* INFINITY */ + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +typedef union +{ + di_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + si_int high; +#else + si_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} dwords; + +typedef union +{ + du_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + su_int high; +#else + su_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} udwords; + +#if __x86_64 + +typedef int ti_int __attribute__ ((mode (TI))); +typedef unsigned tu_int __attribute__ ((mode (TI))); + +typedef union +{ + ti_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + di_int high; +#else + di_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} twords; + +typedef union +{ + tu_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + du_int high; +#else + du_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} utwords; + +static inline ti_int make_ti(di_int h, di_int l) { + twords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +static inline tu_int make_tu(du_int h, du_int l) { + utwords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +#endif /* __x86_64 */ + +typedef union +{ + su_int u; + float f; +} float_bits; + +typedef union +{ + udwords u; + double f; +} double_bits; + +typedef struct +{ +#if _YUGA_LITTLE_ENDIAN + udwords low; + udwords high; +#else + udwords high; + udwords low; +#endif /* _YUGA_LITTLE_ENDIAN */ +} uqwords; + +typedef union +{ + uqwords u; + long double f; +} long_double_bits; + +#endif /* INT_LIB_H */ diff --git a/lib/lshrdi3.c b/lib/lshrdi3.c new file mode 100644 index 000000000000..57484ee750af --- /dev/null +++ b/lib/lshrdi3.c @@ -0,0 +1,41 @@ +/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __lshrdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: logical a >> b */ + +/* Precondition: 0 <= b < bits_in_dword */ + +di_int +__lshrdi3(di_int a, si_int b) +{ + const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); + udwords input; + udwords result; + input.all = a; + if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ + { + result.s.high = 0; + result.s.low = input.s.high >> (b - bits_in_word); + } + else /* 0 <= b < bits_in_word */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b); + } + return result.all; +} diff --git a/lib/lshrti3.c b/lib/lshrti3.c new file mode 100644 index 000000000000..3272c9ca831a --- /dev/null +++ b/lib/lshrti3.c @@ -0,0 +1,45 @@ +/* ===-- lshrti3.c - Implement __lshrti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __lshrti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: logical a >> b */ + +/* Precondition: 0 <= b < bits_in_tword */ + +ti_int +__lshrti3(ti_int a, si_int b) +{ + const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT); + utwords input; + utwords result; + input.all = a; + if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ + { + result.s.high = 0; + result.s.low = input.s.high >> (b - bits_in_dword); + } + else /* 0 <= b < bits_in_dword */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b); + } + return result.all; +} + +#endif /* __x86_64 */ diff --git a/lib/moddi3.c b/lib/moddi3.c new file mode 100644 index 000000000000..453355596825 --- /dev/null +++ b/lib/moddi3.c @@ -0,0 +1,32 @@ +/*===-- moddi3.c - Implement __moddi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __moddi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a % b */ + +di_int +__moddi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s = b >> bits_in_dword_m1; /* s = b < 0 ? -1 : 0 */ + b = (b ^ s) - s; /* negate if s == -1 */ + s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */ + a = (a ^ s) - s; /* negate if s == -1 */ + di_int r; + __udivmoddi4(a, b, (du_int*)&r); + return (r ^ s) - s; /* negate if s == -1 */ +} diff --git a/lib/modsi3.c b/lib/modsi3.c new file mode 100644 index 000000000000..c9214a24f39b --- /dev/null +++ b/lib/modsi3.c @@ -0,0 +1,23 @@ +/* ===-- modsi3.c - Implement __modsi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __modsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a % b */ + +si_int +__modsi3(si_int a, si_int b) +{ + return a - (a / b) * b; +} diff --git a/lib/modti3.c b/lib/modti3.c new file mode 100644 index 000000000000..75d688ef0a63 --- /dev/null +++ b/lib/modti3.c @@ -0,0 +1,36 @@ +/* ===-- modti3.c - Implement __modti3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __modti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/*Returns: a % b */ + +ti_int +__modti3(ti_int a, ti_int b) +{ + const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; + ti_int s = b >> bits_in_tword_m1; /* s = b < 0 ? -1 : 0 */ + b = (b ^ s) - s; /* negate if s == -1 */ + s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */ + a = (a ^ s) - s; /* negate if s == -1 */ + ti_int r; + __udivmodti4(a, b, (tu_int*)&r); + return (r ^ s) - s; /* negate if s == -1 */ +} + +#endif diff --git a/lib/muldc3.c b/lib/muldc3.c new file mode 100644 index 000000000000..c048d84faa1f --- /dev/null +++ b/lib/muldc3.c @@ -0,0 +1,74 @@ +/* ===-- muldc3.c - Implement __muldc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include +#include + +/* Returns: the product of a + ib and c + id */ + +double _Complex +__muldc3(double __a, double __b, double __c, double __d) +{ + double __ac = __a * __c; + double __bd = __b * __d; + double __ad = __a * __d; + double __bc = __b * __c; + double _Complex z; + __real__ z = __ac - __bd; + __imag__ z = __ad + __bc; + if (isnan(__real__ z) && isnan(__imag__ z)) + { + int __recalc = 0; + if (isinf(__a) || isinf(__b)) + { + __a = copysign(isinf(__a) ? 1 : 0, __a); + __b = copysign(isinf(__b) ? 1 : 0, __b); + if (isnan(__c)) + __c = copysign(0, __c); + if (isnan(__d)) + __d = copysign(0, __d); + __recalc = 1; + } + if (isinf(__c) || isinf(__d)) + { + __c = copysign(isinf(__c) ? 1 : 0, __c); + __d = copysign(isinf(__d) ? 1 : 0, __d); + if (isnan(__a)) + __a = copysign(0, __a); + if (isnan(__b)) + __b = copysign(0, __b); + __recalc = 1; + } + if (!__recalc && (isinf(__ac) || isinf(__bd) || + isinf(__ad) || isinf(__bc))) + { + if (isnan(__a)) + __a = copysign(0, __a); + if (isnan(__b)) + __b = copysign(0, __b); + if (isnan(__c)) + __c = copysign(0, __c); + if (isnan(__d)) + __d = copysign(0, __d); + __recalc = 1; + } + if (__recalc) + { + __real__ z = INFINITY * (__a * __c - __b * __d); + __imag__ z = INFINITY * (__a * __d + __b * __c); + } + } + return z; +} diff --git a/lib/muldf3.c b/lib/muldf3.c new file mode 100644 index 000000000000..63a473e88d21 --- /dev/null +++ b/lib/muldf3.c @@ -0,0 +1,119 @@ +//===-- lib/muldf3.c - Double-precision multiplication ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float multiplication +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t __muldf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs) return fromRep(aAbs | productSign); + // infinity * zero = NaN + else return fromRep(qnanRep); + } + + if (bAbs == infRep) { + // non-zero * infinity = +/- infinity + if (aAbs) return fromRep(bAbs | productSign); + // zero * infinity = NaN + else return fromRep(qnanRep); + } + + // zero * anything = +/- zero + if (!aAbs) return fromRep(productSign); + // anything * zero = +/- zero + if (!bAbs) return fromRep(productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale += normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + rep_t productHi, productLo; + wideMultiply(aSignificand, bSignificand << exponentBits, + &productHi, &productLo); + + int productExponent = aExponent + bExponent - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if (productHi & implicitBit) productExponent++; + else wideLeftShift(&productHi, &productLo, 1); + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return fromRep(infRep | productSign); + + if (productExponent <= 0) { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + const int shift = 1 - productExponent; + if (shift >= typeWidth) return fromRep(productSign); + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of productLo. + wideRightShiftWithSticky(&productHi, &productLo, shift); + } + + else { + // Result is normal before rounding; insert the exponent. + productHi &= significandMask; + productHi |= (rep_t)productExponent << significandBits; + } + + // Insert the sign of the result: + productHi |= productSign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if (productLo > signBit) productHi++; + if (productLo == signBit) productHi += productHi & 1; + return fromRep(productHi); +} diff --git a/lib/muldi3.c b/lib/muldi3.c new file mode 100644 index 000000000000..38963b72630d --- /dev/null +++ b/lib/muldi3.c @@ -0,0 +1,54 @@ +/* ===-- muldi3.c - Implement __muldi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +static +di_int +__muldsi3(su_int a, su_int b) +{ + dwords r; + const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2; + const su_int lower_mask = (su_int)~0 >> bits_in_word_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + su_int t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (a >> bits_in_word_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high = t >> bits_in_word_2; + t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (b >> bits_in_word_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high += t >> bits_in_word_2; + r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2); + return r.all; +} + +/* Returns: a * b */ + +di_int +__muldi3(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + dwords r; + r.all = __muldsi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} diff --git a/lib/mulsc3.c b/lib/mulsc3.c new file mode 100644 index 000000000000..c7b9f6417269 --- /dev/null +++ b/lib/mulsc3.c @@ -0,0 +1,74 @@ +/* ===-- mulsc3.c - Implement __mulsc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulsc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include +#include + +/* Returns: the product of a + ib and c + id */ + +float _Complex +__mulsc3(float __a, float __b, float __c, float __d) +{ + float __ac = __a * __c; + float __bd = __b * __d; + float __ad = __a * __d; + float __bc = __b * __c; + float _Complex z; + __real__ z = __ac - __bd; + __imag__ z = __ad + __bc; + if (isnan(__real__ z) && isnan(__imag__ z)) + { + int __recalc = 0; + if (isinf(__a) || isinf(__b)) + { + __a = copysignf(isinf(__a) ? 1 : 0, __a); + __b = copysignf(isinf(__b) ? 1 : 0, __b); + if (isnan(__c)) + __c = copysignf(0, __c); + if (isnan(__d)) + __d = copysignf(0, __d); + __recalc = 1; + } + if (isinf(__c) || isinf(__d)) + { + __c = copysignf(isinf(__c) ? 1 : 0, __c); + __d = copysignf(isinf(__d) ? 1 : 0, __d); + if (isnan(__a)) + __a = copysignf(0, __a); + if (isnan(__b)) + __b = copysignf(0, __b); + __recalc = 1; + } + if (!__recalc && (isinf(__ac) || isinf(__bd) || + isinf(__ad) || isinf(__bc))) + { + if (isnan(__a)) + __a = copysignf(0, __a); + if (isnan(__b)) + __b = copysignf(0, __b); + if (isnan(__c)) + __c = copysignf(0, __c); + if (isnan(__d)) + __d = copysignf(0, __d); + __recalc = 1; + } + if (__recalc) + { + __real__ z = INFINITY * (__a * __c - __b * __d); + __imag__ z = INFINITY * (__a * __d + __b * __c); + } + } + return z; +} diff --git a/lib/mulsf3.c b/lib/mulsf3.c new file mode 100644 index 000000000000..6bd2f9dcae50 --- /dev/null +++ b/lib/mulsf3.c @@ -0,0 +1,109 @@ +//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float multiplication +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __mulsf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs) return fromRep(aAbs | productSign); + // infinity * zero = NaN + else return fromRep(qnanRep); + } + + if (bAbs == infRep) { + // non-zero * infinity = +/- infinity + if (aAbs) return fromRep(bAbs | productSign); + // zero * infinity = NaN + else return fromRep(qnanRep); + } + + // zero * anything = +/- zero + if (!aAbs) return fromRep(productSign); + // anything * zero = +/- zero + if (!bAbs) return fromRep(productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale += normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + rep_t productHi, productLo; + wideMultiply(aSignificand, bSignificand << exponentBits, + &productHi, &productLo); + + int productExponent = aExponent + bExponent - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if (productHi & implicitBit) productExponent++; + else wideLeftShift(&productHi, &productLo, 1); + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return fromRep(infRep | productSign); + + if (productExponent <= 0) { + // Result is denormal before rounding, the exponent is zero and we + // need to shift the significand. + wideRightShiftWithSticky(&productHi, &productLo, 1 - productExponent); + } + + else { + // Result is normal before rounding; insert the exponent. + productHi &= significandMask; + productHi |= (rep_t)productExponent << significandBits; + } + + // Insert the sign of the result: + productHi |= productSign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. + if (productLo > signBit) productHi++; + if (productLo == signBit) productHi += productHi & 1; + return fromRep(productHi); +} diff --git a/lib/multi3.c b/lib/multi3.c new file mode 100644 index 000000000000..13a386781a9a --- /dev/null +++ b/lib/multi3.c @@ -0,0 +1,58 @@ +/* ===-- multi3.c - Implement __multi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + + * This file implements __multi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: a * b */ + +static +ti_int +__mulddi3(du_int a, du_int b) +{ + twords r; + const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2; + const du_int lower_mask = (du_int)~0 >> bits_in_dword_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + du_int t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t += (a >> bits_in_dword_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_dword_2; + r.s.high = t >> bits_in_dword_2; + t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t += (b >> bits_in_dword_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_dword_2; + r.s.high += t >> bits_in_dword_2; + r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2); + return r.all; +} + +/* Returns: a * b */ + +ti_int +__multi3(ti_int a, ti_int b) +{ + twords x; + x.all = a; + twords y; + y.all = b; + twords r; + r.all = __mulddi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} + +#endif /* __x86_64 */ diff --git a/lib/mulvdi3.c b/lib/mulvdi3.c new file mode 100644 index 000000000000..295ae18d3c85 --- /dev/null +++ b/lib/mulvdi3.c @@ -0,0 +1,57 @@ +/*===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulvdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: a * b */ + +/* Effects: aborts if a * b overflows */ + +di_int +__mulvdi3(di_int a, di_int b) +{ + const int N = (int)(sizeof(di_int) * CHAR_BIT); + const di_int MIN = (di_int)1 << (N-1); + const di_int MAX = ~MIN; + if (a == MIN) + { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) + { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + di_int sa = a >> (N - 1); + di_int abs_a = (a ^ sa) - sa; + di_int sb = b >> (N - 1); + di_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } + else + { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} diff --git a/lib/mulvsi3.c b/lib/mulvsi3.c new file mode 100644 index 000000000000..b4a509be2093 --- /dev/null +++ b/lib/mulvsi3.c @@ -0,0 +1,57 @@ +/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulvsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: a * b */ + +/* Effects: aborts if a * b overflows */ + +si_int +__mulvsi3(si_int a, si_int b) +{ + const int N = (int)(sizeof(si_int) * CHAR_BIT); + const si_int MIN = (si_int)1 << (N-1); + const si_int MAX = ~MIN; + if (a == MIN) + { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) + { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + si_int sa = a >> (N - 1); + si_int abs_a = (a ^ sa) - sa; + si_int sb = b >> (N - 1); + si_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } + else + { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} diff --git a/lib/mulvti3.c b/lib/mulvti3.c new file mode 100644 index 000000000000..778222ee6c96 --- /dev/null +++ b/lib/mulvti3.c @@ -0,0 +1,61 @@ +/* ===-- mulvti3.c - Implement __mulvti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulvti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: a * b */ + +/* Effects: aborts if a * b overflows */ + +ti_int +__mulvti3(ti_int a, ti_int b) +{ + const int N = (int)(sizeof(ti_int) * CHAR_BIT); + const ti_int MIN = (ti_int)1 << (N-1); + const ti_int MAX = ~MIN; + if (a == MIN) + { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) + { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + ti_int sa = a >> (N - 1); + ti_int abs_a = (a ^ sa) - sa; + ti_int sb = b >> (N - 1); + ti_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } + else + { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} + +#endif diff --git a/lib/mulxc3.c b/lib/mulxc3.c new file mode 100644 index 000000000000..94895f2551fd --- /dev/null +++ b/lib/mulxc3.c @@ -0,0 +1,78 @@ +/* ===-- mulxc3.c - Implement __mulxc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulxc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" +#include +#include + +/* Returns: the product of a + ib and c + id */ + +long double _Complex +__mulxc3(long double __a, long double __b, long double __c, long double __d) +{ + long double __ac = __a * __c; + long double __bd = __b * __d; + long double __ad = __a * __d; + long double __bc = __b * __c; + long double _Complex z; + __real__ z = __ac - __bd; + __imag__ z = __ad + __bc; + if (isnan(__real__ z) && isnan(__imag__ z)) + { + int __recalc = 0; + if (isinf(__a) || isinf(__b)) + { + __a = copysignl(isinf(__a) ? 1 : 0, __a); + __b = copysignl(isinf(__b) ? 1 : 0, __b); + if (isnan(__c)) + __c = copysignl(0, __c); + if (isnan(__d)) + __d = copysignl(0, __d); + __recalc = 1; + } + if (isinf(__c) || isinf(__d)) + { + __c = copysignl(isinf(__c) ? 1 : 0, __c); + __d = copysignl(isinf(__d) ? 1 : 0, __d); + if (isnan(__a)) + __a = copysignl(0, __a); + if (isnan(__b)) + __b = copysignl(0, __b); + __recalc = 1; + } + if (!__recalc && (isinf(__ac) || isinf(__bd) || + isinf(__ad) || isinf(__bc))) + { + if (isnan(__a)) + __a = copysignl(0, __a); + if (isnan(__b)) + __b = copysignl(0, __b); + if (isnan(__c)) + __c = copysignl(0, __c); + if (isnan(__d)) + __d = copysignl(0, __d); + __recalc = 1; + } + if (__recalc) + { + __real__ z = INFINITY * (__a * __c - __b * __d); + __imag__ z = INFINITY * (__a * __d + __b * __c); + } + } + return z; +} + +#endif diff --git a/lib/negdf2.c b/lib/negdf2.c new file mode 100644 index 000000000000..527b068a17a8 --- /dev/null +++ b/lib/negdf2.c @@ -0,0 +1,19 @@ +//===-- lib/negdf2.c - double-precision negation ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float negation. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t __negdf2(fp_t a) { + return fromRep(toRep(a) ^ signBit); +} diff --git a/lib/negdi2.c b/lib/negdi2.c new file mode 100644 index 000000000000..707b0dd78255 --- /dev/null +++ b/lib/negdi2.c @@ -0,0 +1,26 @@ +/* ===-- negdi2.c - Implement __negdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: -a */ + +di_int +__negdi2(di_int a) +{ + /* Note: this routine is here for API compatibility; any sane compiler + * should expand it inline. + */ + return -a; +} diff --git a/lib/negsf2.c b/lib/negsf2.c new file mode 100644 index 000000000000..5e91e87e9888 --- /dev/null +++ b/lib/negsf2.c @@ -0,0 +1,19 @@ +//===-- lib/negsf2.c - single-precision negation ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float negation. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t __negsf2(fp_t a) { + return fromRep(toRep(a) ^ signBit); +} diff --git a/lib/negti2.c b/lib/negti2.c new file mode 100644 index 000000000000..6ce6a0403acc --- /dev/null +++ b/lib/negti2.c @@ -0,0 +1,30 @@ +/* ===-- negti2.c - Implement __negti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: -a */ + +ti_int +__negti2(ti_int a) +{ + /* Note: this routine is here for API compatibility; any sane compiler + * should expand it inline. + */ + return -a; +} + +#endif diff --git a/lib/negvdi2.c b/lib/negvdi2.c new file mode 100644 index 000000000000..0baf377400e6 --- /dev/null +++ b/lib/negvdi2.c @@ -0,0 +1,29 @@ +/* ===-- negvdi2.c - Implement __negvdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negvdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: -a */ + +/* Effects: aborts if -a overflows */ + +di_int +__negvdi2(di_int a) +{ + const di_int MIN = (di_int)1 << ((int)(sizeof(di_int) * CHAR_BIT)-1); + if (a == MIN) + compilerrt_abort(); + return -a; +} diff --git a/lib/negvsi2.c b/lib/negvsi2.c new file mode 100644 index 000000000000..e5a36a5dacf5 --- /dev/null +++ b/lib/negvsi2.c @@ -0,0 +1,29 @@ +/* ===-- negvsi2.c - Implement __negvsi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negvsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: -a */ + +/* Effects: aborts if -a overflows */ + +si_int +__negvsi2(si_int a) +{ + const si_int MIN = (si_int)1 << ((int)(sizeof(si_int) * CHAR_BIT)-1); + if (a == MIN) + compilerrt_abort(); + return -a; +} diff --git a/lib/negvti2.c b/lib/negvti2.c new file mode 100644 index 000000000000..d56e1e32ade1 --- /dev/null +++ b/lib/negvti2.c @@ -0,0 +1,33 @@ +/*===-- negvti2.c - Implement __negvti2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + *This file implements __negvti2 for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: -a */ + +/* Effects: aborts if -a overflows */ + +ti_int +__negvti2(ti_int a) +{ + const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1); + if (a == MIN) + compilerrt_abort(); + return -a; +} + +#endif diff --git a/lib/paritydi2.c b/lib/paritydi2.c new file mode 100644 index 000000000000..90e5559bc799 --- /dev/null +++ b/lib/paritydi2.c @@ -0,0 +1,27 @@ +/* ===-- paritydi2.c - Implement __paritydi2 -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __paritydi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: 1 if number of bits is odd else returns 0 */ + +si_int __paritysi2(si_int a); + +si_int +__paritydi2(di_int a) +{ + dwords x; + x.all = a; + return __paritysi2(x.s.high ^ x.s.low); +} diff --git a/lib/paritysi2.c b/lib/paritysi2.c new file mode 100644 index 000000000000..ba05782a2a7e --- /dev/null +++ b/lib/paritysi2.c @@ -0,0 +1,27 @@ +/* ===-- paritysi2.c - Implement __paritysi2 -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __paritysi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: 1 if number of bits is odd else returns 0 */ + +si_int +__paritysi2(si_int a) +{ + su_int x = (su_int)a; + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + return (0x6996 >> (x & 0xF)) & 1; +} diff --git a/lib/parityti2.c b/lib/parityti2.c new file mode 100644 index 000000000000..650d417936af --- /dev/null +++ b/lib/parityti2.c @@ -0,0 +1,31 @@ +/* ===-- parityti2.c - Implement __parityti2 -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __parityti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: 1 if number of bits is odd else returns 0 */ + +si_int __paritydi2(di_int a); + +si_int +__parityti2(ti_int a) +{ + twords x; + x.all = a; + return __paritydi2(x.s.high ^ x.s.low); +} + +#endif diff --git a/lib/popcountdi2.c b/lib/popcountdi2.c new file mode 100644 index 000000000000..78b6d88d7311 --- /dev/null +++ b/lib/popcountdi2.c @@ -0,0 +1,36 @@ +/* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __popcountdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: count of 1 bits */ + +si_int +__popcountdi2(di_int a) +{ + du_int x2 = (du_int)a; + x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL); + /* Every 2 bits holds the sum of every pair of bits (32) */ + x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL); + /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */ + x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL; + /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */ + su_int x = (su_int)(x2 + (x2 >> 32)); + /* The lower 32 bits hold four 16 bit sums (5 significant bits). */ + /* Upper 32 bits are garbage */ + x = x + (x >> 16); + /* The lower 16 bits hold two 32 bit sums (6 significant bits). */ + /* Upper 16 bits are garbage */ + return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */ +} diff --git a/lib/popcountsi2.c b/lib/popcountsi2.c new file mode 100644 index 000000000000..4f092ee4017c --- /dev/null +++ b/lib/popcountsi2.c @@ -0,0 +1,33 @@ +/* ===-- popcountsi2.c - Implement __popcountsi2 ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __popcountsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: count of 1 bits */ + +si_int +__popcountsi2(si_int a) +{ + su_int x = (su_int)a; + x = x - ((x >> 1) & 0x55555555); + /* Every 2 bits holds the sum of every pair of bits */ + x = ((x >> 2) & 0x33333333) + (x & 0x33333333); + /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) */ + x = (x + (x >> 4)) & 0x0F0F0F0F; + /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) */ + x = (x + (x >> 16)); + /* The lower 16 bits hold two 8 bit sums (5 significant bits).*/ + /* Upper 16 bits are garbage */ + return (x + (x >> 8)) & 0x0000003F; /* (6 significant bits) */ +} diff --git a/lib/popcountti2.c b/lib/popcountti2.c new file mode 100644 index 000000000000..16f89b7abab8 --- /dev/null +++ b/lib/popcountti2.c @@ -0,0 +1,44 @@ +/* ===-- popcountti2.c - Implement __popcountti2 ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __popcountti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: count of 1 bits */ + +si_int +__popcountti2(ti_int a) +{ + tu_int x3 = (tu_int)a; + x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) | + 0x5555555555555555uLL)); + /* Every 2 bits holds the sum of every pair of bits (64) */ + x3 = ((x3 >> 2) & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL)) + + (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL)); + /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32) */ + x3 = (x3 + (x3 >> 4)) + & (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL); + /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16) */ + du_int x2 = (du_int)(x3 + (x3 >> 64)); + /* Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8) */ + su_int x = (su_int)(x2 + (x2 >> 32)); + /* Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4) */ + x = x + (x >> 16); + /* Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2) */ + /* Upper 16 bits are garbage */ + return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */ +} + +#endif diff --git a/lib/powidf2.c b/lib/powidf2.c new file mode 100644 index 000000000000..37972b68b6ea --- /dev/null +++ b/lib/powidf2.c @@ -0,0 +1,34 @@ +/* ===-- powidf2.cpp - Implement __powidf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powidf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a ^ b */ + +double +__powidf2(double a, si_int b) +{ + const int recip = b < 0; + double r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} diff --git a/lib/powisf2.c b/lib/powisf2.c new file mode 100644 index 000000000000..ace08c266752 --- /dev/null +++ b/lib/powisf2.c @@ -0,0 +1,34 @@ +/*===-- powisf2.cpp - Implement __powisf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powisf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a ^ b */ + +float +__powisf2(float a, si_int b) +{ + const int recip = b < 0; + float r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} diff --git a/lib/powitf2.c b/lib/powitf2.c new file mode 100644 index 000000000000..3dacbf6bfc2a --- /dev/null +++ b/lib/powitf2.c @@ -0,0 +1,38 @@ +/* ===-- powitf2.cpp - Implement __powitf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powitf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if _ARCH_PPC + +#include "int_lib.h" + +/* Returns: a ^ b */ + +long double +__powitf2(long double a, si_int b) +{ + const int recip = b < 0; + long double r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} + +#endif diff --git a/lib/powixf2.c b/lib/powixf2.c new file mode 100644 index 000000000000..1a816e9131cb --- /dev/null +++ b/lib/powixf2.c @@ -0,0 +1,38 @@ +/* ===-- powixf2.cpp - Implement __powixf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powixf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: a ^ b */ + +long double +__powixf2(long double a, si_int b) +{ + const int recip = b < 0; + long double r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} + +#endif diff --git a/lib/ppc/CMakeLists.txt b/lib/ppc/CMakeLists.txt new file mode 100644 index 000000000000..fb0fcd5a771c --- /dev/null +++ b/lib/ppc/CMakeLists.txt @@ -0,0 +1,12 @@ +SET( SRCS + fixtfdi.c + gcc_qdiv.c + gcc_qmul.c + divtc3.c + gcc_qsub.c + multc3.c + floatditf.c + gcc_qadd.c + fixunstfdi.c + floatunditf.c + ) diff --git a/lib/ppc/DD.h b/lib/ppc/DD.h new file mode 100644 index 000000000000..9ecd1f50b8a9 --- /dev/null +++ b/lib/ppc/DD.h @@ -0,0 +1,46 @@ +#ifndef __DD_HEADER +#define __DD_HEADER + +#include + +typedef union { + long double ld; + struct { + double hi; + double lo; + }s; +}DD; + +typedef union { + double d; + uint64_t x; +} doublebits; + +#define LOWORDER(xy,xHi,xLo,yHi,yLo) \ + (((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo)) + +static inline double __attribute__((always_inline)) +fabs(double x) +{ + doublebits result = { .d = x }; + result.x &= UINT64_C(0x7fffffffffffffff); + return result.d; +} + +static inline double __attribute__((always_inline)) +high26bits(double x) +{ + doublebits result = { .d = x }; + result.x &= UINT64_C(0xfffffffff8000000); + return result.d; +} + +static inline int __attribute__((always_inline)) +different_sign(double x, double y) +{ + doublebits xsignbit = { .d = x }, ysignbit = { .d = y }; + int result = (int)(xsignbit.x >> 63) ^ (int)(ysignbit.x >> 63); + return result; +} + +#endif /* __DD_HEADER */ diff --git a/lib/ppc/Makefile.mk b/lib/ppc/Makefile.mk new file mode 100644 index 000000000000..519d65467311 --- /dev/null +++ b/lib/ppc/Makefile.mk @@ -0,0 +1,19 @@ +#===- lib/ppc/Makefile.mk ----------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +SubDirs := +OnlyArchs := ppc + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/ppc/divtc3.c b/lib/ppc/divtc3.c new file mode 100644 index 000000000000..d41f62111b3d --- /dev/null +++ b/lib/ppc/divtc3.c @@ -0,0 +1,93 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +#include "DD.h" +#include + +#if !defined(INFINITY) && defined(HUGE_VAL) +#define INFINITY HUGE_VAL +#endif /* INFINITY */ + +#define makeFinite(x) { \ + (x).s.hi = __builtin_copysign(isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \ + (x).s.lo = 0.0; \ + } + +long double __gcc_qadd(long double, long double); +long double __gcc_qsub(long double, long double); +long double __gcc_qmul(long double, long double); +long double __gcc_qdiv(long double, long double); + +long double _Complex +__divtc3(long double a, long double b, long double c, long double d) +{ + DD cDD = { .ld = c }; + DD dDD = { .ld = d }; + + int ilogbw = 0; + const double logbw = logb(__builtin_fmax( __builtin_fabs(cDD.s.hi), __builtin_fabs(dDD.s.hi) )); + + if (isfinite(logbw)) + { + ilogbw = (int)logbw; + + cDD.s.hi = scalbn(cDD.s.hi, -ilogbw); + cDD.s.lo = scalbn(cDD.s.lo, -ilogbw); + dDD.s.hi = scalbn(dDD.s.hi, -ilogbw); + dDD.s.lo = scalbn(dDD.s.lo, -ilogbw); + } + + const long double denom = __gcc_qadd(__gcc_qmul(cDD.ld, cDD.ld), __gcc_qmul(dDD.ld, dDD.ld)); + const long double realNumerator = __gcc_qadd(__gcc_qmul(a,cDD.ld), __gcc_qmul(b,dDD.ld)); + const long double imagNumerator = __gcc_qsub(__gcc_qmul(b,cDD.ld), __gcc_qmul(a,dDD.ld)); + + DD real = { .ld = __gcc_qdiv(realNumerator, denom) }; + DD imag = { .ld = __gcc_qdiv(imagNumerator, denom) }; + + real.s.hi = scalbn(real.s.hi, -ilogbw); + real.s.lo = scalbn(real.s.lo, -ilogbw); + imag.s.hi = scalbn(imag.s.hi, -ilogbw); + imag.s.lo = scalbn(imag.s.lo, -ilogbw); + + if (isnan(real.s.hi) && isnan(imag.s.hi)) + { + DD aDD = { .ld = a }; + DD bDD = { .ld = b }; + DD rDD = { .ld = denom }; + + if ((rDD.s.hi == 0.0) && (!isnan(aDD.s.hi) || !isnan(bDD.s.hi))) + { + real.s.hi = __builtin_copysign(INFINITY,cDD.s.hi) * aDD.s.hi; + real.s.lo = 0.0; + imag.s.hi = __builtin_copysign(INFINITY,cDD.s.hi) * bDD.s.hi; + imag.s.lo = 0.0; + } + + else if ((isinf(aDD.s.hi) || isinf(bDD.s.hi)) && isfinite(cDD.s.hi) && isfinite(dDD.s.hi)) + { + makeFinite(aDD); + makeFinite(bDD); + real.s.hi = INFINITY * (aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi); + real.s.lo = 0.0; + imag.s.hi = INFINITY * (bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi); + imag.s.lo = 0.0; + } + + else if ((isinf(cDD.s.hi) || isinf(dDD.s.hi)) && isfinite(aDD.s.hi) && isfinite(bDD.s.hi)) + { + makeFinite(cDD); + makeFinite(dDD); + real.s.hi = __builtin_copysign(0.0,(aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi)); + real.s.lo = 0.0; + imag.s.hi = __builtin_copysign(0.0,(bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi)); + imag.s.lo = 0.0; + } + } + + long double _Complex z; + __real__ z = real.ld; + __imag__ z = imag.ld; + + return z; +} diff --git a/lib/ppc/fixtfdi.c b/lib/ppc/fixtfdi.c new file mode 100644 index 000000000000..fa113a037e93 --- /dev/null +++ b/lib/ppc/fixtfdi.c @@ -0,0 +1,104 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* int64_t __fixunstfdi(long double x); + * This file implements the PowerPC 128-bit double-double -> int64_t conversion + */ + +#include "DD.h" +#include + +uint64_t __fixtfdi(long double input) +{ + const DD x = { .ld = input }; + const doublebits hibits = { .d = x.s.hi }; + + const uint32_t absHighWord = (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff); + const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000); + + /* If (1.0 - tiny) <= input < 0x1.0p63: */ + if (UINT32_C(0x03f00000) > absHighWordMinusOne) + { + /* Do an unsigned conversion of the absolute value, then restore the sign. */ + const int unbiasedHeadExponent = absHighWordMinusOne >> 20; + + int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */ + result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */ + result <<= 10; /* mantissa(hi) with one zero preceeding bit. */ + + const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63; + + /* If the tail is non-zero, we need to patch in the tail bits. */ + if (0.0 != x.s.lo) + { + const doublebits lobits = { .d = x.s.lo }; + int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff); + tailMantissa |= INT64_C(0x0010000000000000); + + /* At this point we have the mantissa of |tail| */ + /* We need to negate it if head and tail have different signs. */ + const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63; + const int64_t negationMask = loNegationMask ^ hiNegationMask; + tailMantissa = (tailMantissa ^ negationMask) - negationMask; + + /* Now we have the mantissa of tail as a signed 2s-complement integer */ + + const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff; + + /* Shift the tail mantissa into the right position, accounting for the + * bias of 10 that we shifted the head mantissa by. + */ + tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10))); + + result += tailMantissa; + } + + result >>= (62 - unbiasedHeadExponent); + + /* Restore the sign of the result and return */ + result = (result ^ hiNegationMask) - hiNegationMask; + return result; + + } + + /* Edge cases handled here: */ + + /* |x| < 1, result is zero. */ + if (1.0 > __builtin_fabs(x.s.hi)) + return INT64_C(0); + + /* x very close to INT64_MIN, care must be taken to see which side we are on. */ + if (x.s.hi == -0x1.0p63) { + + int64_t result = INT64_MIN; + + if (0.0 < x.s.lo) + { + /* If the tail is positive, the correct result is something other than INT64_MIN. + * we'll need to figure out what it is. + */ + + const doublebits lobits = { .d = x.s.lo }; + int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff); + tailMantissa |= INT64_C(0x0010000000000000); + + /* Now we negate the tailMantissa */ + tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1); + + /* And shift it by the appropriate amount */ + const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff; + tailMantissa >>= 1075 - biasedTailExponent; + + result -= tailMantissa; + } + + return result; + } + + /* Signed overflows, infinities, and NaNs */ + if (x.s.hi > 0.0) + return INT64_MAX; + else + return INT64_MIN; +} diff --git a/lib/ppc/fixunstfdi.c b/lib/ppc/fixunstfdi.c new file mode 100644 index 000000000000..1fb52488172c --- /dev/null +++ b/lib/ppc/fixunstfdi.c @@ -0,0 +1,60 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* uint64_t __fixunstfdi(long double x); */ +/* This file implements the PowerPC 128-bit double-double -> uint64_t conversion */ + +#include "DD.h" +#include + +uint64_t __fixunstfdi(long double input) +{ + const DD x = { .ld = input }; + const doublebits hibits = { .d = x.s.hi }; + + const uint32_t highWordMinusOne = (uint32_t)(hibits.x >> 32) - UINT32_C(0x3ff00000); + + /* If (1.0 - tiny) <= input < 0x1.0p64: */ + if (UINT32_C(0x04000000) > highWordMinusOne) + { + const int unbiasedHeadExponent = highWordMinusOne >> 20; + + uint64_t result = hibits.x & UINT64_C(0x000fffffffffffff); /* mantissa(hi) */ + result |= UINT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */ + result <<= 11; /* mantissa(hi) left aligned in the int64 field. */ + + /* If the tail is non-zero, we need to patch in the tail bits. */ + if (0.0 != x.s.lo) + { + const doublebits lobits = { .d = x.s.lo }; + int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff); + tailMantissa |= INT64_C(0x0010000000000000); + + /* At this point we have the mantissa of |tail| */ + + const int64_t negationMask = ((int64_t)(lobits.x)) >> 63; + tailMantissa = (tailMantissa ^ negationMask) - negationMask; + + /* Now we have the mantissa of tail as a signed 2s-complement integer */ + + const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff; + + /* Shift the tail mantissa into the right position, accounting for the + * bias of 11 that we shifted the head mantissa by. + */ + tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 11))); + + result += tailMantissa; + } + + result >>= (63 - unbiasedHeadExponent); + return result; + } + + /* Edge cases are handled here, with saturation. */ + if (1.0 > x.s.hi) + return UINT64_C(0); + else + return UINT64_MAX; +} diff --git a/lib/ppc/floatditf.c b/lib/ppc/floatditf.c new file mode 100644 index 000000000000..ed23dc84d73c --- /dev/null +++ b/lib/ppc/floatditf.c @@ -0,0 +1,37 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __floatditf(long long x); */ +/* This file implements the PowerPC long long -> long double conversion */ + +#include "DD.h" +#include + +long double __floatditf(int64_t a) { + + static const double twop32 = 0x1.0p32; + static const double twop52 = 0x1.0p52; + + doublebits low = { .d = twop52 }; + low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a. */ + + const double high_addend = (double)((int32_t)(a >> 32))*twop32 - twop52; + + /* At this point, we have two double precision numbers + * high_addend and low.d, and we wish to return their sum + * as a canonicalized long double: + */ + + /* This implementation sets the inexact flag spuriously. + * This could be avoided, but at some substantial cost. + */ + + DD result; + + result.s.hi = high_addend + low.d; + result.s.lo = (high_addend - result.s.hi) + low.d; + + return result.ld; + +} diff --git a/lib/ppc/floatunditf.c b/lib/ppc/floatunditf.c new file mode 100644 index 000000000000..20a3b71b317c --- /dev/null +++ b/lib/ppc/floatunditf.c @@ -0,0 +1,42 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __floatunditf(unsigned long long x); */ +/* This file implements the PowerPC unsigned long long -> long double conversion */ + +#include "DD.h" +#include + +long double __floatunditf(uint64_t a) { + + /* Begins with an exact copy of the code from __floatundidf */ + + static const double twop52 = 0x1.0p52; + static const double twop84 = 0x1.0p84; + static const double twop84_plus_twop52 = 0x1.00000001p84; + + doublebits high = { .d = twop84 }; + doublebits low = { .d = twop52 }; + + high.x |= a >> 32; /* 0x1.0p84 + high 32 bits of a */ + low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a */ + + const double high_addend = high.d - twop84_plus_twop52; + + /* At this point, we have two double precision numbers + * high_addend and low.d, and we wish to return their sum + * as a canonicalized long double: + */ + + /* This implementation sets the inexact flag spuriously. */ + /* This could be avoided, but at some substantial cost. */ + + DD result; + + result.s.hi = high_addend + low.d; + result.s.lo = (high_addend - result.s.hi) + low.d; + + return result.ld; + +} diff --git a/lib/ppc/gcc_qadd.c b/lib/ppc/gcc_qadd.c new file mode 100644 index 000000000000..c388c7e99c6e --- /dev/null +++ b/lib/ppc/gcc_qadd.c @@ -0,0 +1,76 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qadd(long double x, long double y); + * This file implements the PowerPC 128-bit double-double add operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qadd(long double x, long double y) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + + DD dst = { .ld = x }, src = { .ld = y }; + + register double A = dst.s.hi, a = dst.s.lo, + B = src.s.hi, b = src.s.lo; + + /* If both operands are zero: */ + if ((A == 0.0) && (B == 0.0)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If either operand is NaN or infinity: */ + const doublebits abits = { .d = A }; + const doublebits bbits = { .d = B }; + if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) || + (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If the computation overflows: */ + /* This may be playing things a little bit fast and loose, but it will do for a start. */ + const double testForOverflow = A + (B + (a + b)); + const doublebits testbits = { .d = testForOverflow }; + if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = testForOverflow; + dst.s.lo = 0.0; + return dst.ld; + } + + double H, h; + double T, t; + double W, w; + double Y; + + H = B + (A - (A + B)); + T = b + (a - (a + b)); + h = A + (B - (A + B)); + t = a + (b - (a + b)); + + if (fabs(A) <= fabs(B)) + w = (a + b) + h; + else + w = (a + b) + H; + + W = (A + B) + w; + Y = (A + B) - W; + Y += w; + + if (fabs(a) <= fabs(b)) + w = t + Y; + else + w = T + Y; + + dst.s.hi = Y = W + w; + dst.s.lo = (W - Y) + w; + + return dst.ld; +} diff --git a/lib/ppc/gcc_qdiv.c b/lib/ppc/gcc_qdiv.c new file mode 100644 index 000000000000..70aa00b64400 --- /dev/null +++ b/lib/ppc/gcc_qdiv.c @@ -0,0 +1,55 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qdiv(long double x, long double y); + * This file implements the PowerPC 128-bit double-double division operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qdiv(long double a, long double b) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + DD dst = { .ld = a }, src = { .ld = b }; + + register double x = dst.s.hi, x1 = dst.s.lo, + y = src.s.hi, y1 = src.s.lo; + + double yHi, yLo, qHi, qLo; + double yq, tmp, q; + + q = x / y; + + /* Detect special cases */ + if (q == 0.0) { + dst.s.hi = q; + dst.s.lo = 0.0; + return dst.ld; + } + + const doublebits qBits = { .d = q }; + if (((uint32_t)(qBits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = q; + dst.s.lo = 0.0; + return dst.ld; + } + + yHi = high26bits(y); + qHi = high26bits(q); + + yq = y * q; + yLo = y - yHi; + qLo = q - qHi; + + tmp = LOWORDER(yq, yHi, yLo, qHi, qLo); + tmp = (x - yq) - tmp; + tmp = ((tmp + x1) - y1 * q) / y; + x = q + tmp; + + dst.s.lo = (q - x) + tmp; + dst.s.hi = x; + + return dst.ld; +} diff --git a/lib/ppc/gcc_qmul.c b/lib/ppc/gcc_qmul.c new file mode 100644 index 000000000000..fb4c5164ccb5 --- /dev/null +++ b/lib/ppc/gcc_qmul.c @@ -0,0 +1,53 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qmul(long double x, long double y); + * This file implements the PowerPC 128-bit double-double multiply operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qmul(long double x, long double y) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + DD dst = { .ld = x }, src = { .ld = y }; + + register double A = dst.s.hi, a = dst.s.lo, + B = src.s.hi, b = src.s.lo; + + double aHi, aLo, bHi, bLo; + double ab, tmp, tau; + + ab = A * B; + + /* Detect special cases */ + if (ab == 0.0) { + dst.s.hi = ab; + dst.s.lo = 0.0; + return dst.ld; + } + + const doublebits abBits = { .d = ab }; + if (((uint32_t)(abBits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = ab; + dst.s.lo = 0.0; + return dst.ld; + } + + /* Generic cases handled here. */ + aHi = high26bits(A); + bHi = high26bits(B); + aLo = A - aHi; + bLo = B - bHi; + + tmp = LOWORDER(ab, aHi, aLo, bHi, bLo); + tmp += (A * b + a * B); + tau = ab + tmp; + + dst.s.lo = (ab - tau) + tmp; + dst.s.hi = tau; + + return dst.ld; +} diff --git a/lib/ppc/gcc_qsub.c b/lib/ppc/gcc_qsub.c new file mode 100644 index 000000000000..4f1f7ac70f3c --- /dev/null +++ b/lib/ppc/gcc_qsub.c @@ -0,0 +1,76 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qsub(long double x, long double y); + * This file implements the PowerPC 128-bit double-double add operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qsub(long double x, long double y) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + + DD dst = { .ld = x }, src = { .ld = y }; + + register double A = dst.s.hi, a = dst.s.lo, + B = -src.s.hi, b = -src.s.lo; + + /* If both operands are zero: */ + if ((A == 0.0) && (B == 0.0)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If either operand is NaN or infinity: */ + const doublebits abits = { .d = A }; + const doublebits bbits = { .d = B }; + if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) || + (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If the computation overflows: */ + /* This may be playing things a little bit fast and loose, but it will do for a start. */ + const double testForOverflow = A + (B + (a + b)); + const doublebits testbits = { .d = testForOverflow }; + if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = testForOverflow; + dst.s.lo = 0.0; + return dst.ld; + } + + double H, h; + double T, t; + double W, w; + double Y; + + H = B + (A - (A + B)); + T = b + (a - (a + b)); + h = A + (B - (A + B)); + t = a + (b - (a + b)); + + if (fabs(A) <= fabs(B)) + w = (a + b) + h; + else + w = (a + b) + H; + + W = (A + B) + w; + Y = (A + B) - W; + Y += w; + + if (fabs(a) <= fabs(b)) + w = t + Y; + else + w = T + Y; + + dst.s.hi = Y = W + w; + dst.s.lo = (W - Y) + w; + + return dst.ld; +} diff --git a/lib/ppc/multc3.c b/lib/ppc/multc3.c new file mode 100644 index 000000000000..9d17a2c6bc6a --- /dev/null +++ b/lib/ppc/multc3.c @@ -0,0 +1,97 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +#include "DD.h" +#include + +#if !defined(INFINITY) && defined(HUGE_VAL) +#define INFINITY HUGE_VAL +#endif /* INFINITY */ + +#define makeFinite(x) { \ + (x).s.hi = __builtin_copysign(isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \ + (x).s.lo = 0.0; \ + } + +#define zeroNaN(x) { \ + if (isnan((x).s.hi)) { \ + (x).s.hi = __builtin_copysign(0.0, (x).s.hi); \ + (x).s.lo = 0.0; \ + } \ + } + +long double __gcc_qadd(long double, long double); +long double __gcc_qsub(long double, long double); +long double __gcc_qmul(long double, long double); + +long double _Complex +__multc3(long double a, long double b, long double c, long double d) +{ + long double ac = __gcc_qmul(a,c); + long double bd = __gcc_qmul(b,d); + long double ad = __gcc_qmul(a,d); + long double bc = __gcc_qmul(b,c); + + DD real = { .ld = __gcc_qsub(ac,bd) }; + DD imag = { .ld = __gcc_qadd(ad,bc) }; + + if (isnan(real.s.hi) && isnan(imag.s.hi)) + { + int recalc = 0; + + DD aDD = { .ld = a }; + DD bDD = { .ld = b }; + DD cDD = { .ld = c }; + DD dDD = { .ld = d }; + + if (isinf(aDD.s.hi) || isinf(bDD.s.hi)) + { + makeFinite(aDD); + makeFinite(bDD); + zeroNaN(cDD); + zeroNaN(dDD); + recalc = 1; + } + + if (isinf(cDD.s.hi) || isinf(dDD.s.hi)) + { + makeFinite(cDD); + makeFinite(dDD); + zeroNaN(aDD); + zeroNaN(bDD); + recalc = 1; + } + + if (!recalc) + { + DD acDD = { .ld = ac }; + DD bdDD = { .ld = bd }; + DD adDD = { .ld = ad }; + DD bcDD = { .ld = bc }; + + if (isinf(acDD.s.hi) || isinf(bdDD.s.hi) || isinf(adDD.s.hi) || isinf(bcDD.s.hi)) + { + zeroNaN(aDD); + zeroNaN(bDD); + zeroNaN(cDD); + zeroNaN(dDD); + recalc = 1; + } + } + + if (recalc) + { + real.s.hi = INFINITY * (aDD.s.hi*cDD.s.hi - bDD.s.hi*dDD.s.hi); + real.s.lo = 0.0; + imag.s.hi = INFINITY * (aDD.s.hi*dDD.s.hi + bDD.s.hi*cDD.s.hi); + imag.s.lo = 0.0; + } + } + + long double _Complex z; + __real__ z = real.ld; + __imag__ z = imag.ld; + + return z; +} diff --git a/lib/ppc/restFP.S b/lib/ppc/restFP.S new file mode 100644 index 000000000000..00919c8cdce4 --- /dev/null +++ b/lib/ppc/restFP.S @@ -0,0 +1,43 @@ +//===-- restFP.S - Implement restFP ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// Helper function used by compiler to restore ppc floating point registers at +// the end of the function epilog. This function returns to the address +// in the LR slot. So a function epilog must branch (b) not branch and link +// (bl) to this function. +// If the compiler wants to restore f27..f31, it does a "b restFP+52" +// +// This function should never be exported by a shared library. Each linkage +// unit carries its own copy of this function. +// +DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(restFP) + lfd f14,-144(r1) + lfd f15,-136(r1) + lfd f16,-128(r1) + lfd f17,-120(r1) + lfd f18,-112(r1) + lfd f19,-104(r1) + lfd f20,-96(r1) + lfd f21,-88(r1) + lfd f22,-80(r1) + lfd f23,-72(r1) + lfd f24,-64(r1) + lfd f25,-56(r1) + lfd f26,-48(r1) + lfd f27,-40(r1) + lfd f28,-32(r1) + lfd f29,-24(r1) + lfd f30,-16(r1) + lfd f31,-8(r1) + lwz r0,8(r1) + mtlr r0 + blr diff --git a/lib/ppc/saveFP.S b/lib/ppc/saveFP.S new file mode 100644 index 000000000000..302da6e9c595 --- /dev/null +++ b/lib/ppc/saveFP.S @@ -0,0 +1,40 @@ +//===-- saveFP.S - Implement saveFP ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// Helper function used by compiler to save ppc floating point registers in +// function prologs. This routines also saves r0 in the LR slot. +// If the compiler wants to save f27..f31, it does a "bl saveFP+52" +// +// This function should never be exported by a shared library. Each linkage +// unit carries its own copy of this function. +// +DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(saveFP) + stfd f14,-144(r1) + stfd f15,-136(r1) + stfd f16,-128(r1) + stfd f17,-120(r1) + stfd f18,-112(r1) + stfd f19,-104(r1) + stfd f20,-96(r1) + stfd f21,-88(r1) + stfd f22,-80(r1) + stfd f23,-72(r1) + stfd f24,-64(r1) + stfd f25,-56(r1) + stfd f26,-48(r1) + stfd f27,-40(r1) + stfd f28,-32(r1) + stfd f29,-24(r1) + stfd f30,-16(r1) + stfd f31,-8(r1) + stw r0,8(r1) + blr diff --git a/lib/subvdi3.c b/lib/subvdi3.c new file mode 100644 index 000000000000..e4926b816460 --- /dev/null +++ b/lib/subvdi3.c @@ -0,0 +1,37 @@ +/* ===-- subvdi3.c - Implement __subvdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __subvdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: a - b */ + +/* Effects: aborts if a - b overflows */ + +di_int +__subvdi3(di_int a, di_int b) +{ + di_int s = a - b; + if (b >= 0) + { + if (s > a) + compilerrt_abort(); + } + else + { + if (s <= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/subvsi3.c b/lib/subvsi3.c new file mode 100644 index 000000000000..ce39c815b86e --- /dev/null +++ b/lib/subvsi3.c @@ -0,0 +1,37 @@ +/* ===-- subvsi3.c - Implement __subvsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __subvsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include + +/* Returns: a - b */ + +/* Effects: aborts if a - b overflows */ + +si_int +__subvsi3(si_int a, si_int b) +{ + si_int s = a - b; + if (b >= 0) + { + if (s > a) + compilerrt_abort(); + } + else + { + if (s <= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/subvti3.c b/lib/subvti3.c new file mode 100644 index 000000000000..55b7925a14b3 --- /dev/null +++ b/lib/subvti3.c @@ -0,0 +1,41 @@ +/* ===-- subvti3.c - Implement __subvti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __subvti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" +#include + +/* Returns: a - b */ + +/* Effects: aborts if a - b overflows */ + +ti_int +__subvti3(ti_int a, ti_int b) +{ + ti_int s = a - b; + if (b >= 0) + { + if (s > a) + compilerrt_abort(); + } + else + { + if (s <= a) + compilerrt_abort(); + } + return s; +} + +#endif /* __x86_64 */ diff --git a/lib/trampoline_setup.c b/lib/trampoline_setup.c new file mode 100644 index 000000000000..8254e362a7d7 --- /dev/null +++ b/lib/trampoline_setup.c @@ -0,0 +1,50 @@ +/* ===----- trampoline_setup.c - Implement __trampoline_setup -------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include +#include + +#include "int_lib.h" + +extern void __clear_cache(void* start, void* end); + +/* + * The ppc compiler generates calls to __trampoline_setup() when creating + * trampoline functions on the stack for use with nested functions. + * This function creates a custom 40-byte trampoline function on the stack + * which loads r11 with a pointer to the outer function's locals + * and then jumps to the target nested function. + */ + +#if __ppc__ +void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated, + const void* realFunc, void* localsPtr) +{ + /* should never happen, but if compiler did not allocate */ + /* enough space on stack for the trampoline, abort */ + if ( trampSizeAllocated < 40 ) + compilerrt_abort(); + + /* create trampoline */ + trampOnStack[0] = 0x7c0802a6; /* mflr r0 */ + trampOnStack[1] = 0x4800000d; /* bl Lbase */ + trampOnStack[2] = (uint32_t)realFunc; + trampOnStack[3] = (uint32_t)localsPtr; + trampOnStack[4] = 0x7d6802a6; /* Lbase: mflr r11 */ + trampOnStack[5] = 0x818b0000; /* lwz r12,0(r11) */ + trampOnStack[6] = 0x7c0803a6; /* mtlr r0 */ + trampOnStack[7] = 0x7d8903a6; /* mtctr r12 */ + trampOnStack[8] = 0x816b0004; /* lwz r11,4(r11) */ + trampOnStack[9] = 0x4e800420; /* bctr */ + + /* clear instruction cache */ + __clear_cache(trampOnStack, &trampOnStack[10]); +} +#endif /* __ppc__ */ diff --git a/lib/truncdfsf2.c b/lib/truncdfsf2.c new file mode 100644 index 000000000000..d289cb989186 --- /dev/null +++ b/lib/truncdfsf2.c @@ -0,0 +1,167 @@ +//===-- lib/truncdfsf2.c - double -> single conversion ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a fairly generic conversion from a wider to a narrower +// IEEE-754 floating-point type in the default (round to nearest, ties to even) +// rounding mode. The constants and types defined following the includes below +// parameterize the conversion. +// +// This routine can be trivially adapted to support conversions to +// half-precision or from quad-precision. It does not support types that don't +// use the usual IEEE-754 interchange formats; specifically, some work would be +// needed to adapt it to (for example) the Intel 80-bit format or PowerPC +// double-double format. +// +// Note please, however, that this implementation is only intended to support +// *narrowing* operations; if you need to convert to a *wider* floating-point +// type (e.g. float -> double), then this routine will not do what you want it +// to. +// +// It also requires that integer types at least as large as both formats +// are available on the target platform; this may pose a problem when trying +// to add support for quad on some 32-bit systems, for example. +// +// Finally, the following assumptions are made: +// +// 1. floating-point types and integer types have the same endianness on the +// target platform +// +// 2. quiet NaNs, if supported, are indicated by the leading bit of the +// significand field being set +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +typedef double src_t; +typedef uint64_t src_rep_t; +#define SRC_REP_C UINT64_C +static const int srcSigBits = 52; + +typedef float dst_t; +typedef uint32_t dst_rep_t; +#define DST_REP_C UINT32_C +static const int dstSigBits = 23; + +// End of specialization parameters. Two helper routines for conversion to and +// from the representation of floating-point data as integer values follow. + +static inline src_rep_t srcToRep(src_t x) { + const union { src_t f; src_rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline dst_t dstFromRep(dst_rep_t x) { + const union { dst_t f; dst_rep_t i; } rep = {.i = x}; + return rep.f; +} + +// End helper routines. Conversion implementation follows. + +dst_t __truncdfsf2(src_t a) { + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const int srcBits = sizeof(src_t)*CHAR_BIT; + const int srcExpBits = srcBits - srcSigBits - 1; + const int srcInfExp = (1 << srcExpBits) - 1; + const int srcExpBias = srcInfExp >> 1; + + const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits; + const src_rep_t significandMask = srcMinNormal - 1; + const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits; + const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits); + const src_rep_t srcAbsMask = srcSignMask - 1; + const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1; + const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1); + + const int dstBits = sizeof(dst_t)*CHAR_BIT; + const int dstExpBits = dstBits - dstSigBits - 1; + const int dstInfExp = (1 << dstExpBits) - 1; + const int dstExpBias = dstInfExp >> 1; + + const int underflowExponent = srcExpBias + 1 - dstExpBias; + const int overflowExponent = srcExpBias + dstInfExp - dstExpBias; + const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits; + const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits; + + const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1); + const dst_rep_t dstNaNCode = dstQNaN - 1; + + // Break a into a sign and representation of the absolute value + const src_rep_t aRep = srcToRep(a); + const src_rep_t aAbs = aRep & srcAbsMask; + const src_rep_t sign = aRep & srcSignMask; + dst_rep_t absResult; + + if (aAbs - underflow < aAbs - overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + absResult = aAbs >> (srcSigBits - dstSigBits); + absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits; + + const src_rep_t roundBits = aAbs & roundMask; + + // Round to nearest + if (roundBits > halfway) + absResult++; + + // Ties to even + else if (roundBits == halfway) + absResult += absResult & 1; + } + + else if (aAbs > srcInfinity) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + absResult = (dst_rep_t)dstInfExp << dstSigBits; + absResult |= dstQNaN; + absResult |= aAbs & dstNaNCode; + } + + else if (aAbs > overflow) { + // a overflows to infinity. + absResult = (dst_rep_t)dstInfExp << dstSigBits; + } + + else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + const int aExp = aAbs >> srcSigBits; + const int shift = srcExpBias - dstExpBias - aExp + 1; + + const src_rep_t significand = (aRep & significandMask) | srcMinNormal; + + // Right shift by the denormalization amount with sticky. + if (shift > srcSigBits) { + absResult = 0; + } else { + const bool sticky = significand << (srcBits - shift); + src_rep_t denormalizedSignificand = significand >> shift | sticky; + absResult = denormalizedSignificand >> (srcSigBits - dstSigBits); + const src_rep_t roundBits = denormalizedSignificand & roundMask; + // Round to nearest + if (roundBits > halfway) + absResult++; + // Ties to even + else if (roundBits == halfway) + absResult += absResult & 1; + } + } + + // Apply the signbit to (dst_t)abs(a). + const dst_rep_t result = absResult | sign >> (srcBits - dstBits); + return dstFromRep(result); + +} diff --git a/lib/ucmpdi2.c b/lib/ucmpdi2.c new file mode 100644 index 000000000000..d2900cae4368 --- /dev/null +++ b/lib/ucmpdi2.c @@ -0,0 +1,38 @@ +/* ===-- ucmpdi2.c - Implement __ucmpdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ucmpdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: if (a < b) returns 0 + * if (a == b) returns 1 + * if (a > b) returns 2 + */ + +si_int +__ucmpdi2(du_int a, du_int b) +{ + udwords x; + x.all = a; + udwords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} diff --git a/lib/ucmpti2.c b/lib/ucmpti2.c new file mode 100644 index 000000000000..0e7eea3e3d1c --- /dev/null +++ b/lib/ucmpti2.c @@ -0,0 +1,42 @@ +/* ===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ucmpti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Returns: if (a < b) returns 0 + * if (a == b) returns 1 + * if (a > b) returns 2 + */ + +si_int +__ucmpti2(tu_int a, tu_int b) +{ + utwords x; + x.all = a; + utwords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} + +#endif diff --git a/lib/udivdi3.c b/lib/udivdi3.c new file mode 100644 index 000000000000..25d1df643c91 --- /dev/null +++ b/lib/udivdi3.c @@ -0,0 +1,25 @@ +/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +du_int +__udivdi3(du_int a, du_int b) +{ + return __udivmoddi4(a, b, 0); +} diff --git a/lib/udivmoddi4.c b/lib/udivmoddi4.c new file mode 100644 index 000000000000..92742302cf68 --- /dev/null +++ b/lib/udivmoddi4.c @@ -0,0 +1,251 @@ +/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmoddi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +du_int +__udivmoddi4(du_int a, du_int b, du_int* rem) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 2 or sr large */ + if (sr > n_uword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits - 1 */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + unsigned sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + *0 K + */ + sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + /* 2 <= sr <= n_udword_bits - 1 + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_uword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_uword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 + * { + * q.s.low = n.s.low << (n_udword_bits - sr); + * q.s.high = (n.s.high << (n_udword_bits - sr)) | + * (n.s.low >> (sr - n_uword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_uword_bits); + * } + */ + q.s.low = (n.s.low << (n_udword_bits - sr)) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)); + q.s.high = ((n.s.low << ( n_uword_bits - sr)) & + ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits))) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_uword_bits)) & + ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_uword_bits - sr)) | + (n.s.low >> sr)) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 1 or sr large */ + if (sr > n_uword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_uword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = (n.s.high << (n_uword_bits - sr)) | + ((n.s.low >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_udword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} diff --git a/lib/udivmodti4.c b/lib/udivmodti4.c new file mode 100644 index 000000000000..53b407256e67 --- /dev/null +++ b/lib/udivmodti4.c @@ -0,0 +1,256 @@ +/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmodti4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +tu_int +__udivmodti4(tu_int a, tu_int b, tu_int* rem) +{ + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT; + utwords n; + n.all = a; + utwords d; + d.all = b; + utwords q; + utwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctzll(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); + /* 0 <= sr <= n_udword_bits - 2 or sr large */ + if (sr > n_udword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_udword_bits - 1 */ + /* q.all = n.all << (n_utword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_udword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + unsigned sr = __builtin_ctzll(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + * 0 K + */ + sr = 1 + n_udword_bits + __builtin_clzll(d.s.low) + - __builtin_clzll(n.s.high); + /* 2 <= sr <= n_utword_bits - 1 + * q.all = n.all << (n_utword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_udword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_udword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_udword_bits + 1 <= sr <= n_utword_bits - 1 + * { + * q.s.low = n.s.low << (n_utword_bits - sr); + * q.s.high = (n.s.high << (n_utword_bits - sr)) | + * (n.s.low >> (sr - n_udword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_udword_bits); + * } + */ + q.s.low = (n.s.low << (n_utword_bits - sr)) & + ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1)); + q.s.high = ((n.s.low << ( n_udword_bits - sr)) & + ((di_int)(int)(sr - n_udword_bits - 1) >> (n_udword_bits-1))) | + (((n.s.high << (n_utword_bits - sr)) | + (n.s.low >> (sr - n_udword_bits))) & + ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_udword_bits)) & + ((di_int)(int)(n_udword_bits - sr - 1) >> (n_udword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> sr)) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); + /*0 <= sr <= n_udword_bits - 1 or sr large */ + if (sr > n_udword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_udword_bits */ + /* q.all = n.all << (n_utword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_udword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_udword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)); + r.s.low = (n.s.high << (n_udword_bits - sr)) | + ((n.s.low >> sr) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_utword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_utword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} + +#endif /* __x86_64 */ diff --git a/lib/udivsi3.c b/lib/udivsi3.c new file mode 100644 index 000000000000..70528b66e2b4 --- /dev/null +++ b/lib/udivsi3.c @@ -0,0 +1,63 @@ +/* ===-- udivsi3.c - Implement __udivsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a / b */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +su_int +__udivsi3(su_int n, su_int d) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + su_int q; + su_int r; + unsigned sr; + /* special cases */ + if (d == 0) + return 0; /* ?! */ + if (n == 0) + return 0; + sr = __builtin_clz(d) - __builtin_clz(n); + /* 0 <= sr <= n_uword_bits - 1 or sr large */ + if (sr > n_uword_bits - 1) /* d > r */ + return 0; + if (sr == n_uword_bits - 1) /* d == 1 */ + return n; + ++sr; + /* 1 <= sr <= n_uword_bits - 1 */ + /* Not a special case */ + q = n << (n_uword_bits - sr); + r = n >> sr; + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r = (r << 1) | (q >> (n_uword_bits - 1)); + q = (q << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1); + carry = s & 1; + r -= d & s; + } + q = (q << 1) | carry; + return q; +} diff --git a/lib/udivti3.c b/lib/udivti3.c new file mode 100644 index 000000000000..fb810fda5fae --- /dev/null +++ b/lib/udivti3.c @@ -0,0 +1,29 @@ +/* ===-- udivti3.c - Implement __udivti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/* Returns: a / b */ + +tu_int +__udivti3(tu_int a, tu_int b) +{ + return __udivmodti4(a, b, 0); +} + +#endif /* __x86_64 */ diff --git a/lib/umoddi3.c b/lib/umoddi3.c new file mode 100644 index 000000000000..807bb5cec622 --- /dev/null +++ b/lib/umoddi3.c @@ -0,0 +1,27 @@ +/* ===-- umoddi3.c - Implement __umoddi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __umoddi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a % b */ + +du_int +__umoddi3(du_int a, du_int b) +{ + du_int r; + __udivmoddi4(a, b, &r); + return r; +} diff --git a/lib/umodsi3.c b/lib/umodsi3.c new file mode 100644 index 000000000000..ead7737587a8 --- /dev/null +++ b/lib/umodsi3.c @@ -0,0 +1,25 @@ +/* ===-- umodsi3.c - Implement __umodsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __umodsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a % b */ + +su_int __udivsi3(su_int a, su_int b); + +su_int +__umodsi3(su_int a, su_int b) +{ + return a - __udivsi3(a, b) * b; +} diff --git a/lib/umodti3.c b/lib/umodti3.c new file mode 100644 index 000000000000..6c8a7581aeea --- /dev/null +++ b/lib/umodti3.c @@ -0,0 +1,31 @@ +/* ===-- umodti3.c - Implement __umodti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __umodti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if __x86_64 + +#include "int_lib.h" + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/* Returns: a % b */ + +tu_int +__umodti3(tu_int a, tu_int b) +{ + tu_int r; + __udivmodti4(a, b, &r); + return r; +} + +#endif diff --git a/lib/x86_64/CMakeLists.txt b/lib/x86_64/CMakeLists.txt new file mode 100644 index 000000000000..ee21308e20c3 --- /dev/null +++ b/lib/x86_64/CMakeLists.txt @@ -0,0 +1,5 @@ +SET( SRCS + floatdixf.c + floatdisf.c + floatdidf.c + ) diff --git a/lib/x86_64/Makefile.mk b/lib/x86_64/Makefile.mk new file mode 100644 index 000000000000..09037b9fbc8a --- /dev/null +++ b/lib/x86_64/Makefile.mk @@ -0,0 +1,19 @@ +#===- lib/x86_64/Makefile.mk -------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +SubDirs := +OnlyArchs := x86_64 + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/x86_64/floatdidf.c b/lib/x86_64/floatdidf.c new file mode 100644 index 000000000000..cce3cd514a40 --- /dev/null +++ b/lib/x86_64/floatdidf.c @@ -0,0 +1,16 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* double __floatdidf(di_int a); */ + +#ifdef __x86_64__ + +#include + +double __floatdidf(int64_t a) +{ + return (double)a; +} + +#endif /* __x86_64__ */ diff --git a/lib/x86_64/floatdisf.c b/lib/x86_64/floatdisf.c new file mode 100644 index 000000000000..753ba90dfb0e --- /dev/null +++ b/lib/x86_64/floatdisf.c @@ -0,0 +1,14 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +#ifdef __x86_64__ + +#include + +float __floatdisf(int64_t a) +{ + return (float)a; +} + +#endif /* __x86_64__ */ diff --git a/lib/x86_64/floatdixf.c b/lib/x86_64/floatdixf.c new file mode 100644 index 000000000000..569f72774001 --- /dev/null +++ b/lib/x86_64/floatdixf.c @@ -0,0 +1,16 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __floatdixf(di_int a); */ + +#ifdef __x86_64__ + +#include + +long double __floatdixf(int64_t a) +{ + return (long double)a; +} + +#endif /* __i386__ */ diff --git a/lib/x86_64/floatundidf.S b/lib/x86_64/floatundidf.S new file mode 100644 index 000000000000..6e684b2a4cab --- /dev/null +++ b/lib/x86_64/floatundidf.S @@ -0,0 +1,43 @@ +//===-- floatundidf.S - Implement __floatundidf for x86_64 ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements __floatundidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// double __floatundidf(du_int a); + +#ifdef __x86_64__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52: + .quad 0x4530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundidf) + movd %edi, %xmm0 // low 32 bits of a + shrq $32, %rdi // high 32 bits of a + orq REL_ADDR(twop84), %rdi // 0x1p84 + a_hi (no rounding occurs) + orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs) + movd %rdi, %xmm1 + subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs) + addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here) + ret + +#endif // __x86_64__ diff --git a/lib/x86_64/floatundisf.S b/lib/x86_64/floatundisf.S new file mode 100644 index 000000000000..fe209632a38e --- /dev/null +++ b/lib/x86_64/floatundisf.S @@ -0,0 +1,33 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatundisf(du_int a); + +#ifdef __x86_64__ + +#ifndef __ELF__ +.literal4 +#endif +two: .single 2.0 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundisf) + movq $1, %rsi + testq %rdi, %rdi + js 1f + cvtsi2ssq %rdi, %xmm0 + ret + +1: andq %rdi, %rsi + shrq %rdi + orq %rsi, %rdi + cvtsi2ssq %rdi, %xmm0 + mulss REL_ADDR(two), %xmm0 + ret + +#endif // __x86_64__ diff --git a/lib/x86_64/floatundixf.S b/lib/x86_64/floatundixf.S new file mode 100644 index 000000000000..246f0266c8a1 --- /dev/null +++ b/lib/x86_64/floatundixf.S @@ -0,0 +1,62 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +#include "../assembly.h" + +// long double __floatundixf(du_int a); + +#ifdef __x86_64__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop64: .quad 0x43f0000000000000 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundixf) + movq %rdi, -8(%rsp) + fildq -8(%rsp) + test %rdi, %rdi + js 1f + ret +1: faddl REL_ADDR(twop64) + ret + +#endif // __x86_64__ + + +/* Branch-free implementation is ever so slightly slower, but more beautiful. + It is likely superior for inlining, so I kept it around for future reference. + +#ifdef __x86_64__ + +.const +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52_neg: + .quad 0xc530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundixf) + movl %edi, %esi // low 32 bits of input + shrq $32, %rdi // hi 32 bits of input + orq REL_ADDR(twop84), %rdi // 2^84 + hi (as a double) + orq REL_ADDR(twop52), %rsi // 2^52 + lo (as a double) + movq %rdi, -8(%rsp) + movq %rsi, -16(%rsp) + fldl REL_ADDR(twop84_plus_twop52_neg) + faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs) + faddl -16(%rsp) // hi + lo (as double extended) + ret + +#endif // __x86_64__ + +*/ diff --git a/make/AppleBI.mk b/make/AppleBI.mk new file mode 100644 index 000000000000..8cbce5fbaf56 --- /dev/null +++ b/make/AppleBI.mk @@ -0,0 +1,84 @@ + +# +# Make rules to build compiler_rt in Apple B&I infrastructure +# + +# set ProjSrcRoot appropriately +ProjSrcRoot := $(SRCROOT) +# set ProjObjRoot appropriately +ifdef OBJROOT + ProjObjRoot := $(OBJROOT) +else + ProjObjRoot := $(ProjSrcRoot) +endif + +ifeq (,$(SDKROOT)) + INSTALL_TARGET = install-MacOSX +else + INSTALL_TARGET = install-iOS +endif + + +# Log full compile lines in B&I logs and omit summary lines. +Verb := +Summary := @true + +# List of functions needed for each architecture. + +# Copies any public headers to DSTROOT. +installhdrs: + + +# Copies source code to SRCROOT. +installsrc: + cp -r . $(SRCROOT) + + +install: $(INSTALL_TARGET) + +# Copy results to DSTROOT. +install-MacOSX : $(SYMROOT)/libcompiler_rt.dylib + mkdir -p $(DSTROOT)/usr/lib/system + strip -S $(SYMROOT)/libcompiler_rt.dylib \ + -o $(DSTROOT)/usr/lib/system/libcompiler_rt.dylib + cd $(DSTROOT)/usr/lib/system; \ + ln -s libcompiler_rt.dylib libcompiler_rt_profile.dylib; \ + ln -s libcompiler_rt.dylib libcompiler_rt_debug.dylib + +# Rule to make each dylib slice +$(OBJROOT)/libcompiler_rt-%.dylib : $(OBJROOT)/darwin_bni/Release/%/libcompiler_rt.a + echo "const char vers[] = \"@(#) $(RC_ProjectName)-$(RC_ProjectSourceVersion)\"; " > $(OBJROOT)/version.c + cc $(OBJROOT)/version.c -arch $* -dynamiclib \ + -install_name /usr/lib/system/libcompiler_rt.dylib \ + -compatibility_version 1 -current_version $(RC_ProjectSourceVersion) \ + -nodefaultlibs -lSystem -umbrella System -dead_strip \ + -Wl,-force_load,$^ -o $@ + +# Rule to make fat dylib +$(SYMROOT)/libcompiler_rt.dylib: $(foreach arch,$(RC_ARCHS), \ + $(OBJROOT)/libcompiler_rt-$(arch).dylib) + lipo -create $^ -o $@ + + + + +# Copy results to DSTROOT. +install-iOS: $(SYMROOT)/libcompiler_rt.a $(SYMROOT)/libcompiler_rt-static.a + mkdir -p $(DSTROOT)/usr/local/lib/libgcc + cp $(SYMROOT)/libcompiler_rt.a \ + $(DSTROOT)/usr/local/lib/libgcc/libcompiler_rt.a + mkdir -p $(DSTROOT)/usr/local/ + cp $(SYMROOT)/libcompiler_rt-static.a \ + $(DSTROOT)/usr/local/lib/libcompiler_rt-static.a + + +# Rule to make fat archive +$(SYMROOT)/libcompiler_rt.a : $(foreach arch,$(RC_ARCHS), \ + $(OBJROOT)/darwin_bni/Release/$(arch)/libcompiler_rt.a) + lipo -create $^ -o $@ + +# Rule to make fat archive +$(SYMROOT)/libcompiler_rt-static.a : $(foreach arch,$(RC_ARCHS), \ + $(OBJROOT)/darwin_bni/Static/$(arch)/libcompiler_rt.a) + lipo -create $^ -o $@ + diff --git a/make/config.mk b/make/config.mk new file mode 100644 index 000000000000..d96b1b4354ec --- /dev/null +++ b/make/config.mk @@ -0,0 +1,36 @@ +### +# Configuration variables. + +OS := $(shell uname) + +# Assume make is always run from top-level of source directory. Note than an +# Apple style build overrides these variables later in the makefile. +ProjSrcRoot := $(shell pwd) +ProjObjRoot := $(ProjSrcRoot) + +### +# Tool configuration variables. + +# FIXME: LLVM uses autoconf/mkinstalldirs ? +MKDIR := mkdir -p +DATE := date +LIPO := lipo +CP := cp + +VERBOSE := 0 +DEBUGMAKE := + +### +# Automatic and derived variables. + +# Adjust settings for verbose mode +ifneq ($(VERBOSE),1) + Verb := @ +else + Verb := +endif + +Echo := @echo +ifndef Summary + Summary = $(Echo) +endif diff --git a/make/filter-inputs b/make/filter-inputs new file mode 100755 index 000000000000..8a6bbe2abdc9 --- /dev/null +++ b/make/filter-inputs @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +#===- make/filter-inputs ---------------------------------------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +# Given a list of files, return a new list of files taking only the +# first file for any particular filename. +def main(): + import os,sys + + seen = set() + for file in sys.argv[1:]: + base = os.path.basename(file) + if base not in seen: + seen.add(base) + print file + +if __name__ == '__main__': + main() diff --git a/make/lib_info.mk b/make/lib_info.mk new file mode 100644 index 000000000000..72bc4a17f152 --- /dev/null +++ b/make/lib_info.mk @@ -0,0 +1,51 @@ +# compiler-rt Library Info +# +# This should be included once the subdirectory information has been loaded, and +# uses the utilities in 'util.mk'. +# +# This defines the following variables describing compiler-rt: +# AvailableFunctions - The entire list of function names (unmangled) the +# library can provide. +# CommonFunctions - The list of generic functions available. +# ArchFunctions. - The list of functions commonly available for +# 'arch'. This does not include any config specific +# functions. +# +# AvailableIn. - The list of subdir keys where 'function' is +# defined. + +AvailableArchs := $(sort $(foreach key,$(SubDirKeys),\ + $($(key).OnlyArchs))) + +AvailableFunctions := $(sort $(foreach key,$(SubDirKeys),\ + $(basename $($(key).ObjNames)))) + +CommonFunctions := $(sort\ + $(foreach key,$(SubDirKeys),\ + $(if $(call strneq,,$(strip $($(key).OnlyArchs) $($(key).OnlyConfigs))),,\ + $(basename $($(key).ObjNames))))) + +# Compute common arch functions. +$(foreach key,$(SubDirKeys),\ + $(if $(call strneq,,$($(key).OnlyConfigs)),,\ + $(foreach arch,$($(key).OnlyArchs),\ + $(call Append,ArchFunctions.$(arch),$(sort \ + $(basename $($(key).ObjNames))))))) + +# Compute arch only functions. +$(foreach arch,$(AvailableArchs),\ + $(call Set,ArchFunctions.$(arch),$(sort $(ArchFunctions.$(arch))))\ + $(call Set,ArchOnlyFunctions.$(arch),\ + $(call set_difference,$(ArchFunctions.$(arch)),$(CommonFunctions)))) + +# Compute lists of where each function is available. +$(foreach key,$(SubDirKeys),\ + $(foreach fn,$(basename $($(key).ObjNames)),\ + $(call Append,AvailableIn.$(fn),$(key)))) + +# The names of all the available options. +AvailableOptions := AR ARFLAGS \ + CC CFLAGS FUNCTIONS OPTIMIZED \ + RANLIB RANLIBFLAGS \ + VISIBILITY_HIDDEN \ + KERNEL_USE diff --git a/make/lib_platforms.mk b/make/lib_platforms.mk new file mode 100644 index 000000000000..9cf9704fd174 --- /dev/null +++ b/make/lib_platforms.mk @@ -0,0 +1,82 @@ +# compiler-rt Configuration Support +# +# This should be included following 'lib_util.mk'. + +# The simple variables configurations can define. +PlainConfigVariables := Configs Description +PerConfigVariables := UniversalArchs Arch $(AvailableOptions) +RequiredConfigVariables := Configs Description + +### +# Load Platforms + +# Template: subdir_traverse_template subdir +define load_platform_template +$(call Set,PlatformName,$(basename $(notdir $(1)))) +ifneq ($(DEBUGMAKE),) + $$(info MAKE: $(PlatformName): Loading platform) +endif + +# Construct the variable key for this directory. +$(call Set,PlatformKey,Platform.$(PlatformName)) +$(call Append,PlatformKeys,$(PlatformKey)) +$(call Set,$(PlatformKey).Name,$(PlatformName)) +$(call Set,$(PlatformKey).Path,$(1)) + +# Reset platform specific variables to sentinel value. +$$(foreach var,$(PlainConfigVariables) $(PerConfigVariables),\ + $$(call Set,$$(var),UNDEFINED)) +$$(foreach var,$(PerConfigVariables),\ + $$(foreach config,$$(Configs),\ + $$(call Set,$$(var).$$(config),UNDEFINED))) +$$(foreach var,$(PerConfigVariables),\ + $$(foreach arch,$(AvailableArchs),\ + $$(call Set,$$(var).$$(arch),UNDEFINED))) + +# Get the platform variables. +include make/options.mk +include $(1) + +# Check for undefined required variables. +$$(foreach var,$(RequiredConfigVariables),\ + $$(if $$(call strneq,UNDEFINED,$$($$(var))),, \ + $$(error $(Dir): variable '$$(var)' was not undefined))) + +# Check that exactly one of UniversalArchs or Arch was defined. +$$(if $$(and $$(call strneq,UNDEFINED,$$(UniversalArchs)),\ + $$(call strneq,UNDEFINED,$$(Arch))),\ + $$(error '$(1)': cannot define both 'UniversalArchs' and 'Arch')) +$$(if $$(or $$(call strneq,UNDEFINED,$$(UniversalArchs)),\ + $$(call strneq,UNDEFINED,$$(Arch))),,\ + $$(error '$(1)': must define one of 'UniversalArchs' and 'Arch')) + +# Collect all the platform variables for subsequent use. +$$(foreach var,$(PlainConfigVariables) $(PerConfigVariables),\ + $$(if $$(call strneq,UNDEFINED,$$($$(var))),\ + $$(call CopyVariable,$$(var),$(PlatformKey).$$(var)))) +$$(foreach var,$(PerConfigVariables),\ + $$(foreach config,$$(Configs),\ + $$(if $$(call strneq,UNDEFINED,$$($$(var).$$(config))),\ + $$(call CopyVariable,$$(var).$$(config),$(PlatformKey).$$(var).$$(config))))\ + $$(foreach arch,$(AvailableArchs),\ + $$(if $$(call strneq,UNDEFINED,$$($$(var).$$(arch))),\ + $$(call CopyVariable,$$(var).$$(arch),$(PlatformKey).$$(var).$$(arch))))\ + $$(foreach config,$$(Configs),\ + $$(foreach arch,$(AvailableArchs),\ + $$(if $$(call strneq,UNDEFINED,$$($$(var).$$(config).$$(arch))),\ + $$(call CopyVariable,$$(var).$$(config).$$(arch),\ + $(PlatformKey).$$(var).$$(config).$$(arch)))))) + +ifneq ($(DEBUGMAKE),) + $$(info MAKE: $(PlatformName): Done loading platform) +endif +endef + +# Evaluate this now so we do not have to worry about order of evaluation. +PlatformFiles := $(wildcard make/platform/*.mk) +ifneq ($(DEBUGMAKE),) + $(info MAKE: Loading platforms: $(PlatformFiles)) +endif + +$(foreach file,$(PlatformFiles),\ + $(eval $(call load_platform_template,$(file)))) diff --git a/make/lib_util.mk b/make/lib_util.mk new file mode 100644 index 000000000000..089a0e2eddc9 --- /dev/null +++ b/make/lib_util.mk @@ -0,0 +1,65 @@ +# Library Utility Functions +# +# This should be included following 'lib_info.mk'. + +# Function: GetCNAVar variable-name platform-key config arch +# +# Get a per-config-and-arch variable value. +GetCNAVar = $(strip \ + $(or $($(2).$(1).$(3).$(4)), \ + $($(2).$(1).$(3)), \ + $($(2).$(1).$(4)), \ + $($(2).$(1)))) + +# Function: SelectFunctionDir config arch function-name optimized +# +# Choose the appropriate implementation directory to use for 'function-name' in +# the configuration 'config' and on given arch. +SelectFunctionDir = $(strip \ + $(call Set,Tmp.SelectFunctionDir,$(call SelectFunctionDirs,$(1),$(2),$(3),$(4)))\ + $(if $(call streq,1,$(words $(Tmp.SelectFunctionDir))),\ + $(Tmp.SelectFunctionDir),\ + $(error SelectFunctionDir: invalid function name "$(3)" ($(strip\ + $(if $(call streq,0,$(words $(Tmp.SelectFunctionDir))),\ + no such function,\ + function implemented in multiple directories!!!)))))) + +# Helper functions that select the entire list of subdirs where a function is +# defined with a certain specificity. +SelectFunctionDirs_Opt_ConfigAndArch = $(strip \ + $(foreach key,$(AvailableIn.$(3)),\ + $(if $(and $(call streq,Optimized,$($(key).Implementation)),\ + $(call contains,$($(key).OnlyConfigs),$(1)),\ + $(call contains,$($(key).OnlyArchs),$(2))),$(key),))) +SelectFunctionDirs_Opt_Config = $(strip \ + $(foreach key,$(AvailableIn.$(3)),\ + $(if $(and $(call streq,Optimized,$($(key).Implementation)),\ + $(call contains,$($(key).OnlyConfigs),$(1))),$(key),))) +SelectFunctionDirs_Opt_Arch = $(strip \ + $(foreach key,$(AvailableIn.$(3)),\ + $(if $(and $(call streq,Optimized,$($(key).Implementation)),\ + $(call contains,$($(key).OnlyArchs),$(2))),$(key),))) +SelectFunctionDirs_Gen = $(strip \ + $(foreach key,$(AvailableIn.$(3)),\ + $(if $(call streq,Generic,$($(key).Implementation)),$(key)))) + +# Helper function to select the right set of dirs in generic priority order. +SelectFunctions_Gen = \ + $(or $(call SelectFunctionDirs_Gen,$(1),$(2),$(3)),\ + $(call SelectFunctionDirs_Opt_ConfigAndArch,$(1),$(2),$(3)), \ + $(call SelectFunctionDirs_Opt_Config,$(1),$(2),$(3)), \ + $(call SelectFunctionDirs_Opt_Arch,$(1),$(2),$(3))) + +# Helper function to select the right set of dirs in optimized priority order. +SelectFunctions_Opt = \ + $(or $(call SelectFunctionDirs_Opt_ConfigAndArch,$(1),$(2),$(3)), \ + $(call SelectFunctionDirs_Opt_Config,$(1),$(2),$(3)), \ + $(call SelectFunctionDirs_Opt_Arch,$(1),$(2),$(3)), \ + $(call SelectFunctionDirs_Gen,$(1),$(2),$(3))) + +# Helper function to select the right set of dirs (which should be exactly one) +# for a function. +SelectFunctionDirs = \ + $(if $(call streq,1,$(4)),\ + $(call SelectFunctions_Opt,$(1),$(2),$(3)),\ + $(call SelectFunctions_Gen,$(1),$(2),$(3))) diff --git a/make/options.mk b/make/options.mk new file mode 100644 index 000000000000..f6a331bf0f55 --- /dev/null +++ b/make/options.mk @@ -0,0 +1,33 @@ +# Options which may be overriden for platforms, etc. +# +# This list of such variables should be kept up to date with AvailableOptions in +# 'make/lib_info.mk'. + +# The compiler to use. +CC := gcc + +# The compiler flags to use. +CFLAGS := -Wall -Werror + +# The list of functions to include in the library. +FUNCTIONS := + +# Whether optimized function implementations should be used. +OPTIMIZED := 1 + +# Whether function definitions should use hidden visibility. This adds the +# -fvisibility=hidden compiler option and uses .private_extern annotations in +# assembly files. +# +# FIXME: Make this more portable. When that is done, it should probably be the +# default. +VISIBILITY_HIDDEN := 0 + +# Miscellaneous tools. + +AR := ar +# FIXME: Remove these pipes once ranlib errors are fixed. +ARFLAGS := cru 2> /dev/null +RANLIB := ranlib +# FIXME: Remove these pipes once ranlib errors are fixed. +RANLIBFLAGS := 2> /dev/null diff --git a/make/platform/clang_darwin.mk b/make/platform/clang_darwin.mk new file mode 100644 index 000000000000..23cd3a42f86a --- /dev/null +++ b/make/platform/clang_darwin.mk @@ -0,0 +1,253 @@ +# These are the functions which clang needs when it is targetting a previous +# version of the OS. The issue is that the backend may use functions which were +# not present in the libgcc that shipped on the platform. In such cases, we link +# with a version of the library which contains private_extern definitions of all +# the extra functions which might be referenced. + +Description := Static runtime libraries for clang/Darwin. + +Configs := +UniversalArchs := + +# Configuration solely for providing access to an eprintf symbol, which may +# still be referenced from Darwin system headers. This symbol is only ever +# needed on i386. +Configs += eprintf +UniversalArchs.eprintf := i386 + +# Configuration for targetting 10.4. We need a few functions missing from +# libgcc_s.10.4.dylib. We only build x86 slices since clang doesn't really +# support targetting PowerPC. +Configs += 10.4 +UniversalArchs.10.4 := i386 x86_64 + +# Configuration for targetting armv6. We need a few additional functions which +# must be in the same linkage unit. +Configs += armv6 +UniversalArchs.armv6 := armv6 + +# Configuration for use with kernel/kexts. +Configs += cc_kext +UniversalArchs.cc_kext := armv6 i386 x86_64 + +# FIXME: Don't build an armv7 slice currently, they have the same functions. +# +#UniversalArchs.cc_kext := armv6 armv7 i386 x86_64 + +### + +CC := gcc + +# Forcibly strip off any -arch, as that totally breaks our universal support. +override CC := $(subst -arch ,-arch_,$(CC)) +override CC := $(patsubst -arch_%,,$(CC)) + +CFLAGS := -Wall -Werror -O3 -fomit-frame-pointer + +FUNCTIONS.eprintf := eprintf +FUNCTIONS.10.4 := eprintf floatundidf floatundisf floatundixf +FUNCTIONS.armv6 := switch16 switch32 switch8 switchu8 \ + save_vfp_d8_d15_regs restore_vfp_d8_d15_regs + +CCKEXT_COMMON_FUNCTIONS := \ + absvdi2 \ + absvsi2 \ + addvdi3 \ + addvsi3 \ + ashldi3 \ + ashrdi3 \ + bswapdi2 \ + bswapsi2 \ + clear_cache \ + clzdi2 \ + clzsi2 \ + cmpdi2 \ + ctzdi2 \ + ctzsi2 \ + divdc3 \ + divdi3 \ + divsc3 \ + do_global_dtors \ + eprintf \ + ffsdi2 \ + fixdfdi \ + fixsfdi \ + fixunsdfdi \ + fixunsdfsi \ + fixunssfdi \ + fixunssfsi \ + floatdidf \ + floatdisf \ + floatundidf \ + floatundisf \ + gcc_bcmp \ + lshrdi3 \ + moddi3 \ + muldc3 \ + muldi3 \ + mulsc3 \ + mulvdi3 \ + mulvsi3 \ + negdi2 \ + negvdi2 \ + negvsi2 \ + paritydi2 \ + paritysi2 \ + popcountdi2 \ + popcountsi2 \ + powidf2 \ + powisf2 \ + subvdi3 \ + subvsi3 \ + ucmpdi2 \ + udiv_w_sdiv \ + udivdi3 \ + udivmoddi4 \ + umoddi3 + +CCKEXT_ARM_FUNCTIONS := $(CCKEXT_COMMON_FUNCTONS) \ + adddf3 \ + addsf3 \ + aeabi_cdcmpeq \ + aeabi_cdrcmple \ + aeabi_cfcmpeq \ + aeabi_cfrcmple \ + aeabi_dcmpeq \ + aeabi_dcmpge \ + aeabi_dcmpgt \ + aeabi_dcmple \ + aeabi_dcmplt \ + aeabi_drsub \ + aeabi_fcmpeq \ + aeabi_fcmpge \ + aeabi_fcmpgt \ + aeabi_fcmple \ + aeabi_fcmplt \ + aeabi_frsub \ + aeabi_idivmod \ + aeabi_uidivmod \ + cmpdf2 \ + cmpsf2 \ + div0 \ + divdf3 \ + divsf3 \ + divsi3 \ + extendsfdf2 \ + ffssi2 \ + fixdfsi \ + fixsfsi \ + floatsidf \ + floatsisf \ + floatunsidf \ + floatunsisf \ + gtdf2 \ + gtsf2 \ + ltdf2 \ + ltsf2 \ + modsi3 \ + muldf3 \ + mulsf3 \ + negdf2 \ + negsf2 \ + subdf3 \ + subsf3 \ + switch16 \ + switch32 \ + switch8 \ + switchu8 \ + truncdfsf2 \ + udivsi3 \ + umodsi3 \ + unorddf2 \ + unordsf2 + +FUNCTIONS.cc_kext.armv6 := $(CCKEXT_ARM_FUNCTIONS) +FUNCTIONS.cc_kext.armv7 := $(CCKEXT_ARM_FUNCTIONS) + +CCKEXT_X86_FUNCTIONS := $(CCKEXT_COMMON_FUNCTIONS) \ + divxc3 \ + fixunsxfdi \ + fixunsxfsi \ + fixxfdi \ + floatdixf \ + floatundixf \ + mulxc3 \ + powixf2 + +FUNCTIONS.cc_kext.i386 := $(CCKEXT_X86_FUNCTIONS) \ + ffssi2 \ + i686.get_pc_thunk.eax \ + i686.get_pc_thunk.ebp \ + i686.get_pc_thunk.ebx \ + i686.get_pc_thunk.ecx \ + i686.get_pc_thunk.edi \ + i686.get_pc_thunk.edx \ + i686.get_pc_thunk.esi + +FUNCTIONS.cc_kext.x86_64 := $(CCKEXT_X86_FUNCTIONS) \ + absvti2 \ + addvti3 \ + ashlti3 \ + ashrti3 \ + clzti2 \ + cmpti2 \ + ctzti2 \ + divti3 \ + ffsti2 \ + fixdfti \ + fixsfti \ + fixunsdfti \ + fixunssfti \ + fixunsxfti \ + fixxfti \ + floattidf \ + floattisf \ + floattixf \ + floatuntidf \ + floatuntisf \ + floatuntixf \ + lshrti3 \ + modti3 \ + multi3 \ + mulvti3 \ + negti2 \ + negvti2 \ + parityti2 \ + popcountti2 \ + subvti3 \ + ucmpti2 \ + udivmodti4 \ + udivti3 \ + umodti3 + +# FIXME: Currently, compiler-rt is missing implementations for a number of the +# functions that need to go into libcc_kext.a. Filter them out for now. +CCKEXT_MISSING_FUNCTIONS := \ + adddf3 addsf3 cmpdf2 cmpsf2 div0 divdf3 divsf3 \ + extendsfdf2 ffssi2 fixdfsi fixsfsi floatsidf floatsisf \ + floatunsidf floatunsisf gtdf2 gtsf2 ltdf2 ltsf2 \ + muldf3 mulsf3 negdf2 negsf2 subdf3 subsf3 \ + truncdfsf2 udiv_w_sdiv unorddf2 unordsf2 bswapdi2 \ + bswapsi2 \ + gcc_bcmp \ + do_global_dtors \ + i686.get_pc_thunk.eax i686.get_pc_thunk.ebp i686.get_pc_thunk.ebx \ + i686.get_pc_thunk.ecx i686.get_pc_thunk.edi i686.get_pc_thunk.edx \ + i686.get_pc_thunk.esi \ + aeabi_cdcmpeq aeabi_cdrcmple aeabi_cfcmpeq aeabi_cfrcmple aeabi_dcmpeq \ + aeabi_dcmpge aeabi_dcmpgt aeabi_dcmple aeabi_dcmplt aeabi_drsub aeabi_fcmpeq \ + aeabi_fcmpge aeabi_fcmpgt aeabi_fcmple aeabi_fcmplt aeabi_frsub aeabi_idivmod \ + aeabi_uidivmod + +FUNCTIONS.cc_kext.armv6 := \ + $(filter-out $(CCKEXT_MISSING_FUNCTIONS),$(FUNCTIONS.cc_kext.armv6)) +FUNCTIONS.cc_kext.armv7 := \ + $(filter-out $(CCKEXT_MISSING_FUNCTIONS),$(FUNCTIONS.cc_kext.armv7)) +FUNCTIONS.cc_kext.i386 := \ + $(filter-out $(CCKEXT_MISSING_FUNCTIONS),$(FUNCTIONS.cc_kext.i386)) +FUNCTIONS.cc_kext.x86_64 := \ + $(filter-out $(CCKEXT_MISSING_FUNCTIONS),$(FUNCTIONS.cc_kext.x86_64)) + +KERNEL_USE.cc_kext := 1 + +VISIBILITY_HIDDEN := 1 diff --git a/make/platform/darwin_bni.mk b/make/platform/darwin_bni.mk new file mode 100644 index 000000000000..ec859f3b5d6e --- /dev/null +++ b/make/platform/darwin_bni.mk @@ -0,0 +1,95 @@ + +Description := Target for Darwin using an Apple-style build. + +Configs := Debug Release Profile Static + +# We override this with RC_ARCHS because B&I may want to build on an ARCH we +# haven't explicitly defined support for. If all goes well, this will just work +# and the resulting lib will just have generic versions for anything unknown. +UniversalArchs := $(RC_ARCHS) + +ifeq (,$(SDKROOT)) +else + CC.Release := /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/cc + CC.Static := /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/cc +endif + + +CFLAGS := -Wall -Os -fomit-frame-pointer -g +CFLAGS.Static := $(CFLAGS) -static + +VISIBILITY_HIDDEN := 0 +VISIBILITY_HIDDEN.Static := 1 + + +FUNCTIONS := absvdi2 absvsi2 addvdi3 addvsi3 ashldi3 ashrdi3 \ + clzdi2 clzsi2 cmpdi2 ctzdi2 ctzsi2 \ + divdc3 divdi3 divsc3 ffsdi2 \ + fixdfdi fixsfdi fixunsdfdi fixunsdfsi fixunssfdi \ + fixunssfsi floatdidf floatdisf floatundidf floatundisf \ + gcc_personality_v0 lshrdi3 moddi3 muldc3 muldi3 \ + mulsc3 mulvdi3 mulvsi3 negdi2 negvdi2 negvsi2 \ + paritydi2 paritysi2 popcountdi2 popcountsi2 powidf2 \ + powisf2 subvdi3 subvsi3 ucmpdi2 udivdi3 \ + udivmoddi4 umoddi3 apple_versioning eprintf + +FUNCTIONS.i386 := $(FUNCTIONS) \ + divxc3 fixunsxfdi fixunsxfsi fixxfdi floatdixf \ + floatundixf mulxc3 powixf2 clear_cache \ + enable_execute_stack +FUNCTIONS.ppc := $(FUNCTIONS) \ + divtc3 fixtfdi fixunstfdi floatditf floatunditf \ + gcc_qadd gcc_qdiv gcc_qmul gcc_qsub multc3 \ + powitf2 restFP saveFP trampoline_setup \ + clear_cache enable_execute_stack +FUNCTIONS.x86_64 := $(FUNCTIONS) \ + absvti2 addvti3 ashlti3 ashrti3 clzti2 cmpti2 \ + ctzti2 divti3 divxc3 ffsti2 fixdfti fixsfti \ + fixunsdfti fixunssfti fixunsxfdi fixunsxfsi \ + fixunsxfti fixxfdi fixxfti floatdixf floattidf \ + floattisf floattixf floatundixf floatuntidf \ + floatuntisf floatuntixf lshrti3 modti3 multi3 \ + mulvti3 mulxc3 negti2 negvti2 parityti2 \ + popcountti2 powixf2 subvti3 ucmpti2 udivmodti4 \ + udivti3 umodti3 clear_cache enable_execute_stack +FUNCTIONS.armv5 := $(FUNCTIONS) \ + adddf3 addsf3 bswapdi2 bswapsi2 \ + comparedf2 comparesf2 extendsfdf2 \ + divdf3 divsf3 \ + fixdfsi fixsfsi fixunsdfsi fixunssfsi \ + floatsidf floatsisf floatunsidf floatunsisf \ + muldf3 mulsf3 \ + negdf2 negsf2 \ + truncdfsf2 \ + modsi3 umodsi3 udivsi3 divsi3 \ + switch8 switchu8 switch16 switch32 \ + sync_synchronize + +FUNCTIONS.armv6 := $(FUNCTIONS) \ + comparedf2 comparesf2 \ + adddf3vfp addsf3vfp bswapdi2 bswapsi2 divdf3vfp \ + divsf3vfp eqdf2vfp eqsf2vfp extendsfdf2vfp \ + fixdfsivfp fixsfsivfp fixunsdfsivfp fixunssfsivfp \ + floatsidfvfp floatsisfvfp floatunssidfvfp floatunssisfvfp \ + gedf2vfp gesf2vfp gtdf2vfp gtsf2vfp \ + ledf2vfp lesf2vfp ltdf2vfp ltsf2vfp \ + muldf3vfp mulsf3vfp \ + nedf2vfp nesf2vfp \ + subdf3vfp subsf3vfp truncdfsf2vfp unorddf2vfp unordsf2vfp \ + modsi3 umodsi3 udivsi3 divsi3 \ + switch8 switchu8 switch16 switch32 \ + restore_vfp_d8_d15_regs save_vfp_d8_d15_regs \ + sync_synchronize +FUNCTIONS.armv7 := $(FUNCTIONS) \ + comparedf2 comparesf2 \ + adddf3vfp addsf3vfp bswapdi2 bswapsi2 divdf3vfp \ + divsf3vfp eqdf2vfp eqsf2vfp extendsfdf2vfp \ + fixdfsivfp fixsfsivfp fixunsdfsivfp fixunssfsivfp \ + floatsidfvfp floatsisfvfp floatunssidfvfp floatunssisfvfp \ + gedf2vfp gesf2vfp gtdf2vfp gtsf2vfp \ + ledf2vfp lesf2vfp ltdf2vfp ltsf2vfp \ + muldf3vfp mulsf3vfp \ + nedf2vfp nesf2vfp \ + subdf3vfp subsf3vfp truncdfsf2vfp unorddf2vfp unordsf2vfp \ + modsi3 umodsi3 udivsi3 divsi3 + diff --git a/make/platform/darwin_fat.mk b/make/platform/darwin_fat.mk new file mode 100644 index 000000000000..30e57a198e2e --- /dev/null +++ b/make/platform/darwin_fat.mk @@ -0,0 +1,56 @@ +# Configurations to build +# +# This section must define: +# Description - A description of this target. +# Configs - The names of each configuration to build; this is used to build +# multiple libraries inside a single configuration file (for +# example, Debug and Release builds, or builds with and without +# software floating point). +# +# This section must define one of: +# UniveralArchs - A list of architectures to build for, when using universal build +# support (e.g., on Darwin). This should only be used to build fat +# libraries, simply building multiple libraries for different +# architectures should do so using distinct configs, with the +# appropriate choices for CC and CFLAGS. +# +# Arch - The target architecture; this must match the compiler-rt name for the +# architecture and is used to find the appropriate function +# implementations. +# +# When not universal builds, this section may define: +# Arch. - Set the target architecture on a per-config basis. + +Description := Target for building universal libraries for Darwin. + +Configs := Debug Release Profile +UniversalArchs := i386 ppc x86_64 + +# Platform Options +# +# This section may override any of the variables in make/options.mk, using: +#