summaryrefslogtreecommitdiff
path: root/lib/hipe
diff options
context:
space:
mode:
authorJohn Högberg <john@erlang.org>2020-11-05 12:31:08 +0100
committerJohn Högberg <john@erlang.org>2020-11-09 10:00:39 +0100
commite6d9d0da048513552bacbac80356e1d962431062 (patch)
tree10a8b86f3ab04e35aac9217f5857f9d59bcbf1f9 /lib/hipe
parent18e25cb97a4eddda8f9a440141e8b122e6430873 (diff)
downloaderlang-e6d9d0da048513552bacbac80356e1d962431062.tar.gz
otp: Remove HiPE and HiPE-related accessories
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/Makefile80
-rw-r--r--lib/hipe/TODO130
-rw-r--r--lib/hipe/amd64/Makefile136
-rw-r--r--lib/hipe/amd64/hipe_amd64_assemble.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_defuse.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_encode.erl1502
-rw-r--r--lib/hipe/amd64/hipe_amd64_frame.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_liveness.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_main.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_pp.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_finalise.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_ls.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_naive.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_postconditions.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl167
-rw-r--r--lib/hipe/amd64/hipe_amd64_registers.erl281
-rw-r--r--lib/hipe/amd64/hipe_amd64_spill_restore.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_sse2.erl76
-rw-r--r--lib/hipe/amd64/hipe_amd64_subst.erl13
-rw-r--r--lib/hipe/amd64/hipe_amd64_x87.erl13
-rw-r--r--lib/hipe/amd64/hipe_rtl_to_amd64.erl13
-rw-r--r--lib/hipe/arm/Makefile124
-rw-r--r--lib/hipe/arm/TODO20
-rw-r--r--lib/hipe/arm/hipe_arm.erl381
-rw-r--r--lib/hipe/arm/hipe_arm.hrl119
-rw-r--r--lib/hipe/arm/hipe_arm_assemble.erl617
-rw-r--r--lib/hipe/arm/hipe_arm_cfg.erl148
-rw-r--r--lib/hipe/arm/hipe_arm_defuse.erl160
-rw-r--r--lib/hipe/arm/hipe_arm_encode.erl989
-rw-r--r--lib/hipe/arm/hipe_arm_finalise.erl126
-rw-r--r--lib/hipe/arm/hipe_arm_frame.erl644
-rw-r--r--lib/hipe/arm/hipe_arm_liveness_gpr.erl32
-rw-r--r--lib/hipe/arm/hipe_arm_main.erl54
-rw-r--r--lib/hipe/arm/hipe_arm_pp.erl350
-rw-r--r--lib/hipe/arm/hipe_arm_ra.erl54
-rw-r--r--lib/hipe/arm/hipe_arm_ra_finalise.erl295
-rw-r--r--lib/hipe/arm/hipe_arm_ra_ls.erl49
-rw-r--r--lib/hipe/arm/hipe_arm_ra_naive.erl23
-rw-r--r--lib/hipe/arm/hipe_arm_ra_postconditions.erl283
-rw-r--r--lib/hipe/arm/hipe_arm_registers.erl207
-rw-r--r--lib/hipe/arm/hipe_arm_subst.erl127
-rw-r--r--lib/hipe/arm/hipe_rtl_to_arm.erl858
-rw-r--r--lib/hipe/boot_ebin/.gitignore0
-rw-r--r--lib/hipe/cerl/Makefile114
-rw-r--r--lib/hipe/cerl/cerl_cconv.erl774
-rw-r--r--lib/hipe/cerl/cerl_hipe_primops.hrl77
-rw-r--r--lib/hipe/cerl/cerl_hipeify.erl648
-rw-r--r--lib/hipe/cerl/cerl_to_icode.erl2705
-rw-r--r--lib/hipe/doc/Makefile40
-rw-r--r--lib/hipe/doc/html/.gitignore0
-rw-r--r--lib/hipe/doc/overview.edoc9
-rw-r--r--lib/hipe/doc/pdf/.gitignore0
-rw-r--r--lib/hipe/doc/src/HiPE_app.xml198
-rw-r--r--lib/hipe/doc/src/Makefile45
-rw-r--r--lib/hipe/doc/src/book.xml42
-rw-r--r--lib/hipe/doc/src/notes.xml2028
-rw-r--r--lib/hipe/doc/src/ref_man.xml36
-rw-r--r--lib/hipe/ebin/.gitignore0
-rw-r--r--lib/hipe/flow/Makefile113
-rw-r--r--lib/hipe/flow/cfg.hrl48
-rw-r--r--lib/hipe/flow/cfg.inc1013
-rw-r--r--lib/hipe/flow/ebb.inc244
-rw-r--r--lib/hipe/flow/hipe_bb.erl78
-rw-r--r--lib/hipe/flow/hipe_bb.hrl25
-rw-r--r--lib/hipe/flow/hipe_dominators.erl712
-rw-r--r--lib/hipe/flow/hipe_gen_cfg.erl29
-rw-r--r--lib/hipe/flow/liveness.inc329
-rw-r--r--lib/hipe/icode/Makefile151
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl2494
-rw-r--r--lib/hipe/icode/hipe_icode.erl1847
-rw-r--r--lib/hipe/icode/hipe_icode.hrl177
-rw-r--r--lib/hipe/icode/hipe_icode_bincomp.erl189
-rw-r--r--lib/hipe/icode/hipe_icode_call_elim.erl72
-rw-r--r--lib/hipe/icode/hipe_icode_callgraph.erl210
-rw-r--r--lib/hipe/icode/hipe_icode_cfg.erl199
-rw-r--r--lib/hipe/icode/hipe_icode_coordinator.erl289
-rw-r--r--lib/hipe/icode/hipe_icode_ebb.erl24
-rw-r--r--lib/hipe/icode/hipe_icode_exceptions.erl472
-rw-r--r--lib/hipe/icode/hipe_icode_fp.erl1190
-rw-r--r--lib/hipe/icode/hipe_icode_heap_test.erl192
-rw-r--r--lib/hipe/icode/hipe_icode_inline_bifs.erl238
-rw-r--r--lib/hipe/icode/hipe_icode_instruction_counter.erl131
-rw-r--r--lib/hipe/icode/hipe_icode_liveness.erl97
-rw-r--r--lib/hipe/icode/hipe_icode_mulret.erl1318
-rw-r--r--lib/hipe/icode/hipe_icode_pp.erl297
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl999
-rw-r--r--lib/hipe/icode/hipe_icode_primops.hrl33
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl1974
-rw-r--r--lib/hipe/icode/hipe_icode_split_arith.erl548
-rw-r--r--lib/hipe/icode/hipe_icode_ssa.erl96
-rw-r--r--lib/hipe/icode/hipe_icode_ssa_const_prop.erl730
-rw-r--r--lib/hipe/icode/hipe_icode_ssa_copy_prop.erl36
-rw-r--r--lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl1439
-rw-r--r--lib/hipe/icode/hipe_icode_type.erl2259
-rw-r--r--lib/hipe/icode/hipe_icode_type.hrl19
-rw-r--r--lib/hipe/info2
-rw-r--r--lib/hipe/llvm/Makefile119
-rw-r--r--lib/hipe/llvm/elf32_format.hrl59
-rw-r--r--lib/hipe/llvm/elf64_format.hrl58
-rw-r--r--lib/hipe/llvm/elf_format.erl620
-rw-r--r--lib/hipe/llvm/elf_format.hrl528
-rw-r--r--lib/hipe/llvm/hipe_llvm.erl1144
-rw-r--r--lib/hipe/llvm/hipe_llvm_arch.hrl11
-rw-r--r--lib/hipe/llvm/hipe_llvm_liveness.erl112
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl552
-rw-r--r--lib/hipe/llvm/hipe_llvm_merge.erl114
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl1638
-rw-r--r--lib/hipe/main/Makefile125
-rw-r--r--lib/hipe/main/hipe.app.src231
-rw-r--r--lib/hipe/main/hipe.appup.src19
-rw-r--r--lib/hipe/main/hipe.erl1638
-rw-r--r--lib/hipe/main/hipe.hrl.src319
-rw-r--r--lib/hipe/main/hipe_main.erl592
-rw-r--r--lib/hipe/misc/Makefile117
-rw-r--r--lib/hipe/misc/hipe_consttab.erl502
-rw-r--r--lib/hipe/misc/hipe_consttab.hrl22
-rw-r--r--lib/hipe/misc/hipe_data_pp.erl152
-rw-r--r--lib/hipe/misc/hipe_gensym.erl237
-rw-r--r--lib/hipe/misc/hipe_pack_constants.erl278
-rw-r--r--lib/hipe/misc/hipe_sdi.erl393
-rw-r--r--lib/hipe/misc/hipe_sdi.hrl18
-rw-r--r--lib/hipe/misc/hipe_segment_trees.erl174
-rw-r--r--lib/hipe/native.mk7
-rw-r--r--lib/hipe/opt/Makefile109
-rw-r--r--lib/hipe/opt/hipe_bb_weights.erl449
-rw-r--r--lib/hipe/opt/hipe_spillmin.erl118
-rw-r--r--lib/hipe/opt/hipe_spillmin_color.erl583
-rw-r--r--lib/hipe/opt/hipe_spillmin_scan.erl558
-rw-r--r--lib/hipe/ppc/Makefile128
-rw-r--r--lib/hipe/ppc/hipe_ppc.erl522
-rw-r--r--lib/hipe/ppc/hipe_ppc.hrl113
-rw-r--r--lib/hipe/ppc/hipe_ppc_assemble.erl609
-rw-r--r--lib/hipe/ppc/hipe_ppc_cfg.erl152
-rw-r--r--lib/hipe/ppc/hipe_ppc_defuse.erl150
-rw-r--r--lib/hipe/ppc/hipe_ppc_encode.erl1553
-rw-r--r--lib/hipe/ppc/hipe_ppc_finalise.erl59
-rw-r--r--lib/hipe/ppc/hipe_ppc_frame.erl686
-rw-r--r--lib/hipe/ppc/hipe_ppc_liveness_all.erl32
-rw-r--r--lib/hipe/ppc/hipe_ppc_liveness_fpr.erl28
-rw-r--r--lib/hipe/ppc/hipe_ppc_liveness_gpr.erl32
-rw-r--r--lib/hipe/ppc/hipe_ppc_main.erl47
-rw-r--r--lib/hipe/ppc/hipe_ppc_pp.erl350
-rw-r--r--lib/hipe/ppc/hipe_ppc_ra.erl54
-rw-r--r--lib/hipe/ppc/hipe_ppc_ra_finalise.erl281
-rw-r--r--lib/hipe/ppc/hipe_ppc_ra_ls.erl49
-rw-r--r--lib/hipe/ppc/hipe_ppc_ra_naive.erl23
-rw-r--r--lib/hipe/ppc/hipe_ppc_ra_postconditions.erl248
-rw-r--r--lib/hipe/ppc/hipe_ppc_ra_postconditions_fp.erl135
-rw-r--r--lib/hipe/ppc/hipe_ppc_registers.erl242
-rw-r--r--lib/hipe/ppc/hipe_ppc_subst.erl79
-rw-r--r--lib/hipe/ppc/hipe_rtl_to_ppc.erl1336
-rw-r--r--lib/hipe/prebuild.skip1
-rw-r--r--lib/hipe/regalloc/Makefile133
-rw-r--r--lib/hipe/regalloc/hipe_adj_list.erl138
-rw-r--r--lib/hipe/regalloc/hipe_amd64_specific.erl14
-rw-r--r--lib/hipe/regalloc/hipe_amd64_specific_sse2.erl245
-rw-r--r--lib/hipe/regalloc/hipe_amd64_specific_x87.erl14
-rw-r--r--lib/hipe/regalloc/hipe_arm_specific.erl221
-rw-r--r--lib/hipe/regalloc/hipe_coalescing_regalloc.erl1040
-rw-r--r--lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl807
-rw-r--r--lib/hipe/regalloc/hipe_ig.erl806
-rw-r--r--lib/hipe/regalloc/hipe_ig_moves.erl77
-rw-r--r--lib/hipe/regalloc/hipe_ls_regalloc.erl786
-rw-r--r--lib/hipe/regalloc/hipe_moves.erl159
-rw-r--r--lib/hipe/regalloc/hipe_node_sets.erl42
-rw-r--r--lib/hipe/regalloc/hipe_optimistic_regalloc.erl2075
-rw-r--r--lib/hipe/regalloc/hipe_ppc_specific.erl214
-rw-r--r--lib/hipe/regalloc/hipe_ppc_specific_fp.erl192
-rw-r--r--lib/hipe/regalloc/hipe_range_split.erl1187
-rw-r--r--lib/hipe/regalloc/hipe_reg_worklists.erl358
-rw-r--r--lib/hipe/regalloc/hipe_regalloc_loop.erl117
-rw-r--r--lib/hipe/regalloc/hipe_regalloc_prepass.erl953
-rw-r--r--lib/hipe/regalloc/hipe_restore_reuse.erl516
-rw-r--r--lib/hipe/regalloc/hipe_sparc_specific.erl214
-rw-r--r--lib/hipe/regalloc/hipe_sparc_specific_fp.erl192
-rw-r--r--lib/hipe/regalloc/hipe_spillcost.erl95
-rw-r--r--lib/hipe/regalloc/hipe_spillcost.hrl20
-rw-r--r--lib/hipe/regalloc/hipe_temp_map.erl120
-rw-r--r--lib/hipe/regalloc/hipe_x86_specific.erl259
-rw-r--r--lib/hipe/regalloc/hipe_x86_specific_x87.erl172
-rw-r--r--lib/hipe/rtl/Makefile182
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl727
-rw-r--r--lib/hipe/rtl/hipe_rtl.erl1804
-rw-r--r--lib/hipe/rtl/hipe_rtl.hrl56
-rw-r--r--lib/hipe/rtl/hipe_rtl_arch.erl677
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc171
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith_32.erl46
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith_64.erl33
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary.erl225
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl1227
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl1115
-rw-r--r--lib/hipe/rtl/hipe_rtl_cfg.erl192
-rw-r--r--lib/hipe/rtl/hipe_rtl_cleanup_const.erl80
-rw-r--r--lib/hipe/rtl/hipe_rtl_exceptions.erl113
-rw-r--r--lib/hipe/rtl/hipe_rtl_lcm.erl1700
-rw-r--r--lib/hipe/rtl/hipe_rtl_liveness.erl139
-rw-r--r--lib/hipe/rtl/hipe_rtl_mk_switch.erl980
-rw-r--r--lib/hipe/rtl/hipe_rtl_primops.erl1280
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa.erl88
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_avail_expr.erl351
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl1018
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssapre.erl1666
-rw-r--r--lib/hipe/rtl/hipe_rtl_symbolic.erl94
-rw-r--r--lib/hipe/rtl/hipe_rtl_varmap.erl155
-rw-r--r--lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl89
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl1302
-rw-r--r--lib/hipe/sparc/Makefile128
-rw-r--r--lib/hipe/sparc/hipe_rtl_to_sparc.erl907
-rw-r--r--lib/hipe/sparc/hipe_sparc.erl415
-rw-r--r--lib/hipe/sparc/hipe_sparc.hrl112
-rw-r--r--lib/hipe/sparc/hipe_sparc_assemble.erl540
-rw-r--r--lib/hipe/sparc/hipe_sparc_cfg.erl155
-rw-r--r--lib/hipe/sparc/hipe_sparc_defuse.erl154
-rw-r--r--lib/hipe/sparc/hipe_sparc_encode.erl471
-rw-r--r--lib/hipe/sparc/hipe_sparc_finalise.erl132
-rw-r--r--lib/hipe/sparc/hipe_sparc_frame.erl674
-rw-r--r--lib/hipe/sparc/hipe_sparc_liveness_all.erl32
-rw-r--r--lib/hipe/sparc/hipe_sparc_liveness_fpr.erl28
-rw-r--r--lib/hipe/sparc/hipe_sparc_liveness_gpr.erl32
-rw-r--r--lib/hipe/sparc/hipe_sparc_main.erl54
-rw-r--r--lib/hipe/sparc/hipe_sparc_pp.erl336
-rw-r--r--lib/hipe/sparc/hipe_sparc_ra.erl53
-rw-r--r--lib/hipe/sparc/hipe_sparc_ra_finalise.erl264
-rw-r--r--lib/hipe/sparc/hipe_sparc_ra_ls.erl49
-rw-r--r--lib/hipe/sparc/hipe_sparc_ra_naive.erl23
-rw-r--r--lib/hipe/sparc/hipe_sparc_ra_postconditions.erl227
-rw-r--r--lib/hipe/sparc/hipe_sparc_ra_postconditions_fp.erl126
-rw-r--r--lib/hipe/sparc/hipe_sparc_registers.erl291
-rw-r--r--lib/hipe/sparc/hipe_sparc_subst.erl82
-rw-r--r--lib/hipe/ssa/hipe_ssa.inc973
-rw-r--r--lib/hipe/ssa/hipe_ssa_const_prop.inc517
-rw-r--r--lib/hipe/ssa/hipe_ssa_copy_prop.inc193
-rw-r--r--lib/hipe/ssa/hipe_ssa_liveness.inc326
-rw-r--r--lib/hipe/test/Makefile82
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_arith.erl72
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl102
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bifs.erl257
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bignums.erl143
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_boolean.erl47
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl138
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl531
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_comparisons.erl157
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_edge_cases.erl142
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_exceptions.erl693
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_floats.erl250
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_fun.erl124
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_guards.erl164
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_inline_module.erl31
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl326
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl177
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_lists.erl61
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_module_info.erl32
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_num_bif.erl217
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl46
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_random.erl238
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_receive.erl145
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_records.erl28
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl65
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_switches.erl52
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl39
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_tuples.erl191
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_add.erl26
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_bincomp.erl79
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_bits.erl150
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_bitsize.erl23
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_bugs_R08.erl32
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_bugs_R09.erl35
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_bugs_R12.erl133
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_build.erl41
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_catch_bug.erl25
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_checksum.erl35
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_construct.erl314
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_decode.erl980
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_decode_extract.hrl91
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_des.erl734
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_extract.erl94
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_flatb.erl29
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_id3.erl75
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_match.erl289
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_match_compiler.erl1235
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_native_float.erl22
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_orber.erl26
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_pmatch.erl269
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl115
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_pmatch_in_guards.erl23
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_potpurri.erl200
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_remove3.erl104
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_save.erl21
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_shell_native.erl275
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_split.erl105
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_system_limit_32.erl26
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_utf.erl356
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_var_segs.erl76
-rw-r--r--lib/hipe/test/hipe.spec6
-rw-r--r--lib/hipe/test/hipe_SUITE.erl57
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl185
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_build_and_match_aliasing.erl20
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_build_and_match_empty_val.erl17
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_build_and_match_literals.erl40
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_build_and_match_over_alloc.erl16
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_build_and_match_val.erl23
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_expand_map_update.erl7
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_export.erl11
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_get_map_elements.erl23
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_guard_bifs.erl31
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_guard_fun.erl36
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_guard_receive.erl54
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_guard_sequence.erl35
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_guard_update.erl14
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_has_map_fields.erl46
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_is_map.erl24
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_list_comprehension.erl6
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_map_size.erl29
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_map_sort_literals.erl42
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_match_and_update_literals.erl24
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_put_map_assoc.erl23
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_put_map_exact.erl28
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl14
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_update_assoc.erl22
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_update_exact.erl32
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_update_literals.erl13
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_update_map_expressions.erl32
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_update_values.erl28
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_warn_pair_key_overloaded.erl26
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_warn_useless_build.erl9
-rw-r--r--lib/hipe/test/opt_verify_SUITE.erl65
-rw-r--r--lib/hipe/test/opt_verify_SUITE_data/call_elim_test.erl12
-rw-r--r--lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_no_opt_poss.erl32
-rw-r--r--lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl26
-rw-r--r--lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl28
-rw-r--r--lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl21
-rw-r--r--lib/hipe/tools/Makefile114
-rw-r--r--lib/hipe/tools/hipe_jit.erl82
-rw-r--r--lib/hipe/tools/hipe_profile.erl185
-rw-r--r--lib/hipe/tools/hipe_timer.erl153
-rw-r--r--lib/hipe/util/Makefile115
-rw-r--r--lib/hipe/util/hipe_digraph.erl235
-rw-r--r--lib/hipe/util/hipe_dsets.erl84
-rw-r--r--lib/hipe/util/hipe_timing.erl126
-rw-r--r--lib/hipe/util/hipe_vectors.erl129
-rw-r--r--lib/hipe/vsn.mk1
-rw-r--r--lib/hipe/x86/Makefile140
-rw-r--r--lib/hipe/x86/NOTES.OPTIM198
-rw-r--r--lib/hipe/x86/NOTES.RA30
-rw-r--r--lib/hipe/x86/TODO31
-rw-r--r--lib/hipe/x86/hipe_rtl_to_x86.erl936
-rw-r--r--lib/hipe/x86/hipe_x86.erl508
-rw-r--r--lib/hipe/x86/hipe_x86.hrl112
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl1004
-rw-r--r--lib/hipe/x86/hipe_x86_cfg.erl162
-rw-r--r--lib/hipe/x86/hipe_x86_defuse.erl170
-rw-r--r--lib/hipe/x86/hipe_x86_encode.erl1319
-rw-r--r--lib/hipe/x86/hipe_x86_encode.txt211
-rw-r--r--lib/hipe/x86/hipe_x86_frame.erl713
-rw-r--r--lib/hipe/x86/hipe_x86_liveness.erl52
-rw-r--r--lib/hipe/x86/hipe_x86_main.erl68
-rw-r--r--lib/hipe/x86/hipe_x86_postpass.erl285
-rw-r--r--lib/hipe/x86/hipe_x86_pp.erl351
-rw-r--r--lib/hipe/x86/hipe_x86_ra.erl116
-rw-r--r--lib/hipe/x86/hipe_x86_ra_finalise.erl335
-rw-r--r--lib/hipe/x86/hipe_x86_ra_ls.erl104
-rw-r--r--lib/hipe/x86/hipe_x86_ra_naive.erl412
-rw-r--r--lib/hipe/x86/hipe_x86_ra_postconditions.erl474
-rw-r--r--lib/hipe/x86/hipe_x86_registers.erl249
-rw-r--r--lib/hipe/x86/hipe_x86_spill_restore.erl334
-rw-r--r--lib/hipe/x86/hipe_x86_subst.erl112
-rw-r--r--lib/hipe/x86/hipe_x86_x87.erl629
368 files changed, 0 insertions, 109755 deletions
diff --git a/lib/hipe/Makefile b/lib/hipe/Makefile
deleted file mode 100644
index 4998522943..0000000000
--- a/lib/hipe/Makefile
+++ /dev/null
@@ -1,80 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-SHELL=/bin/sh
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-ifdef HIPE_ENABLED
-HIPE_SUBDIRS = regalloc sparc ppc x86 amd64 arm opt tools llvm
-else
-HIPE_SUBDIRS =
-endif
-
-ALWAYS_SUBDIRS = misc main cerl icode flow util doc/src
-
-ifdef HIPE_ENABLED
-# "rtl" below must be the first directory so that file rtl/hipe_literals.hrl
-# which is needed by many other HiPE files is built first
-SUB_DIRECTORIES = rtl $(ALWAYS_SUBDIRS) $(HIPE_SUBDIRS)
-else
-SUB_DIRECTORIES = $(ALWAYS_SUBDIRS)
-endif
-
-
-include native.mk
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-#
-# Default Subdir Targets
-#
-include $(ERL_TOP)/make/otp_subdir.mk
-
-# The overriding docs target have been removed so the default make rules work properly.
-
-edocs:
- @if [ -d $(ERL_TOP)/lib/edoc/ebin ]; then \
- erl -noshell -pa $(ERL_TOP)/lib/edoc/ebin $(ERL_TOP)/lib/syntax_tools/ebin $(ERL_TOP)/lib/xmerl/ebin -run edoc_run application 'hipe' '"."' '[new,no_packages]' -s init stop ; \
- fi
-
-all-subdirs:
- $(V_at)for dir in $(SUB_DIRECTORIES); do \
- (cd $$dir; $(MAKE) $(MAKETARGET) EBIN=$(EBIN); cd ..); \
- done
-
-# distclean and realclean should clean the bootstrap files
-all-subdirs-x:
- $(V_at)for dir in $(SUB_DIRECTORIES); do \
- (cd $$dir; $(MAKE) $(MAKETARGET) EBIN=../boot_ebin; cd ..); \
- done
-
-clean:
- $(V_at)$(MAKE) MAKETARGET="clean" all-subdirs all-subdirs-x
-distclean:
- $(V_at)$(MAKE) MAKETARGET="distclean" all-subdirs all-subdirs-x
-realclean:
- $(V_at)$(MAKE) MAKETARGET="realclean" all-subdirs all-subdirs-x
-
-DIA_PLT_APPS=compiler syntax_tools
-
-include $(ERL_TOP)/make/app_targets.mk
diff --git a/lib/hipe/TODO b/lib/hipe/TODO
deleted file mode 100644
index f166472df6..0000000000
--- a/lib/hipe/TODO
+++ /dev/null
@@ -1,130 +0,0 @@
-Bugfix
-======
- P->current (Fix observable behaviour?)
- New calling convention for guard bifs (Recognize at load time).
- Long branches:
- timer:tc(hipe,c,[megaco_text_parser,[{timeout,infinity}]]).
- {4801210531,
- {error,[{problem,too_long_branch},{address,3381732},{length,-828622}]}}
-
-Performance
-===========
-
- Better handling of multimove in regalloc.
- Faster closure creation. (Can static fields be preallocated?)
- Expand pseudo-ops before scheduler (SPARC)
- Stack maps for SPARC + Make frames in Sparc not in RTL.
- Coalesce spill locations.
-
-Feature
-=======
-
- Stack traces from stack maps.
-
-Cleanup
-=======
-
- Speedup renaming and other bottlenecks in the compiler.
- Only calls with fail label should end basic blocks.
- Remove fail-entry-points from RTL (sparc/x86).
- Cleanup hipe_*_registers.erl and interface/rules with regalloc.
- HiPE in bootstrap.
- Cleanup and merge loaders. (Better handling of data.)
- Re-examine switching code.
-
-Extensions
-==========
-
- Design strategy for finding all processes holding a certain closure.
- Design strategy for native code unloading.
- mbufs: In guards -> throw away, in bifs -> trigger special GC. (fix for native.)
- Unified heap + process optimization (+ PE).
- Incremental GC.
-
-
-Old list compiled by Thomas Lindgren (needs cleaning up)
-========================================================
-
-<h1>Experimental implementations</h1>
-<h2>RTL</h2>
-<UL>
- <LI> Algebraiska förenklingar av uttryck (ex. reducera integer multiply,
- ta bort addition med 0, etc)
- <LI> Partial redundancy elimination
-</UL>
-
-<h1>Unimplemented optimizations</h1>
-
-<H2>Erlang/Core source-level-optimizations</H2>
-<UL>
- <LI> "Context compilation"
- <LI> CDR-kodning
- <LI> List reuse
- <LI> Compilation by transformation
-</UL>
-
-<H2>Icode-optimizations</H2>
-<UL>
- <LI> Convertion to loops from recursive programs
- <LI> Dominatorer
- (<a href="./thomasl/icode/dominators.erl">långsamma</a>, snabba)
-</UL>
-
-<H2>RTL-optimizations</H2>
-<UL>
- <LI> Common subexpression elimination
- <LI> Ta bort redundanta tester globalt (ex. upprepade typtester)
- <LI> Ordna om hopp (ex. byt ordning på nil/cons-tester)
- <LI> Goto eliminering (= expandera uncond. jumps m. känd måltavla)
- <LI> Save/restore-placering: dataflödesanalys, interaktion m. catch-frames
- <LI> Loop optimeringar
- <UL>
- <LI> Dominatorer (se dominatorer för icode)
- <LI> Unrolling
- <LI> Invariant expression removal
- </UL>
- <LI> Partial redundancy elimination by lazy code motion
- <LI> Partially dead code
-</UL>
-
-<H2>Sparc-optimizations</H2>
-<UL>
- <LI> Global register allocation
- <UL>
- <LI> <a href="./thomasl/regalloc/regalloc.erl">
- Pessimistisk färgning</a>
- <LI> Optimistisk färgning (kan slås på i samma fil som pessimistisk
- färgning ovan).
- <LI> Bättre beräkning av spillkostnader
- <LI> Renaming
- <LI> Callee-saves register
- <LI> Live-range splitting
- </UL>
- <LI> Instruktionsschedulering
- <UL>
- <LI> Branch delay slot scheduling
- <LI> Load delay slot scheduling
- <LI> Spekulativa loads med lduwa
- <LI> Kollapsa serier av tester med bpr
- <LI> Begränsad predicated execution med movcc
- </UL>
- <LI> Kodlayout: statiska förutsägelser om riktning av hopp,
- layout, sätta branch prediction bits i hopp, etc.
- <LI> Prefetching av kod med SparcV9:s bpn.
-</UL>
-
-<H2>Other optimizations</H2>
-
-Profile driven optimizations.
-<UL>
- <LI> Utplacering av räknare i CFG:er (per block, per båge)
- <LI> Statiska metoder att uppskatta exekveringstid (inom och mellan proc.)
- <LI> Feedback till program, annotering av CFG:er med profileringsinfo.
- <LI> Kodlayout med profileringsinfo.
- <LI> Skapa superblock
- <LI> Skapa hyperblock
- <LI> Plocka fram heta block, skapa en 'het' sub-CFG som hoppar
- till den kalla huvud-CFG:n vid behov.
- <LI> Optimering av het CFG, kodförflyttning från het till kall CFG.
- <LI> Spawn-time specialization
-</UL>
diff --git a/lib/hipe/amd64/Makefile b/lib/hipe/amd64/Makefile
deleted file mode 100644
index 1b6e4ea947..0000000000
--- a/lib/hipe/amd64/Makefile
+++ /dev/null
@@ -1,136 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-# Please keep this list sorted.
-MODULES=hipe_amd64_assemble \
- hipe_amd64_defuse \
- hipe_amd64_encode \
- hipe_amd64_frame \
- hipe_amd64_liveness \
- hipe_amd64_main \
- hipe_amd64_pp \
- hipe_amd64_ra \
- hipe_amd64_ra_finalise \
- hipe_amd64_ra_ls \
- hipe_amd64_ra_naive \
- hipe_amd64_ra_postconditions \
- hipe_amd64_ra_sse2_postconditions \
- hipe_amd64_registers \
- hipe_amd64_spill_restore \
- hipe_amd64_subst \
- hipe_amd64_x87 \
- hipe_amd64_sse2 \
- hipe_rtl_to_amd64
-
-ERL_FILES=$(MODULES:%=%.erl)
-TARGET_FILES=$(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -DHIPE_AMD64 -Werror +warn_export_vars
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-# Please keep this list sorted.
-$(EBIN)/hipe_amd64_assemble.beam: ../main/hipe.hrl ../rtl/hipe_literals.hrl ../x86/hipe_x86.hrl ../../kernel/src/hipe_ext_format.hrl ../misc/hipe_sdi.hrl ../x86/hipe_x86_assemble.erl
-$(EBIN)/hipe_amd64_defuse.beam: ../x86/hipe_x86.hrl ../x86/hipe_x86_defuse.erl
-$(EBIN)/hipe_amd64_frame.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl ../x86/hipe_x86_frame.erl ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_amd64_liveness.beam: ../flow/liveness.inc ../x86/hipe_x86_liveness.erl
-$(EBIN)/hipe_amd64_main.beam: ../main/hipe.hrl ../x86/hipe_x86_main.erl
-$(EBIN)/hipe_amd64_pp.beam: ../x86/hipe_x86.hrl ../x86/hipe_x86_pp.erl
-$(EBIN)/hipe_amd64_ra.beam: ../main/hipe.hrl ../x86/hipe_x86_ra.erl
-$(EBIN)/hipe_amd64_ra_dummy.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl
-$(EBIN)/hipe_amd64_ra_finalise.beam: ../x86/hipe_x86.hrl ../x86/hipe_x86_ra_finalise.erl
-$(EBIN)/hipe_amd64_ra_ls.beam: ../main/hipe.hrl ../x86/hipe_x86_ra_ls.erl
-$(EBIN)/hipe_amd64_ra_naive.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl ../x86/hipe_x86_ra_naive.erl
-$(EBIN)/hipe_amd64_ra_postconditions.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl ../x86/hipe_x86_ra_postconditions.erl
-$(EBIN)/hipe_amd64_ra_sse2_postconditions.beam: ../main/hipe.hrl
-$(EBIN)/hipe_amd64_registers.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_amd64_spill_restore.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl ../flow/cfg.hrl ../x86/hipe_x86_spill_restore.erl
-$(EBIN)/hipe_amd64_subst.beam: ../x86/hipe_x86_subst.erl
-$(EBIN)/hipe_amd64_x87.beam: ../x86/hipe_x86_x87.erl
-$(EBIN)/hipe_amd64_sse2.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl
-$(EBIN)/hipe_rtl_to_amd64.beam: ../x86/hipe_rtl_to_x86.erl ../rtl/hipe_rtl.hrl
-
-$(TARGET_FILES): ../x86/hipe_x86.hrl ../misc/hipe_consttab.hrl
diff --git a/lib/hipe/amd64/hipe_amd64_assemble.erl b/lib/hipe/amd64/hipe_amd64_assemble.erl
deleted file mode 100644
index 1379850515..0000000000
--- a/lib/hipe/amd64/hipe_amd64_assemble.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_assemble.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_defuse.erl b/lib/hipe/amd64/hipe_amd64_defuse.erl
deleted file mode 100644
index 9074c3e05e..0000000000
--- a/lib/hipe/amd64/hipe_amd64_defuse.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_defuse.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_encode.erl b/lib/hipe/amd64/hipe_amd64_encode.erl
deleted file mode 100644
index bda2824ffc..0000000000
--- a/lib/hipe/amd64/hipe_amd64_encode.erl
+++ /dev/null
@@ -1,1502 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Copyright (C) 2000-2004 Mikael Pettersson
-%%% Copyright (C) 2004 Daniel Luna
-%%%
-%%% This is the syntax of amd64 r/m operands:
-%%%
-%%% opnd ::= reg mod == 11
-%%% | MEM[ea] mod != 11
-%%%
-%%% ea ::= disp32(reg) mod == 10, r/m != ESP
-%%% | disp32 sib12 mod == 10, r/m == 100
-%%% | disp8(reg) mod == 01, r/m != ESP
-%%% | disp8 sib12 mod == 01, r/m == 100
-%%% | (reg) mod == 00, r/m != ESP and EBP
-%%% | sib0 mod == 00, r/m == 100
-%%% | disp32(%rip) mod == 00, r/m == 101
-%%%
-%%% // sib0: mod == 00
-%%% sib0 ::= disp32(,index,scale) base == EBP, index != ESP
-%%% | disp32 base == EBP, index == 100
-%%% | (base,index,scale) base != EBP, index != ESP
-%%% | (base) base != EBP, index == 100
-%%%
-%%% // sib12: mod == 01 or 10
-%%% sib12 ::= (base,index,scale) index != ESP
-%%% | (base) index == 100
-%%%
-%%% scale ::= 00 | 01 | 10 | 11 index << scale
-%%%
-%%% Notes:
-%%%
-%%% 1. ESP cannot be used as index register.
-%%% 2. Use of ESP as base register requires a SIB byte.
-%%% 3. disp(reg), when reg != ESP, can be represented without
-%%% [r/m == reg] or with [r/m == 100, base == reg] a SIB byte.
-%%% 4. disp32 can be represented without [mod == 00, r/m == 101]
-%%% or with [mod == 00, r/m == 100, base == 101, index == 100]
-%%% a SIB byte.
-%%% 5. AMD64 and x86 interpret mod==00b r/m==101b EAs differently:
-%%% on x86 the disp32 is an absolute address, but on AMD64 the
-%%% disp32 is relative to the %rip of the next instruction.
-
--module(hipe_amd64_encode).
-
--export([% condition codes
- cc/1,
- % 8-bit registers
- %% al/0, cl/0, dl/0, bl/0,
- % 32-bit registers
- %% eax/0, ecx/0, edx/0, ebx/0, esp/0, ebp/0, esi/0, edi/0,
- % operands
- sindex/2, sib/1, sib/2,
- ea_disp32_base/2, ea_disp32_sib/2,
- ea_disp8_base/2, ea_disp8_sib/2,
- ea_base/1,
- ea_disp32_sindex/1, %%ea_disp32_sindex/2,
- ea_sib/1, %ea_disp32_rip/1,
- rm_reg/1, rm_mem/1,
- % instructions
- insn_encode/3, insn_sizeof/2]).
-
-%%-define(DO_HIPE_AMD64_ENCODE_TEST,true).
--ifdef(DO_HIPE_AMD64_ENCODE_TEST).
--export([dotest/0, dotest/1]). % for testing, don't use
--endif.
-
--define(ASSERT(F,G), if G -> [] ; true -> exit({?MODULE,F}) end).
-%-define(ASSERT(F,G), []).
-
-%%% condition codes
-
--define(CC_O, 2#0000). % overflow
--define(CC_NO, 2#0001). % no overflow
--define(CC_B, 2#0010). % below, <u
--define(CC_AE, 2#0011). % above or equal, >=u
--define(CC_E, 2#0100). % equal
--define(CC_NE, 2#0101). % not equal
--define(CC_BE, 2#0110). % below or equal, <=u
--define(CC_A, 2#0111). % above, >u
--define(CC_S, 2#1000). % sign, +
--define(CC_NS, 2#1001). % not sign, -
--define(CC_PE, 2#1010). % parity even
--define(CC_PO, 2#1011). % parity odd
--define(CC_L, 2#1100). % less than, <s
--define(CC_GE, 2#1101). % greater or equal, >=s
--define(CC_LE, 2#1110). % less or equal, <=s
--define(CC_G, 2#1111). % greater than, >s
-
-cc(o) -> ?CC_O;
-cc(no) -> ?CC_NO;
-cc(b) -> ?CC_B;
-cc(ae) -> ?CC_AE;
-cc(e) -> ?CC_E;
-cc(ne) -> ?CC_NE;
-cc(be) -> ?CC_BE;
-cc(a) -> ?CC_A;
-cc(s) -> ?CC_S;
-cc(ns) -> ?CC_NS;
-cc(pe) -> ?CC_PE;
-cc(po) -> ?CC_PO;
-cc(l) -> ?CC_L;
-cc(ge) -> ?CC_GE;
-cc(le) -> ?CC_LE;
-cc(g) -> ?CC_G.
-
-%%% 8-bit registers
-
--define(AL, 2#000).
--define(CL, 2#001).
--define(DL, 2#010).
--define(BL, 2#011).
--define(SPL, 2#100).
--define(BPL, 2#101).
--define(SIL, 2#110).
--define(DIL, 2#111).
-
-%% al() -> ?AL.
-%% cl() -> ?CL.
-%% dl() -> ?DL.
-%% bl() -> ?BL.
-
-%%% 32-bit registers
-
--define(EAX, 2#000).
--define(ECX, 2#001).
--define(EDX, 2#010).
--define(EBX, 2#011).
--define(ESP, 2#100).
--define(EBP, 2#101).
--define(ESI, 2#110).
--define(EDI, 2#111).
-
-%% eax() -> ?EAX.
-%% ecx() -> ?ECX.
-%% edx() -> ?EDX.
-%% ebx() -> ?EBX.
-%% esp() -> ?ESP.
-%% ebp() -> ?EBP.
-%% esi() -> ?ESI.
-%% edi() -> ?EDI.
-
-%%% r/m operands
-
-sindex(Scale, Index) when is_integer(Scale), is_integer(Index) ->
- ?ASSERT(sindex, Scale >= 0),
- ?ASSERT(sindex, Scale =< 3),
- ?ASSERT(sindex, Index =/= ?ESP),
- {sindex, Scale, Index}.
-
--record(sib, {sindex_opt, base :: integer()}).
-sib(Base) when is_integer(Base) -> #sib{sindex_opt=none, base=Base}.
-sib(Base, Sindex) when is_integer(Base) -> #sib{sindex_opt=Sindex, base=Base}.
-
-ea_disp32_base(Disp32, Base) when is_integer(Base) ->
- ?ASSERT(ea_disp32_base, Base =/= ?ESP),
- {ea_disp32_base, Disp32, Base}.
-ea_disp32_sib(Disp32, SIB) -> {ea_disp32_sib, Disp32, SIB}.
-ea_disp8_base(Disp8, Base) when is_integer(Base) ->
- ?ASSERT(ea_disp8_base, Base =/= ?ESP),
- {ea_disp8_base, Disp8, Base}.
-ea_disp8_sib(Disp8, SIB) -> {ea_disp8_sib, Disp8, SIB}.
-ea_base(Base) when is_integer(Base) ->
- ?ASSERT(ea_base, Base =/= ?ESP),
- ?ASSERT(ea_base, Base =/= ?EBP),
- {ea_base, Base}.
-ea_disp32_sindex(Disp32) -> {ea_disp32_sindex, Disp32, none}.
-%% ea_disp32_sindex(Disp32, Sindex) -> {ea_disp32_sindex, Disp32, Sindex}.
-ea_sib(SIB) ->
- ?ASSERT(ea_sib, SIB#sib.base =/= ?EBP),
- {ea_sib, SIB}.
-%ea_disp32_rip(Disp32) -> {ea_disp32_rip, Disp32}.
-
-rm_reg(Reg) -> {rm_reg, Reg}.
-rm_mem(EA) -> {rm_mem, EA}.
-
-mk_modrm(Mod, RO, RM) ->
- {rex([{r,RO}, {b,RM}]),
- (Mod bsl 6) bor ((RO band 2#111) bsl 3) bor (RM band 2#111)}.
-
-mk_sib(Scale, Index, Base) ->
- {rex([{x,Index}, {b,Base}]),
- (Scale bsl 6) bor ((Index band 2#111) bsl 3) bor (Base band 2#111)}.
-
-rex(REXs) -> {rex, rex_(REXs)}.
-rex_([]) -> 0;
-rex_([{r8, Reg8}| Rest]) -> % 8 bit registers
- case Reg8 of
- {rm_mem, _} -> rex_(Rest);
- {rm_reg, R} -> rex_([{r8, R} | Rest]);
- 4 -> (1 bsl 8) bor rex_(Rest);
- 5 -> (1 bsl 8) bor rex_(Rest);
- 6 -> (1 bsl 8) bor rex_(Rest);
- 7 -> (1 bsl 8) bor rex_(Rest);
- X when is_integer(X) -> rex_(Rest)
- end;
-rex_([{w, REXW}| Rest]) -> % 64-bit mode
- (REXW bsl 3) bor rex_(Rest);
-rex_([{r, ModRM_regRegister}| Rest]) when is_integer(ModRM_regRegister) ->
- REXR = if (ModRM_regRegister > 7) -> 1;
- true -> 0
- end,
- (REXR bsl 2) bor rex_(Rest);
-rex_([{x, SIB_indexRegister}| Rest]) when is_integer(SIB_indexRegister) ->
- REXX = if (SIB_indexRegister > 7) -> 1;
- true -> 0
- end,
- (REXX bsl 1) bor rex_(Rest);
-rex_([{b, OtherRegister}| Rest]) when is_integer(OtherRegister) ->
- %% ModRM r/m, SIB base or opcode reg
- REXB = if (OtherRegister > 7) -> 1;
- true -> 0
- end,
- REXB bor rex_(Rest).
-
-le16(Word, Tail) ->
- [Word band 16#FF, (Word bsr 8) band 16#FF | Tail].
-
-le32(Word, Tail) when is_integer(Word) ->
- [Word band 16#FF, (Word bsr 8) band 16#FF,
- (Word bsr 16) band 16#FF, (Word bsr 24) band 16#FF | Tail];
-le32({Tag,Val}, Tail) -> % a relocatable datum
- [{le32,Tag,Val} | Tail].
-
-le64(Word, Tail) when is_integer(Word) ->
- [ Word band 16#FF, (Word bsr 8) band 16#FF,
- (Word bsr 16) band 16#FF, (Word bsr 24) band 16#FF,
- (Word bsr 32) band 16#FF, (Word bsr 40) band 16#FF,
- (Word bsr 48) band 16#FF, (Word bsr 56) band 16#FF | Tail];
-le64({Tag,Val}, Tail) ->
- [{le64,Tag,Val} | Tail].
-
-enc_sindex_opt({sindex,Scale,Index}) -> {Scale, Index};
-enc_sindex_opt(none) -> {2#00, 2#100}.
-
-enc_sib(#sib{sindex_opt=SindexOpt, base=Base}) ->
- {Scale, Index} = enc_sindex_opt(SindexOpt),
- mk_sib(Scale, Index, Base).
-
-enc_ea(EA, RO, Tail) ->
- case EA of
- {ea_disp32_base, Disp32, Base} ->
- [mk_modrm(2#10, RO, Base) | le32(Disp32, Tail)];
- {ea_disp32_sib, Disp32, SIB} ->
- [mk_modrm(2#10, RO, 2#100), enc_sib(SIB) | le32(Disp32, Tail)];
- {ea_disp8_base, Disp8, Base} ->
- [mk_modrm(2#01, RO, Base), Disp8 | Tail];
- {ea_disp8_sib, Disp8, SIB} ->
- [mk_modrm(2#01, RO, 2#100), enc_sib(SIB), Disp8 | Tail];
- {ea_base, Base} ->
- [mk_modrm(2#00, RO, Base) | Tail];
- {ea_disp32_sindex, Disp32, SindexOpt} ->
- {Scale, Index} = enc_sindex_opt(SindexOpt),
- SIB = mk_sib(Scale, Index, 2#101),
- MODRM = mk_modrm(2#00, RO, 2#100),
- [MODRM, SIB | le32(Disp32, Tail)];
- {ea_sib, SIB} ->
- [mk_modrm(2#00, RO, 2#100), enc_sib(SIB) | Tail];
- {ea_disp32_rip, Disp32} ->
- [mk_modrm(2#00, RO, 2#101) | le32(Disp32, Tail)]
- end.
-
-encode_rm(RM, RO, Tail) ->
- case RM of
- {rm_reg, Reg} -> [mk_modrm(2#11, RO, Reg) | Tail];
- {rm_mem, EA} -> enc_ea(EA, RO, Tail)
- end.
-
-%% sizeof_ea(EA) ->
-%% case element(1, EA) of
-%% ea_disp32_base -> 5;
-%% ea_disp32_sib -> 6;
-%% ea_disp8_base -> 2;
-%% ea_disp8_sib -> 3;
-%% ea_base -> 1;
-%% ea_disp32_sindex -> 6;
-%% ea_sib -> 2;
-%% ea_disp32_rip -> 5
-%% end.
-
-%% sizeof_rm(RM) ->
-%% case RM of
-%% {rm_reg, _} -> 1;
-%% {rm_mem, EA} -> sizeof_ea(EA)
-%% end.
-
-%%% x87 stack postitions
-
--define(ST0, 2#000).
--define(ST1, 2#001).
--define(ST2, 2#010).
--define(ST3, 2#011).
--define(ST4, 2#100).
--define(ST5, 2#101).
--define(ST6, 2#110).
--define(ST7, 2#111).
-
-st(0) -> ?ST0;
-st(1) -> ?ST1;
-st(2) -> ?ST2;
-st(3) -> ?ST3;
-st(4) -> ?ST4;
-st(5) -> ?ST5;
-st(6) -> ?ST6;
-st(7) -> ?ST7.
-
-
-%%% Instructions
-%%%
-%%% Insn ::= {Op,Opnds}
-%%% Opnds ::= {Opnd1,...,Opndn} (n >= 0)
-%%% Opnd ::= eax | ax | al | 1 | cl
-%%% | {imm32,Imm32} | {imm16,Imm16} | {imm8,Imm8}
-%%% | {rm32,RM32} | {rm16,RM16} | {rm8,RM8}
-%%% | {rel32,Rel32} | {rel8,Rel8}
-%%% | {moffs32,Moffs32} | {moffs16,Moffs16} | {moffs8,Moffs8}
-%%% | {cc,CC}
-%%% | {reg32,Reg32} | {reg16,Reg16} | {reg8,Reg8}
-%%% | {ea,EA}
-
--define(PFX_OPND_16BITS, 16#66).
-
-arith_binop_encode(SubOpcode, Opnds) ->
- %% add, or, adc, sbb, and, sub, xor, cmp
- case Opnds of
- {eax, {imm32,Imm32}} ->
- [16#05 bor (SubOpcode bsl 3) | le32(Imm32, [])];
- {{rm32,RM32}, {imm32,Imm32}} ->
- [16#81 | encode_rm(RM32, SubOpcode, le32(Imm32, []))];
- {{rm32,RM32}, {imm8,Imm8}} ->
- [16#83 | encode_rm(RM32, SubOpcode, [Imm8])];
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#01 bor (SubOpcode bsl 3) | encode_rm(RM32, Reg32, [])];
- {{reg32,Reg32}, {rm32,RM32}} ->
- [16#03 bor (SubOpcode bsl 3) | encode_rm(RM32, Reg32, [])];
- %% Below starts amd64 stuff with rex prefix
- {rax, {imm32,Imm32}} ->
- [rex([{w,1}]), 16#05 bor (SubOpcode bsl 3) | le32(Imm32, [])];
- {{rm64,RM64}, {imm32,Imm32}} ->
- [rex([{w,1}]), 16#81
- | encode_rm(RM64, SubOpcode, le32(Imm32, []))];
- {{rm64,RM64}, {imm8,Imm8}} ->
- [rex([{w,1}]), 16#83 | encode_rm(RM64, SubOpcode, [Imm8])];
- {{rm64,RM64}, {reg64,Reg64}} ->
- [rex([{w,1}]), 16#01 bor (SubOpcode bsl 3)
- | encode_rm(RM64, Reg64, [])];
- {{reg64,Reg64}, {rm64,RM64}} ->
- [rex([{w,1}]), 16#03 bor (SubOpcode bsl 3)
- | encode_rm(RM64, Reg64, [])]
- end.
-
-sse2_arith_binop_encode(Prefix, Opcode, {{xmm, XMM64}, {rm64fp, RM64}}) ->
- %% addpd, cmpsd, divsd, maxsd, minsd, mulsd, sqrtsd, subsd
- [Prefix, 16#0F, Opcode | encode_rm(RM64, XMM64, [])].
-
-sse2_cvtsi2sd_encode({{xmm,XMM64}, {rm64,RM64}}) ->
- [rex([{w, 1}]), 16#F2, 16#0F, 16#2A | encode_rm(RM64, XMM64, [])].
-
-sse2_mov_encode(Opnds) ->
- case Opnds of
- {{xmm, XMM64}, {rm64fp, RM64}} -> % movsd
- [16#F2, 16#0F, 16#10 | encode_rm(RM64, XMM64, [])];
- {{rm64fp, RM64}, {xmm, XMM64}} -> % movsd
- [16#F2, 16#0F, 16#11 | encode_rm(RM64, XMM64, [])]
-% {{xmm, XMM64}, {rm64, RM64}} -> % cvtsi2sd
-% [rex([{w, 1}]), 16#F2, 16#0F, 16#2A | encode_rm(RM64, XMM64, [])]
- end.
-
-%% arith_binop_sizeof(Opnds) ->
-%% %% add, or, adc, sbb, and, sub, xor, cmp
-%% case Opnds of
-%% {eax, {imm32,_}} ->
-%% 1 + 4;
-%% {{rm32,RM32}, {imm32,_}} ->
-%% 1 + sizeof_rm(RM32) + 4;
-%% {{rm32,RM32}, {imm8,_}} ->
-%% 1 + sizeof_rm(RM32) + 1;
-%% {{rm32,RM32}, {reg32,_}} ->
-%% 1 + sizeof_rm(RM32);
-%% {{reg32,_}, {rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32)
-%% end.
-
-bs_op_encode(Opcode, {{reg32,Reg32}, {rm32,RM32}}) -> % bsf, bsr
- [16#0F, Opcode | encode_rm(RM32, Reg32, [])].
-
-%% bs_op_sizeof({{reg32,_}, {rm32,RM32}}) -> % bsf, bsr
-%% 2 + sizeof_rm(RM32).
-
-bswap_encode(Opnds) ->
- case Opnds of
- {{reg32,Reg32}} ->
- [rex([{b, Reg32}]), 16#0F, 16#C8 bor (Reg32 band 2#111)];
- {{reg64,Reg64}} ->
- [rex([{w, 1}, {b, Reg64}]), 16#0F, 16#C8 bor (Reg64 band 2#111)]
- end.
-
-%% bswap_sizeof({{reg32,_}}) ->
-%% 2.
-
-bt_op_encode(SubOpcode, Opnds) -> % bt, btc, btr, bts
- case Opnds of
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#0F, 16#A3 bor (SubOpcode bsl 3) | encode_rm(RM32, Reg32, [])];
- {{rm32,RM32}, {imm8,Imm8}} ->
- [16#0F, 16#BA | encode_rm(RM32, SubOpcode, [Imm8])]
- end.
-
-%% bt_op_sizeof(Opnds) -> % bt, btc, btr, bts
-%% case Opnds of
-%% {{rm32,RM32}, {reg32,_}} ->
-%% 2 + sizeof_rm(RM32);
-%% {{rm32,RM32}, {imm8,_}} ->
-%% 2 + sizeof_rm(RM32) + 1
-%% end.
-
-call_encode(Opnds) ->
- case Opnds of
- {{rel32,Rel32}} ->
- [16#E8 | le32(Rel32, [])];
-%%% {{rm32,RM32}} ->
-%%% [16#FF | encode_rm(RM32, 2#010, [])];
- {{rm64,RM64}} -> % Defaults to 64 bits on amd64
- [16#FF | encode_rm(RM64, 2#010, [])]
- end.
-
-%% call_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rel32,_}} ->
-%% 1 + 4;
-%% {{rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32)
-%% end.
-
-cbw_encode({}) ->
- [?PFX_OPND_16BITS, 16#98].
-
-cbw_sizeof({}) ->
- 2.
-
-nullary_op_encode(Opcode, {}) ->
- %% cdq, clc, cld, cmc, cwde, into, leave, nop, prefix_fs, stc, std
- [Opcode].
-
-nullary_op_sizeof({}) ->
- %% cdq, clc, cld, cmc, cwde, into, leave, nop, prefix_fs, stc, std
- 1.
-
-cmovcc_encode({{cc,CC}, {reg32,Reg32}, {rm32,RM32}}) ->
- [16#0F, 16#40 bor CC | encode_rm(RM32, Reg32, [])].
-
-%% cmovcc_sizeof({{cc,_}, {reg32,_}, {rm32,RM32}}) ->
-%% 2 + sizeof_rm(RM32).
-
-incdec_encode(SubOpcode, Opnds) -> % SubOpcode is either 0 or 1
- case Opnds of
- {{rm32,RM32}} ->
- [16#FF | encode_rm(RM32, SubOpcode, [])];
- {{rm64,RM64}} ->
- [rex([{w, 1}]), 16#FF | encode_rm(RM64, SubOpcode, [])]
- end.
-
-%% incdec_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32);
-%% {{reg32,_}} ->
-%% 1
-%% end.
-
-arith_unop_encode(Opcode, Opnds) -> % div, idiv, mul, neg, not
- case Opnds of
- {{rm32,RM32}} ->
- [16#F7 | encode_rm(RM32, Opcode, [])];
- {{rm64,RM64}} ->
- [rex([{w,1}]), 16#F7 | encode_rm(RM64, Opcode, [])]
- end.
-
-%% arith_unop_sizeof({{rm32,RM32}}) -> % div, idiv, mul, neg, not
-%% 1 + sizeof_rm(RM32).
-
-enter_encode({{imm16,Imm16}, {imm8,Imm8}}) ->
- [16#C8 | le16(Imm16, [Imm8])].
-
-enter_sizeof({{imm16,_}, {imm8,_}}) ->
- 1 + 2 + 1.
-
-imul_encode(Opnds) ->
- case Opnds of
- {{rm32,RM32}} -> % <edx,eax> *= rm32
- [16#F7 | encode_rm(RM32, 2#101, [])];
- {{rm64,RM64}} ->
- [rex([{w,1}]), 16#F7 | encode_rm(RM64, 2#101, [])];
- {{reg32,Reg32}, {rm32,RM32}} -> % reg *= rm32
- [16#0F, 16#AF | encode_rm(RM32, Reg32, [])];
- {{reg64,Reg64}, {rm64,RM64}} ->
- [rex([{w,1}]), 16#0F, 16#AF | encode_rm(RM64, Reg64, [])];
- {{reg32,Reg32}, {rm32,RM32}, {imm8,Imm8}} -> % reg := rm32 * sext(imm8)
- [16#6B | encode_rm(RM32, Reg32, [Imm8])];
- {{reg64,Reg64}, {rm64,RM64}, {imm8,Imm8}} ->
- [rex([{w,1}]), 16#6B | encode_rm(RM64, Reg64, [Imm8])];
- {{reg32,Reg32}, {rm32,RM32}, {imm32,Imm32}} -> % reg := rm32 * imm32
- [16#69 | encode_rm(RM32, Reg32, le32(Imm32, []))];
- {{reg64,Reg64}, {rm64,RM64}, {imm32,Imm32}} ->
- [rex([{w,1}]), 16#69 | encode_rm(RM64, Reg64, le32(Imm32, []))]
- end.
-
-%% imul_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32);
-%% {{reg32,_}, {rm32,RM32}} ->
-%% 2 + sizeof_rm(RM32);
-%% {{reg32,_}, {rm32,RM32}, {imm8,_}} ->
-%% 1 + sizeof_rm(RM32) + 1;
-%% {{reg32,_}, {rm32,RM32}, {imm32,_}} ->
-%% 1 + sizeof_rm(RM32) + 4
-%% end.
-
-jcc_encode(Opnds) ->
- case Opnds of
- {{cc,CC}, {rel8,Rel8}} ->
- [16#70 bor CC, Rel8];
- {{cc,CC}, {rel32,Rel32}} ->
- [16#0F, 16#80 bor CC | le32(Rel32, [])]
- end.
-
-jcc_sizeof(Opnds) ->
- case Opnds of
- {{cc,_}, {rel8,_}} ->
- 2;
- {{cc,_}, {rel32,_}} ->
- 2 + 4
- end.
-
-jmp8_op_encode(Opcode, {{rel8,Rel8}}) -> % jecxz, loop, loope, loopne
- [Opcode, Rel8].
-
-jmp8_op_sizeof({{rel8,_}}) -> % jecxz, loop, loope, loopne
- 2.
-
-jmp_encode(Opnds) ->
- case Opnds of
- {{rel8,Rel8}} ->
- [16#EB, Rel8];
- {{rel32,Rel32}} ->
- [16#E9 | le32(Rel32, [])];
-%%% {{rm32,RM32}} ->
-%%% [16#FF | encode_rm(RM32, 2#100, [])]
- {{rm64,RM64}} ->
- [16#FF | encode_rm(RM64, 2#100, [])]
- end.
-
-%% jmp_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rel8,_}} ->
-%% 2;
-%% {{rel32,_}} ->
-%% 1 + 4;
-%% {{rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32)
-%% end.
-
-lea_encode({{reg32,Reg32}, {ea,EA}}) ->
- [16#8D | enc_ea(EA, Reg32, [])];
-lea_encode({{reg64,Reg64}, {ea,EA}}) ->
- [rex([{w, 1}]), 16#8D | enc_ea(EA, Reg64, [])].
-
-%% lea_sizeof({{reg32,_}, {ea,EA}}) ->
-%% 1 + sizeof_ea(EA).
-
-mov_encode(Opnds) ->
- case Opnds of
- {{rm8,RM8}, {reg8,Reg8}} ->
- [rex([{r8, RM8}, {r8, Reg8}]), 16#88 | encode_rm(RM8, Reg8, [])];
- {{rm16,RM16}, {reg16,Reg16}} ->
- [?PFX_OPND_16BITS, 16#89 | encode_rm(RM16, Reg16, [])];
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#89 | encode_rm(RM32, Reg32, [])];
- {{rm64,RM64}, {reg64,Reg64}} ->
- [rex([{w, 1}]), 16#89 | encode_rm(RM64, Reg64, [])];
- {{reg8,Reg8}, {rm8,RM8}} ->
- [rex([{r8, RM8}, {r8, Reg8}]), 16#8A |
- encode_rm(RM8, Reg8, [])];
- {{reg16,Reg16}, {rm16,RM16}} ->
- [?PFX_OPND_16BITS, 16#8B | encode_rm(RM16, Reg16, [])];
- {{reg32,Reg32}, {rm32,RM32}} ->
- [16#8B | encode_rm(RM32, Reg32, [])];
- {{reg64,Reg64}, {rm64,RM64}} ->
- [rex([{w, 1}]), 16#8B | encode_rm(RM64, Reg64, [])];
- {al, {moffs8,Moffs8}} ->
- [16#A0 | le32(Moffs8, [])];
- {ax, {moffs16,Moffs16}} ->
- [?PFX_OPND_16BITS, 16#A1 | le32(Moffs16, [])];
- {eax, {moffs32,Moffs32}} ->
- [16#A1 | le32(Moffs32, [])];
- {rax, {moffs32,Moffs32}} ->
- [rex([{w, 1}]), 16#A1 | le32(Moffs32, [])];
- {{moffs8,Moffs8}, al} ->
- [16#A2 | le32(Moffs8, [])];
- {{moffs16,Moffs16}, ax} ->
- [?PFX_OPND_16BITS, 16#A3 | le32(Moffs16, [])];
- {{moffs32,Moffs32}, eax} ->
- [16#A3 | le32(Moffs32, [])];
- {{moffs32,Moffs32}, rax} ->
- [rex([{w, 1}]), 16#A3 | le32(Moffs32, [])];
- {{reg8,Reg8}, {imm8,Imm8}} ->
- [rex([{b, Reg8}, {r8, Reg8}]), 16#B0 bor (Reg8 band 2#111), Imm8];
- {{reg16,Reg16}, {imm16,Imm16}} ->
- [?PFX_OPND_16BITS, rex([{b, Reg16}]), 16#B8 bor (Reg16 band 2#111)
- | le16(Imm16, [])];
- {{reg32,Reg32}, {imm32,Imm32}} ->
- [rex([{b, Reg32}]), 16#B8 bor (Reg32 band 2#111)
- | le32(Imm32, [])];
- {{reg64,Reg64}, {imm64,Imm64}} ->
- [rex([{w, 1}, {b, Reg64}]), 16#B8 bor (Reg64 band 2#111)
- | le64(Imm64, [])];
- {{rm8,RM8}, {imm8,Imm8}} ->
- [rex([{r8, RM8}]), 16#C6 | encode_rm(RM8, 2#000, [Imm8])];
- {{rm16,RM16}, {imm16,Imm16}} ->
- [?PFX_OPND_16BITS, 16#C7 |
- encode_rm(RM16, 2#000, le16(Imm16, []))];
- {{rm32,RM32}, {imm32,Imm32}} ->
- [16#C7 | encode_rm(RM32, 2#000, le32(Imm32, []))];
- {{rm64,RM64}, {imm32,Imm32}} ->
- [rex([{w, 1}]), 16#C7 | encode_rm(RM64, 2#000, le32(Imm32, []))]
- end.
-
-%% mov_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm8,RM8}, {reg8,_}} ->
-%% 1 + sizeof_rm(RM8);
-%% {{rm16,RM16}, {reg16,_}} ->
-%% 2 + sizeof_rm(RM16);
-%% {{rm32,RM32}, {reg32,_}} ->
-%% 1 + sizeof_rm(RM32);
-%% {{reg8,_}, {rm8,RM8}} ->
-%% 1 + sizeof_rm(RM8);
-%% {{reg16,_}, {rm16,RM16}} ->
-%% 2 + sizeof_rm(RM16);
-%% {{reg32,_}, {rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32);
-%% {al, {moffs8,_}} ->
-%% 1 + 4;
-%% {ax, {moffs16,_}} ->
-%% 2 + 4;
-%% {eax, {moffs32,_}} ->
-%% 1 + 4;
-%% {{moffs8,_}, al} ->
-%% 1 + 4;
-%% {{moffs16,_}, ax} ->
-%% 2 + 4;
-%% {{moffs32,_}, eax} ->
-%% 1 + 4;
-%% {{reg8,_}, {imm8,_}} ->
-%% 2;
-%% {{reg16,_}, {imm16,_}} ->
-%% 2 + 2;
-%% {{reg32,_}, {imm32,_}} ->
-%% 1 + 4;
-%% {{rm8,RM8}, {imm8,_}} ->
-%% 1 + sizeof_rm(RM8) + 1;
-%% {{rm16,RM16}, {imm16,_}} ->
-%% 2 + sizeof_rm(RM16) + 2;
-%% {{rm32,RM32}, {imm32,_}} ->
-%% 1 + sizeof_rm(RM32) + 4
-%% end.
-
-movx_op_encode(Opcode, Opnds) -> % movsx, movzx
- case Opnds of
- {{reg16,Reg16}, {rm8,RM8}} ->
- [?PFX_OPND_16BITS, rex([{r8, RM8}]), 16#0F, Opcode |
- encode_rm(RM8, Reg16, [])];
- {{reg32,Reg32}, {rm8,RM8}} ->
- [rex([{r8, RM8}]), 16#0F, Opcode | encode_rm(RM8, Reg32, [])];
- {{reg32,Reg32}, {rm16,RM16}} ->
- [16#0F, Opcode bor 1 | encode_rm(RM16, Reg32, [])];
- {{reg64,Reg64}, {rm8,RM8}} ->
- [rex([{w,1}]), 16#0F, Opcode | encode_rm(RM8, Reg64, [])];
- {{reg64,Reg64}, {rm16,RM16}} ->
- [rex([{w,1}]), 16#0F, Opcode bor 1 | encode_rm(RM16, Reg64, [])];
- {{reg64,Reg64}, {rm32,RM32}} ->
- %% This is magic... /Luna
- [rex([{w,(1 band (Opcode bsr 3))}]), 16#63 |
- encode_rm(RM32, Reg64, [])]
- end.
-
-%% movx_op_sizeof(Opnds) ->
-%% case Opnds of
-%% {{reg16,_}, {rm8,RM8}} ->
-%% 3 + sizeof_rm(RM8);
-%% {{reg32,_}, {rm8,RM8}} ->
-%% 1 + 2 + sizeof_rm(RM8);
-%% {{reg32,_}, {rm16,RM16}} ->
-%% 1 + 2 + sizeof_rm(RM16)
-%% end.
-
-pop_encode(Opnds) ->
- case Opnds of
- {{rm64,RM64}} ->
- [16#8F | encode_rm(RM64, 2#000, [])];
- {{reg64,Reg64}} ->
- [rex([{b,Reg64}]),16#58 bor (Reg64 band 2#111)]
- end.
-
-%% pop_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32);
-%% {{reg32,_}} ->
-%% 1
-%% end.
-
-push_encode(Opnds) ->
- case Opnds of
-%%% {{rm32,RM32}} ->
-%%% [16#FF | encode_rm(RM32, 2#110, [])];
- {{rm64,RM64}} ->
- [16#FF | encode_rm(RM64, 2#110, [])];
-%%% {{reg32,Reg32}} ->
-%%% [rex([{b, 1}]), 16#50 bor (Reg32 band 2#111)];
- {{reg64,Reg64}} ->
- [rex([{b, Reg64}]), 16#50 bor (Reg64 band 2#111)];
- {{imm8,Imm8}} -> % sign-extended
- [16#6A, Imm8];
- {{imm32,Imm32}} -> % Sign extended to 64 bits
- [16#68 | le32(Imm32, [])]
- end.
-
-%% push_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm32,RM32}} ->
-%% 1 + sizeof_rm(RM32);
-%% {{reg32,_}} ->
-%% 1;
-%% {{imm8,_}} ->
-%% 2;
-%% {{imm32,_}} ->
-%% 1 + 4
-%% end.
-
-shift_op_encode(SubOpcode, Opnds) -> % rol, ror, rcl, rcr, shl, shr, sar
- case Opnds of
- {{rm32,RM32}, 1} ->
- [16#D1 | encode_rm(RM32, SubOpcode, [])];
- {{rm32,RM32}, cl} ->
- [16#D3 | encode_rm(RM32, SubOpcode, [])];
- {{rm32,RM32}, {imm8,Imm8}} ->
- [16#C1 | encode_rm(RM32, SubOpcode, [Imm8])];
- {{rm64,RM64}, 1} ->
- [rex([{w,1}]), 16#D1 | encode_rm(RM64, SubOpcode, [])];
- {{rm64,RM64}, cl} ->
- [rex([{w,1}]), 16#D3 | encode_rm(RM64, SubOpcode, [])];
- {{rm64,RM64}, {imm8,Imm8}} ->
- [rex([{w,1}]), 16#C1 | encode_rm(RM64, SubOpcode, [Imm8])]
- end.
-
-%% shift_op_sizeof(Opnds) -> % rcl, rcr, rol, ror, sar, shl, shr
-%% case Opnds of
-%% {{rm32,RM32}, 1} ->
-%% 1 + sizeof_rm(RM32);
-%% {{rm32,RM32}, cl} ->
-%% 1 + sizeof_rm(RM32);
-%% {{rm32,RM32}, {imm8,_Imm8}} ->
-%% 1 + sizeof_rm(RM32) + 1
-%% end.
-
-ret_encode(Opnds) ->
- case Opnds of
- {} ->
- [16#C3];
- {{imm16,Imm16}} ->
- [16#C2 | le16(Imm16, [])]
- end.
-
-ret_sizeof(Opnds) ->
- case Opnds of
- {} ->
- 1;
- {{imm16,_}} ->
- 1 + 2
- end.
-
-setcc_encode({{cc,CC}, {rm8,RM8}}) ->
- [rex([{r8, RM8}]), 16#0F, 16#90 bor CC | encode_rm(RM8, 2#000, [])].
-
-%% setcc_sizeof({{cc,_}, {rm8,RM8}}) ->
-%% 2 + sizeof_rm(RM8).
-
-shd_op_encode(Opcode, Opnds) ->
- case Opnds of
- {{rm32,RM32}, {reg32,Reg32}, {imm8,Imm8}} ->
- [16#0F, Opcode | encode_rm(RM32, Reg32, [Imm8])];
- {{rm32,RM32}, {reg32,Reg32}, cl} ->
- [16#0F, Opcode bor 1 | encode_rm(RM32, Reg32, [])]
- end.
-
-%% shd_op_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm32,RM32}, {reg32,_}, {imm8,_}} ->
-%% 2 + sizeof_rm(RM32) + 1;
-%% {{rm32,RM32}, {reg32,_}, cl} ->
-%% 2 + sizeof_rm(RM32)
-%% end.
-
-test_encode(Opnds) ->
- case Opnds of
- {al, {imm8,Imm8}} ->
- [16#A8, Imm8];
- {ax, {imm16,Imm16}} ->
- [?PFX_OPND_16BITS, 16#A9 | le16(Imm16, [])];
- {eax, {imm32,Imm32}} ->
- [16#A9 | le32(Imm32, [])];
- {rax, {imm32,Imm32}} ->
- [rex([{w,1}]), 16#A9 | le32(Imm32, [])];
- {{rm8,RM8}, {imm8,Imm8}} ->
- [rex([{r8,RM8}]), 16#F6 | encode_rm(RM8, 2#000, [Imm8])];
- {{rm16,RM16}, {imm16,Imm16}} ->
- [?PFX_OPND_16BITS, 16#F7 | encode_rm(RM16, 2#000, le16(Imm16, []))];
- {{rm32,RM32}, {imm32,Imm32}} ->
- [16#F7 | encode_rm(RM32, 2#000, le32(Imm32, []))];
- {{rm64,RM64}, {imm32,Imm32}} ->
- [rex([{w,1}]), 16#F7 | encode_rm(RM64, 2#000, le32(Imm32, []))];
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#85 | encode_rm(RM32, Reg32, [])];
- {{rm64,RM64}, {reg64,Reg64}} ->
- [rex([{w,1}]), 16#85 | encode_rm(RM64, Reg64, [])]
- end.
-
-%% test_sizeof(Opnds) ->
-%% case Opnds of
-%% {eax, {imm32,_}} ->
-%% 1 + 4;
-%% {{rm32,RM32}, {imm32,_}} ->
-%% 1 + sizeof_rm(RM32) + 4;
-%% {{rm32,RM32}, {reg32,_}} ->
-%% 1 + sizeof_rm(RM32)
-%% end.
-
-fild_encode(Opnds) ->
- %% The operand cannot be a register!
- {{rm64, RM64}} = Opnds,
- [16#DB | encode_rm(RM64, 2#000, [])].
-
-%% fild_sizeof(Opnds) ->
-%% {{rm32, RM32}} = Opnds,
-%% 1 + sizeof_rm(RM32).
-
-fld_encode(Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DD | encode_rm(RM64fp, 2#000, [])];
- {{fpst, St}} ->
- [16#D9, 16#C0 bor st(St)]
- end.
-
-%% fld_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm64fp, RM64fp}} ->
-%% 1 + sizeof_rm(RM64fp);
-%% {{fpst, _}} ->
-%% 2
-%% end.
-
-x87_comm_arith_encode(OpCode, Opnds) ->
- %% fadd, fmul
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DC | encode_rm(RM64fp, OpCode, [])];
- {{fpst,0}, {fpst,St}} ->
- [16#D8, (16#C0 bor (OpCode bsl 3)) bor st(St)];
- {{fpst,St}, {fpst,0}} ->
- [16#DC, (16#C0 bor (OpCode bsl 3)) bor st(St)]
- end.
-
-x87_comm_arith_pop_encode(OpCode, Opnds) ->
- %% faddp, fmulp
- case Opnds of
- [] ->
- [16#DE, 16#C0 bor (OpCode bsl 3) bor st(1)];
- {{fpst,St},{fpst,0}} ->
- [16#DE, 16#C0 bor (OpCode bsl 3) bor st(St)]
- end.
-
-x87_arith_encode(OpCode, Opnds) ->
- %% fdiv, fsub
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DC | encode_rm(RM64fp, OpCode, [])];
- {{fpst,0}, {fpst,St}} ->
- OpCode0 = OpCode band 2#110,
- [16#D8, 16#C0 bor (OpCode0 bsl 3) bor st(St)];
- {{fpst,St}, {fpst,0}} ->
- OpCode0 = OpCode bor 1,
- [16#DC, 16#C0 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-x87_arith_pop_encode(OpCode, Opnds) ->
- %% fdivp, fsubp
- OpCode0 = OpCode bor 1,
- case Opnds of
- [] ->
- [16#DE, 16#C8 bor (OpCode0 bsl 3) bor st(1)];
- {{fpst,St}, {fpst,0}} ->
- [16#DE, 16#C8 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-x87_arith_rev_encode(OpCode, Opnds) ->
- %% fdivr, fsubr
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DC | encode_rm(RM64fp, OpCode, [])];
- {{fpst,0}, {fpst,St}} ->
- OpCode0 = OpCode bor 1,
- [16#D8, 16#C0 bor (OpCode0 bsl 3) bor st(St)];
- {{fpst,St}, {fpst,0}} ->
- OpCode0 = OpCode band 2#110,
- [16#DC, 16#C0 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-x87_arith_rev_pop_encode(OpCode, Opnds) ->
- %% fdivrp, fsubrp
- OpCode0 = OpCode band 2#110,
- case Opnds of
- [] ->
- [16#DE, 16#C0 bor (OpCode0 bsl 3) bor st(1)];
- {{fpst,St}, {fpst, 0}} ->
- [16#DE, 16#C0 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-%% x87_arith_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm64fp, RM64fp}} ->
-%% 1 + sizeof_rm(RM64fp);
-%% {{fpst,0}, {fpst,_}} ->
-%% 2;
-%% {{fpst,_}, {fpst,0}} ->
-%% 2
-%% end.
-
-fst_encode(OpCode, Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DD | encode_rm(RM64fp, OpCode, [])];
- {{fpst, St}} ->
- [16#DD, 16#C0 bor (OpCode bsl 3) bor st(St)]
- end.
-
-%% fst_sizeof(Opnds) ->
-%% case Opnds of
-%% {{rm64fp, RM64fp}} ->
-%% 1 + sizeof_rm(RM64fp);
-%% {{fpst, _}} ->
-%% 2
-%% end.
-
-fchs_encode() ->
- [16#D9, 16#E0].
-
-fchs_sizeof() ->
- 2.
-
-ffree_encode({{fpst, St}})->
- [16#DD, 16#C0 bor st(St)].
-
-ffree_sizeof() ->
- 2.
-
-fwait_encode() ->
- [16#9B].
-
-fwait_sizeof() ->
- 1.
-
-fxch_encode(Opnds) ->
- case Opnds of
- [] ->
- [16#D9, 16#C8 bor st(1)];
- {{fpst, St}} ->
- [16#D9, 16#C8 bor st(St)]
- end.
-
-fxch_sizeof() ->
- 2.
-
-insn_encode(Op, Opnds, Offset) ->
- Bytes_and_REX = insn_encode_internal(Op, Opnds),
- Bytes = fix_rex(Bytes_and_REX),
- case has_relocs(Bytes) of
- false -> % the common case
- {Bytes, []};
- _ ->
- fix_relocs(Bytes, Offset, [], [])
- end.
-
-fix_rex(Bytes) ->
- fix_rex(Bytes, 2#0100 bsl 4, []).
-
-fix_rex([{rex, REX} | Rest], REXAcc, Bytes) ->
- fix_rex(Rest, REXAcc bor REX, Bytes);
-fix_rex([{{rex, REX}, Byte} | Rest], REXAcc, Bytes) ->
- fix_rex(Rest, REXAcc bor REX, [Byte | Bytes]);
-fix_rex([Byte | Rest], REXAcc, Bytes) ->
- fix_rex(Rest, REXAcc, [Byte | Bytes]);
-fix_rex([], 2#01000000, Bytes) -> % no rex prefix
- lists:reverse(Bytes);
-fix_rex([], REX0, Bytes) -> % rex prefix...
- REX = REX0 band 16#FF, % for 8 bit registers
- [Head|Tail] = lists:reverse(Bytes),
- case Head of
- 16#66 -> % ...and 16 bit/sse2 prefix
- [16#66, REX | Tail];
- 16#F2 -> % ...and sse2 prefix
- [16#F2, REX | Tail];
- _ -> % ...only
- [REX, Head | Tail]
- end.
-
-has_relocs([{le32,_,_}|_]) -> true;
-has_relocs([{le64,_,_}|_]) -> true;
-has_relocs([_|Bytes]) -> has_relocs(Bytes);
-has_relocs([]) -> false.
-
-fix_relocs([{le32,Tag,Val}|Bytes], Offset, Code, Relocs) ->
- fix_relocs(Bytes, Offset+4,
- [16#00, 16#00, 16#00, 16#00 | Code],
- [{Tag,Offset,Val}|Relocs]);
-fix_relocs([{le64,Tag,Val}|Bytes], Offset, Code, Relocs) ->
- fix_relocs(Bytes, Offset+8,
- [16#00, 16#00, 16#00, 16#00,
- 16#00, 16#00, 16#00, 16#00 | Code],
- [{Tag,Offset,Val}|Relocs]);
-fix_relocs([Byte|Bytes], Offset, Code, Relocs) ->
- fix_relocs(Bytes, Offset+1, [Byte|Code], Relocs);
-fix_relocs([], _Offset, Code, Relocs) ->
- {lists:reverse(Code), lists:reverse(Relocs)}.
-
-insn_encode_internal(Op, Opnds) ->
- case Op of
- 'adc' -> arith_binop_encode(2#010, Opnds);
- 'add' -> arith_binop_encode(2#000, Opnds);
- 'and' -> arith_binop_encode(2#100, Opnds);
- 'bsf' -> bs_op_encode(16#BC, Opnds);
- 'bsr' -> bs_op_encode(16#BD, Opnds);
- 'bswap' -> bswap_encode(Opnds);
- 'bt' -> bt_op_encode(2#100, Opnds);
- 'btc' -> bt_op_encode(2#111, Opnds);
- 'btr' -> bt_op_encode(2#110, Opnds);
- 'bts' -> bt_op_encode(2#101, Opnds);
- 'call' -> call_encode(Opnds);
- 'cbw' -> cbw_encode(Opnds);
- 'cdq' -> nullary_op_encode(16#99, Opnds);
- 'clc' -> nullary_op_encode(16#F8, Opnds);
- 'cld' -> nullary_op_encode(16#FC, Opnds);
- 'cmc' -> nullary_op_encode(16#F5, Opnds);
- 'cmovcc' -> cmovcc_encode(Opnds);
- 'cmp' -> arith_binop_encode(2#111, Opnds);
- 'cwde' -> nullary_op_encode(16#98, Opnds);
- 'dec' -> incdec_encode(2#001, Opnds);
- 'div' -> arith_unop_encode(2#110, Opnds);
- 'enter' -> enter_encode(Opnds);
- 'idiv' -> arith_unop_encode(2#111, Opnds);
- 'imul' -> imul_encode(Opnds);
- 'inc' -> incdec_encode(2#000, Opnds);
- 'into' -> case get(hipe_target_arch) of
- x86 -> nullary_op_encode(16#CE, Opnds);
- amd64 -> exit({invalid_amd64_opcode,
- hipe_amd64_encode__erl})
- end;
- 'jcc' -> jcc_encode(Opnds);
- 'jecxz' -> jmp8_op_encode(16#E3, Opnds);
- 'jmp' -> jmp_encode(Opnds);
- 'lea' -> lea_encode(Opnds);
- 'leave' -> nullary_op_encode(16#C9, Opnds);
- 'loop' -> jmp8_op_encode(16#E2, Opnds);
- 'loope' -> jmp8_op_encode(16#E1, Opnds);
- 'loopne' -> jmp8_op_encode(16#E0, Opnds);
- 'mov' -> mov_encode(Opnds);
- 'movsx' -> movx_op_encode(16#BE, Opnds);
- 'movzx' -> movx_op_encode(16#B6, Opnds);
- 'mul' -> arith_unop_encode(2#100, Opnds);
- 'neg' -> arith_unop_encode(2#011, Opnds);
- 'nop' -> nullary_op_encode(16#90, Opnds);
- 'not' -> arith_unop_encode(2#010, Opnds);
- 'or' -> arith_binop_encode(2#001, Opnds);
- 'pop' -> pop_encode(Opnds);
- 'prefix_fs' -> nullary_op_encode(16#64, Opnds);
- 'push' -> push_encode(Opnds);
- 'rcl' -> shift_op_encode(2#010, Opnds);
- 'rcr' -> shift_op_encode(2#011, Opnds);
- 'ret' -> ret_encode(Opnds);
- 'rol' -> shift_op_encode(2#000, Opnds);
- 'ror' -> shift_op_encode(2#001, Opnds);
- 'sar' -> shift_op_encode(2#111, Opnds);
- 'sbb' -> arith_binop_encode(2#011, Opnds);
- 'setcc' -> setcc_encode(Opnds);
- 'shl' -> shift_op_encode(2#100, Opnds);
- 'shld' -> shd_op_encode(16#A4, Opnds);
- 'shr' -> shift_op_encode(2#101, Opnds);
- 'shrd' -> shd_op_encode(16#AC, Opnds);
- 'stc' -> nullary_op_encode(16#F9, Opnds);
- 'std' -> nullary_op_encode(16#FD, Opnds);
- 'sub' -> arith_binop_encode(2#101, Opnds);
- 'test' -> test_encode(Opnds);
- 'xor' -> arith_binop_encode(2#110, Opnds);
-
- %% sse2
- 'addsd' -> sse2_arith_binop_encode(16#F2, 16#58, Opnds);
- 'cmpsd' -> sse2_arith_binop_encode(16#F2, 16#C2, Opnds);
- 'comisd' -> sse2_arith_binop_encode(16#66, 16#2F, Opnds);
- 'cvtsi2sd' -> sse2_cvtsi2sd_encode(Opnds);
- 'divsd' -> sse2_arith_binop_encode(16#F2, 16#5E, Opnds);
- 'maxsd' -> sse2_arith_binop_encode(16#F2, 16#5F, Opnds);
- 'minsd' -> sse2_arith_binop_encode(16#F2, 16#5D, Opnds);
- 'movsd' -> sse2_mov_encode(Opnds);
- 'mulsd' -> sse2_arith_binop_encode(16#F2, 16#59, Opnds);
- 'sqrtsd' -> sse2_arith_binop_encode(16#F2, 16#51, Opnds);
- 'subsd' -> sse2_arith_binop_encode(16#F2, 16#5C, Opnds);
- 'ucomisd' -> sse2_arith_binop_encode(16#66, 16#2E, Opnds);
- 'xorpd' -> sse2_arith_binop_encode(16#66, 16#57, Opnds);
- %% End of sse2
-
- %% x87
- 'fadd' -> x87_comm_arith_encode(2#000, Opnds);
- 'faddp' -> x87_comm_arith_pop_encode(2#000, Opnds);
- 'fchs' -> fchs_encode();
- 'fdiv' -> x87_arith_encode(2#110, Opnds);
- 'fdivp' -> x87_arith_pop_encode(2#110, Opnds);
- 'fdivr' -> x87_arith_rev_encode(2#111, Opnds);
- 'fdivrp' -> x87_arith_rev_pop_encode(2#111, Opnds);
- 'ffree' -> ffree_encode(Opnds);
- 'fild' -> fild_encode(Opnds);
- 'fld' -> fld_encode(Opnds);
- 'fmul' -> x87_comm_arith_encode(2#001, Opnds);
- 'fmulp' -> x87_comm_arith_pop_encode(2#001, Opnds);
- 'fst' -> fst_encode(2#010, Opnds);
- 'fstp' -> fst_encode(2#011, Opnds);
- 'fsub' -> x87_arith_encode(2#100, Opnds);
- 'fsubp' -> x87_arith_pop_encode(2#100, Opnds);
- 'fsubr' -> x87_arith_rev_encode(2#101, Opnds);
- 'fsubrp' -> x87_arith_rev_pop_encode(2#101, Opnds);
- 'fwait' -> fwait_encode();
- 'fxch' -> fxch_encode(Opnds);
- %% End of x87
-
- _ -> exit({?MODULE,insn_encode,Op})
- end.
-
-insn_sizeof(Op, Opnds) ->
- case Op of
- 'cbw' -> cbw_sizeof(Opnds);
- 'cdq' -> nullary_op_sizeof(Opnds);
- 'clc' -> nullary_op_sizeof(Opnds);
- 'cld' -> nullary_op_sizeof(Opnds);
- 'cmc' -> nullary_op_sizeof(Opnds);
- 'cwde' -> nullary_op_sizeof(Opnds);
- 'enter' -> enter_sizeof(Opnds);
- 'into' -> nullary_op_sizeof(Opnds);
- 'jcc' -> jcc_sizeof(Opnds);
- 'jecxz' -> jmp8_op_sizeof(Opnds);
- 'leave' -> nullary_op_sizeof(Opnds);
- 'loop' -> jmp8_op_sizeof(Opnds);
- 'loope' -> jmp8_op_sizeof(Opnds);
- 'loopne' -> jmp8_op_sizeof(Opnds);
- 'nop' -> nullary_op_sizeof(Opnds);
- 'prefix_fs' -> nullary_op_sizeof(Opnds);
- 'ret' -> ret_sizeof(Opnds);
- 'stc' -> nullary_op_sizeof(Opnds);
- 'std' -> nullary_op_sizeof(Opnds);
-
-%% %% x87
-%% 'fadd' -> x87_arith_sizeof(Opnds);
-%% 'faddp' -> x87_arith_sizeof(Opnds);
- 'fchs' -> fchs_sizeof();
-%% 'fdiv' -> x87_arith_sizeof(Opnds);
-%% 'fdivp' -> x87_arith_sizeof(Opnds);
-%% 'fdivr' -> x87_arith_sizeof(Opnds);
-%% 'fdivrp' -> x87_arith_sizeof(Opnds);
- 'ffree' -> ffree_sizeof();
-%% 'fild' -> fild_sizeof(Opnds);
-%% 'fld' -> fld_sizeof(Opnds);
-%% 'fmul' -> x87_arith_sizeof(Opnds);
-%% 'fmulp' -> x87_arith_sizeof(Opnds);
-%% 'fst' -> fst_sizeof(Opnds);
-%% 'fstp' -> fst_sizeof(Opnds);
-%% 'fsub' -> x87_arith_sizeof(Opnds);
-%% 'fsubp' -> x87_arith_sizeof(Opnds);
-%% 'fsubr' -> x87_arith_sizeof(Opnds);
-%% 'fsubrp' -> x87_arith_sizeof(Opnds);
- 'fwait' -> fwait_sizeof();
- 'fxch' -> fxch_sizeof();
-%% %% End of x87
- _ -> %% Hack that is to be removed some day... Maybe...
- {Bytes, _} = insn_encode(Op, Opnds, 0),
- length(Bytes)
-%% 'adc' -> arith_binop_sizeof(Opnds);
-%% 'add' -> arith_binop_sizeof(Opnds);
-%% 'and' -> arith_binop_sizeof(Opnds);
-%% 'bsf' -> bs_op_sizeof(Opnds);
-%% 'bsr' -> bs_op_sizeof(Opnds);
-%% 'bswap' -> bswap_sizeof(Opnds);
-%% 'bt' -> bt_op_sizeof(Opnds);
-%% 'btc' -> bt_op_sizeof(Opnds);
-%% 'btr' -> bt_op_sizeof(Opnds);
-%% 'bts' -> bt_op_sizeof(Opnds);
-%% 'call' -> call_sizeof(Opnds);
-%% 'cmovcc' -> cmovcc_sizeof(Opnds);
-%% 'cmp' -> arith_binop_sizeof(Opnds);
-%% 'dec' -> incdec_sizeof(Opnds);
-%% 'div' -> arith_unop_sizeof(Opnds);
-%% 'idiv' -> arith_unop_sizeof(Opnds);
-%% 'imul' -> imul_sizeof(Opnds);
-%% 'inc' -> incdec_sizeof(Opnds);
-%% 'jmp' -> jmp_sizeof(Opnds);
-%% 'lea' -> lea_sizeof(Opnds);
-%% 'mov' -> mov_sizeof(Opnds);
-%% 'movsx' -> movx_op_sizeof(Opnds);
-%% 'movzx' -> movx_op_sizeof(Opnds);
-%% 'mul' -> arith_unop_sizeof(Opnds);
-%% 'neg' -> arith_unop_sizeof(Opnds);
-%% 'not' -> arith_unop_sizeof(Opnds);
-%% 'or' -> arith_binop_sizeof(Opnds);
-%% 'pop' -> pop_sizeof(Opnds);
-%% 'push' -> push_sizeof(Opnds);
-%% 'rcl' -> shift_op_sizeof(Opnds);
-%% 'rcr' -> shift_op_sizeof(Opnds);
-%% 'rol' -> shift_op_sizeof(Opnds);
-%% 'ror' -> shift_op_sizeof(Opnds);
-%% 'sar' -> shift_op_sizeof(Opnds);
-%% 'sbb' -> arith_binop_sizeof(Opnds);
-%% 'setcc' -> setcc_sizeof(Opnds);
-%% 'shl' -> shift_op_sizeof(Opnds);
-%% 'shld' -> shd_op_sizeof(Opnds);
-%% 'shr' -> shift_op_sizeof(Opnds);
-%% 'shrd' -> shd_op_sizeof(Opnds);
-%% 'sub' -> arith_binop_sizeof(Opnds);
-%% 'test' -> test_sizeof(Opnds);
-%% 'xor' -> arith_binop_sizeof(Opnds);
-%% _ -> exit({?MODULE,insn_sizeof,Op})
- end.
-
-%%=====================================================================
-%% testing interface
-%%=====================================================================
-
--ifdef(DO_HIPE_AMD64_ENCODE_TEST).
-
-say(OS, Str) ->
- file:write(OS, Str).
-
-digit16(Dig0) ->
- Dig = Dig0 band 16#F,
- if Dig >= 16#A -> $A + (Dig - 16#A);
- true -> $0 + Dig
- end.
-
-say_byte(OS, Byte) ->
- say(OS, "0x"),
- say(OS, [digit16(Byte bsr 4)]),
- say(OS, [digit16(Byte)]).
-
-init(OS) ->
- say(OS, "\t.text\n").
-
-say_bytes(OS, Byte0, Bytes0) ->
- say_byte(OS, Byte0),
- case Bytes0 of
- [] ->
- say(OS, "\n");
- [Byte1|Bytes1] ->
- say(OS, ","),
- say_bytes(OS, Byte1, Bytes1)
- end.
-
-t(OS, Op, Opnds) ->
- insn_sizeof(Op, Opnds),
- {[Byte|Bytes],[]} = insn_encode(Op, Opnds, 0),
- say(OS, "\t.byte "),
- say_bytes(OS, Byte, Bytes).
-
-dotest1(OS) ->
- init(OS),
- % exercise all rm32 types
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_rip(16#87654321)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_sib(sib(?ECX))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_sib(sib(?ECX,sindex(2#10,?EDI)))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sindex(16#87654321)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sindex(16#87654321,sindex(2#10,?EDI))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_base(?ECX)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp8_sib(16#03,sib(?ECX))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp8_sib(16#03,sib(?ECX,sindex(2#10,?EDI)))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp8_base(16#3,?ECX)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sib(16#87654321,sib(?ECX))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sib(16#87654321,sib(?ECX,sindex(2#10,?EDI)))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_base(16#87654321,?EBP)}}),
- t(OS,call,{{rm32,rm_reg(?EAX)}}),
- t(OS,call,{{rm32,rm_mem(ea_disp32_sindex(16#87654321,sindex(2#10,?EDI)))}}),
- t(OS,call,{{rel32,-5}}),
- % default parameters for the tests below
- Word32 = 16#87654321,
- Word16 = 16#F00F,
- Word8 = 16#80,
- Imm32 = {imm32,Word32},
- Imm16 = {imm16,Word16},
- Imm8 = {imm8,Word8},
- RM64 = {rm64,rm_reg(?EDX)},
- RM32 = {rm32,rm_reg(?EDX)},
- RM16 = {rm16,rm_reg(?EDX)},
- RM16REX = {rm16,rm_reg(?R13)},
- RM8 = {rm8,rm_reg(?EDX)},
- RM8REX = {rm8,rm_reg(?SIL)},
- Rel32 = {rel32,Word32},
- Rel8 = {rel8,Word8},
- Moffs32 = {moffs32,Word32},
- Moffs16 = {moffs16,Word32},
- Moffs8 = {moffs8,Word32},
- CC = {cc,?CC_G},
- Reg64 = {reg64,?EAX},
- Reg32 = {reg32,?EAX},
- Reg16 = {reg16,?EAX},
- Reg8 = {reg8,?SPL},
- EA = {ea,ea_base(?ECX)},
- % exercise each instruction definition
- t(OS,'adc',{eax,Imm32}),
- t(OS,'adc',{RM32,Imm32}),
- t(OS,'adc',{RM32,Imm8}),
- t(OS,'adc',{RM32,Reg32}),
- t(OS,'adc',{Reg32,RM32}),
- t(OS,'add',{eax,Imm32}),
- t(OS,'add',{RM32,Imm32}),
- t(OS,'add',{RM32,Imm8}),
- t(OS,'add',{RM32,Reg32}),
- t(OS,'add',{Reg32,RM32}),
- t(OS,'and',{eax,Imm32}),
- t(OS,'and',{RM32,Imm32}),
- t(OS,'and',{RM32,Imm8}),
- t(OS,'and',{RM32,Reg32}),
- t(OS,'and',{Reg32,RM32}),
- t(OS,'bsf',{Reg32,RM32}),
- t(OS,'bsr',{Reg32,RM32}),
- t(OS,'bswap',{Reg32}),
- t(OS,'bt',{RM32,Reg32}),
- t(OS,'bt',{RM32,Imm8}),
- t(OS,'btc',{RM32,Reg32}),
- t(OS,'btc',{RM32,Imm8}),
- t(OS,'btr',{RM32,Reg32}),
- t(OS,'btr',{RM32,Imm8}),
- t(OS,'bts',{RM32,Reg32}),
- t(OS,'bts',{RM32,Imm8}),
- t(OS,'call',{Rel32}),
- t(OS,'call',{RM32}),
- t(OS,'cbw',{}),
- t(OS,'cdq',{}),
- t(OS,'clc',{}),
- t(OS,'cld',{}),
- t(OS,'cmc',{}),
- t(OS,'cmovcc',{CC,Reg32,RM32}),
- t(OS,'cmp',{eax,Imm32}),
- t(OS,'cmp',{RM32,Imm32}),
- t(OS,'cmp',{RM32,Imm8}),
- t(OS,'cmp',{RM32,Reg32}),
- t(OS,'cmp',{Reg32,RM32}),
- t(OS,'cwde',{}),
- t(OS,'dec',{RM32}),
- t(OS,'dec',{Reg32}),
- t(OS,'div',{RM32}),
- t(OS,'enter',{Imm16,{imm8,3}}),
- t(OS,'idiv',{RM32}),
- t(OS,'imul',{RM32}),
- t(OS,'imul',{Reg32,RM32}),
- t(OS,'imul',{Reg32,RM32,Imm8}),
- t(OS,'imul',{Reg32,RM32,Imm32}),
- t(OS,'inc',{RM32}),
- t(OS,'inc',{Reg32}),
- t(OS,'into',{}),
- t(OS,'jcc',{CC,Rel8}),
- t(OS,'jcc',{CC,Rel32}),
- t(OS,'jecxz',{Rel8}),
- t(OS,'jmp',{Rel8}),
- t(OS,'jmp',{Rel32}),
- t(OS,'jmp',{RM32}),
- t(OS,'lea',{Reg32,EA}),
- t(OS,'leave',{}),
- t(OS,'loop',{Rel8}),
- t(OS,'loope',{Rel8}),
- t(OS,'loopne',{Rel8}),
- t(OS,'mov',{RM8,Reg8}),
- t(OS,'mov',{RM16,Reg16}),
- t(OS,'mov',{RM32,Reg32}),
- t(OS,'mov',{Reg8,RM8}),
- t(OS,'mov',{Reg16,RM16}),
- t(OS,'mov',{Reg32,RM32}),
- t(OS,'mov',{al,Moffs8}),
- t(OS,'mov',{ax,Moffs16}),
- t(OS,'mov',{eax,Moffs32}),
- t(OS,'mov',{Moffs8,al}),
- t(OS,'mov',{Moffs16,ax}),
- t(OS,'mov',{Moffs32,eax}),
- t(OS,'mov',{Reg8,Imm8}),
- t(OS,'mov',{Reg16,Imm16}),
- t(OS,'mov',{Reg32,Imm32}),
- t(OS,'mov',{RM8,Imm8}),
- t(OS,'mov',{RM16,Imm16}),
- t(OS,'mov',{RM32,Imm32}),
- t(OS,'movsx',{Reg16,RM8}),
- t(OS,'movsx',{Reg32,RM8}),
- t(OS,'movsx',{Reg32,RM16}),
- t(OS,'movzx',{Reg16,RM8}),
- t(OS,'movzx',{Reg32,RM8}),
- t(OS,'movzx',{Reg32,RM16}),
- t(OS,'mul',{RM32}),
- t(OS,'neg',{RM32}),
- t(OS,'nop',{}),
- t(OS,'not',{RM32}),
- t(OS,'or',{eax,Imm32}),
- t(OS,'or',{RM32,Imm32}),
- t(OS,'or',{RM32,Imm8}),
- t(OS,'or',{RM32,Reg32}),
- t(OS,'or',{Reg32,RM32}),
- t(OS,'pop',{RM32}),
- t(OS,'pop',{Reg32}),
- t(OS,'push',{RM32}),
- t(OS,'push',{Reg32}),
- t(OS,'push',{Imm8}),
- t(OS,'push',{Imm32}),
- t(OS,'rcl',{RM32,1}),
- t(OS,'rcl',{RM32,cl}),
- t(OS,'rcl',{RM32,Imm8}),
- t(OS,'rcr',{RM32,1}),
- t(OS,'rcr',{RM32,cl}),
- t(OS,'rcr',{RM32,Imm8}),
- t(OS,'ret',{}),
- t(OS,'ret',{Imm16}),
- t(OS,'rol',{RM32,1}),
- t(OS,'rol',{RM32,cl}),
- t(OS,'rol',{RM32,Imm8}),
- t(OS,'ror',{RM32,1}),
- t(OS,'ror',{RM32,cl}),
- t(OS,'ror',{RM32,Imm8}),
- t(OS,'sar',{RM32,1}),
- t(OS,'sar',{RM32,cl}),
- t(OS,'sar',{RM32,Imm8}),
- t(OS,'sbb',{eax,Imm32}),
- t(OS,'sbb',{RM32,Imm32}),
- t(OS,'sbb',{RM32,Imm8}),
- t(OS,'sbb',{RM32,Reg32}),
- t(OS,'sbb',{Reg32,RM32}),
- t(OS,'setcc',{CC,RM8}),
- t(OS,'shl',{RM32,1}),
- t(OS,'shl',{RM32,cl}),
- t(OS,'shl',{RM32,Imm8}),
- t(OS,'shld',{RM32,Reg32,Imm8}),
- t(OS,'shld',{RM32,Reg32,cl}),
- t(OS,'shr',{RM32,1}),
- t(OS,'shr',{RM32,cl}),
- t(OS,'shr',{RM32,Imm8}),
- t(OS,'shrd',{RM32,Reg32,Imm8}),
- t(OS,'shrd',{RM32,Reg32,cl}),
- t(OS,'stc',{}),
- t(OS,'std',{}),
- t(OS,'sub',{eax,Imm32}),
- t(OS,'sub',{RM32,Imm32}),
- t(OS,'sub',{RM32,Imm8}),
- t(OS,'sub',{RM32,Reg32}),
- t(OS,'sub',{Reg32,RM32}),
- t(OS,'test',{al,Imm8}),
- t(OS,'test',{ax,Imm16}),
- t(OS,'test',{eax,Imm32}),
- t(OS,'test',{rax,Imm32}),
- t(OS,'test',{RM8,Imm8}),
- t(OS,'test',{RM8REX,Imm8}),
- t(OS,'test',{RM16,Imm16}),
- t(OS,'test',{RM16REX,Imm16}),
- t(OS,'test',{RM32,Imm32}),
- t(OS,'test',{RM64,Imm32}),
- t(OS,'test',{RM32,Reg32}),
- t(OS,'test',{RM64,Reg64}),
- t(OS,'xor',{eax,Imm32}),
- t(OS,'xor',{RM32,Imm32}),
- t(OS,'xor',{RM32,Imm8}),
- t(OS,'xor',{RM32,Reg32}),
- t(OS,'xor',{Reg32,RM32}),
- t(OS,'prefix_fs',{}), t(OS,'add',{{reg32,?EAX},{rm32,rm_mem(ea_disp32_rip(16#20))}}),
- [].
-
-dotest() -> dotest1(group_leader()). % stdout == group_leader
-
-dotest(File) ->
- {ok,OS} = file:open(File, [write]),
- dotest1(OS),
- file:close(OS).
--endif.
diff --git a/lib/hipe/amd64/hipe_amd64_frame.erl b/lib/hipe/amd64/hipe_amd64_frame.erl
deleted file mode 100644
index 800f1c1a08..0000000000
--- a/lib/hipe/amd64/hipe_amd64_frame.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_frame.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_liveness.erl b/lib/hipe/amd64/hipe_amd64_liveness.erl
deleted file mode 100644
index a1e8403df1..0000000000
--- a/lib/hipe/amd64/hipe_amd64_liveness.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_liveness.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_main.erl b/lib/hipe/amd64/hipe_amd64_main.erl
deleted file mode 100644
index 75b7746500..0000000000
--- a/lib/hipe/amd64/hipe_amd64_main.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_main.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_pp.erl b/lib/hipe/amd64/hipe_amd64_pp.erl
deleted file mode 100644
index 9dfe571122..0000000000
--- a/lib/hipe/amd64/hipe_amd64_pp.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_pp.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_ra.erl b/lib/hipe/amd64/hipe_amd64_ra.erl
deleted file mode 100644
index 052e9c1e63..0000000000
--- a/lib/hipe/amd64/hipe_amd64_ra.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_ra.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_ra_finalise.erl b/lib/hipe/amd64/hipe_amd64_ra_finalise.erl
deleted file mode 100644
index 82d462fad7..0000000000
--- a/lib/hipe/amd64/hipe_amd64_ra_finalise.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_ra_finalise.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_ra_ls.erl b/lib/hipe/amd64/hipe_amd64_ra_ls.erl
deleted file mode 100644
index 9fa0edca47..0000000000
--- a/lib/hipe/amd64/hipe_amd64_ra_ls.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_ra_ls.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_ra_naive.erl b/lib/hipe/amd64/hipe_amd64_ra_naive.erl
deleted file mode 100644
index 1aa40121c9..0000000000
--- a/lib/hipe/amd64/hipe_amd64_ra_naive.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_ra_naive.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_ra_postconditions.erl b/lib/hipe/amd64/hipe_amd64_ra_postconditions.erl
deleted file mode 100644
index 9359e0db0a..0000000000
--- a/lib/hipe/amd64/hipe_amd64_ra_postconditions.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_ra_postconditions.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl b/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
deleted file mode 100644
index 891c874a15..0000000000
--- a/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
+++ /dev/null
@@ -1,167 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_amd64_ra_sse2_postconditions).
-
--export([check_and_rewrite/2, check_and_rewrite/3]).
-
--include("../x86/hipe_x86.hrl").
--define(HIPE_INSTRUMENT_COMPILER, true).
--include("../main/hipe.hrl").
--define(count_temp(T), ?cons_counter(counter_mfa_mem_temps, T)).
-
-
-check_and_rewrite(AMD64CFG, Coloring) ->
- check_and_rewrite(AMD64CFG, Coloring, 'normal').
-
-check_and_rewrite(AMD64CFG, Coloring, Strategy) ->
- %%io:format("Converting\n"),
- TempMap = hipe_temp_map:cols2tuple(Coloring,hipe_amd64_specific_sse2,no_context),
- %%io:format("Rewriting\n"),
- do_bbs(hipe_x86_cfg:labels(AMD64CFG), TempMap, Strategy, AMD64CFG, false).
-
-do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_x86_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0),
- CFG = hipe_x86_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
- do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum),
- DidSpill0 or DidSpill1);
-do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap, Strategy) -> % Insn -> {Insn list, DidSpill}
- case I of
- #fmove{} ->
- do_fmove(I, TempMap, Strategy);
- #fp_unop{} ->
- do_fp_unop(I, TempMap, Strategy);
- #fp_binop{} ->
- do_fp_binop(I, TempMap, Strategy);
- #pseudo_spill_fmove{} ->
- do_pseudo_spill_fmove(I, TempMap, Strategy);
- _ ->
- %% All non sse2 ops
- {[I], false}
- end.
-
-%%% Fix an fp_binop.
-do_fp_binop(I, TempMap, Strategy) ->
- #fp_binop{src=Src,dst=Dst} = I,
- case is_mem_opnd(Dst, TempMap) of
- true ->
- Tmp = clone(Dst, Strategy),
- {[#fmove{src=Dst, dst=Tmp},
- I#fp_binop{src=Src,dst=Tmp},
- #fmove{src=Tmp,dst=Dst}],
- true};
- false ->
- {[I], false}
- end.
-
-do_fp_unop(I, TempMap, Strategy) ->
- #fp_unop{arg=Arg} = I,
- case is_mem_opnd(Arg, TempMap) of
- true ->
- Tmp = clone(Arg, Strategy),
- {[#fmove{src=Arg, dst=Tmp},
- I#fp_unop{arg=Tmp},
- #fmove{src=Tmp,dst=Arg}],
- true};
- false ->
- {[I], false}
- end.
-
-%%% Fix an fmove op.
-do_fmove(I, TempMap, Strategy) ->
- #fmove{src=Src,dst=Dst} = I,
- case
- (is_mem_opnd(Src, TempMap) andalso is_mem_opnd(Dst, TempMap))
- orelse (is_mem_opnd(Src, TempMap) andalso (not is_float_temp(Dst)))
- orelse ((not is_float_temp(Src)) andalso is_mem_opnd(Dst, TempMap))
- of
- true ->
- Tmp = spill_temp(double, Strategy),
- %% pseudo_spill_fmove allows spill slot move coalescing, but must not
- %% contain memory operands (except for spilled temps)
- Is = case is_float_temp(Src) andalso is_float_temp(Dst) of
- true -> [#pseudo_spill_fmove{src=Src, temp=Tmp, dst=Dst}];
- false -> [#fmove{src=Src, dst=Tmp},I#fmove{src=Tmp,dst=Dst}]
- end,
- {Is, true};
- false ->
- {[I], false}
- end.
-
-is_float_temp(#x86_temp{type=Type}) -> Type =:= double;
-is_float_temp(#x86_mem{}) -> false.
-
-%%% Fix an pseudo_spill_fmove op.
-do_pseudo_spill_fmove(I = #pseudo_spill_fmove{temp=Temp}, TempMap, _Strategy) ->
- %% Temp is above the low water mark and must not have been spilled
- false = is_mem_opnd(Temp, TempMap),
- {[I], false}. % nothing to do
-
-%%% Check if an operand denotes a memory cell (mem or pseudo).
-
-is_mem_opnd(Opnd, TempMap) ->
- case Opnd of
- #x86_mem{} -> true;
- #x86_temp{type=double} ->
- Reg = hipe_x86:temp_reg(Opnd),
- case hipe_x86:temp_is_allocatable(Opnd) of
- true ->
- case hipe_temp_map:is_spilled(Reg, TempMap) of
- true ->
- ?count_temp(Reg),
- true;
- false -> false
- end;
- false -> true
- end;
- _ -> false
- end.
-
-%%% Make Reg a clone of Dst (attach Dst's type to Reg).
-
-clone(Dst, Strategy) ->
- Type =
- case Dst of
- #x86_mem{} -> hipe_x86:mem_type(Dst);
- #x86_temp{} -> hipe_x86:temp_type(Dst)
- end,
- spill_temp(Type, Strategy).
-
-spill_temp(Type, 'normal') ->
- hipe_x86:mk_new_temp(Type);
-spill_temp(double, 'linearscan') ->
- hipe_x86:mk_temp(hipe_amd64_specific_sse2:temp0(no_context), double);
-spill_temp(Type, 'linearscan') when Type =:= tagged; Type =/= untagged ->
- %% We can make a new temp here since we have yet to allocate registers for
- %% these types
- hipe_x86:mk_new_temp(Type).
-
-%%% Make a certain reg into a clone of Dst
-
-%% clone2(Dst, Reg) ->
-%% Type =
-%% case Dst of
-%% #x86_mem{} -> hipe_x86:mem_type(Dst);
-%% #x86_temp{} -> hipe_x86:temp_type(Dst)
-%% end,
-%% hipe_x86:mk_temp(Reg,Type).
diff --git a/lib/hipe/amd64/hipe_amd64_registers.erl b/lib/hipe/amd64/hipe_amd64_registers.erl
deleted file mode 100644
index a5cecef5a1..0000000000
--- a/lib/hipe/amd64/hipe_amd64_registers.erl
+++ /dev/null
@@ -1,281 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_amd64_registers).
-
--export([
- all_precoloured/0,
- allocatable/0,
- allocatable_sse2/0,
- allocatable_x87/0,
- arg/1,
- args/1,
- call_clobbered/0,
- fcalls/0,
- float_size/0,
- first_virtual/0,
- heap_limit/0,
- is_arg/1,
- is_fixed/1,
- is_precoloured/1,
- is_precoloured_sse2/1,
- is_precoloured_x87/1,
- live_at_return/0,
- nr_args/0,
- proc_offset/1,
- proc_pointer/0,
- rax/0,
- rcx/0,
- ret/1,
- sp/0,
- sp_limit_offset/0,
- reg_name/1,
- alignment/0,
- tailcall_clobbered/0,
- temp0/0,
- temp1/0,
- sse2_temp0/0,
- %% fixed/0,
- wordsize/0
- ]).
-
--include("../rtl/hipe_literals.hrl").
-
--ifdef(AMD64_HP_IN_REGISTER).
--export([heap_pointer/0]).
--endif.
-
--ifdef(AMD64_FCALLS_IN_REGISTER).
-fcalls_offset() -> false.
--else.
-fcalls_offset() -> ?P_FCALLS.
--define(AMD64_FCALLS_REGISTER,16).
--endif.
-
--ifdef(AMD64_HEAP_LIMIT_IN_REGISTER).
-heap_limit_offset() -> false.
--else.
--define(AMD64_HEAP_LIMIT_REGISTER, 17).
-heap_limit_offset() -> ?P_HP_LIMIT.
--endif.
-
-
--define(RAX, 0).
--define(RCX, 1).
--define(RDX, 2).
--define(RBX, 3).
--define(RSP, 4).
--define(RBP, 5).
--define(RSI, 6).
--define(RDI, 7).
--define(R8 , 8).
--define(R9 , 9).
--define(R10, 10).
--define(R11, 11).
--define(R12, 12).
--define(R13, 13).
--define(R14, 14).
--define(R15, 15).
--define(FCALLS, ?AMD64_FCALLS_REGISTER).
--define(HEAP_LIMIT, ?AMD64_HEAP_LIMIT_REGISTER).
--define(LAST_PRECOLOURED, 17).
-
--define(ARG0, ?RSI).
--define(ARG1, ?RDX).
--define(ARG2, ?RCX).
--define(ARG3, ?R8).
--define(ARG4, ?R9).
--define(ARG5, ?RDI).
-
--define(TEMP0, ?R14).
--define(TEMP1, ?R13).
-
--define(SSE2_TEMP0, 00).
-
--define(PROC_POINTER, ?RBP).
-
-reg_name(R) ->
- case R of
- ?RAX -> "%rax";
- ?RCX -> "%rcx";
- ?RDX -> "%rdx";
- ?RBX -> "%rbx";
- ?RSP -> "%rsp";
- ?RBP -> "%rbp";
- ?RSI -> "%rsi";
- ?RDI -> "%rdi";
- ?FCALLS -> "%fcalls";
- ?HEAP_LIMIT -> "%hplim";
- Other -> "%r" ++ integer_to_list(Other)
- end.
-
-alignment() -> 8.
-
-float_size() -> 8.
-
-first_virtual() -> ?LAST_PRECOLOURED + 1.
-
-is_precoloured(X) -> X =< ?LAST_PRECOLOURED.
-
-is_precoloured_sse2(X) -> X =< 15.
-
-is_precoloured_x87(X) -> X =< 6.
-
-all_precoloured() ->
- [?RAX,
- ?RCX,
- ?RDX,
- ?RBX,
- ?RSP,
- ?RBP,
- ?RSI,
- ?RDI,
- ?R8 ,
- ?R9 ,
- ?R10,
- ?R11,
- ?R12,
- ?R13,
- ?R14,
- ?R15,
- ?FCALLS,
- ?HEAP_LIMIT].
-
-rax() -> ?RAX.
-rcx() -> ?RCX.
-temp0() -> ?TEMP0.
-temp1() -> ?TEMP1.
-sp() -> ?RSP.
-proc_pointer() -> ?PROC_POINTER.
-fcalls() -> ?FCALLS.
-heap_limit() -> ?HEAP_LIMIT.
-
-
--ifdef(AMD64_HP_IN_REGISTER).
--define(HEAP_POINTER, ?AMD64_HEAP_POINTER).
-heap_pointer() -> ?HEAP_POINTER.
--define(LIST_HP_LIVE_AT_RETURN,[{?HEAP_POINTER,untagged}]).
-is_heap_pointer(?HEAP_POINTER) -> true;
-is_heap_pointer(_) -> false.
-%% -define(LIST_HP_FIXED,[?HEAP_POINTER]).
-
--else.
--define(HEAP_POINTER, -1).
-is_heap_pointer(_) -> false.
-%% -define(LIST_HP_FIXED,[]).
--define(LIST_HP_LIVE_AT_RETURN,[]).
--endif.
-
-proc_offset(?FCALLS) -> fcalls_offset();
-proc_offset(?HEAP_LIMIT) -> heap_limit_offset();
-proc_offset(_) -> false.
-
-sp_limit_offset() -> ?P_NSP_LIMIT.
-
-is_fixed(?RSP) -> true;
-is_fixed(?PROC_POINTER) -> true;
-is_fixed(?FCALLS) -> true;
-is_fixed(?HEAP_LIMIT) -> true;
-is_fixed(R) -> is_heap_pointer(R).
-
-%% fixed() ->
-%% [?ESP, ?PROC_POINTER, ?FCALLS, ?HEAP_LIMIT | ?LIST_HP_FIXED].
-
-allocatable() ->
- [?RDX, ?RCX, ?RBX, ?RAX, ?RSI, ?RDI,
- ?R8 , ?R9 , ?R10, ?R11, ?R12, ?R13, ?R14, ?R15]
- -- [?FCALLS, ?HEAP_POINTER, ?HEAP_LIMIT].
-
-allocatable_sse2() ->
- [00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15]. %% xmm0 - xmm15
-
-sse2_temp0() -> ?SSE2_TEMP0.
-
-allocatable_x87() ->
- [0,1,2,3,4,5,6].
-
-nr_args() -> ?AMD64_NR_ARG_REGS.
-
-arg(N) when N < ?AMD64_NR_ARG_REGS ->
- case N of
- 0 -> ?ARG0;
- 1 -> ?ARG1;
- 2 -> ?ARG2;
- 3 -> ?ARG3;
- 4 -> ?ARG4;
- 5 -> ?ARG5
- end.
-
-is_arg(R) ->
- case R of
- ?ARG0 -> ?AMD64_NR_ARG_REGS > 0;
- ?ARG1 -> ?AMD64_NR_ARG_REGS > 1;
- ?ARG2 -> ?AMD64_NR_ARG_REGS > 2;
- ?ARG3 -> ?AMD64_NR_ARG_REGS > 3;
- ?ARG4 -> ?AMD64_NR_ARG_REGS > 4;
- ?ARG5 -> ?AMD64_NR_ARG_REGS > 5;
- _ -> false
- end.
-
-args(Arity) when is_integer(Arity), Arity >= 0 ->
- N = erlang:min(Arity, ?AMD64_NR_ARG_REGS),
- args(N-1, []).
-
-args(I, Rest) when I < 0 -> Rest;
-args(I, Rest) -> args(I-1, [arg(I) | Rest]).
-
-ret(0) -> ?RAX.
-
-%% Note: the fact that (allocatable() UNION allocatable_x87() UNION
-%% allocatable_sse2()) is a subset of call_clobbered() is hard-coded in
-%% hipe_x86_defuse:insn_defs_all/1
-call_clobbered() ->
- [{?RAX,tagged},{?RAX,untagged}, % does the RA strip the type or not?
- {?RDX,tagged},{?RDX,untagged},
- {?RCX,tagged},{?RCX,untagged},
- {?RBX,tagged},{?RBX,untagged},
- {?RDI,tagged},{?RDI,untagged},
- {?RSI,tagged},{?RSI,untagged},
- {?R8 ,tagged},{?R8 ,untagged},
- {?R9 ,tagged},{?R9 ,untagged},
- {?R10,tagged},{?R10,untagged},
- {?R11,tagged},{?R11,untagged},
- {?R12,tagged},{?R12,untagged},
- {?R13,tagged},{?R13,untagged},
- {?R14,tagged},{?R14,untagged},
- {?R15,tagged},{?R15,untagged}
- | fp_call_clobbered()]
- --
- [{?FCALLS,tagged},{?FCALLS,untagged},
- {?HEAP_POINTER,tagged},{?HEAP_POINTER,untagged},
- {?HEAP_LIMIT,tagged},{?HEAP_LIMIT,untagged}
- ].
-
-fp_call_clobbered() -> %% sse2 since it has more registers than x87
- [{Reg,double} || Reg <- allocatable_sse2()].
-
-tailcall_clobbered() -> % tailcall crapola needs two temps
- [{?TEMP0,tagged},{?TEMP0,untagged},
- {?TEMP1,tagged},{?TEMP1,untagged}
- | fp_call_clobbered()].
-
-live_at_return() ->
- [{?RSP,untagged}
- ,{?PROC_POINTER,untagged}
- ,{?FCALLS,untagged}
- ,{?HEAP_LIMIT,untagged}
- | ?LIST_HP_LIVE_AT_RETURN
- ].
-
-wordsize() -> 8.
diff --git a/lib/hipe/amd64/hipe_amd64_spill_restore.erl b/lib/hipe/amd64/hipe_amd64_spill_restore.erl
deleted file mode 100644
index 915ac1adc4..0000000000
--- a/lib/hipe/amd64/hipe_amd64_spill_restore.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_spill_restore.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_sse2.erl b/lib/hipe/amd64/hipe_amd64_sse2.erl
deleted file mode 100644
index 1a2d3eac48..0000000000
--- a/lib/hipe/amd64/hipe_amd64_sse2.erl
+++ /dev/null
@@ -1,76 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% Fix {mem, mem} floating point operations that result from linear scan
-%% allocated floats.
-
--module(hipe_amd64_sse2).
-
--export([map/1]).
-
--include("../x86/hipe_x86.hrl").
--include("../main/hipe.hrl").
-
-%%----------------------------------------------------------------------
-
-map(CFG) ->
- hipe_x86_cfg:map_bbs(fun do_bb/2, CFG).
-
-do_bb(_Lbl, BB) ->
- Code = do_insns(hipe_bb:code(BB), []),
- hipe_bb:code_update(BB, Code).
-
-do_insns([I|Insns], Accum) ->
- NewIs = do_insn(I),
- do_insns(Insns, lists:reverse(NewIs, Accum));
-do_insns([], Accum) ->
- lists:reverse(Accum).
-
-do_insn(I) ->
- case I of
- #fp_binop{} -> do_fp_binop(I);
- #fmove{} -> do_fmove(I);
- _ -> [I]
- end.
-
-do_fp_binop(I = #fp_binop{src=Src0,dst=Dst}) ->
- {FixSrc, Src} = fix_binary(Src0, Dst),
- FixSrc ++ [I#fp_binop{src=Src}].
-
-do_fmove(I = #fmove{src=Src0,dst=Dst}) ->
- {FixSrc, Src} = fix_binary(Src0, Dst),
- FixSrc ++ [I#fmove{src=Src}].
-
-fix_binary(Src0, Dst) ->
- case is_mem_opnd(Src0) of
- false -> {[], Src0};
- true ->
- case is_mem_opnd(Dst) of
- false -> {[], Src0};
- true ->
- Src1 = spill_temp(),
- {[hipe_x86:mk_fmove(Src0, Src1)], Src1}
- end
- end.
-
-is_mem_opnd(#x86_fpreg{reg=Reg}) ->
- not hipe_amd64_registers:is_precoloured_sse2(Reg);
-is_mem_opnd(#x86_temp{type=double, reg=Reg}) ->
- not hipe_amd64_registers:is_precoloured_sse2(Reg);
-is_mem_opnd(#x86_temp{type=_, reg=Reg}) ->
- not hipe_amd64_registers:is_precoloured(Reg);
-is_mem_opnd(#x86_mem{}) -> true.
-
-spill_temp() ->
- hipe_x86:mk_temp(hipe_amd64_registers:sse2_temp0(), double).
diff --git a/lib/hipe/amd64/hipe_amd64_subst.erl b/lib/hipe/amd64/hipe_amd64_subst.erl
deleted file mode 100644
index b0b9ccbe38..0000000000
--- a/lib/hipe/amd64/hipe_amd64_subst.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_subst.erl").
diff --git a/lib/hipe/amd64/hipe_amd64_x87.erl b/lib/hipe/amd64/hipe_amd64_x87.erl
deleted file mode 100644
index afb3aa63e7..0000000000
--- a/lib/hipe/amd64/hipe_amd64_x87.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_x86_x87.erl").
diff --git a/lib/hipe/amd64/hipe_rtl_to_amd64.erl b/lib/hipe/amd64/hipe_rtl_to_amd64.erl
deleted file mode 100644
index 7243e75f84..0000000000
--- a/lib/hipe/amd64/hipe_rtl_to_amd64.erl
+++ /dev/null
@@ -1,13 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--include("../x86/hipe_rtl_to_x86.erl").
diff --git a/lib/hipe/arm/Makefile b/lib/hipe/arm/Makefile
deleted file mode 100644
index ed2eccf428..0000000000
--- a/lib/hipe/arm/Makefile
+++ /dev/null
@@ -1,124 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-# Please keep this list sorted.
-MODULES=hipe_arm \
- hipe_arm_assemble \
- hipe_arm_cfg \
- hipe_arm_defuse \
- hipe_arm_encode \
- hipe_arm_finalise \
- hipe_arm_frame \
- hipe_arm_liveness_gpr \
- hipe_arm_main \
- hipe_arm_pp \
- hipe_arm_ra \
- hipe_arm_ra_finalise \
- hipe_arm_ra_ls \
- hipe_arm_ra_naive \
- hipe_arm_ra_postconditions \
- hipe_arm_registers \
- hipe_arm_subst \
- hipe_rtl_to_arm
-
-HRL_FILES=hipe_arm.hrl
-ERL_FILES=$(MODULES:%=%.erl)
-TARGET_FILES=$(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-# Please keep this list sorted.
-$(EBIN)/hipe_arm_assemble.beam: ../main/hipe.hrl ../../kernel/src/hipe_ext_format.hrl ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_arm_cfg.beam: ../flow/cfg.hrl ../flow/cfg.inc
-$(EBIN)/hipe_arm_frame.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_arm_liveness_gpr.beam: ../flow/liveness.inc
-$(EBIN)/hipe_arm_registers.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_rtl_to_arm.beam: ../rtl/hipe_rtl.hrl
-
-$(TARGET_FILES): hipe_arm.hrl ../misc/hipe_consttab.hrl
diff --git a/lib/hipe/arm/TODO b/lib/hipe/arm/TODO
deleted file mode 100644
index 546d22737a..0000000000
--- a/lib/hipe/arm/TODO
+++ /dev/null
@@ -1,20 +0,0 @@
-Assembler:
-
-Peephole optimiser:
-- Could e.g. turn "ldr lr,[sp,#OFF]; mov pc,lr"
- into "ldr pc,[sp#OFF]", but then the LR save slot must
- be in the caller's frame not the callee's.
-- Also kill "mov r0,r0" which seems to occur often.
-
-hipe_arm:
-- Handle more non-trivial immediates in mk_li/mk_load/mk_store.
- See e.g. big_list, which has many 11-bit character constants.
-
-Floating point:
-- Drop no_inline_fp. Implement FP ops as calls to C or ASM
- primops. All FP values passed by reference in memory.
- This should at least reduce consing costs.
-
-Linear scan:
-- Do not hardcode temp1/temp2/temp3. Instead just take three
- regs from (All\Fixed)\Params. (Ditto in PowerPC.)
diff --git a/lib/hipe/arm/hipe_arm.erl b/lib/hipe/arm/hipe_arm.erl
deleted file mode 100644
index 3b090b501a..0000000000
--- a/lib/hipe/arm/hipe_arm.erl
+++ /dev/null
@@ -1,381 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm).
--export([
- mk_temp/2,
- mk_new_temp/1,
- mk_new_nonallocatable_temp/1,
- is_temp/1,
- temp_reg/1,
- temp_type/1,
- temp_is_allocatable/1,
- temp_is_precoloured/1,
-
- mk_mfa/3,
-
- mk_prim/1,
- is_prim/1,
- prim_prim/1,
-
- mk_sdesc/4,
-
- mk_am2/3,
- mk_am3/3,
-
- mk_alu/5,
-
- mk_b_fun/2,
-
- mk_b_label/2,
- mk_b_label/1,
-
- mk_bl/3,
-
- mk_blx/2,
-
- mk_cmp/3,
-
- mk_comment/1,
-
- mk_label/1,
- is_label/1,
- label_label/1,
-
- mk_load/3,
- mk_load/6,
-
- mk_ldrsb/2,
-
- mk_move/3,
- mk_move/2,
-
- mk_pseudo_bc/4,
-
- mk_pseudo_call/4,
- pseudo_call_contlab/1,
- pseudo_call_funv/1,
- pseudo_call_sdesc/1,
- pseudo_call_linkage/1,
-
- mk_pseudo_call_prepare/1,
- pseudo_call_prepare_nrstkargs/1,
-
- mk_pseudo_li/2,
-
- mk_pseudo_move/2,
- is_pseudo_move/1,
- pseudo_move_dst/1,
- pseudo_move_src/1,
-
- mk_pseudo_spill_move/3,
- is_pseudo_spill_move/1,
-
- mk_pseudo_switch/3,
-
- mk_pseudo_tailcall/4,
- pseudo_tailcall_funv/1,
- pseudo_tailcall_stkargs/1,
- pseudo_tailcall_linkage/1,
-
- mk_pseudo_tailcall_prepare/0,
-
- mk_smull/4,
-
- mk_store/3,
- mk_store/6,
-
- mk_pseudo_blr/0,
- mk_bx/1,
- mk_mflr/1,
- mk_mtlr/1,
- mk_lr/0,
- mk_pc/0,
-
- mk_li/2,
- mk_li/3,
-
- mk_addi/4,
-
- try_aluop_imm/2,
-
- mk_defun/8,
- defun_mfa/1,
- defun_formals/1,
- defun_is_closure/1,
- defun_is_leaf/1,
- defun_code/1,
- defun_data/1,
- defun_var_range/1
- ]).
-
--include("hipe_arm.hrl").
-
-mk_temp(Reg, Type, Allocatable) ->
- #arm_temp{reg=Reg, type=Type, allocatable=Allocatable}.
-mk_temp(Reg, Type) -> mk_temp(Reg, Type, true).
-mk_new_temp(Type, Allocatable) ->
- mk_temp(hipe_gensym:get_next_var(arm), Type, Allocatable).
-mk_new_temp(Type) -> mk_new_temp(Type, true).
-mk_new_nonallocatable_temp(Type) -> mk_new_temp(Type, false).
-is_temp(X) -> case X of #arm_temp{} -> true; _ -> false end.
-temp_reg(#arm_temp{reg=Reg}) -> Reg.
-temp_type(#arm_temp{type=Type}) -> Type.
-temp_is_allocatable(#arm_temp{allocatable=A}) -> A.
-temp_is_precoloured(#arm_temp{reg=Reg}) ->
- hipe_arm_registers:is_precoloured_gpr(Reg).
-
-mk_mfa(M, F, A) -> #arm_mfa{m=M, f=F, a=A}.
-
-mk_prim(Prim) -> #arm_prim{prim=Prim}.
-is_prim(X) -> case X of #arm_prim{} -> true; _ -> false end.
-prim_prim(#arm_prim{prim=Prim}) -> Prim.
-
-mk_am2(Src, Sign, Offset) -> #am2{src=Src, sign=Sign, offset=Offset}.
-mk_am3(Src, Sign, Offset) -> #am3{src=Src, sign=Sign, offset=Offset}.
-
-mk_alu(AluOp, S, Dst, Src, Am1) ->
- #alu{aluop=AluOp, s=S, dst=Dst, src=Src, am1=Am1}.
-mk_alu(AluOp, Dst, Src, Am1) -> mk_alu(AluOp, false, Dst, Src, Am1).
-
-mk_b_fun(Fun, Linkage) -> #b_fun{'fun'=Fun, linkage=Linkage}.
-
-mk_b_label(Cond, Label) -> #b_label{'cond'=Cond, label=Label}.
-mk_b_label(Label) -> mk_b_label('al', Label).
-
-mk_bl(Fun, SDesc, Linkage) -> #bl{'fun'=Fun, sdesc=SDesc, linkage=Linkage}.
-
-mk_blx(Src, SDesc) -> #blx{src=Src, sdesc=SDesc}.
-
-mk_cmp(CmpOp, Src, Am1) -> #cmp{cmpop=CmpOp, src=Src, am1=Am1}.
-
-mk_sdesc(ExnLab, FSize, Arity, Live) ->
- #arm_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}.
-
-mk_comment(Term) -> #comment{term=Term}.
-
-mk_label(Label) -> #label{label=Label}.
-is_label(I) -> case I of #label{} -> true; _ -> false end.
-label_label(#label{label=Label}) -> Label.
-
-mk_load(LdOp, Dst, Am2) -> #load{ldop=LdOp, dst=Dst, am2=Am2}.
-
-mk_load(LdOp, Dst, Base, Offset, Scratch, Rest) when is_integer(Offset) ->
- {Sign,AbsOffset} =
- if Offset < 0 -> {'-', -Offset};
- true -> {'+', Offset}
- end,
- if AbsOffset =< 4095 ->
- Am2 = #am2{src=Base,sign=Sign,offset=AbsOffset},
- [mk_load(LdOp, Dst, Am2) | Rest];
- true ->
- Index =
- begin
- DstReg = temp_reg(Dst),
- BaseReg = temp_reg(Base),
- if DstReg =/= BaseReg -> Dst;
- true -> mk_scratch(Scratch)
- end
- end,
- Am2 = #am2{src=Base,sign=Sign,offset=Index},
- mk_li(Index, AbsOffset,
- [mk_load(LdOp, Dst, Am2) | Rest])
- end.
-
-mk_scratch(Scratch) ->
- case Scratch of
- 'temp2' -> mk_temp(hipe_arm_registers:temp2(), 'untagged');
- 'new' -> mk_new_temp('untagged')
- end.
-
-mk_ldrsb(Dst, Am3) -> #ldrsb{dst=Dst, am3=Am3}.
-
-mk_move(MovOp, S, Dst, Am1) -> #move{movop=MovOp, s=S, dst=Dst, am1=Am1}.
-mk_move(S, Dst, Am1) -> mk_move('mov', S, Dst, Am1).
-mk_move(Dst, Am1) -> mk_move('mov', false, Dst, Am1).
-
-mk_pseudo_bc(Cond, TrueLab, FalseLab, Pred) ->
- if Pred >= 0.5 ->
- mk_pseudo_bc_simple(negate_cond(Cond), FalseLab,
- TrueLab, 1.0-Pred);
- true ->
- mk_pseudo_bc_simple(Cond, TrueLab, FalseLab, Pred)
- end.
-
-mk_pseudo_bc_simple(Cond, TrueLab, FalseLab, Pred) when Pred =< 0.5 ->
- #pseudo_bc{'cond'=Cond, true_label=TrueLab,
- false_label=FalseLab, pred=Pred}.
-
-negate_cond(Cond) ->
- case Cond of
- 'lt' -> 'ge'; % <, >=
- 'ge' -> 'lt'; % >=, <
- 'gt' -> 'le'; % >, <=
- 'le' -> 'gt'; % <=, >
- 'eq' -> 'ne'; % ==, !=
- 'ne' -> 'eq'; % !=, ==
- 'hi' -> 'ls'; % >u, <=u
- 'ls' -> 'hi'; % <=u, >u
- 'hs' -> 'lo'; % >=u, <u
- 'lo' -> 'hs'; % <u, >=u
- 'vs' -> 'vc'; % overflow, not_overflow
- 'vc' -> 'vs' % not_overflow, overflow
- end.
-
-mk_pseudo_call(FunV, SDesc, ContLab, Linkage) ->
- #pseudo_call{funv=FunV, sdesc=SDesc, contlab=ContLab, linkage=Linkage}.
-pseudo_call_funv(#pseudo_call{funv=FunV}) -> FunV.
-pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc.
-pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab.
-pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage.
-
-mk_pseudo_call_prepare(NrStkArgs) ->
- #pseudo_call_prepare{nrstkargs=NrStkArgs}.
-pseudo_call_prepare_nrstkargs(#pseudo_call_prepare{nrstkargs=NrStkArgs}) ->
- NrStkArgs.
-
-mk_pseudo_li(Dst, Imm) ->
- #pseudo_li{dst=Dst, imm=Imm, label=hipe_gensym:get_next_label(arm)}.
-
-mk_pseudo_move(Dst, Src) -> #pseudo_move{dst=Dst, src=Src}.
-is_pseudo_move(I) -> case I of #pseudo_move{} -> true; _ -> false end.
-pseudo_move_dst(#pseudo_move{dst=Dst}) -> Dst.
-pseudo_move_src(#pseudo_move{src=Src}) -> Src.
-
-mk_pseudo_spill_move(Dst, Temp, Src) ->
- #pseudo_spill_move{dst=Dst, temp=Temp, src=Src}.
-is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move).
-
-mk_pseudo_switch(JTab, Index, Labels) ->
- #pseudo_switch{jtab=JTab, index=Index, labels=Labels}.
-
-mk_pseudo_tailcall(FunV, Arity, StkArgs, Linkage) ->
- #pseudo_tailcall{funv=FunV, arity=Arity, stkargs=StkArgs, linkage=Linkage}.
-pseudo_tailcall_funv(#pseudo_tailcall{funv=FunV}) -> FunV.
-pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs.
-pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage.
-
-mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}.
-
-mk_smull(DstLo, DstHi, Src1, Src2) ->
- #smull{dstlo=DstLo, dsthi=DstHi, src1=Src1, src2=Src2}.
-
-mk_store(StOp, Src, Am2) -> #store{stop=StOp, src=Src, am2=Am2}.
-
-mk_store(StOp, Src, Base, Offset, Scratch, Rest) when is_integer(Offset) ->
- {Sign,AbsOffset} =
- if Offset < 0 -> {'-', -Offset};
- true -> {'+', Offset}
- end,
- if AbsOffset =< 4095 ->
- Am2 = #am2{src=Base,sign=Sign,offset=AbsOffset},
- [mk_store(StOp, Src, Am2) | Rest];
- true ->
- Index = mk_scratch(Scratch),
- Am2 = #am2{src=Base,sign=Sign,offset=Index},
- mk_li(Index, AbsOffset,
- [mk_store(StOp, Src, Am2) | Rest])
- end.
-
-mk_pseudo_blr() -> #pseudo_blr{}.
-mk_bx(Src) -> #pseudo_bx{src=Src}.
-mk_mflr(Dst) -> mk_move(Dst, mk_lr()).
-mk_mtlr(Src) -> mk_move(mk_lr(), Src).
-mk_lr() -> mk_temp(hipe_arm_registers:lr(), 'untagged').
-mk_pc() -> mk_temp(hipe_arm_registers:pc(), 'untagged').
-
-%%% Load an integer constant into a register.
-mk_li(Dst, Value) -> mk_li(Dst, Value, []).
-
-mk_li(Dst, Value, Rest) ->
- %% XXX: expand to handle 2-instruction sequences
- case try_aluop_imm('mov', Value) of
- {NewMovOp,Am1} ->
- [mk_move(NewMovOp, false, Dst, Am1) | Rest];
- [] ->
- [mk_pseudo_li(Dst, Value) | Rest]
- end.
-
-%%% Add an integer constant. Dst may equal Src,
-%%% in which case temp2 may be clobbered.
-
-mk_addi(Dst, Src, Value, Rest) ->
- case try_aluop_imm('add', Value) of
- {NewAluOp,Am1} ->
- [mk_alu(NewAluOp, Dst, Src, Am1) | Rest];
- [] ->
- Tmp =
- begin
- DstReg = temp_reg(Dst),
- SrcReg = temp_reg(Src),
- if DstReg =:= SrcReg ->
- mk_temp(hipe_arm_registers:temp2(), 'untagged');
- true -> Dst
- end
- end,
- [mk_pseudo_li(Tmp, Value), mk_alu('add', Dst, Src, Tmp) | Rest]
- end.
-
-try_aluop_imm(AluOp, Imm) -> % -> {NewAluOp,Am1} or []
- case imm_to_am1(Imm) of
- (Am1={_Imm8,_Imm4}) -> {AluOp, Am1};
- [] ->
- case invert_aluop_imm(AluOp, Imm) of
- {NewAluOp,NewImm} ->
- case imm_to_am1(NewImm) of
- (Am1={_Imm8,_Imm4}) -> {NewAluOp, Am1};
- [] -> []
- end;
- [] -> []
- end
- end.
-
-invert_aluop_imm(AluOp, Imm) ->
- case AluOp of
- 'mov' -> {'mvn', bnot Imm};
- 'mvn' -> {'mov', bnot Imm};
- 'cmp' -> {'cmn', -Imm};
- 'cmn' -> {'cmp', -Imm};
- 'and' -> {'bic', bnot Imm};
- 'bic' -> {'and', bnot Imm};
- 'orr' -> {'orn', bnot Imm};
- 'orn' -> {'orr', bnot Imm};
- 'add' -> {'sub', -Imm};
- 'sub' -> {'add', -Imm};
- _ -> [] % no inverted form available
- end.
-
-imm_to_am1(Imm) -> imm_to_am1(Imm band 16#FFFFFFFF, 16).
-imm_to_am1(Imm, RotCnt) ->
- if Imm >= 0, Imm =< 255 -> {Imm, RotCnt band 15};
- true ->
- NewRotCnt = RotCnt - 1,
- if NewRotCnt =:= 0 -> []; % full circle, no joy
- true ->
- NewImm = (Imm bsr 2) bor ((Imm band 3) bsl 30),
- imm_to_am1(NewImm, NewRotCnt)
- end
- end.
-
-mk_defun(MFA, Formals, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) ->
- #defun{mfa=MFA, formals=Formals, code=Code, data=Data,
- isclosure=IsClosure, isleaf=IsLeaf,
- var_range=VarRange, label_range=LabelRange}.
-defun_mfa(#defun{mfa=MFA}) -> MFA.
-defun_formals(#defun{formals=Formals}) -> Formals.
-defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure.
-defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf.
-defun_code(#defun{code=Code}) -> Code.
-defun_data(#defun{data=Data}) -> Data.
-defun_var_range(#defun{var_range=VarRange}) -> VarRange.
diff --git a/lib/hipe/arm/hipe_arm.hrl b/lib/hipe/arm/hipe_arm.hrl
deleted file mode 100644
index be06b1ebd7..0000000000
--- a/lib/hipe/arm/hipe_arm.hrl
+++ /dev/null
@@ -1,119 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
-%%%--------------------------------------------------------------------
-%%% Basic Values:
-%%%
-%%% temp ::= #arm_temp{reg, type, allocatable}
-%%% reg ::= <token from hipe_arm_registers>
-%%% type ::= tagged | untagged
-%%% allocatable ::= true | false
-%%%
-%%% sdesc ::= #arm_sdesc{exnlab, fsize, arity, live}
-%%% exnlab ::= [] | label
-%%% fsize ::= int32 (frame size in words)
-%%% live ::= <tuple of int32> (word offsets)
-%%% arity ::= uint8
-%%%
-%%% mfa ::= #arm_mfa{atom, atom, arity}
-%%% prim ::= #arm_prim{atom}
-
--record(arm_mfa, {m::atom(), f::atom(), a::arity()}).
--record(arm_prim, {prim}).
--record(arm_sdesc, {exnlab, fsize, arity::arity(), live}).
--record(arm_temp, {reg, type, allocatable}).
-
-%%% Instruction Operands:
-%%%
-%%% aluop ::= adc | add | and | bic | eor | orr | rsb | rsc | sbc | sub
-%%% cmpop ::= cmn | cmp | tst | teq (alu with s flag and no dst)
-%%% cond ::= eq | ne | hs | lo | mi | pl | vs | vc | hi | ls | ge | lt | gt | le | al
-%%% ldop ::= ldr | ldrb (am2)
-%%% movop ::= mov | mvn (alu with no src)
-%%% stop ::= str | strb (am2)
-%%%
-%%% dst ::= temp
-%%% src ::= temp
-%%%
-%%% s ::= true | false
-%%%
-%%% imm<N> ::= <an N-bit non-negative integer>
-%%%
-%%% Note: am1 represents all 11 variants of "Adressing Mode 1".
-%%%
-%%% am1 ::= {imm8,imm4} imm8 rotated right 2*imm4 bits
-%%% | src
-%%% | {src,rrx}
-%%% | {src,shiftop,imm5}
-%%% | {src,shiftop,src}
-%%% shiftop ::= lsl | lsr | asr | ror
-%%%
-%%% Note: am2 can represent the first 3 variants of "Addressing Mode 2",
-%%% i.e., not the pre- or post-indexed variants.
-%%%
-%%% am2 ::= #am2{src, sign, am2offset}
-%%% am2offset ::= imm12 | src | {src,rrx} | {src,shiftop,imm5}
-%%% sign ::= + | -
-%%%
-%%% Note: am3 can represent the first 2 variants of "Addressing Mode 3",
-%%% i.e., not the pre- or post-indexed variants.
-%%%
-%%% am3 ::= #am3{src, sign, am3offset}
-%%% am3offset ::= imm8 | src
-%%%
-%%% fun ::= mfa | prim
-%%% funv ::= mfa | prim | temp
-%%%
-%%% immediate ::= int32 | atom | {label,label_type}
-%%% label_type ::= constant | closure | c_const
-
--record(am2, {src, sign, offset}).
--record(am3, {src, sign, offset}).
-
-%%% Instructions:
-
--record(alu, {aluop, s, dst, src, am1}).% cond not included
--record(b_fun, {'fun', linkage}). % known tailcall; cond not included
--record(b_label, {'cond', label}). % local jump
--record(bl, {'fun', sdesc, linkage}). % known recursive call; cond not included
--record(blx, {src, sdesc}). % computed recursive call; cond not included
--record(cmp, {cmpop, src, am1}). % cond not included
--record(comment, {term}).
--record(label, {label}).
--record(load, {ldop, dst, am2}). % cond not included; ldrh/ldrsh not included
--record(ldrsb, {dst, am3}). % cond not included
--record(move, {movop, s, dst, am1}). % cond not included
--record(pseudo_bc, {'cond', true_label, false_label, pred}).
--record(pseudo_blr, {}). % alias for "mov pc,lr" to help cfg
--record(pseudo_bx, {src}). % alias for "mov pc,src" to help cfg
--record(pseudo_call, {funv, sdesc, contlab, linkage}).
--record(pseudo_call_prepare, {nrstkargs}).
--record(pseudo_li, {dst, imm, label}). % pre-generated label for use by the assembler
--record(pseudo_move, {dst, src}).
--record(pseudo_spill_move, {dst, temp, src}).
--record(pseudo_switch, {jtab, index, labels}).
--record(pseudo_tailcall, {funv, arity, stkargs, linkage}).
--record(pseudo_tailcall_prepare, {}).
--record(smull, {dstlo, dsthi, src1, src2}). % cond not included, s not included
--record(store, {stop, src, am2}). % cond not included; strh not included
-
-%%% Function definitions.
-
--include("../misc/hipe_consttab.hrl").
-
--record(defun, {mfa :: mfa(), formals, code,
- data :: hipe_consttab(),
- isclosure :: boolean(),
- isleaf :: boolean(),
- var_range, label_range}).
diff --git a/lib/hipe/arm/hipe_arm_assemble.erl b/lib/hipe/arm/hipe_arm_assemble.erl
deleted file mode 100644
index 9aa730afa9..0000000000
--- a/lib/hipe/arm/hipe_arm_assemble.erl
+++ /dev/null
@@ -1,617 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_assemble).
--export([assemble/4]).
-
--include("../main/hipe.hrl"). % for VERSION_STRING, when_option
--include("hipe_arm.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../rtl/hipe_literals.hrl").
--undef(ASSERT).
--define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).
-
-assemble(CompiledCode, Closures, Exports, Options) ->
- print("****************** Assembling *******************\n", [], Options),
- %%
- Code = [{MFA,
- hipe_arm:defun_code(Defun),
- hipe_arm:defun_data(Defun)}
- || {MFA, Defun} <- CompiledCode],
- %%
- {ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code),
- %%
- {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =
- encode(translate(Code, ConstMap), Options),
- print("Total num bytes=~w\n", [CodeSize], Options),
- %%
- SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
- SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
- ConstAlign, ConstSize,
- SC,
- DataRelocs, % nee LM, LabelMap
- SSE,
- CodeSize,CodeBinary,SlimRefs,
- 0,[] % ColdCodeSize, SlimColdRefs
- ]),
- %%
- Bin.
-
-%%%
-%%% Assembly Pass 1.
-%%% Process initial {MFA,Code,Data} list.
-%%% Translate each MFA's body, choosing operand & instruction kinds.
-%%% Manage placement of large immediates in the code segment. (ARM-specific)
-%%%
-%%% Assembly Pass 2.
-%%% Perform short/long form optimisation for jumps.
-%%% (Trivial on ARM.)
-%%%
-%%% Result is {MFA,NewCode,CodeSize,LabelMap} list.
-%%%
-
-translate(Code, ConstMap) ->
- translate_mfas(Code, ConstMap, []).
-
-translate_mfas([{MFA,Insns,_Data}|Code], ConstMap, NewCode) ->
- {NewInsns,CodeSize,LabelMap} = translate_insns(Insns, MFA, ConstMap),
- translate_mfas(Code, ConstMap, [{MFA,NewInsns,CodeSize,LabelMap}|NewCode]);
-translate_mfas([], _ConstMap, NewCode) ->
- lists:reverse(NewCode).
-
-translate_insns(Insns, MFA, ConstMap) ->
- translate_insns(Insns, MFA, ConstMap, gb_trees:empty(), 0, [],
- previous_empty(), pending_empty()).
-
-translate_insns([I|Is] = Insns, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms) ->
- IsNotFallthroughInsn = is_not_fallthrough_insn(I),
- MustFlushPending = must_flush_pending(PendImms, Address),
- {NewIs,Insns1,PendImms1,DoFlushPending} =
- case {MustFlushPending,IsNotFallthroughInsn} of
- {true,false} ->
- %% To avoid having to create new symbolic labels, which is problematic
- %% in the assembler, we emit a forward branch with an offset computed
- %% from the size of the pending literals.
- N = pending_size(PendImms), % N >= 1 since MustFlushPending is true
- BranchOffset = N - 1, % in units of 32-bit words!
- NewIs0 = [{b, {do_cond('al'),{imm24,BranchOffset}}, #comment{term='skip'}}],
- %% io:format("~w: forced flush of pending literals in ~w at ~w\n", [?MODULE,MFA,Address]),
- {NewIs0,Insns,PendImms,true};
- {_,_} ->
- {NewIs0,PendImms0} = translate_insn(I, MFA, ConstMap, Address, PrevImms, PendImms),
- {NewIs0,Is,PendImms0,IsNotFallthroughInsn}
- end,
- add_insns(NewIs, Insns1, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms1, DoFlushPending);
-translate_insns([], _MFA, _ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms) ->
- {LabelMap1, Address1, NewInsns1, _PrevImms1} = % at end-of-function we ignore PrevImms1
- flush_pending(PendImms, LabelMap, Address, NewInsns, PrevImms),
- {lists:reverse(NewInsns1), Address1, LabelMap1}.
-
-add_insns([I|Is], Insns, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms, DoFlushPending) ->
- NewLabelMap =
- case I of
- {'.label',L,_} ->
- gb_trees:insert(L, Address, LabelMap);
- _ ->
- LabelMap
- end,
- Address1 = Address + insn_size(I),
- add_insns(Is, Insns, MFA, ConstMap, NewLabelMap, Address1, [I|NewInsns], PrevImms, PendImms, DoFlushPending);
-add_insns([], Insns, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms, DoFlushPending) ->
- {LabelMap1, Address1, NewInsns1, PrevImms1, PendImms1} =
- case DoFlushPending of
- true ->
- {LabelMap0,Address0,NewInsns0,PrevImms0} =
- flush_pending(PendImms, LabelMap, Address, NewInsns, PrevImms),
- {LabelMap0,Address0,NewInsns0,PrevImms0,pending_empty()};
- false ->
- PrevImms0 = expire_previous(PrevImms, Address),
- {LabelMap,Address,NewInsns,PrevImms0,PendImms}
- end,
- translate_insns(Insns, MFA, ConstMap, LabelMap1, Address1, NewInsns1, PrevImms1, PendImms1).
-
-must_flush_pending(PendImms, Address) ->
- case pending_firstref(PendImms) of
- [] -> false;
- LP0 ->
- Distance = Address - LP0,
- %% In "LP0: ldr R,[PC +/- imm12]", the PC value is LP0+8 so the
- %% range for the ldr is [LP0-4084, LP0+4100] (32-bit alignment!).
- %% LP0+4096 is the last point where we can emit a branch (4 bytes)
- %% followed by the pending immediates.
- %%
- %% The translation of an individual instruction must not advance
- %% . by more than 4 bytes, because that could cause us to miss
- %% the point where PendImms must be flushed.
- ?ASSERT(Distance =< 4096),
- Distance =:= 4096
- end.
-
-flush_pending(PendImms, LabelMap, Address, Insns, PrevImms) ->
- Address1 = Address + 4*pending_size(PendImms),
- PrevImms1 = expire_previous(PrevImms, Address1),
- {LabelMap1,Address1,Insns1,PrevImms2} =
- flush_pending2(pending_to_list(PendImms), LabelMap, Address, Insns, PrevImms1),
- PrevImms3 = expire_previous(PrevImms2, Address1),
- {LabelMap1,Address1,Insns1,PrevImms3}.
-
-flush_pending2([{Lab,RelocOrInt,Imm}|Imms], LabelMap, Address, Insns, PrevImms) ->
- PrevImms1 = previous_append(PrevImms, Address, Lab, Imm),
- LabelMap1 = gb_trees:insert(Lab, Address, LabelMap),
- {RelocOpt,LongVal} =
- if is_integer(RelocOrInt) ->
- {[],RelocOrInt};
- true ->
- {[RelocOrInt],0}
- end,
- Insns1 =
- [{'.long', LongVal, #comment{term=Imm}} |
- RelocOpt ++
- [{'.label', Lab, #comment{term=Imm}} |
- Insns]],
- flush_pending2(Imms, LabelMap1, Address+4, Insns1, PrevImms1);
-flush_pending2([], LabelMap, Address, Insns, PrevImms) ->
- {LabelMap, Address, Insns, PrevImms}.
-
-expire_previous(PrevImms, CodeAddress) ->
- case previous_findmin(PrevImms) of
- [] -> PrevImms;
- {ImmAddress,_Imm} ->
- if CodeAddress - ImmAddress > 4084 ->
- expire_previous(previous_delmin(PrevImms), CodeAddress);
- true ->
- PrevImms
- end
- end.
-
-is_not_fallthrough_insn(I) ->
- case I of
- #b_fun{} -> true;
- #b_label{'cond'='al'} -> true;
- %% bl and blx are not included since they return to ".+4"
- %% a load to PC was originally a pseudo_switch insn
- #load{dst=#arm_temp{reg=15,type=Type}} when Type =/= 'double' -> true;
- %% a move to PC was originally a pseudo_blr or pseudo_bx insn
- #move{dst=#arm_temp{reg=15,type=Type}} when Type =/= 'double' -> true;
- _ -> false
- end.
-
-insn_size(I) ->
- case I of
- {'.label',_,_} -> 0;
- {'.reloc',_,_} -> 0;
- _ -> 4
- end.
-
-translate_insn(I, MFA, ConstMap, Address, PrevImms, PendImms) ->
- case I of
- %% pseudo_li is the only insn using MFA, ConstMap, Address, PrevImms, or PendLits
- #pseudo_li{} -> do_pseudo_li(I, MFA, ConstMap, Address, PrevImms, PendImms);
- _ -> {translate_insn(I), PendImms}
- end.
-
-translate_insn(I) -> % -> [{Op,Opnd,OrigI}]
- case I of
- #alu{} -> do_alu(I);
- #b_fun{} -> do_b_fun(I);
- #b_label{} -> do_b_label(I);
- #bl{} -> do_bl(I);
- #blx{} -> do_blx(I);
- #cmp{} -> do_cmp(I);
- #comment{} -> [];
- #label{} -> do_label(I);
- #load{} -> do_load(I);
- #ldrsb{} -> do_ldrsb(I);
- #move{} -> do_move(I);
- %% pseudo_b: eliminated by finalise
- %% pseudo_blr: eliminated by finalise
- %% pseudo_call: eliminated by finalise
- %% pseudo_call_prepare: eliminated by frame
- %% pseudo_li: handled separately
- %% pseudo_move: eliminated by frame
- %% pseudo_switch: eliminated by finalise
- %% pseudo_tailcall: eliminated by frame
- %% pseudo_tailcall_prepare: eliminated by finalise
- #smull{} -> do_smull(I);
- #store{} -> do_store(I)
- end.
-
-do_alu(I) ->
- #alu{aluop=AluOp,s=S,dst=Dst,src=Src,am1=Am1} = I,
- NewCond = do_cond('al'),
- NewS = do_s(S),
- NewDst = do_reg(Dst),
- NewSrc = do_reg(Src),
- NewAm1 = do_am1(Am1),
- {NewI,NewOpnds} = {AluOp, {NewCond,NewS,NewDst,NewSrc,NewAm1}},
- [{NewI, NewOpnds, I}].
-
-do_b_fun(I) ->
- #b_fun{'fun'=Fun,linkage=Linkage} = I,
- [{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},
- {b, {do_cond('al'),{imm24,0}}, I}].
-
-do_b_label(I) ->
- #b_label{'cond'=Cond,label=Label} = I,
- [{b, {do_cond(Cond),do_label_ref(Label)}, I}].
-
-do_bl(I) ->
- #bl{'fun'=Fun,sdesc=SDesc,linkage=Linkage} = I,
- [{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},
- {bl, {do_cond('al'),{imm24,0}}, I},
- {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}}].
-
-do_blx(I) ->
- #blx{src=Src,sdesc=SDesc} = I,
- [{blx, {do_cond('al'),do_reg(Src)}, I},
- {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}}].
-
-do_cmp(I) ->
- #cmp{cmpop=CmpOp,src=Src,am1=Am1} = I,
- NewCond = do_cond('al'),
- NewSrc = do_reg(Src),
- NewAm1 = do_am1(Am1),
- [{CmpOp, {NewCond,NewSrc,NewAm1}, I}].
-
-do_label(I) ->
- #label{label=Label} = I,
- [{'.label', Label, I}].
-
-do_load(I) ->
- #load{ldop=LdOp,dst=Dst,am2=Am2} = I,
- NewCond = do_cond('al'),
- NewDst = do_reg(Dst),
- NewAm2 = do_am2(Am2),
- [{LdOp, {NewCond,NewDst,NewAm2}, I}].
-
-do_ldrsb(I) ->
- #ldrsb{dst=Dst,am3=Am3} = I,
- NewCond = do_cond('al'),
- NewDst = do_reg(Dst),
- NewAm3 = do_am3(Am3),
- [{'ldrsb', {NewCond,NewDst,NewAm3}, I}].
-
-do_move(I) ->
- #move{movop=MovOp,s=S,dst=Dst,am1=Am1} = I,
- NewCond = do_cond('al'),
- NewS = do_s(S),
- NewDst = do_reg(Dst),
- NewAm1 = do_am1(Am1),
- [{MovOp, {NewCond,NewS,NewDst,NewAm1}, I}].
-
-do_pseudo_li(I, MFA, ConstMap, Address, PrevImms, PendImms) ->
- #pseudo_li{dst=Dst,imm=Imm,label=Label0} = I,
- {Label1,PendImms1} =
- case previous_lookup(PrevImms, Imm) of
- {value,Lab} -> {Lab,PendImms};
- none ->
- case pending_lookup(PendImms, Imm) of
- {value,Lab} -> {Lab,PendImms};
- none ->
- RelocOrInt =
- if is_integer(Imm) ->
- %% This is for immediates that require too much work
- %% to reconstruct using only arithmetic instructions.
- Imm;
- true ->
- RelocData =
- case Imm of
- Atom when is_atom(Atom) ->
- {load_atom, Atom};
- {Label,constant} ->
- ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
- {load_address, {constant,ConstNo}};
- {Label,closure} ->
- {load_address, {closure,Label}};
- {Label,c_const} ->
- {load_address, {c_const,Label}}
- end,
- {'.reloc', RelocData, #comment{term=reloc}}
- end,
- Lab = Label0, % preallocated: creating labels in the assembler doesn't work
- {Lab, pending_append(PendImms, Address, Lab, RelocOrInt, Imm)}
- end
- end,
- NewDst = do_reg(Dst),
- {[{'.pseudo_li', {NewDst,do_label_ref(Label1)}, I}], PendImms1}.
-
-do_smull(I) ->
- #smull{dstlo=DstLo,dsthi=DstHi,src1=Src1,src2=Src2} = I,
- NewCond = do_cond('al'),
- NewS = do_s(false),
- NewDstLo = do_reg(DstLo),
- NewDstHi = do_reg(DstHi),
- NewSrc1 = do_reg(Src1),
- NewSrc2 = do_reg(Src2),
- [{'smull', {NewCond,NewS,NewDstLo,NewDstHi,NewSrc1,NewSrc2}, I}].
-
-do_store(I) ->
- #store{stop=StOp,src=Src,am2=Am2} = I,
- NewCond = do_cond('al'),
- NewSrc = do_reg(Src),
- NewAm2 = do_am2(Am2),
- [{StOp, {NewCond,NewSrc,NewAm2}, I}].
-
-do_reg(#arm_temp{reg=Reg,type=Type})
- when is_integer(Reg), 0 =< Reg, Reg < 16, Type =/= 'double' ->
- {r,Reg}.
-
-do_cond(Cond) -> {'cond',Cond}.
-
-do_s(S) -> {'s', case S of false -> 0; true -> 1 end}.
-
-do_label_ref(Label) when is_integer(Label) ->
- {label,Label}. % symbolic, since offset is not yet computable
-
-do_am1(Am1) ->
- case Am1 of
- #arm_temp{} -> do_reg(Am1);
- {Src1,'rrx'} -> {do_reg(Src1),'rrx'};
- {Src1,ShiftOp,Src2=#arm_temp{}} -> {do_reg(Src1),{ShiftOp,do_reg(Src2)}};
- {Src1,ShiftOp,Imm5} -> {do_reg(Src1),{ShiftOp,{imm5,Imm5}}};
- {Imm8,Imm4} -> {{imm8,Imm8},{imm4,Imm4}}
- end.
-
-do_am2(#am2{src=Src,sign=Sign,offset=Offset}) ->
- NewSrc = do_reg(Src),
- case Offset of
- #arm_temp{} -> {'register_offset',NewSrc,Sign,do_reg(Offset)};
- {Src3,'rrx'} -> {'scaled_register_offset',NewSrc,Sign,do_reg(Src3),'rrx'};
- {Src3,ShiftOp,Imm5} -> {'scaled_register_offset',NewSrc,Sign,do_reg(Src3),{ShiftOp,{imm5,Imm5}}};
- Imm12 -> {'immediate_offset',NewSrc,Sign,{imm12,Imm12}}
- end.
-
-do_am3(#am3{src=Src,sign=Sign,offset=Offset}) ->
- NewSrc = do_reg(Src),
- case Offset of
- #arm_temp{} -> {'register_offset',NewSrc,Sign,do_reg(Offset)};
- _ -> {'immediate_offset',NewSrc,Sign,{'imm8',Offset}}
- end.
-
-%%%
-%%% Assembly Pass 3.
-%%% Process final {MFA,Code,CodeSize,LabelMap} list from pass 2.
-%%% Translate to a single binary code segment.
-%%% Collect relocation patches.
-%%% Build ExportMap (MFA-to-address mapping).
-%%% Combine LabelMaps to a single one (for mk_data_relocs/2 compatibility).
-%%% Return {CombinedCodeSize,BinaryCode,Relocs,CombinedLabelMap,ExportMap}.
-%%%
-
-encode(Code, Options) ->
- CodeSize = compute_code_size(Code, 0),
- ExportMap = build_export_map(Code, 0, []),
- {AccCode,Relocs} = encode_mfas(Code, 0, [], [], Options),
- CodeBinary = list_to_binary(lists:reverse(AccCode)),
- ?ASSERT(CodeSize =:= byte_size(CodeBinary)),
- CombinedLabelMap = combine_label_maps(Code, 0, gb_trees:empty()),
- {CodeSize,CodeBinary,Relocs,CombinedLabelMap,ExportMap}.
-
-compute_code_size([{_MFA,_Insns,CodeSize,_LabelMap}|Code], Size) ->
- compute_code_size(Code, Size+CodeSize);
-compute_code_size([], Size) -> Size.
-
-build_export_map([{{M,F,A},_Insns,CodeSize,_LabelMap}|Code], Address, ExportMap) ->
- build_export_map(Code, Address+CodeSize, [{Address,M,F,A}|ExportMap]);
-build_export_map([], _Address, ExportMap) -> ExportMap.
-
-combine_label_maps([{MFA,_Insns,CodeSize,LabelMap}|Code], Address, CLM) ->
- NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
- combine_label_maps(Code, Address+CodeSize, NewCLM);
-combine_label_maps([], _Address, CLM) -> CLM.
-
-merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
- NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
- merge_label_map(Rest, MFA, Address, NewCLM);
-merge_label_map([], _MFA, _Address, CLM) -> CLM.
-
-encode_mfas([{MFA,Insns,CodeSize,LabelMap}|Code], Address, AccCode, Relocs, Options) ->
- print("Generating code for: ~w\n", [MFA], Options),
- print("Offset | Opcode | Instruction\n", [], Options),
- {Address1,Relocs1,AccCode1} =
- encode_insns(Insns, Address, Address, LabelMap, Relocs, AccCode, Options),
- ExpectedAddress = Address + CodeSize,
- ?ASSERT(Address1 =:= ExpectedAddress),
- print("Finished.\n", [], Options),
- encode_mfas(Code, Address1, AccCode1, Relocs1, Options);
-encode_mfas([], _Address, AccCode, Relocs, _Options) ->
- {AccCode,Relocs}.
-
-encode_insns([I|Insns], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case I of
- {'.label',L,_} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ?ASSERT(Address =:= LabelAddress), % sanity check
- print_insn(Address, [], I, Options),
- encode_insns(Insns, Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- {'.reloc',Data,_} ->
- print_insn(Address, [], I, Options),
- Reloc = encode_reloc(Data, Address, FunAddress, LabelMap),
- encode_insns(Insns, Address, FunAddress, LabelMap, [Reloc|Relocs], AccCode, Options);
- {'.long',Value,_} ->
- print_insn(Address, Value, I, Options),
- Segment = <<Value:32/integer-native>>,
- NewAccCode = [Segment|AccCode],
- encode_insns(Insns, Address+4, FunAddress, LabelMap, Relocs, NewAccCode, Options);
- _ ->
- {Op,Arg,_} = fix_pc_refs(I, Address, FunAddress, LabelMap),
- Word = hipe_arm_encode:insn_encode(Op, Arg),
- print_insn(Address, Word, I, Options),
- Segment = <<Word:32/integer-native>>,
- NewAccCode = [Segment|AccCode],
- encode_insns(Insns, Address+4, FunAddress, LabelMap, Relocs, NewAccCode, Options)
- end;
-encode_insns([], Address, _FunAddress, _LabelMap, Relocs, AccCode, _Options) ->
- {Address,Relocs,AccCode}.
-
-encode_reloc(Data, Address, FunAddress, LabelMap) ->
- case Data of
- {b_fun,MFAorPrim,Linkage} ->
- %% b and bl are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case Linkage of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- {PatchTypeExt, Address, untag_mfa_or_prim(MFAorPrim)};
- {load_atom,Atom} ->
- {?LOAD_ATOM, Address, Atom};
- {load_address,X} ->
- {?LOAD_ADDRESS, Address, X};
- {sdesc,SDesc} ->
- #arm_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live} = SDesc,
- ExnRA =
- case ExnLab of
- [] -> []; % don't cons up a new one
- ExnLab -> gb_trees:get(ExnLab, LabelMap) + FunAddress
- end,
- {?SDESC, Address,
- ?STACK_DESC(ExnRA, FSize, Arity, Live)}
- end.
-
-untag_mfa_or_prim(#arm_mfa{m=M,f=F,a=A}) -> {M,F,A};
-untag_mfa_or_prim(#arm_prim{prim=Prim}) -> Prim.
-
-fix_pc_refs(I, InsnAddress, FunAddress, LabelMap) ->
- case I of
- {b, {Cond,{label,L}}, OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- Imm24 = (LabelAddress - (InsnAddress+8)) div 4,
- %% ensure Imm24 fits in a 24 bit sign-extended field
- ?ASSERT(Imm24 =< 16#7FFFFF),
- ?ASSERT(Imm24 >= -(16#800000)),
- {b, {Cond,{imm24,Imm24 band 16#FFFFFF}}, OrigI};
- {'.pseudo_li', {Dst,{label,L}}, OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- Offset = LabelAddress - (InsnAddress+8),
- {Sign,Imm12} =
- if Offset < 0 -> {'-', -Offset};
- true -> {'+', Offset}
- end,
- ?ASSERT(Imm12 =< 16#FFF),
- Am2 = {'immediate_offset',{r,15},Sign,{imm12,Imm12}},
- {ldr, {do_cond('al'),Dst,Am2}, OrigI};
- _ -> I
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%
-%%% Assembly listing support (pp_asm option).
-%%%
-
-print(String, Arglist, Options) ->
- ?when_option(pp_asm, Options, io:format(String, Arglist)).
-
-print_insn(Address, Word, I, Options) ->
- ?when_option(pp_asm, Options, print_insn_2(Address, Word, I)).
-
-print_insn_2(Address, Word, {NewI,NewArgs,OrigI}) ->
- io:format("~8.16.0b | ", [Address]),
- print_code_list(word_to_bytes(Word), 0),
- case NewI of
- '.long' ->
- io:format("\t.long ~.16x\n", [Word, "0x"]);
- '.reloc' ->
- io:format("\t.reloc ~w\n", [NewArgs]);
- _ ->
- hipe_arm_pp:pp_insn(OrigI)
- end.
-
-word_to_bytes(W) ->
- case W of
- [] -> []; % label or other pseudo instruction
- _ -> [(W bsr 24) band 16#FF, (W bsr 16) band 16#FF,
- (W bsr 8) band 16#FF, W band 16#FF]
- end.
-
-print_code_list([Byte|Rest], Len) ->
- print_byte(Byte),
- print_code_list(Rest, Len+1);
-print_code_list([], Len) ->
- fill_spaces(8-(Len*2)),
- io:format(" | ").
-
-print_byte(Byte) ->
- io:format("~2.16.0b", [Byte band 16#FF]).
-
-fill_spaces(N) when N > 0 ->
- io:format(" "),
- fill_spaces(N-1);
-fill_spaces(0) ->
- [].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%
-%%% ADT for previous immediates.
-%%% This is a queue (fifo) of the previously defined immediates,
-%%% plus a mapping from these immediates to their labels.
-%%%
--record(previous, {set, head, tail}). % INV: tail=[] if head=[]
-
-previous_empty() -> #previous{set=gb_trees:empty(), head=[], tail=[]}.
-
-previous_lookup(#previous{set=S}, Imm) -> gb_trees:lookup(Imm, S).
-
-previous_findmin(#previous{head=H}) ->
- case H of
- [X|_] -> X;
- _ -> []
- end.
-
-previous_delmin(#previous{set=S, head=[{_Address,Imm}|H], tail=T}) ->
- {NewH,NewT} =
- case H of
- [] -> {lists:reverse(T), []};
- _ -> {H, T}
- end,
- #previous{set=gb_trees:delete(Imm, S), head=NewH, tail=NewT}.
-
-previous_append(#previous{set=S, head=H, tail=T}, Address, Lab, Imm) ->
- {NewH,NewT} =
- case H of
- [] -> {[{Address,Imm}], []};
- _ -> {H, [{Address,Imm}|T]}
- end,
- #previous{set=gb_trees:insert(Imm, Lab, S), head=NewH, tail=NewT}.
-
-%%%
-%%% ADT for pending immediates.
-%%% This is a queue (fifo) of immediates pending definition,
-%%% plus a mapping from these immediates to their labels,
-%%% and a recording of the first (lowest) code address referring
-%%% to a pending immediate.
-%%%
--record(pending, {set, list, firstref}).
-
-pending_empty() -> #pending{set=gb_trees:empty(), list=[], firstref=[]}.
-
-pending_to_list(#pending{list=L}) -> lists:reverse(L).
-
-pending_lookup(#pending{set=S}, Imm) -> gb_trees:lookup(Imm, S).
-
-pending_firstref(#pending{firstref=F}) -> F.
-
-pending_append(#pending{set=S, list=L, firstref=F}, Address, Lab, RelocOrInt, Imm) ->
- #pending{set=gb_trees:insert(Imm, Lab, S),
- list=[{Lab,RelocOrInt,Imm}|L],
- firstref=case F of [] -> Address; _ -> F end}.
-
-pending_size(#pending{list=L}) -> length(L).
diff --git a/lib/hipe/arm/hipe_arm_cfg.erl b/lib/hipe/arm/hipe_arm_cfg.erl
deleted file mode 100644
index 0bc3df30b9..0000000000
--- a/lib/hipe/arm/hipe_arm_cfg.erl
+++ /dev/null
@@ -1,148 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_cfg).
-
--export([init/1,
- labels/1, start_label/1,
- succ/2,
- map_bbs/2, fold_bbs/3,
- bb/2, bb_add/3]).
--export([postorder/1]).
--export([linearise/1]).
--export([params/1, reverse_postorder/1]).
--export([arity/1]). % for linear scan
-%%-export([redirect_jmp/3]).
--export([branch_preds/1]).
-
-%%% these tell cfg.inc what to define (ugly as hell)
--define(BREADTH_ORDER,true). % for linear scan
--define(PARAMS_NEEDED,true).
--define(START_LABEL_UPDATE_NEEDED,true).
--define(MAP_FOLD_NEEDED,true).
-
--include("hipe_arm.hrl").
--include("../flow/cfg.hrl").
--include("../flow/cfg.inc").
-
-init(Defun) ->
- Code = hipe_arm:defun_code(Defun),
- StartLab = hipe_arm:label_label(hd(Code)),
- Data = hipe_arm:defun_data(Defun),
- IsClosure = hipe_arm:defun_is_closure(Defun),
- Name = hipe_arm:defun_mfa(Defun),
- IsLeaf = hipe_arm:defun_is_leaf(Defun),
- Formals = hipe_arm:defun_formals(Defun),
- CFG0 = mk_empty_cfg(Name, StartLab, Data, IsClosure, IsLeaf, Formals),
- take_bbs(Code, CFG0).
-
-is_branch(I) ->
- case I of
- #b_fun{} -> true;
- #b_label{'cond'='al'} -> true;
- #pseudo_bc{} -> true;
- #pseudo_blr{} -> true;
- #pseudo_bx{} -> true;
- #pseudo_call{} -> true;
- #pseudo_switch{} -> true;
- #pseudo_tailcall{} -> true;
- _ -> false
- end.
-
-branch_successors(Branch) ->
- case Branch of
- #b_fun{} -> [];
- #b_label{'cond'='al',label=Label} -> [Label];
- #pseudo_bc{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
- #pseudo_blr{} -> [];
- #pseudo_bx{} -> [];
- #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=ExnLab}} ->
- case ExnLab of
- [] -> [ContLab];
- _ -> [ContLab,ExnLab]
- end;
- #pseudo_switch{labels=Labels} -> Labels;
- #pseudo_tailcall{} -> []
- end.
-
-branch_preds(Branch) ->
- case Branch of
- #pseudo_bc{true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
- [{FalseLab, 1.0-Pred}, {TrueLab, Pred}];
- #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=[]}} ->
- %% A function can still cause an exception, even if we won't catch it
- [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}];
- #pseudo_call{contlab=ContLab, sdesc=#arm_sdesc{exnlab=ExnLab}} ->
- CallExnPred = hipe_bb_weights:call_exn_pred(),
- [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}];
- #pseudo_switch{labels=Labels} ->
- Prob = 1.0/length(Labels),
- [{L, Prob} || L <- Labels];
- _ ->
- case branch_successors(Branch) of
- [] -> [];
- [Single] -> [{Single, 1.0}]
- end
- end.
-
--ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
-fails_to(_Instr) -> [].
--endif.
-
--ifdef(notdef).
-redirect_jmp(I, Old, New) ->
- case I of
- #b_label{label=Label} ->
- if Old =:= Label -> I#b_label{label=New};
- true -> I
- end;
- #pseudo_bc{true_label=TrueLab, false_label=FalseLab} ->
- I1 = if Old =:= TrueLab -> I#pseudo_bc{true_label=New};
- true -> I
- end,
- if Old =:= FalseLab -> I1#pseudo_bc{false_label=New};
- true -> I1
- end;
- %% handle pseudo_call too?
- _ -> I
- end.
--endif.
-
-mk_goto(Label) ->
- hipe_arm:mk_b_label(Label).
-
-is_label(I) ->
- hipe_arm:is_label(I).
-
-label_name(Label) ->
- hipe_arm:label_label(Label).
-
-mk_label(Name) ->
- hipe_arm:mk_label(Name).
-
-linearise(CFG) -> % -> defun, not insn list
- MFA = function(CFG),
- Formals = params(CFG),
- Code = linearize_cfg(CFG),
- Data = data(CFG),
- VarRange = hipe_gensym:var_range(arm),
- LabelRange = hipe_gensym:label_range(arm),
- IsClosure = is_closure(CFG),
- IsLeaf = is_leaf(CFG),
- hipe_arm:mk_defun(MFA, Formals, IsClosure, IsLeaf,
- Code, Data, VarRange, LabelRange).
-
-arity(CFG) ->
- {_M, _F, A} = function(CFG),
- A.
diff --git a/lib/hipe/arm/hipe_arm_defuse.erl b/lib/hipe/arm/hipe_arm_defuse.erl
deleted file mode 100644
index 652299a514..0000000000
--- a/lib/hipe/arm/hipe_arm_defuse.erl
+++ /dev/null
@@ -1,160 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_defuse).
--export([insn_def_all/1, insn_use_all/1]).
--export([insn_def_gpr/1, insn_use_gpr/1]).
--export([insn_defs_all_gpr/1]).
--include("hipe_arm.hrl").
-
-%%%
-%%% Defs and uses for both general-purpose and floating-point registers.
-%%% This is needed for the frame module, alas.
-%%%
-insn_def_all(I) ->
- insn_def_gpr(I).
-
-insn_use_all(I) ->
- insn_use_gpr(I).
-
-%%%
-%%% Defs and uses for general-purpose (integer) registers only.
-%%%
-insn_def_gpr(I) ->
- case I of
- #alu{dst=Dst} -> [Dst];
- #load{dst=Dst} -> [Dst];
- #ldrsb{dst=Dst} -> [Dst];
- #move{dst=Dst} -> [Dst];
- #pseudo_call{} -> call_clobbered_gpr();
- #pseudo_li{dst=Dst} -> [Dst];
- #pseudo_move{dst=Dst} -> [Dst];
- #pseudo_spill_move{dst=Dst, temp=Temp} -> [Dst, Temp];
- #pseudo_tailcall_prepare{} -> tailcall_clobbered_gpr();
- #smull{dstlo=DstLo,dsthi=DstHi,src1=Src1} ->
- %% ARM requires DstLo, DstHi, and Src1 to be distinct.
- %% Add fake DEF of Src1 to prevent regalloc from reusing
- %% it as DstLo or DstHi.
- [DstLo, DstHi, Src1];
- _ -> []
- end.
-
-insn_defs_all_gpr(I) ->
- case I of
- #pseudo_call{} -> true;
- _ -> false
- end.
-
-call_clobbered_gpr() ->
- [hipe_arm:mk_temp(R, T)
- || {R,T} <- hipe_arm_registers:call_clobbered() ++ all_fp_pseudos()].
-
-all_fp_pseudos() -> []. % XXX: for now
-
-tailcall_clobbered_gpr() ->
- [hipe_arm:mk_temp(R, T)
- || {R,T} <- hipe_arm_registers:tailcall_clobbered() ++ all_fp_pseudos()].
-
-insn_use_gpr(I) ->
- case I of
- #alu{src=Src,am1=Am1} -> am1_use(Am1, [Src]);
- #blx{src=Src} -> [Src];
- #cmp{src=Src,am1=Am1} -> am1_use(Am1, [Src]);
- #load{am2=Am2} -> am2_use(Am2, []);
- #ldrsb{am3=Am3} -> am3_use(Am3, []);
- #move{am1=Am1} -> am1_use(Am1, []);
- #pseudo_blr{} ->
- LR = hipe_arm:mk_temp(hipe_arm_registers:lr(), 'untagged'),
- RV = hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged'),
- [RV, LR];
- #pseudo_bx{src=Src} ->
- io:format("~w: whoa there! insn_use of ~w occurred\n", [?MODULE,I]),
- [Src];
- #pseudo_call{funv=FunV,sdesc=#arm_sdesc{arity=Arity}} ->
- funv_use(FunV, arity_use_gpr(Arity));
- #pseudo_move{src=Src} -> [Src];
- #pseudo_spill_move{src=Src} -> [Src];
- #pseudo_switch{jtab=JTabR,index=IndexR} -> addtemp(JTabR, [IndexR]);
- #pseudo_tailcall{funv=FunV,arity=Arity,stkargs=StkArgs} ->
- addargs(StkArgs, addtemps(tailcall_clobbered_gpr(), funv_use(FunV, arity_use_gpr(Arity))));
- #smull{src1=Src1,src2=Src2} -> addtemp(Src1, [Src2]);
- #store{src=Src,am2=Am2} -> am2_use(Am2, [Src]);
- _ -> []
- end.
-
-addargs([Arg|Args], Set) ->
- addargs(Args, addarg(Arg, Set));
-addargs([], Set) ->
- Set.
-
-addarg(Arg, Set) ->
- case Arg of
- #arm_temp{} -> addtemp(Arg, Set);
- _ -> Set
- end.
-
-arity_use_gpr(Arity) ->
- [hipe_arm:mk_temp(R, 'tagged')
- || R <- hipe_arm_registers:args(Arity)].
-
-funv_use(FunV, Set) ->
- case FunV of
- #arm_temp{} -> addtemp(FunV, Set);
- _ -> Set
- end.
-
-am1_use(Am1, Set) ->
- case Am1 of
- #arm_temp{} -> addtemp(Am1, Set);
- {Src,rrx} -> addtemp(Src, Set);
- {Src,_,ShiftArg} ->
- Set1 = addtemp(Src, Set),
- case ShiftArg of
- #arm_temp{} -> addtemp(ShiftArg, Set1);
- _ -> Set1
- end;
- _ -> Set
- end.
-
-am2_use(#am2{src=Src,offset=Am2Offset}, Set) ->
- Set1 = addtemp(Src, Set),
- case Am2Offset of
- #arm_temp{} -> addtemp(Am2Offset, Set1);
- {Src2,_} -> addtemp(Src2, Set1);
- {Src2,_,_} -> addtemp(Src2, Set1);
- _ -> Set1
- end.
-
-am3_use(#am3{src=Src,offset=Am3Offset}, Set) ->
- Set1 = addtemp(Src, Set),
- case Am3Offset of
- #arm_temp{} -> addtemp(Am3Offset, Set1);
- _ -> Set1
- end.
-
-%%%
-%%% Auxiliary operations on sets of temps
-%%% These sets are small. No point using gb_trees, right?
-%%%
-
-addtemps([Arg|Args], Set) ->
- addtemps(Args, addtemp(Arg, Set));
-addtemps([], Set) ->
- Set.
-
-addtemp(Temp, Set) ->
- case lists:member(Temp, Set) of
- false -> [Temp|Set];
- _ -> Set
- end.
diff --git a/lib/hipe/arm/hipe_arm_encode.erl b/lib/hipe/arm/hipe_arm_encode.erl
deleted file mode 100644
index dedb6547bb..0000000000
--- a/lib/hipe/arm/hipe_arm_encode.erl
+++ /dev/null
@@ -1,989 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Encode symbolic ARM instructions to binary form.
-%%% Copyright (C) 2005 Mikael Pettersson
-%%%
-%%% Implementation Notes:
-%%% - The Thumb instruction set is a different entity, and is
-%%% not and never will be supported by this module.
-%%% - Instructions and instruction forms that are unpredictable
-%%% or useless in User mode are not supported. They include:
-%%% + Data Processing Instructions with S=1 and Rd=15.
-%%% + The LDM(2), LDM(3), and STM(2) instructions.
-%%% + MRS instructions that access the SPSR.
-%%% + MSR instructions that access the SPSR.
-%%% + The LDBRT, LDRT, STBRT, and STRT instructions.
-%%%
-%%% Instruction Operands:
-%%%
-%%% S ::= {s,0} | {s,1}
-%%% L ::= {l,0} | {l,1}
-%%% R ::= {r,RNum}
-%%% CR ::= {cr,CRNum}
-%%%
-%%% Cond ::= {cond,CondName}
-%%% CondName ::= eq | ne | cs | hs | cc | lo | mi | pl | vs
-%%% | vc | hi | ls | ge | lt | gt | ge | al
-%%%
-%%% Imm<N> ::= {imm<N>,<N bits>} for N in 4, 5, 8, 12, 16, 24, and 25
-%%%
-%%% Am1ShifterOperand
-%%% ::= {Imm8,Imm4}
-%%% | Rm
-%%% | {Rm,Am1ShiftOp}
-%%% Am1ShiftOp ::= {ShiftOp,Imm5}
-%%% | {ShiftOp,Rs}
-%%% | rrx
-%%% ShiftOp ::= lsl | lsr | asr | ror
-%%%
-%%% Am2LSWUBOperand ::= {immediate_offset,Rn,Sign,Imm12}
-%%% | {register_offset,Rn,Sign,Rm} // redundant
-%%% | {scaled_register_offset,Rn,Sign,Rm,Am2ShiftOp}
-%%% | {immediate_pre_indexed,Rn,Sign,Imm12}
-%%% | {register_pre_indexed,Rn,Sign,Rm} // redundant
-%%% | {scaled_register_pre_indexed,Rn,Sign,Rm,Am2ShiftOp}
-%%% | {immediate_post_indexed,Rn,Sign,Imm12}
-%%% | {register_post_indexed,Rn,Sign,Rm} // redundant
-%%% | {scaled_register_post_indexed,Rn,Sign,Rm,Am2ShiftOp}
-%%% Am2ShiftOp ::= {ShiftOp,Imm5}
-%%% | rrx
-%%% Sign ::= + | -
-%%%
-%%% Am3MiscLSOperand::= {immediate_offset,Rn,Sign,Imm8}
-%%% | {register_offset,Rn,Sign,Rm}
-%%% | {immediate_pre_indexed,Rn,Sign,Imm8}
-%%% | {register_pre_indexed,Rn,Sign,Rm}
-%%% | {immediate_post_indexed,Rn,Sign,Imm8}
-%%% | {register_post_indexed,Rn,Sign,Rm}
-%%%
-%%% Am4LSMultiple ::= ia | ib | da | db
-%%% | fd | ed | fa | ea
-%%%
-%%% Am5LSCoprocessor::= {offset,Rn,Sign,Imm8}
-%%% | {pre_indexed,Rn,Sign,Imm8}
-%%% | {post_indexed,Rn,Sign,Imm8}
-%%% | {unindexed,Rn,Imm8}
-
--module(hipe_arm_encode).
-
--export([insn_encode/2]).
-
-%%-define(TESTING,1).
--ifdef(TESTING).
--export([dotest/0, dotest/1]).
--endif.
-
--define(ASSERT(G),
- if G -> [];
- true -> exit({assertion_failed,?MODULE,?LINE,??G})
- end).
-
-bf(LeftBit, RightBit, Value) ->
- ?ASSERT(32 > LeftBit),
- ?ASSERT(LeftBit >= RightBit),
- ?ASSERT(RightBit >= 0),
- ?ASSERT(Value >= 0),
- ?ASSERT(Value < (1 bsl ((LeftBit - RightBit) + 1))),
- Value bsl RightBit.
-
--define(BF(LB,RB,V), bf(LB,RB,V)).
--define(BIT(Pos,Val), ?BF(Pos,Pos,Val)).
-%%-define(BITS(N,Val), ?BF(N,0,Val)).
-
-%%%
-%%% Addressing Modes
-%%%
-
-am1_shifter_operand(Rn, Rd, ShifterOperand) ->
- case ShifterOperand of
- {{imm8,Imm8},{imm4,RotImm4}} ->
- ?BIT(25,1) bor ?BF(11,8,RotImm4) bor ?BF(7,0,Imm8);
- {r,Rm} ->
- %% same as Rm LSL #0
- ?BF(3,0,Rm);
- {{r,Rm},ShiftOp} ->
- am1_shift_op(Rn, Rd, Rm, ShiftOp) bor ?BF(3,0,Rm)
- end.
-
-am1_shift_op(_Rn, _Rd, _Rm, {ShiftOp,{imm5,ShiftImm5}}) ->
- case ShiftOp of
- 'ror' -> ?ASSERT(ShiftImm5 =/= 0); % denotes RRX form
- _ -> []
- end,
- ?BF(11,7,ShiftImm5) bor shift_op_bits65(ShiftOp);
-am1_shift_op(Rn, Rd, Rm, {ShiftOp,{r,Rs}}) ->
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rs =/= 15), % UNPREDICTABLE
- ?BF(11,8,Rs) bor shift_op_bits65(ShiftOp) bor ?BIT(4,1);
-am1_shift_op(_Rn, _Rd, _Rm, 'rrx') ->
- ?BF(6,5,2#11).
-
-shift_op_bits65(ShiftOp) ->
- case ShiftOp of
- 'lsl' -> ?BF(6,5,2#00);
- 'lsr' -> ?BF(6,5,2#01);
- 'asr' -> ?BF(6,5,2#10);
- 'ror' -> ?BF(6,5,2#11)
- end.
-
-sign('+') -> ?BIT(23,1);
-sign('-') -> 0.
-
-am2_lswub(Rd, AddressingMode) ->
- case AddressingMode of
- {immediate_offset,{r,Rn},Sign,{imm12,Imm12}} ->
- ?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor ?BF(11,0,Imm12);
- {register_offset,{r,Rn},Sign,{r,Rm}} ->
- %% same as scaled_register_offset LSL #0
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
- {scaled_register_offset,{r,Rn},Sign,{r,Rm},ShiftOp} ->
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor am2_shift_op(ShiftOp) bor ?BF(3,0,Rm);
- {immediate_pre_indexed,{r,Rn},Sign,{imm12,Imm12}} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(11,0,Imm12);
- {register_pre_indexed,{r,Rn},Sign,{r,Rm}} ->
- %% same as scaled_register_pre_indexed LSL #0
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= Rm), % UNPREDICTABLE
- ?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
- {scaled_register_pre_indexed,{r,Rn},Sign,{r,Rm},ShiftOp} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= Rm), % UNPREDICTABLE
- ?BIT(25,1) bor ?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor am2_shift_op(ShiftOp) bor ?BF(3,0,Rm);
- {immediate_post_indexed,{r,Rn},Sign,{imm12,Imm12}} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- sign(Sign) bor ?BF(19,16,Rn) bor ?BF(11,0,Imm12);
- {register_post_indexed,{r,Rn},Sign,{r,Rm}} ->
- %% same as scaled_register_post_indexed LSL #0
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?BIT(25,1) bor sign(Sign) bor ?BF(19,6,Rn) bor ?BF(3,0,Rm);
- {scaled_register_post_indexed,{r,Rn},Sign,{r,Rm},ShiftOp} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= Rm), % UNPREDICTABLE
- ?BIT(25,1) bor sign(Sign) bor ?BF(19,16,Rn) bor am2_shift_op(ShiftOp) bor ?BF(3,0,Rm)
- end.
-
-am2_shift_op({ShiftOp,{imm5,ShiftImm5}}) ->
- case ShiftOp of
- 'ror' -> ?ASSERT(ShiftImm5 =/= 0); % denotes RRX form
- _ -> []
- end,
- ?BF(11,7,ShiftImm5) bor shift_op_bits65(ShiftOp);
-am2_shift_op('rrx') ->
- ?BF(6,5,2#11).
-
-am3_miscls(Rd, AddressingMode) ->
- case AddressingMode of
- {immediate_offset,{r,Rn},Sign,{imm8,Imm8}} ->
- ?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#10) bor ?BF(19,16,Rn) bor ?BF(11,8,Imm8 bsr 4) bor ?BF(3,0,Imm8 band 2#1111);
- {register_offset,{r,Rn},Sign,{r,Rm}} ->
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#00) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
- {immediate_pre_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#11) bor ?BF(19,16,Rn) bor ?BF(11,8,Imm8 bsr 4) bor ?BF(3,0,Imm8 band 2#1111);
- {register_pre_indexed,{r,Rn},Sign,{r,Rm}} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= Rn), % UNPREDICTABLE
- ?BIT(24,1) bor sign(Sign) bor ?BF(22,21,2#01) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm);
- {immediate_post_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?BIT(24,0) bor sign(Sign) bor ?BF(22,21,2#10) bor ?BF(19,16,Rn) bor ?BF(11,8,Imm8 bsr 4) bor ?BF(3,0,Imm8 band 2#1111);
- {register_post_indexed,{r,Rn},Sign,{r,Rm}} ->
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= Rn), % UNPREDICTABLE
- ?BIT(24,0) bor sign(Sign) bor ?BF(22,21,2#00) bor ?BF(19,16,Rn) bor ?BF(3,0,Rm)
- end.
-
-am4_ls_multiple(L, AddressingMode) ->
- case AddressingMode of
- 'ia' -> ?BF(24,23,2#01);
- 'ib' -> ?BF(24,23,2#11);
- 'da' -> ?BF(24,23,2#00);
- 'db' -> ?BF(24,23,2#10);
- _ ->
- %% context-sensitive alias crap
- case {L,AddressingMode} of
- {1,'fa'} -> ?BF(24,23,2#00);
- {1,'fd'} -> ?BF(24,23,2#01);
- {1,'ea'} -> ?BF(24,23,2#10);
- {1,'ed'} -> ?BF(24,23,2#11);
- {0,'ed'} -> ?BF(24,23,2#00);
- {0,'ea'} -> ?BF(24,23,2#01);
- {0,'fd'} -> ?BF(24,23,2#10);
- {0,'fa'} -> ?BF(24,23,2#11)
- end
- end.
-
-am5_ls_coprocessor(AddressingMode) ->
- case AddressingMode of
- {offset,{r,Rn},Sign,{imm8,Imm8}} ->
- ?BIT(24,1) bor sign(Sign) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8);
- {pre_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?BIT(24,1) bor sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8);
- {post_indexed,{r,Rn},Sign,{imm8,Imm8}} ->
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- sign(Sign) bor ?BIT(21,1) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8);
- {unindexed,{r,Rn},{imm8,Imm8}} ->
- ?BIT(23,1) bor ?BF(19,16,Rn) bor ?BF(7,0,Imm8)
- end.
-
-%%%
-
-'cond'(Cond) ->
- case Cond of
- 'eq' -> ?BF(31,28,2#0000); % equal
- 'ne' -> ?BF(31,28,2#0001); % not equal
- 'cs' -> ?BF(31,28,2#0010); % carry set
- 'hs' -> ?BF(31,28,2#0010); % unsigned higher or same
- 'cc' -> ?BF(31,28,2#0011); % carry clear
- 'lo' -> ?BF(31,28,2#0011); % unsigned lower
- 'mi' -> ?BF(31,28,2#0100); % minus/negative
- 'pl' -> ?BF(31,28,2#0101); % plus/positive or zero
- 'vs' -> ?BF(31,28,2#0110); % overflow
- 'vc' -> ?BF(31,28,2#0111); % no overflow
- 'hi' -> ?BF(31,28,2#1000); % unsigned higher
- 'ls' -> ?BF(31,28,2#1001); % unsigned lower or same
- 'ge' -> ?BF(31,28,2#1010); % signed greater than or equal
- 'lt' -> ?BF(31,28,2#1011); % signed less than
- 'gt' -> ?BF(31,28,2#1100); % signed greater than
- 'le' -> ?BF(31,28,2#1101); % signed less than or equal
- 'al' -> ?BF(31,28,2#1110) % always
- end.
-
-%%%
-%%% ARM Instructions
-%%%
-
-data_processing_form(Cond, OpCode, S, Rn, Rd, ShifterOperand) ->
- case S of
- 1 -> ?ASSERT(Rd =/= 15); % UNPREDICTABLE in User or System mode
- _ -> []
- end,
- 'cond'(Cond) bor ?BF(24,21,OpCode) bor ?BIT(20,S) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor am1_shifter_operand(Rn,Rd,ShifterOperand).
-
-data_processing_form(OpCode, {{'cond',Cond},{s,S},{r,Rd},{r,Rn},ShifterOperand}) ->
- data_processing_form(Cond, OpCode, S, Rn, Rd, ShifterOperand).
-
-adc(Opnds) -> data_processing_form(2#0101, Opnds).
-add(Opnds) -> data_processing_form(2#0100, Opnds).
-'and'(Opnds) -> data_processing_form(2#0000, Opnds).
-bic(Opnds) -> data_processing_form(2#1110, Opnds).
-eor(Opnds) -> data_processing_form(2#0001, Opnds).
-orr(Opnds) -> data_processing_form(2#1100, Opnds).
-rsb(Opnds) -> data_processing_form(2#0011, Opnds).
-rsc(Opnds) -> data_processing_form(2#0111, Opnds).
-sbc(Opnds) -> data_processing_form(2#0110, Opnds).
-sub(Opnds) -> data_processing_form(2#0010, Opnds).
-
-cmp_form(OpCode, {{'cond',Cond},{r,Rn},ShifterOperand}) ->
- data_processing_form(Cond, OpCode, 1, Rn, 0, ShifterOperand).
-
-cmn(Opnds) -> cmp_form(2#1011, Opnds).
-cmp(Opnds) -> cmp_form(2#1010, Opnds).
-teq(Opnds) -> cmp_form(2#1001, Opnds).
-tst(Opnds) -> cmp_form(2#1000, Opnds).
-
-mov_form(OpCode, {{'cond',Cond},{s,S},{r,Rd},ShifterOperand}) ->
- data_processing_form(Cond, OpCode, S, 0, Rd, ShifterOperand).
-
-mov(Opnds) -> mov_form(2#1101, Opnds).
-mvn(Opnds) -> mov_form(2#1111, Opnds).
-
-%%%
-
-b_form(L, {{'cond',Cond},{imm24,Imm24}}) ->
- 'cond'(Cond) bor ?BF(27,25,2#101) bor ?BIT(24,L) bor ?BF(23,0,Imm24).
-
-b(Opnds) -> b_form(0, Opnds).
-bl(Opnds) -> b_form(1, Opnds).
-
-bkpt({{imm16,Imm16}}) ->
- ?BF(31,28,2#1110) bor ?BF(27,20,2#00010010) bor ?BF(19,8,Imm16 bsr 4) bor ?BF(7,4,2#0111) bor ?BF(3,0,Imm16 band 2#1111).
-
-bx_form(SubOpcode, {{'cond',Cond},{r,Rm}}, IsBlx) ->
- case IsBlx of
- true -> ?ASSERT(Rm =/= 15); % UNPREDICTABLE
- _ -> []
- end,
- 'cond'(Cond) bor ?BF(27,20,2#00010010) bor ?BF(19,16,2#1111) bor ?BF(15,12,2#1111) bor ?BF(11,8,2#1111) bor ?BF(7,4,SubOpcode) bor ?BF(3,0,Rm).
-
-blx(Opnds) ->
- case Opnds of
- {{imm25,Imm25}} -> % u16-offset!
- ?BF(31,28,2#1111) bor ?BF(27,25,2#101) bor ?BIT(24,Imm25 band 1) bor ?BF(23,0,Imm25 bsr 1);
- _ ->
- bx_form(2#0011, Opnds, true)
- end.
-
-bx(Opnds) -> bx_form(2#0001, Opnds, false).
-
-cdp_form(Cond, CpOp4, CRn, CRd, CpNum, CpOp3, CRm) ->
- Cond bor ?BF(27,24,2#1110) bor ?BF(23,20,CpOp4) bor ?BF(19,16,CRn) bor ?BF(15,12,CRd) bor ?BF(11,8,CpNum) bor ?BF(7,5,CpOp3) bor ?BF(3,0,CRm).
-
-cdp({{'cond',Cond},{cpnum,CpNum},{cpop4,CpOp4},{cr,CRd},{cr,CRn},{cr,CRm},{cpop3,CpOp3}}) ->
- cdp_form('cond'(Cond), CpOp4, CRn, CRd, CpNum, CpOp3, CRm).
-
-cdp2({{cpnum,CpNum},{cpop4,CpOp4},{cr,CRd},{cr,CRn},{cr,CRm},{cpop3,CpOp3}}) ->
- cdp_form(?BF(31,28,2#1111), CpOp4, CRn, CRd, CpNum, CpOp3, CRm).
-
-clz({{'cond',Cond},{r,Rd},{r,Rm}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- 'cond'(Cond) bor ?BF(27,20,2#00010110) bor ?BF(19,16,2#1111) bor ?BF(15,12,Rd) bor ?BF(11,8,2#1111) bor ?BF(7,4,2#0001) bor ?BF(3,0,Rm).
-
-ldstc_form(Cond, L, B20, CRd, CpNum, AddressingMode) ->
- Cond bor ?BF(27,25,2#110) bor ?BIT(22,L) bor ?BIT(20,B20) bor ?BF(15,12,CRd) bor ?BF(11,8,CpNum) bor am5_ls_coprocessor(AddressingMode).
-
-ldstc(B20, {{'cond',Cond},{l,L},{cpnum,CpNum},{cr,CRd},AddressingMode}) ->
- ldstc_form('cond'(Cond), L, B20, CRd, CpNum, AddressingMode).
-
-ldc(Opnds) -> ldstc(1, Opnds).
-stc(Opnds) -> ldstc(0, Opnds).
-
-ldstc2(B20, {{l,L},{cpnum,CpNum},{cr,CRd},AddressingMode}) ->
- ldstc_form(?BF(31,28,2#1111), L, B20, CRd, CpNum, AddressingMode).
-
-ldc2(Opnds) -> ldstc2(1, Opnds).
-stc2(Opnds) -> ldstc2(0, Opnds).
-
-ldstm_form(Cond, AddressingMode, W, L, Rn, Registers) ->
- RegisterList = register_list(Registers),
- ?ASSERT(RegisterList =/= 0), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- case W of
- 1 ->
- BitRn = 1 bsl Rn,
- case L of
- 1 ->
- %% LDM! Rn in Registers is UNPREDICTABLE
- ?ASSERT((RegisterList band BitRn) =:= 0);
- 0 ->
- %% STM! Rn in Registers and not lowest is UNPREDICTABLE
- case RegisterList band BitRn of
- 0 -> [];
- _ ->
- ?ASSERT((RegisterList band (-RegisterList)) =:= BitRn)
- end
- end;
- _ -> []
- end,
- 'cond'(Cond) bor ?BF(27,25,2#100) bor am4_ls_multiple(L, AddressingMode) bor ?BIT(21,W) bor ?BIT(20,L) bor ?BF(19,16,Rn) bor ?BF(15,0,RegisterList).
-
-register_list(Registers) -> register_list(Registers, 0).
-
-register_list([{r,R}|Rs], Mask) -> register_list(Rs, Mask bor (1 bsl R));
-register_list([], Mask) -> Mask.
-
-ldstm(L, Opnds) ->
- case Opnds of
- {{'cond',Cond},AddressingMode,{r,Rn},'!',Registers} ->
- ldstm_form(Cond, AddressingMode, 1, L, Rn, Registers);
- {{'cond',Cond},AddressingMode,{r,Rn},Registers} ->
- ldstm_form(Cond, AddressingMode, 0, L, Rn, Registers)
- %% the ldm(2), ldm(3), and stm(2) forms are UNPREDICTABLE
- %% in User or System mode
- end.
-
-ldm(Opnds) -> ldstm(1, Opnds).
-stm(Opnds) -> ldstm(0, Opnds).
-
-ldstr_form2(B, L, {{'cond',Cond},{r,Rd},AddressingMode}) ->
- 'cond'(Cond) bor ?BF(27,26,2#01) bor am2_lswub(Rd, AddressingMode) bor ?BIT(22,B) bor ?BIT(20,L) bor ?BF(15,12,Rd).
-
-ldr(Opnds) -> ldstr_form2(0, 1, Opnds).
-ldrb(Opnds) -> ldstr_form2(1, 1, Opnds).
-str(Opnds) -> ldstr_form2(0, 0, Opnds).
-strb(Opnds) -> ldstr_form2(1, 0, Opnds).
-
-ldstr_form3(L, SubOpcode, {{'cond',Cond},{r,Rd},AddressingMode}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- 'cond'(Cond) bor am3_miscls(Rd, AddressingMode) bor ?BIT(20,L) bor ?BF(15,12,Rd) bor ?BF(7,4,SubOpcode).
-
-ldrh(Opnds) -> ldstr_form3(1, 2#1011, Opnds).
-ldrsb(Opnds) -> ldstr_form3(1, 2#1101, Opnds).
-ldrsh(Opnds) -> ldstr_form3(1, 2#1111, Opnds).
-strh(Opnds) -> ldstr_form3(0, 2#1011, Opnds).
-
-mcr_form(Cond, OP1, CRn, Rd, CpNum, OP2, CRm) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- Cond bor ?BF(27,24,2#1110) bor ?BF(23,21,OP1) bor ?BF(19,16,CRn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,5,OP2) bor ?BIT(4,1) bor ?BF(3,0,CRm).
-
-mcr({{'cond',Cond},{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
- mcr_form('cond'(Cond), OP1, CRn, Rd, CpNum, OP2, CRm).
-
-mcr2({{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
- mcr_form(?BF(31,28,2#1111), OP1, CRn, Rd, CpNum, OP2, CRm).
-
-mla({{'cond',Cond},{s,S},{r,Rd},{r,Rm},{r,Rs},{r,Rn}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rs =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rd =/= Rm), % UNPREDICTABLE
- 'cond'(Cond) bor ?BIT(21,1) bor ?BIT(20,S) bor ?BF(19,16,Rd) bor ?BF(15,12,Rn) bor ?BF(11,8,Rs) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
-
-mrc_form(Cond, OP1, CRn, Rd, CpNum, OP2, CRm) ->
- Cond bor ?BF(27,24,2#1110) bor ?BF(23,21,OP1) bor ?BIT(20,1) bor ?BF(19,16,CRn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,5,OP2) bor ?BIT(4,1) bor ?BF(3,0,CRm).
-
-mrc({{'cond',Cond},{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
- mrc_form('cond'(Cond), OP1, CRn, Rd, CpNum, OP2, CRm).
-
-mrc2({{cpnum,CpNum},{cpop3,OP1},{r,Rd},{cr,CRn},{cr,CRm},{cpop3,OP2}}) ->
- mrc_form(?BF(31,28,2#1111), OP1, CRn, Rd, CpNum, OP2, CRm).
-
-mrs({{'cond',Cond},{r,Rd},'cpsr'}) ->
- %% the SPSR form is UNPREDICTABLE in User or System mode
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- 'cond'(Cond) bor ?BIT(24,1) bor ?BF(19,16,2#1111) bor ?BF(15,12,Rd).
-
-msr_form(Cond, FieldMask4, Operand) ->
- 'cond'(Cond) bor ?BIT(24,1) bor ?BIT(21,1) bor ?BF(19,16,FieldMask4) bor ?BF(15,12,2#1111) bor Operand.
-
-msr(Opnds) ->
- %% the SPSR form is UNPREDICTABLE in User or System mode
- case Opnds of
- {{'cond',Cond},'cpsr',{field_mask,FieldMask4},{imm8,Imm8},{imm4,RotImm4}} ->
- msr_form(Cond, FieldMask4, ?BIT(25,1) bor ?BF(11,8,RotImm4) bor ?BF(7,0,Imm8));
- {{'cond',Cond},'cpsr',{field_mask,FieldMask4},{r,Rm}} ->
- msr_form(Cond, FieldMask4, ?BF(3,0,Rm))
- end.
-
-mul({{'cond',Cond},{s,S},{r,Rd},{r,Rm},{r,Rs}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rs =/= 15), % UNPREDICTABLE
- ?ASSERT(Rd =/= Rm), % UNPREDICTABLE
- 'cond'(Cond) bor ?BIT(20,S) bor ?BF(19,16,Rd) bor ?BF(11,8,Rs) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
-
-ml_form2(OpCode, Cond, S, RdLo, RdHi, Rm, Rs) ->
- ?ASSERT(RdHi =/= 15), % UNPREDICTABLE
- ?ASSERT(RdLo =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rs =/= 15), % UNPREDICTABLE
- ?ASSERT(RdHi =/= RdLo),% UNPREDICTABLE
- ?ASSERT(RdHi =/= Rm), % UNPREDICTABLE
- ?ASSERT(RdLo =/= Rm), % UNPREDICTABLE
- 'cond'(Cond) bor ?BF(27,21,OpCode) bor ?BIT(20,S) bor ?BF(19,16,RdHi) bor ?BF(15,12,RdLo) bor ?BF(11,8,Rs) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
-
-ml_form(OpCode, {{'cond',Cond},{s,S},{r,RdLo},{r,RdHi},{r,Rm},{r,Rs}}) ->
- ml_form2(OpCode, Cond, S, RdLo, RdHi, Rm, Rs).
-
-%%smlal(Opnds) -> ml_form(2#0000111, Opnds).
-smull(Opnds) -> ml_form(2#0000110, Opnds).
-umlal(Opnds) -> ml_form(2#0000101, Opnds).
-umull(Opnds) -> ml_form(2#0000100, Opnds).
-
-swi({{'cond',Cond},{imm24,Imm24}}) ->
- 'cond'(Cond) bor ?BF(27,24,2#1111) bor ?BF(23,0,Imm24).
-
-swp_form(B22, {{'cond',Cond},{r,Rd},{r,Rm},{r,Rn}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= Rm), % UNPREDICTABLE
- ?ASSERT(Rn =/= Rd), % UNPREDICTABLE
- 'cond'(Cond) bor ?BIT(24,1) bor ?BIT(22,B22) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor ?BF(7,4,2#1001) bor ?BF(3,0,Rm).
-
-swp(Opnds) -> swp_form(0, Opnds).
-swpb(Opnds) -> swp_form(1, Opnds).
-
-%%%
-%%% Enhanced DSP Extension Instructions
-%%%
-
-ldstrd_form(OpCode, {{'cond',Cond},{r,Rd},AddressingMode}) ->
- ?ASSERT(Rd =/= 14), % UNPREDICTABLE
- ?ASSERT((Rd band 1) =:= 0), % UNDEFINED
- %% XXX: unpredictable if write-back and base reg Rn equals Rd or Rd+1
- %% XXX: if is load then unpredictable if index reg Rm and Rm equals Rd or Rd+1
- 'cond'(Cond) bor am3_miscls(Rd, AddressingMode) bor ?BF(15,12,Rd) bor ?BF(7,4,OpCode).
-
-ldrd(Opnds) -> ldstrd_form(2#1101, Opnds).
-strd(Opnds) -> ldstrd_form(2#1111, Opnds).
-
-mcrr({{'cond',Cond},{cpnum,CpNum},{cpop4,OP},{r,Rd},{r,Rn},{cr,CRm}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- 'cond'(Cond) bor ?BF(27,20,2#11000100) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,4,OP) bor ?BF(3,0,CRm).
-
-mrrc({{'cond',Cond},{cpnum,CpNum},{cpop4,OP},{r,Rd},{r,Rn},{cr,CRm}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- ?ASSERT(Rd =/= Rn), % UNPREDICTABLE
- 'cond'(Cond) bor ?BF(27,20,2#11000101) bor ?BF(19,16,Rn) bor ?BF(15,12,Rd) bor ?BF(11,8,CpNum) bor ?BF(7,4,OP) bor ?BF(3,0,CRm).
-
-pld({AddressingMode}) ->
- AM = am2_lswub(42, AddressingMode), % 42 is a dummy reg nr
- %% not all adressing modes are allowed: bit 24 must be 1
- %% and bit 21 must be 0
- ?ASSERT(((AM bsr 21) band 2#1001) =:= 2#1000),
- 16#F550F000 bor AM.
-
-q_form(OpCode, {{'cond',Cond},{r,Rd},{r,Rm},{r,Rn}}) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- 'cond'(Cond) bor ?BF(27,20,OpCode) bor ?BF(19,16,Rn) bor ?BF(15,11,Rd) bor ?BF(7,4,2#0101) bor ?BF(3,0,Rm).
-
-qadd(Opnds) -> q_form(2#00010000, Opnds).
-qdadd(Opnds) -> q_form(2#00010100, Opnds).
-qdsub(Opnds) -> q_form(2#00010110, Opnds).
-qsub(Opnds) -> q_form(2#00010010, Opnds).
-
-smlaxy_form(Cond, OpCode, Rd, Rn, Rs, Y, X, Rm) ->
- ?ASSERT(Rd =/= 15), % UNPREDICTABLE
- ?ASSERT(Rm =/= 15), % UNPREDICTABLE
- ?ASSERT(Rs =/= 15), % UNPREDICTABLE
- ?ASSERT(Rn =/= 15), % UNPREDICTABLE
- 'cond'(Cond) bor ?BF(27,20,OpCode) bor ?BF(19,16,Rd) bor ?BF(15,12,Rn) bor ?BF(11,8,Rs) bor ?BIT(7,1) bor ?BIT(6,Y) bor ?BIT(5,X) bor ?BF(3,0,Rm).
-
-smla({{bt,X},{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs},{r,Rn}}) ->
- smlaxy_form(Cond, 2#00010000, Rd, Rn, Rs, Y, X, Rm).
-
-smlal(Opnds) -> % may be regular ARM or DSP insn :-(
- case Opnds of
- {{'cond',Cond},{s,S},{r,RdLo},{r,RdHi},{r,Rm},{r,Rs}} ->
- ml_form2(2#0000111, Cond, S, RdLo, RdHi, Rm, Rs);
- {{bt,X},{bt,Y},{'cond',Cond},{r,RdLo},{r,RdHi},{r,Rm},{r,Rs}} ->
- ?ASSERT(RdLo =/= RdHi), % UNPREDICTABLE
- smlaxy_form(Cond, 2#00010100, RdHi, RdLo, Rs, Y, X, Rm)
- end.
-
-smlaw({{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs},{r,Rn}}) ->
- smlaxy_form(Cond, 2#00010010, Rd, Rn, Rs, Y, 0, Rm).
-
-smul({{bt,X},{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs}}) ->
- smlaxy_form(Cond, 2#00010110, Rd, 0, Rs, Y, X, Rm).
-
-smulw({{bt,Y},{'cond',Cond},{r,Rd},{r,Rm},{r,Rs}}) ->
- smlaxy_form(Cond, 2#00010010, Rd, 0, Rs, Y, 1, Rm).
-
-%%%
-%%% Main Encode Dispatch
-%%%
-
-insn_encode(Op, Opnds) ->
- case Op of
- 'adc' -> adc(Opnds);
- 'add' -> add(Opnds);
- 'and' -> 'and'(Opnds);
- 'b' -> b(Opnds);
- 'bic' -> bic(Opnds);
- 'bkpt' -> bkpt(Opnds);
- 'bl' -> bl(Opnds);
- 'blx' -> blx(Opnds);
- 'bx' -> bx(Opnds);
- 'cdp' -> cdp(Opnds);
- 'cdp2' -> cdp2(Opnds);
- 'clz' -> clz(Opnds);
- 'cmn' -> cmn(Opnds);
- 'cmp' -> cmp(Opnds);
- 'eor' -> eor(Opnds);
- 'ldc' -> ldc(Opnds);
- 'ldc2' -> ldc2(Opnds);
- 'ldm' -> ldm(Opnds);
- 'ldr' -> ldr(Opnds);
- 'ldrb' -> ldrb(Opnds);
- 'ldrd' -> ldrd(Opnds);
- %% ldrbt: omitted
- 'ldrh' -> ldrh(Opnds);
- 'ldrsb' -> ldrsb(Opnds);
- 'ldrsh' -> ldrsh(Opnds);
- %% ldrt: omitted
- 'mcr' -> mcr(Opnds);
- 'mcr2' -> mcr2(Opnds);
- 'mcrr' -> mcrr(Opnds);
- 'mla' -> mla(Opnds);
- 'mov' -> mov(Opnds);
- 'mrc' -> mrc(Opnds);
- 'mrc2' -> mrc2(Opnds);
- 'mrrc' -> mrrc(Opnds);
- 'mrs' -> mrs(Opnds);
- 'msr' -> msr(Opnds);
- 'mul' -> mul(Opnds);
- 'mvn' -> mvn(Opnds);
- 'orr' -> orr(Opnds);
- 'pld' -> pld(Opnds);
- 'qadd' -> qadd(Opnds);
- 'qdadd' -> qdadd(Opnds);
- 'qdsub' -> qdsub(Opnds);
- 'qsub' -> qsub(Opnds);
- 'rsb' -> rsb(Opnds);
- 'rsc' -> rsc(Opnds);
- 'sbc' -> sbc(Opnds);
- 'smla' -> smla(Opnds);
- 'smlal' -> smlal(Opnds); % may be regular ARM or DSP insn :-(
- 'smlaw' -> smlaw(Opnds);
- 'smull' -> smull(Opnds);
- 'smul' -> smul(Opnds);
- 'smulw' -> smulw(Opnds);
- 'stc' -> stc(Opnds);
- 'stc2' -> stc2(Opnds);
- 'stm' -> stm(Opnds);
- 'str' -> str(Opnds);
- 'strb' -> strb(Opnds);
- %% strbt: omitted
- 'strd' -> strd(Opnds);
- 'strh' -> strh(Opnds);
- %% strt: omitted
- 'sub' -> sub(Opnds);
- 'swi' -> swi(Opnds);
- 'swp' -> swp(Opnds);
- 'swpb' -> swpb(Opnds);
- 'teq' -> teq(Opnds);
- 'tst' -> tst(Opnds);
- 'umlal' -> umlal(Opnds);
- 'umull' -> umull(Opnds);
- _ -> exit({?MODULE,insn_encode,Op})
- end.
-
-%%%
-%%% Testing Interface
-%%%
-
--ifdef(TESTING).
-
-say(OS, Str) ->
- file:write(OS, Str).
-
-hex_digit(Dig0) ->
- Dig = Dig0 band 16#F,
- if Dig >= 16#A -> $A + (Dig - 16#A);
- true -> $0 + Dig
- end.
-
-say_byte(OS, Byte) ->
- say(OS, [hex_digit(Byte bsr 4)]),
- say(OS, [hex_digit(Byte)]).
-
-say_word(OS, Word) ->
- say(OS, "0x"),
- say_byte(OS, Word bsr 24),
- say_byte(OS, Word bsr 16),
- say_byte(OS, Word bsr 8),
- say_byte(OS, Word).
-
-t(OS, Op, Opnds) ->
- Word = insn_encode(Op, Opnds),
- say(OS, "\t.long "),
- say_word(OS, Word),
- say(OS, "\n").
-
-dotest1(OS) ->
- say(OS, "\t.text\n\t.align 4\n"),
- %%
- Rn = {r,9},
- Rd = {r,8}, % must be even and less than 14 for some insns
- Rm = {r,7},
- Rs = {r,6},
- RdLo = Rn,
- RdHi = Rd,
- Registers = [Rm,Rs,Rd], % must exclude Rn for some insns
- CRd = {cr,15},
- CRn = {cr,14},
- CRm = {cr,13},
- BT0 = {bt,0},
- BT1 = {bt,1},
- CpNum = {cpnum,15},
- CpOp3 = {cpop3,16#3},
- CpOp4 = {cpop4,16#F},
- L0 = {l,0},
- L1 = {l,1},
- S0 = {s,0},
- S1 = {s,1},
- FieldMask4 = {field_mask,16#F},
- Imm4 = {imm4,16#F},
- Imm5 = {imm5,16#1F},
- Imm8 = {imm8,16#FF},
- Imm12 = {imm12,16#FFF},
- Imm16 = {imm16,16#FFFF},
- Imm24 = {imm24,16#FFFFF},
- Imm25 = {imm25,16#FFFFF1},
- %%
- AM1_1 = {Imm8,Imm4},
- AM1_2 = Rm,
- AM1_3_1 = {Rm,{'lsl',Imm5}},
- AM1_3_2 = {Rm,{'lsr',Imm5}},
- AM1_3_3 = {Rm,{'asr',Imm5}},
- AM1_3_4 = {Rm,{'ror',Imm5}},
- AM1_3_5 = {Rm,{'lsl',Rs}},
- AM1_3_6 = {Rm,{'lsr',Rs}},
- AM1_3_7 = {Rm,{'asr',Rs}},
- AM1_3_8 = {Rm,{'ror',Rs}},
- AM1_3_9 = {Rm,'rrx'},
- %%
- AM2ShiftOp1 = {'lsl',Imm5},
- AM2ShiftOp2 = {'lsr',Imm5},
- AM2ShiftOp3 = {'asr',Imm5},
- AM2ShiftOp4 = {'ror',Imm5},
- AM2ShiftOp5 = 'rrx',
- SignP = '+',
- SignM = '-',
- AM2_1_1 = {immediate_offset,Rn,SignP,Imm12},
- AM2_1_2 = {immediate_offset,Rn,SignM,Imm12},
- AM2_2_1 = {register_offset,Rn,SignP,Rm},
- AM2_2_2 = {register_offset,Rn,SignM,Rm},
- AM2_3_1 = {scaled_register_offset,Rn,SignP,Rm,AM2ShiftOp1},
- AM2_3_2 = {scaled_register_offset,Rn,SignM,Rm,AM2ShiftOp2},
- AM2_3_3 = {scaled_register_offset,Rn,SignP,Rm,AM2ShiftOp3},
- AM2_3_4 = {scaled_register_offset,Rn,SignM,Rm,AM2ShiftOp4},
- AM2_3_5 = {scaled_register_offset,Rn,SignP,Rm,AM2ShiftOp5},
- AM2_4_1 = {immediate_pre_indexed,Rn,SignP,Imm12},
- AM2_4_2 = {immediate_pre_indexed,Rn,SignM,Imm12},
- AM2_5_1 = {register_pre_indexed,Rn,SignP,Rm},
- AM2_5_2 = {register_pre_indexed,Rn,SignM,Rm},
- AM2_6_1 = {scaled_register_pre_indexed,Rn,SignP,Rm,AM2ShiftOp1},
- AM2_6_2 = {scaled_register_pre_indexed,Rn,SignM,Rm,AM2ShiftOp2},
- AM2_6_3 = {scaled_register_pre_indexed,Rn,SignP,Rm,AM2ShiftOp3},
- AM2_6_4 = {scaled_register_pre_indexed,Rn,SignM,Rm,AM2ShiftOp4},
- AM2_6_5 = {scaled_register_pre_indexed,Rn,SignP,Rm,AM2ShiftOp5},
- AM2_7_1 = {immediate_post_indexed,Rn,SignP,Imm12},
- AM2_7_2 = {immediate_post_indexed,Rn,SignM,Imm12},
- AM2_8_1 = {register_post_indexed,Rn,SignP,Rm},
- AM2_8_2 = {register_post_indexed,Rn,SignM,Rm},
- AM2_9_1 = {scaled_register_post_indexed,Rn,SignP,Rm,AM2ShiftOp1},
- AM2_9_2 = {scaled_register_post_indexed,Rn,SignM,Rm,AM2ShiftOp2},
- AM2_9_3 = {scaled_register_post_indexed,Rn,SignP,Rm,AM2ShiftOp3},
- AM2_9_4 = {scaled_register_post_indexed,Rn,SignM,Rm,AM2ShiftOp4},
- AM2_9_5 = {scaled_register_post_indexed,Rn,SignP,Rm,AM2ShiftOp5},
- %%
- AM3_1_1 = {immediate_offset,Rn,SignP,Imm8},
- AM3_1_2 = {immediate_offset,Rn,SignM,Imm8},
- AM3_2_1 = {register_offset,Rn,SignP,Rm},
- AM3_2_2 = {register_offset,Rn,SignM,Rm},
- AM3_3_1 = {immediate_pre_indexed,Rn,SignP,Imm8},
- AM3_3_2 = {immediate_pre_indexed,Rn,SignM,Imm8},
- AM3_4_1 = {register_pre_indexed,Rn,SignP,Rm},
- AM3_4_2 = {register_pre_indexed,Rn,SignM,Rm},
- AM3_5_1 = {immediate_post_indexed,Rn,SignP,Imm8},
- AM3_5_2 = {immediate_post_indexed,Rn,SignM,Imm8},
- AM3_6_1 = {register_post_indexed,Rn,SignP,Rm},
- AM3_6_2 = {register_post_indexed,Rn,SignM,Rm},
- %%
- AM4_1 = 'ia',
- AM4_2 = 'ib',
- AM4_3 = 'da',
- AM4_4 = 'db',
- AM4_5 = 'fa',
- AM4_6 = 'fd',
- AM4_7 = 'ea',
- AM4_8 = 'ed',
- %%
- AM5_1_1 = {offset,Rn,SignP,Imm8},
- AM5_1_2 = {offset,Rn,SignM,Imm8},
- AM5_2_1 = {pre_indexed,Rn,SignP,Imm8},
- AM5_2_2 = {pre_indexed,Rn,SignM,Imm8},
- AM5_3_1 = {post_indexed,Rn,SignP,Imm8},
- AM5_3_2 = {post_indexed,Rn,SignM,Imm8},
- AM5_4 = {unindexed,Rn,Imm8},
- %%
- Cond_eq = {'cond','eq'},
- Cond_ne = {'cond','ne'},
- Cond_cs = {'cond','cs'},
- Cond_hs = {'cond','hs'},
- Cond_cc = {'cond','cc'},
- Cond_lo = {'cond','lo'},
- Cond_mi = {'cond','mi'},
- Cond_pl = {'cond','pl'},
- Cond_vs = {'cond','vs'},
- Cond_vc = {'cond','vc'},
- Cond_hi = {'cond','hi'},
- Cond_ls = {'cond','ls'},
- Cond_ge = {'cond','ge'},
- Cond_lt = {'cond','lt'},
- Cond_gt = {'cond','gt'},
- Cond_le = {'cond','le'},
- Cond_al = {'cond','al'},
- %%
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_1}), % test all AM1 operands
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_2}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_1}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_2}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_3}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_4}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_5}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_6}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_7}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_8}),
- t(OS,'adc',{Cond_al,S0,Rd,Rn,AM1_3_9}),
- t(OS,'add',{Cond_al,S0,Rd,Rn,AM1_1}), % test all S operands
- t(OS,'add',{Cond_al,S1,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_eq,S0,Rd,Rn,AM1_1}), % test all Cond operands
- t(OS,'and',{Cond_ne,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_cs,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_hs,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_cc,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_lo,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_mi,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_pl,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_vs,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_vc,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_hi,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_ls,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_ge,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_lt,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_gt,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_le,S0,Rd,Rn,AM1_1}),
- t(OS,'and',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'b',{Cond_al,Imm24}),
- t(OS,'bic',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'bkpt',{Imm16}),
- t(OS,'bl',{Cond_al,Imm24}),
- t(OS,'blx',{Imm25}),
- t(OS,'blx',{Cond_al,Rm}),
- t(OS,'bx',{Cond_al,Rm}),
- t(OS,'cdp',{Cond_al,CpNum,CpOp4,CRd,CRn,CRm,CpOp3}),
- t(OS,'cdp2',{CpNum,CpOp4,CRd,CRn,CRm,CpOp3}),
- t(OS,'clz',{Cond_al,Rd,Rm}),
- t(OS,'cmn',{Cond_al,Rn,AM1_1}),
- t(OS,'cmp',{Cond_al,Rn,AM1_1}),
- t(OS,'eor',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_1_1}), % test all AM5 operands
- t(OS,'ldc',{Cond_al,L1,CpNum,CRd,AM5_1_2}),
- t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_2_1}),
- t(OS,'ldc',{Cond_al,L1,CpNum,CRd,AM5_2_2}),
- t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_3_1}),
- t(OS,'ldc',{Cond_al,L1,CpNum,CRd,AM5_3_2}),
- t(OS,'ldc',{Cond_al,L0,CpNum,CRd,AM5_4}),
- t(OS,'ldc2',{L0,CpNum,CRd,AM5_1_1}),
- t(OS,'ldm',{Cond_al,AM4_1,Rn,'!',Registers}),
- t(OS,'ldm',{Cond_al,AM4_1,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_2,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_3,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_4,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_5,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_6,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_7,Rn,Registers}), % test all AM4 operands
- t(OS,'ldm',{Cond_al,AM4_8,Rn,Registers}), % test all AM4 operands
- t(OS,'ldr',{Cond_al,Rd,AM2_1_1}), % test all AM2 operands
- t(OS,'ldr',{Cond_al,Rd,AM2_1_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_2_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_2_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_3_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_3_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_3_3}),
- t(OS,'ldr',{Cond_al,Rd,AM2_3_4}),
- t(OS,'ldr',{Cond_al,Rd,AM2_3_5}),
- t(OS,'ldr',{Cond_al,Rd,AM2_4_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_4_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_5_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_5_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_6_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_6_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_6_3}),
- t(OS,'ldr',{Cond_al,Rd,AM2_6_4}),
- t(OS,'ldr',{Cond_al,Rd,AM2_6_5}),
- t(OS,'ldr',{Cond_al,Rd,AM2_7_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_7_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_8_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_8_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_9_1}),
- t(OS,'ldr',{Cond_al,Rd,AM2_9_2}),
- t(OS,'ldr',{Cond_al,Rd,AM2_9_3}),
- t(OS,'ldr',{Cond_al,Rd,AM2_9_4}),
- t(OS,'ldr',{Cond_al,Rd,AM2_9_5}),
- t(OS,'ldrb',{Cond_al,Rd,AM2_1_1}),
- t(OS,'ldrd',{Cond_al,Rd,AM3_1_1}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_1_1}), % test all AM3 operands
- t(OS,'ldrh',{Cond_al,Rd,AM3_1_2}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_2_1}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_2_2}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_3_1}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_3_2}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_4_1}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_4_2}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_5_1}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_5_2}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_6_1}),
- t(OS,'ldrh',{Cond_al,Rd,AM3_6_2}),
- t(OS,'ldrsb',{Cond_al,Rd,AM3_1_1}),
- t(OS,'ldrsh',{Cond_al,Rd,AM3_1_1}),
- t(OS,'mcr',{Cond_al,CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
- t(OS,'mcr2',{CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
- t(OS,'mcrr',{Cond_al,CpNum,CpOp4,Rd,Rn,CRm}),
- t(OS,'mla',{Cond_al,S0,Rd,Rm,Rs,Rn}),
- t(OS,'mov',{Cond_al,S0,Rd,AM1_1}),
- t(OS,'mrc',{Cond_al,CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
- t(OS,'mrc2',{CpNum,CpOp3,Rd,CRn,CRm,CpOp3}),
- t(OS,'mrrc',{Cond_al,CpNum,CpOp4,Rd,Rn,CRm}),
- t(OS,'mrs',{Cond_al,Rd,'cpsr'}),
- t(OS,'msr',{Cond_al,'cpsr',FieldMask4,Imm8,Imm4}),
- t(OS,'msr',{Cond_al,'cpsr',FieldMask4,Rm}),
- t(OS,'mul',{Cond_al,S0,Rd,Rm,Rs}),
- t(OS,'mvn',{Cond_al,S1,Rd,AM1_1}),
- t(OS,'orr',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'pld',{AM2_1_1}),
- t(OS,'qadd',{Cond_al,Rd,Rm,Rn}),
- t(OS,'qdadd',{Cond_al,Rd,Rm,Rn}),
- t(OS,'qdsub',{Cond_al,Rd,Rm,Rn}),
- t(OS,'qsub',{Cond_al,Rd,Rm,Rn}),
- t(OS,'rsb',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'rsc',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'sbc',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'smla',{BT0,BT0,Cond_al,Rd,Rm,Rs,Rn}),
- t(OS,'smla',{BT0,BT1,Cond_al,Rd,Rm,Rs,Rn}),
- t(OS,'smla',{BT1,BT0,Cond_al,Rd,Rm,Rs,Rn}),
- t(OS,'smla',{BT1,BT1,Cond_al,Rd,Rm,Rs,Rn}),
- t(OS,'smlal',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
- t(OS,'smlal',{BT0,BT1,Cond_al,RdLo,RdHi,Rm,Rs}),
- t(OS,'smlaw',{BT1,Cond_al,Rd,Rm,Rs,Rn}),
- t(OS,'smull',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
- t(OS,'smul',{BT1,BT0,Cond_al,Rd,Rm,Rs}),
- t(OS,'smulw',{BT1,Cond_al,Rd,Rm,Rs}),
- t(OS,'stc',{Cond_al,L0,CpNum,CRd,AM5_1_1}),
- t(OS,'stc2',{L0,CpNum,CRd,AM5_1_1}),
- t(OS,'stm',{Cond_al,AM4_1,Rn,Registers}),
- t(OS,'str',{Cond_al,Rd,AM2_1_1}),
- t(OS,'strb',{Cond_al,Rd,AM2_1_1}),
- t(OS,'strd',{Cond_al,Rd,AM3_1_1}),
- t(OS,'strh',{Cond_al,Rd,AM3_1_1}),
- t(OS,'sub',{Cond_al,S0,Rd,Rn,AM1_1}),
- t(OS,'swi',{Cond_al,Imm24}),
- t(OS,'swp',{Cond_al,Rd,Rm,Rn}),
- t(OS,'swpb',{Cond_al,Rd,Rm,Rn}),
- t(OS,'teq',{Cond_al,Rn,AM1_1}),
- t(OS,'tst',{Cond_al,Rn,AM1_1}),
- t(OS,'umlal',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
- t(OS,'umull',{Cond_al,S0,RdLo,RdHi,Rm,Rs}),
- [].
-
-dotest() -> dotest1(group_leader()).
-
-dotest(File) ->
- {ok,OS} = file:open(File, [write]),
- dotest1(OS),
- file:close(OS).
-
--endif.
diff --git a/lib/hipe/arm/hipe_arm_finalise.erl b/lib/hipe/arm/hipe_arm_finalise.erl
deleted file mode 100644
index 3a6fd5a2dd..0000000000
--- a/lib/hipe/arm/hipe_arm_finalise.erl
+++ /dev/null
@@ -1,126 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_finalise).
--export([finalise/2]).
--include("hipe_arm.hrl").
-
-finalise(Defun, Options) ->
- #defun{code=Code0} = Defun,
- Code1Rev = expand(Code0),
- Code2 = case proplists:get_bool(peephole, Options) of
- true -> peep(Code1Rev);
- false -> lists:reverse(Code1Rev)
- end,
- Defun#defun{code=Code2}.
-
-expand(Insns) ->
- expand_list(Insns, []).
-
-expand_list([I|Insns], Accum) ->
- expand_list(Insns, expand_insn(I, Accum));
-expand_list([], Accum) ->
- Accum.
-
-expand_insn(I, Accum) ->
- case I of
- #pseudo_bc{'cond'=Cond,true_label=TrueLab,false_label=FalseLab} ->
- [hipe_arm:mk_b_label(FalseLab),
- hipe_arm:mk_b_label(Cond, TrueLab) |
- Accum];
- #pseudo_blr{} ->
- [hipe_arm:mk_move(hipe_arm:mk_pc(), hipe_arm:mk_lr()) | Accum];
- #pseudo_bx{src=Src} ->
- [hipe_arm:mk_move(hipe_arm:mk_pc(), Src) | Accum];
- #pseudo_call{funv=FunV,sdesc=SDesc,contlab=ContLab,linkage=Linkage} ->
- [hipe_arm:mk_b_label(ContLab),
- case FunV of
- #arm_temp{} -> hipe_arm:mk_blx(FunV, SDesc);
- _ -> hipe_arm:mk_bl(FunV, SDesc, Linkage)
- end |
- Accum];
- #pseudo_switch{jtab=JTab,index=Index} ->
- PC = hipe_arm:mk_pc(),
- Am2 = hipe_arm:mk_am2(JTab, '+', {Index,'lsl',2}),
- [hipe_arm:mk_load('ldr', PC, Am2) | Accum];
- #pseudo_tailcall_prepare{} ->
- Accum;
- _ ->
- [I|Accum]
- end.
-
-%% We do peephole "bottom-up" (in reverse, but applying rules to the correctly
-%% ordered list). This way, we can do replacements that would take multiple
-%% passes with an in-order peephole optimiser.
-%%
-%% N.B., if a rule wants to produce multiple instructions (even if some of them
-%% are unchanged, it should push the additional instructions on the More list,
-%% so that only the top instruction on Insns is new or changed, i.e. tl(Insns)
-%% should have been peepholed previously.
-peep(RevInsns) ->
- peep_list_skip([], RevInsns).
-
-peep_list([#b_label{'cond'='al',label=Label}
- | (Insns = [#label{label=Label}|_])], More) ->
- peep_list_skip(Insns, More);
-
-peep_list([#move{movop='mov',s=false,dst=#arm_temp{reg=Dst}
- ,am1=#arm_temp{reg=Dst}}|Insns], More) ->
- peep_list_skip(Insns, More);
-
-peep_list([#move{movop='mov',s=false,dst=Dst,am1={Src,lsr,Imm}},
- #move{movop='mov',s=false,dst=Dst,am1={Dst,lsl,Imm}}
- |Insns], More) when Imm > 0, Imm =< 8 ->
- peep_list([#alu{aluop='bic',s=false,dst=Dst,src=Src,am1={(1 bsl Imm)-1,0}}
- |Insns], More);
-peep_list([#move{movop='mov',s=false,dst=Dst,am1={Src,lsl,Imm}},
- #move{movop='mov',s=false,dst=Dst,am1={Dst,lsr,Imm}}
- |Insns], More) when Imm >= 24, Imm < 32 ->
- peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src
- ,am1={(1 bsl (32-Imm))-1,0}} | Insns], More);
-
-%% XXX: Load-after-store optimisation should also be applied to RTL, where it
-%% can be more general, expose opportunities for constant propagation, etc.
-peep_list([#store{stop='strb',src=Src,am2=Mem}=Str,
- #load {ldop='ldrb',dst=Dst,am2=Mem} | Insns], More) ->
- peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src,am1={16#ff,0}}|Insns],
- [Str|More]);
-peep_list([#store{stop='str',src=Src,am2=Mem}=Str,
- #load {ldop='ldr',dst=Dst,am2=Mem} | Insns], More) ->
- peep_list([#move{movop='mov',s=false,dst=Dst,am1=Src}|Insns], [Str|More]);
-
-peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src,am1={Mask,0}},
- #alu{aluop='bic',s=false,dst=Dst,src=Dst,am1={InvMask,0}}
- |Insns], More) ->
- peep_list([#alu{aluop='and',s=false,dst=Dst,src=Src
- ,am1={Mask band (bnot InvMask),0}} | Insns], More);
-
-%% XXX: The place that generates brain-dead code like the following should be
-%% fixed rather than trying to patch it over here.
-peep_list([#load{ldop='ldrb',dst=Dst,am2=_Mem},
- #alu{aluop='bic',s=false,dst=Dst,src=Dst,am1={16#ff,0}}
- | Insns], More) ->
- peep_list([#move{movop='mov',s=false,dst=Dst,am1={0,0}}|Insns], More);
-
-peep_list(Insns, [I|More]) ->
- peep_list([I|Insns], More);
-peep_list(Accum, []) ->
- Accum.
-
-%% Used as an optimisation instead of tailcalling peep_list/2 when Insns has
-%% already been peeped or is otherwise uninteresting (such as empty).
-peep_list_skip(Insns, [I|More]) ->
- peep_list([I|Insns], More);
-peep_list_skip(Accum, []) ->
- Accum.
diff --git a/lib/hipe/arm/hipe_arm_frame.erl b/lib/hipe/arm/hipe_arm_frame.erl
deleted file mode 100644
index a1004fb609..0000000000
--- a/lib/hipe/arm/hipe_arm_frame.erl
+++ /dev/null
@@ -1,644 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_frame).
--export([frame/1]).
-
--include("hipe_arm.hrl").
--include("../rtl/hipe_literals.hrl").
-
--define(LIVENESS_ALL, hipe_arm_liveness_gpr). % since we have no FP yet
-
-frame(CFG) ->
- Formals = fix_formals(hipe_arm_cfg:params(CFG)),
- Temps0 = all_temps(CFG, Formals),
- MinFrame = defun_minframe(CFG),
- Temps = ensure_minframe(MinFrame, Temps0),
- ClobbersLR = clobbers_lr(CFG),
- Liveness = ?LIVENESS_ALL:analyse(CFG),
- do_body(CFG, Liveness, Formals, Temps, ClobbersLR).
-
-fix_formals(Formals) ->
- fix_formals(hipe_arm_registers:nr_args(), Formals).
-
-fix_formals(0, Rest) -> Rest;
-fix_formals(N, [_|Rest]) -> fix_formals(N-1, Rest);
-fix_formals(_, []) -> [].
-
-do_body(CFG0, Liveness, Formals, Temps, ClobbersLR) ->
- Context = mk_context(Liveness, Formals, Temps, ClobbersLR),
- CFG1 = do_blocks(CFG0, Context),
- do_prologue(CFG1, Context).
-
-do_blocks(CFG, Context) ->
- hipe_arm_cfg:map_bbs(fun(Lbl, BB) -> do_block(Lbl, BB, Context) end, CFG).
-
-do_block(Label, Block, Context) ->
- Liveness = context_liveness(Context),
- LiveOut = ?LIVENESS_ALL:liveout(Liveness, Label),
- Code = hipe_bb:code(Block),
- NewCode = do_block(Code, LiveOut, Context, context_framesize(Context), []),
- hipe_bb:code_update(Block, NewCode).
-
-do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) ->
- {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0),
- do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode));
-do_block([], _, Context, FPoff, RevCode) ->
- FPoff0 = context_framesize(Context),
- FPoff0 = FPoff,
- lists:reverse(RevCode, []).
-
-do_insn(I, LiveOut, Context, FPoff) ->
- case I of
- #pseudo_blr{} ->
- {do_pseudo_blr(I, Context, FPoff), context_framesize(Context)};
- #pseudo_call{} ->
- do_pseudo_call(I, LiveOut, Context, FPoff);
- #pseudo_call_prepare{} ->
- do_pseudo_call_prepare(I, FPoff);
- #pseudo_move{} ->
- {do_pseudo_move(I, Context, FPoff), FPoff};
- #pseudo_spill_move{} ->
- {do_pseudo_spill_move(I, Context, FPoff), FPoff};
- #pseudo_tailcall{} ->
- {do_pseudo_tailcall(I, Context), context_framesize(Context)};
- _ ->
- {[I], FPoff}
- end.
-
-%%%
-%%% Moves, with Dst or Src possibly a pseudo
-%%%
-
-do_pseudo_move(I, Context, FPoff) ->
- Dst = hipe_arm:pseudo_move_dst(I),
- Src = hipe_arm:pseudo_move_src(I),
- case temp_is_pseudo(Dst) of
- true ->
- Offset = pseudo_offset(Dst, FPoff, Context),
- mk_store('str', Src, Offset, mk_sp(), []);
- _ ->
- case temp_is_pseudo(Src) of
- true ->
- Offset = pseudo_offset(Src, FPoff, Context),
- mk_load('ldr', Dst, Offset, mk_sp(), []);
- _ ->
- [hipe_arm:mk_move(Dst, Src)]
- end
- end.
-
-pseudo_offset(Temp, FPoff, Context) ->
- FPoff + context_offset(Context, Temp).
-
-%%%
-%%% Moves from one spill slot to another
-%%%
-
-do_pseudo_spill_move(I, Context, FPoff) ->
- #pseudo_spill_move{dst=Dst, temp=Temp, src=Src} = I,
- case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of
- false -> % Register allocator changed its mind, turn back to move
- do_pseudo_move(hipe_arm:mk_pseudo_move(Dst, Src), Context, FPoff);
- true ->
- SrcOffset = pseudo_offset(Src, FPoff, Context),
- DstOffset = pseudo_offset(Dst, FPoff, Context),
- case SrcOffset =:= DstOffset of
- true -> []; % omit move-to-self
- false ->
- mk_load('ldr', Temp, SrcOffset, mk_sp(),
- mk_store('str', Temp, DstOffset, mk_sp(), []))
- end
- end.
-
-%%%
-%%% Return - deallocate frame and emit 'ret $N' insn.
-%%%
-
-do_pseudo_blr(I, Context, FPoff) ->
- %% XXX: perhaps use explicit pseudo_move;mtlr,
- %% avoiding the need to hard-code Temp1 here
- %% XXX: typically only one instruction between
- %% the mtlr and the blr, ouch
- restore_lr(FPoff, Context,
- adjust_sp(FPoff + word_size() * context_arity(Context),
- [I])).
-
-restore_lr(FPoff, Context, Rest) ->
- case context_clobbers_lr(Context) of
- false -> Rest;
- true ->
- LR = hipe_arm:mk_lr(),
- mk_load('ldr', LR, FPoff - word_size(), mk_sp(),
- Rest)
- end.
-
-adjust_sp(N, Rest) ->
- if N =:= 0 ->
- Rest;
- true ->
- SP = mk_sp(),
- hipe_arm:mk_addi(SP, SP, N, Rest)
- end.
-
-%%%
-%%% Recursive calls.
-%%%
-
-do_pseudo_call_prepare(I, FPoff0) ->
- %% Create outgoing arguments area on the stack.
- NrStkArgs = hipe_arm:pseudo_call_prepare_nrstkargs(I),
- Offset = NrStkArgs * word_size(),
- {adjust_sp(-Offset, []), FPoff0 + Offset}.
-
-do_pseudo_call(I, LiveOut, Context, FPoff0) ->
- #arm_sdesc{exnlab=ExnLab,arity=OrigArity} = hipe_arm:pseudo_call_sdesc(I),
- FunV = hipe_arm:pseudo_call_funv(I),
- LiveTemps = [Temp || Temp <- LiveOut, temp_is_pseudo(Temp)],
- SDesc = mk_sdesc(ExnLab, Context, LiveTemps),
- ContLab = hipe_arm:pseudo_call_contlab(I),
- Linkage = hipe_arm:pseudo_call_linkage(I),
- CallCode = [hipe_arm:mk_pseudo_call(FunV, SDesc, ContLab, Linkage)],
- StkArity = erlang:max(0, OrigArity - hipe_arm_registers:nr_args()),
- context_need_stack(Context, stack_need(FPoff0, StkArity, FunV)),
- ArgsBytes = word_size() * StkArity,
- {CallCode, FPoff0 - ArgsBytes}.
-
-stack_need(FPoff, StkArity, FunV) ->
- case FunV of
- #arm_prim{} -> FPoff;
- #arm_mfa{m=M,f=F,a=A} ->
- case erlang:is_builtin(M, F, A) of
- true -> FPoff;
- false -> stack_need_general(FPoff, StkArity)
- end;
- _ -> stack_need_general(FPoff, StkArity)
- end.
-
-stack_need_general(FPoff, StkArity) ->
- erlang:max(FPoff, FPoff + (?ARM_LEAF_WORDS - StkArity) * word_size()).
-
-%%%
-%%% Create stack descriptors for call sites.
-%%%
-
-mk_sdesc(ExnLab, Context, Temps) -> % for normal calls
- Temps0 = only_tagged(Temps),
- Live = mk_live(Context, Temps0),
- Arity = context_arity(Context),
- FSize = context_framesize(Context),
- hipe_arm:mk_sdesc(ExnLab, (FSize div word_size())-1, Arity,
- list_to_tuple(Live)).
-
-only_tagged(Temps)->
- [X || X <- Temps, hipe_arm:temp_type(X) =:= 'tagged'].
-
-mk_live(Context, Temps) ->
- lists:sort([temp_to_slot(Context, Temp) || Temp <- Temps]).
-
-temp_to_slot(Context, Temp) ->
- (context_framesize(Context) + context_offset(Context, Temp))
- div word_size().
-
-mk_minimal_sdesc(Context) -> % for inc_stack_0 calls
- hipe_arm:mk_sdesc([], 0, context_arity(Context), {}).
-
-%%%
-%%% Tailcalls.
-%%%
-
-do_pseudo_tailcall(I, Context) -> % always at FPoff=context_framesize(Context)
- Arity = context_arity(Context),
- Args = hipe_arm:pseudo_tailcall_stkargs(I),
- FunV = hipe_arm:pseudo_tailcall_funv(I),
- Linkage = hipe_arm:pseudo_tailcall_linkage(I),
- {Insns, FPoff1} = do_tailcall_args(Args, Context),
- context_need_stack(Context, FPoff1),
- StkArity = length(Args),
- FPoff2 = FPoff1 + (Arity - StkArity) * word_size(),
- context_need_stack(Context, stack_need(FPoff2, StkArity, FunV)),
- I2 =
- case FunV of
- #arm_temp{} ->
- hipe_arm:mk_bx(FunV);
- Fun ->
- hipe_arm:mk_b_fun(Fun, Linkage)
- end,
- %% XXX: break out the LR restore, just like for pseudo_blr?
- restore_lr(context_framesize(Context), Context,
- Insns ++ adjust_sp(FPoff2, [I2])).
-
-do_tailcall_args(Args, Context) ->
- FPoff0 = context_framesize(Context),
- Arity = context_arity(Context),
- FrameTop = word_size()*Arity,
- DangerOff = FrameTop - word_size()*length(Args),
- %%
- Moves = mk_moves(Args, FrameTop, []),
- %%
- {Stores, Simple, Conflict} =
- split_moves(Moves, Context, DangerOff, [], [], []),
- %% sanity check (shouldn't trigger any more)
- if DangerOff < -FPoff0 ->
- exit({?MODULE,do_tailcall_args,DangerOff,-FPoff0});
- true -> []
- end,
- FPoff1 = FPoff0,
- %%
- {Pushes, Pops, FPoff2} = split_conflict(Conflict, FPoff1, [], []),
- %%
- TempReg = hipe_arm_registers:temp1(),
- %%
- {adjust_sp(-(FPoff2 - FPoff1),
- simple_moves(Pushes, FPoff2, TempReg,
- store_moves(Stores, FPoff2, TempReg,
- simple_moves(Simple, FPoff2, TempReg,
- simple_moves(Pops, FPoff2, TempReg,
- []))))),
- FPoff2}.
-
-mk_moves([Arg|Args], Off, Moves) ->
- Off1 = Off - word_size(),
- mk_moves(Args, Off1, [{Arg,Off1}|Moves]);
-mk_moves([], _, Moves) ->
- Moves.
-
-split_moves([Move|Moves], Context, DangerOff, Stores, Simple, Conflict) ->
- {Src,DstOff} = Move,
- case src_is_pseudo(Src) of
- false ->
- split_moves(Moves, Context, DangerOff, [Move|Stores],
- Simple, Conflict);
- true ->
- SrcOff = context_offset(Context, Src),
- Type = typeof_temp(Src),
- if SrcOff =:= DstOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, Conflict);
- SrcOff >= DangerOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, [{SrcOff,DstOff,Type}|Conflict]);
- true ->
- split_moves(Moves, Context, DangerOff, Stores,
- [{SrcOff,DstOff,Type}|Simple], Conflict)
- end
- end;
-split_moves([], _, _, Stores, Simple, Conflict) ->
- {Stores, Simple, Conflict}.
-
-split_conflict([{SrcOff,DstOff,Type}|Conflict], FPoff, Pushes, Pops) ->
- FPoff1 = FPoff + word_size(),
- Push = {SrcOff,-FPoff1,Type},
- Pop = {-FPoff1,DstOff,Type},
- split_conflict(Conflict, FPoff1, [Push|Pushes], [Pop|Pops]);
-split_conflict([], FPoff, Pushes, Pops) ->
- {lists:reverse(Pushes), Pops, FPoff}.
-
-simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) ->
- Temp = hipe_arm:mk_temp(TempReg, Type),
- SP = mk_sp(),
- LoadOff = FPoff+SrcOff,
- StoreOff = FPoff+DstOff,
- simple_moves(Moves, FPoff, TempReg,
- mk_load('ldr', Temp, LoadOff, SP,
- mk_store('str', Temp, StoreOff, SP,
- Rest)));
-simple_moves([], _, _, Rest) ->
- Rest.
-
-store_moves([{Src,DstOff}|Moves], FPoff, TempReg, Rest) ->
- %%Type = typeof_temp(Src),
- SP = mk_sp(),
- StoreOff = FPoff+DstOff,
- {NewSrc,FixSrc} =
- case hipe_arm:is_temp(Src) of
- true ->
- {Src, []};
- _ ->
- Temp = hipe_arm:mk_temp(TempReg, 'untagged'),
- {Temp, hipe_arm:mk_li(Temp, Src)}
- end,
- store_moves(Moves, FPoff, TempReg,
- FixSrc ++ mk_store('str', NewSrc, StoreOff, SP, Rest));
-store_moves([], _, _, Rest) ->
- Rest.
-
-%%%
-%%% Contexts
-%%%
-
--record(context, {liveness, framesize, arity, map, clobbers_lr, ref_maxstack}).
-
-mk_context(Liveness, Formals, Temps, ClobbersLR) ->
- {Map, MinOff} = mk_temp_map(Formals, ClobbersLR, Temps),
- FrameSize = (-MinOff),
- RefMaxStack = hipe_bifs:ref(FrameSize),
- #context{liveness=Liveness,
- framesize=FrameSize, arity=length(Formals),
- map=Map, clobbers_lr=ClobbersLR, ref_maxstack=RefMaxStack}.
-
-context_need_stack(#context{ref_maxstack=RM}, N) ->
- M = hipe_bifs:ref_get(RM),
- if N > M -> hipe_bifs:ref_set(RM, N);
- true -> []
- end.
-
-context_maxstack(#context{ref_maxstack=RM}) ->
- hipe_bifs:ref_get(RM).
-
-context_arity(#context{arity=Arity}) ->
- Arity.
-
-context_framesize(#context{framesize=FrameSize}) ->
- FrameSize.
-
-context_liveness(#context{liveness=Liveness}) ->
- Liveness.
-
-context_offset(#context{map=Map}, Temp) ->
- tmap_lookup(Map, Temp).
-
-context_clobbers_lr(#context{clobbers_lr=ClobbersLR}) -> ClobbersLR.
-
-mk_temp_map(Formals, ClobbersLR, Temps) ->
- {Map, 0} = enter_vars(Formals, word_size() * length(Formals),
- tmap_empty()),
- TempsList = tset_to_list(Temps),
- AllTemps =
- case ClobbersLR of
- false -> TempsList;
- true ->
- RA = hipe_arm:mk_new_temp('untagged'),
- [RA|TempsList]
- end,
- enter_vars(AllTemps, 0, Map).
-
-enter_vars([V|Vs], PrevOff, Map) ->
- Off =
- case hipe_arm:temp_type(V) of
- 'double' -> PrevOff - 2*word_size();
- _ -> PrevOff - word_size()
- end,
- enter_vars(Vs, Off, tmap_bind(Map, V, Off));
-enter_vars([], Off, Map) ->
- {Map, Off}.
-
-tmap_empty() ->
- gb_trees:empty().
-
-tmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-tmap_lookup(Map, Key) ->
- gb_trees:get(Key, Map).
-
-%%%
-%%% do_prologue: prepend stack frame allocation code.
-%%%
-%%% NewStart:
-%%% temp1 = *(P + P_SP_LIMIT)
-%%% temp2 = SP - MaxStack
-%%% cmp temp2, temp1
-%%% if (ltu) goto IncStack else goto AllocFrame
-%%% AllocFrame:
-%%% SP = temp2 [if FrameSize == MaxStack]
-%%% SP -= FrameSize [if FrameSize != MaxStack]
-%%% *(SP + FrameSize-WordSize) = LR [if ClobbersLR]
-%%% goto OldStart
-%%% OldStart:
-%%% ...
-%%% IncStack:
-%%% temp1 = LR
-%%% bl inc_stack
-%%% LR = temp1
-%%% goto NewStart
-
-do_prologue(CFG, Context) ->
- MaxStack = context_maxstack(Context),
- if MaxStack > 0 ->
- FrameSize = context_framesize(Context),
- OldStartLab = hipe_arm_cfg:start_label(CFG),
- NewStartLab = hipe_gensym:get_next_label(arm),
- %%
- P = hipe_arm:mk_temp(hipe_arm_registers:proc_pointer(), 'untagged'),
- Temp1 = mk_temp1(),
- SP = mk_sp(),
- %%
- LR = hipe_arm:mk_lr(),
- ClobbersLR = context_clobbers_lr(Context),
- GotoOldStartCode = [hipe_arm:mk_b_label(OldStartLab)],
- AllocFrameCodeTail =
- case ClobbersLR of
- false -> GotoOldStartCode;
- true -> mk_store('str', LR, FrameSize-word_size(), SP, GotoOldStartCode)
- end,
- %%
- Arity = context_arity(Context),
- Guaranteed = erlang:max(0, (?ARM_LEAF_WORDS - Arity) * word_size()),
- %%
- {CFG1,NewStartCode} =
- if MaxStack =< Guaranteed ->
- %% io:format("~w: MaxStack ~w =< Guaranteed ~w :-)\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameCode = adjust_sp(-FrameSize, AllocFrameCodeTail),
- NewStartCode0 = AllocFrameCode, % no mflr needed
- {CFG,NewStartCode0};
- true ->
- %% io:format("~w: MaxStack ~w > Guaranteed ~w :-(\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameLab = hipe_gensym:get_next_label(arm),
- IncStackLab = hipe_gensym:get_next_label(arm),
- Temp2 = mk_temp2(),
- %%
- NewStartCodeTail2 =
- [hipe_arm:mk_pseudo_bc('lo', IncStackLab, AllocFrameLab, 0.01)],
- NewStartCodeTail1 = NewStartCodeTail2, % no mflr needed
- NewStartCode0 =
- mk_load('ldr', Temp1, ?P_NSP_LIMIT, P,
- hipe_arm:mk_addi(Temp2, SP, -MaxStack,
- [hipe_arm:mk_cmp('cmp', Temp2, Temp1) |
- NewStartCodeTail1])),
- %%
- AllocFrameCode =
- if MaxStack =:= FrameSize ->
- %% io:format("~w: MaxStack =:= FrameSize =:= ~w :-)\n", [?MODULE,MaxStack]),
- [hipe_arm:mk_move(SP, Temp2) |
- AllocFrameCodeTail];
- true ->
- %% io:format("~w: MaxStack ~w =/= FrameSize ~w :-(\n", [?MODULE,MaxStack,FrameSize]),
- adjust_sp(-FrameSize, AllocFrameCodeTail)
- end,
- %%
- IncStackCodeTail =
- [hipe_arm:mk_bl(hipe_arm:mk_prim('inc_stack_0'),
- mk_minimal_sdesc(Context), not_remote),
- hipe_arm:mk_mtlr(Temp1),
- hipe_arm:mk_b_label(NewStartLab)],
- IncStackCode =
- [hipe_arm:mk_mflr(Temp1) | IncStackCodeTail], % mflr always needed
- %%
- CFG0a = hipe_arm_cfg:bb_add(CFG, AllocFrameLab,
- hipe_bb:mk_bb(AllocFrameCode)),
- CFG0b = hipe_arm_cfg:bb_add(CFG0a, IncStackLab,
- hipe_bb:mk_bb(IncStackCode)),
- %%
- {CFG0b,NewStartCode0}
- end,
- %%
- CFG2 = hipe_arm_cfg:bb_add(CFG1, NewStartLab,
- hipe_bb:mk_bb(NewStartCode)),
- hipe_arm_cfg:start_label_update(CFG2, NewStartLab);
- true ->
- CFG
- end.
-
-%%% Create a load instruction.
-%%% May clobber Dst early for large offsets. In principle we could
-%%% clobber TEMP2 if Dst =:= Base, but Dst =/= Base here in frame.
-
-mk_load(LdOp, Dst, Offset, Base, Rest) ->
- hipe_arm:mk_load(LdOp, Dst, Base, Offset, 'error', Rest).
-
-%%% Create a store instruction.
-%%% May clobber TEMP2 for large offsets.
-
-mk_store(StOp, Src, Offset, Base, Rest) ->
- hipe_arm:mk_store(StOp, Src, Base, Offset, 'temp2', Rest).
-
-%%% typeof_temp -- what's temp's type?
-
-typeof_temp(Temp) ->
- hipe_arm:temp_type(Temp).
-
-%%% Cons up an 'SP' Temp.
-
-mk_sp() ->
- hipe_arm:mk_temp(hipe_arm_registers:stack_pointer(), 'untagged').
-
-%%% Cons up a 'TEMP1' Temp.
-
-mk_temp1() ->
- hipe_arm:mk_temp(hipe_arm_registers:temp1(), 'untagged').
-
-%%% Cons up a 'TEMP2' Temp.
-
-mk_temp2() ->
- hipe_arm:mk_temp(hipe_arm_registers:temp2(), 'untagged').
-
-%%% Check if an operand is a pseudo-Temp.
-
-src_is_pseudo(Src) ->
- hipe_arm:is_temp(Src) andalso temp_is_pseudo(Src).
-
-temp_is_pseudo(Temp) ->
- not(hipe_arm:temp_is_precoloured(Temp)).
-
-%%%
-%%% Detect if a Defun's body clobbers LR.
-%%%
-
-clobbers_lr(CFG) ->
- LRreg = hipe_arm_registers:lr(),
- LRtagged = hipe_arm:mk_temp(LRreg, 'tagged'),
- LRuntagged = hipe_arm:mk_temp(LRreg, 'untagged'),
- any_insn(fun(I) ->
- Defs = hipe_arm_defuse:insn_def_gpr(I),
- lists:member(LRtagged, Defs)
- orelse lists:member(LRuntagged, Defs)
- end, CFG).
-
-any_insn(Pred, CFG) ->
- %% Abuse fold to do an efficient "any"-operation using nonlocal control flow
- FoundSatisfying = make_ref(),
- try fold_insns(fun (I, _) ->
- case Pred(I) of
- true -> throw(FoundSatisfying);
- false -> false
- end
- end, false, CFG)
- of _ -> false
- catch FoundSatisfying -> true
- end.
-
-%%%
-%%% Build the set of all temps used in a Defun's body.
-%%%
-
-all_temps(CFG, Formals) ->
- S0 = fold_insns(fun find_temps/2, tset_empty(), CFG),
- S1 = tset_del_list(S0, Formals),
- tset_filter(S1, fun(T) -> temp_is_pseudo(T) end).
-
-find_temps(I, S0) ->
- S1 = tset_add_list(S0, hipe_arm_defuse:insn_def_all(I)),
- tset_add_list(S1, hipe_arm_defuse:insn_use_all(I)).
-
-fold_insns(Fun, InitAcc, CFG) ->
- hipe_arm_cfg:fold_bbs(
- fun(_, BB, Acc0) -> lists:foldl(Fun, Acc0, hipe_bb:code(BB)) end,
- InitAcc, CFG).
-
-tset_empty() ->
- gb_sets:new().
-
-tset_size(S) ->
- gb_sets:size(S).
-
-tset_insert(S, T) ->
- gb_sets:add_element(T, S).
-
-tset_add_list(S, Ts) ->
- gb_sets:union(S, gb_sets:from_list(Ts)).
-
-tset_del_list(S, Ts) ->
- gb_sets:subtract(S, gb_sets:from_list(Ts)).
-
-tset_filter(S, F) ->
- gb_sets:filter(F, S).
-
-tset_to_list(S) ->
- gb_sets:to_list(S).
-
-%%%
-%%% Compute minimum permissible frame size, ignoring spilled temps.
-%%% This is done to ensure that we won't have to adjust the frame size
-%%% in the middle of a tailcall.
-%%%
-
-defun_minframe(CFG) ->
- MaxTailArity = fold_insns(fun insn_mta/2, 0, CFG),
- MyArity = length(fix_formals(hipe_arm_cfg:params(CFG))),
- erlang:max(MaxTailArity - MyArity, 0).
-
-insn_mta(I, MTA) ->
- case I of
- #pseudo_tailcall{arity=Arity} ->
- erlang:max(MTA, Arity - hipe_arm_registers:nr_args());
- _ -> MTA
- end.
-
-%%%
-%%% Ensure that we have enough temps to satisfy the minimum frame size,
-%%% if necessary by prepending unused dummy temps.
-%%%
-
-ensure_minframe(MinFrame, Temps) ->
- ensure_minframe(MinFrame, tset_size(Temps), Temps).
-
-ensure_minframe(MinFrame, Frame, Temps) ->
- if MinFrame > Frame ->
- Temp = hipe_arm:mk_new_temp('untagged'),
- ensure_minframe(MinFrame, Frame+1, tset_insert(Temps, Temp));
- true -> Temps
- end.
-
-word_size() ->
- 4.
diff --git a/lib/hipe/arm/hipe_arm_liveness_gpr.erl b/lib/hipe/arm/hipe_arm_liveness_gpr.erl
deleted file mode 100644
index ae845e5385..0000000000
--- a/lib/hipe/arm/hipe_arm_liveness_gpr.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_liveness_gpr).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_arm.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_arm_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_arm_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_arm_cfg:succ(CFG, L).
-uses(Insn) -> hipe_arm_defuse:insn_use_gpr(Insn).
-defines(Insn) -> hipe_arm_defuse:insn_def_gpr(Insn).
-liveout_no_succ() ->
- ordsets:from_list(lists:map(fun({Reg,Type}) ->
- hipe_arm:mk_temp(Reg, Type)
- end,
- hipe_arm_registers:live_at_return())).
diff --git a/lib/hipe/arm/hipe_arm_main.erl b/lib/hipe/arm/hipe_arm_main.erl
deleted file mode 100644
index b87a300a9d..0000000000
--- a/lib/hipe/arm/hipe_arm_main.erl
+++ /dev/null
@@ -1,54 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_main).
--export([rtl_to_arm/3]).
-
-rtl_to_arm(MFA, RTL, Options) ->
- Defun1 = hipe_rtl_to_arm:translate(RTL),
- CFG1 = hipe_arm_cfg:init(Defun1),
- %% io:format("~w: after translate\n", [?MODULE]),
- %% hipe_arm_pp:pp(Defun1),
- CFG2 = hipe_arm_ra:ra(CFG1, Options),
- %% io:format("~w: after regalloc\n", [?MODULE]),
- %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG2)),
- CFG3 = hipe_arm_frame:frame(CFG2),
- Defun3 = hipe_arm_cfg:linearise(CFG3),
- %% io:format("~w: after frame\n", [?MODULE]),
- %% hipe_arm_pp:pp(Defun3),
- Defun4 = hipe_arm_finalise:finalise(Defun3, Options),
- %% io:format("~w: after finalise\n", [?MODULE]),
- pp(Defun4, MFA, Options),
- {native, arm, {unprofiled, Defun4}}.
-
-pp(Defun, MFA, Options) ->
- case proplists:get_value(pp_native, Options) of
- true ->
- hipe_arm_pp:pp(Defun);
- {only,Lst} when is_list(Lst) ->
- case lists:member(MFA,Lst) of
- true ->
- hipe_arm_pp:pp(Defun);
- false ->
- ok
- end;
- {only,MFA} ->
- hipe_arm_pp:pp(Defun);
- {file,FileName} ->
- {ok, File} = file:open(FileName, [write,append]),
- hipe_arm_pp:pp(File, Defun),
- ok = file:close(File);
- _ ->
- ok
- end.
diff --git a/lib/hipe/arm/hipe_arm_pp.erl b/lib/hipe/arm/hipe_arm_pp.erl
deleted file mode 100644
index f49e998d06..0000000000
--- a/lib/hipe/arm/hipe_arm_pp.erl
+++ /dev/null
@@ -1,350 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_pp).
--export([pp/1, pp/2, pp_insn/1]).
-
--include("hipe_arm.hrl").
-
-pp(Defun) ->
- pp(standard_io, Defun).
-
-pp(Dev, #defun{mfa={M,F,A}, code=Code, data=Data}) ->
- Fname = atom_to_list(M)++"_"++atom_to_list(F)++"_"++integer_to_list(A),
- io:format(Dev, "\t.text\n", []),
- io:format(Dev, "\t.align 4\n", []),
- io:format(Dev, "\t.global ~s\n", [Fname]),
- io:format(Dev, "~s:\n", [Fname]),
- pp_insns(Dev, Code, Fname),
- io:format(Dev, "\t.rodata\n", []),
- io:format(Dev, "\t.align 4\n", []),
- hipe_data_pp:pp(Dev, Data, arm, Fname),
- io:format(Dev, "\n", []).
-
-pp_insns(Dev, [I|Is], Fname) ->
- pp_insn(Dev, I, Fname),
- pp_insns(Dev, Is, Fname);
-pp_insns(_, [], _) ->
- [].
-
-pp_insn(I) ->
- pp_insn(standard_io, I, "").
-
-pp_insn(Dev, I, Pre) ->
- case I of
- #alu{aluop=AluOp, s=S, dst=Dst, src=Src, am1=Am1} ->
- io:format(Dev, "\t~s~s ", [alu_op_name(AluOp), s_name(S)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_am1(Dev, Am1),
- io:format(Dev, "\n", []);
- #b_fun{'fun'=Fun, linkage=Linkage} ->
- io:format(Dev, "\tb ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " # ~w\n", [Linkage]);
- #b_label{'cond'=Cond, label=Label} ->
- io:format(Dev, "\tb~s .~s_~w\n", [cond_name(Cond), Pre, Label]);
- #bl{'fun'=Fun, sdesc=SDesc, linkage=Linkage} ->
- io:format(Dev, "\tbl ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " #", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #blx{src=Src, sdesc=SDesc} ->
- io:format(Dev, "\tblx ", []),
- pp_temp(Dev, Src),
- io:format(Dev, " # ", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, "\n", []);
- #cmp{cmpop=CmpOp, src=Src, am1=Am1} ->
- io:format(Dev, "\t~s ", [cmp_op_name(CmpOp)]),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_am1(Dev, Am1),
- io:format(Dev, "\n", []);
- #comment{term=Term} ->
- io:format(Dev, "\t# ~p\n", [Term]);
- #label{label=Label} ->
- io:format(Dev, ".~s_~w:~n", [Pre, Label]);
- #load{ldop=LdOp, dst=Dst, am2=Am2} ->
- io:format(Dev, "\t~w ", [ldop_name(LdOp)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_am2(Dev, Am2),
- io:format(Dev, "\n", []);
- #ldrsb{dst=Dst, am3=Am3} ->
- io:format(Dev, "\tldrsb ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_am3(Dev, Am3),
- io:format(Dev, "\n", []);
- #move{movop=MovOp, s=S, dst=Dst, am1=Am1} ->
- io:format(Dev, "\t~s~s ", [mov_op_name(MovOp), s_name(S)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_am1(Dev, Am1),
- io:format(Dev, "\n", []);
- #pseudo_bc{'cond'=Cond, true_label=TrueLab, false_label=FalseLab, pred=Pred} ->
- io:format(Dev, "\tpseudo_bc ~w, .~s_~w # .~s_~w ~.2f\n",
- [cond_name(Cond), Pre, TrueLab, Pre, FalseLab, Pred]);
- #pseudo_blr{} ->
- io:format(Dev, "\tpseudo_blr\n", []);
- #pseudo_bx{src=Src} ->
- io:format(Dev, "\tpseudo_bx ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #pseudo_call{funv=FunV, sdesc=SDesc, contlab=ContLab, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_call ", []),
- pp_funv(Dev, FunV),
- io:format(Dev, " # contlab .~s_~w", [Pre, ContLab]),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #pseudo_call_prepare{nrstkargs=NrStkArgs} ->
- SP = hipe_arm_registers:reg_name_gpr(hipe_arm_registers:stack_pointer()),
- io:format(Dev, "\tsub ~s, ~s, ~w # pseudo_call_prepare\n",
- [SP, SP, (4*NrStkArgs)]);
- #pseudo_li{dst=Dst, imm=Imm} ->
- io:format(Dev, "\tpseudo_li ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_imm(Dev, Imm),
- io:format(Dev, "\n", []);
- #pseudo_move{dst=Dst, src=Src} ->
- io:format(Dev, "\tpseudo_move ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #pseudo_switch{jtab=JTab, index=Index, labels=Labels} ->
- io:format(Dev, "\tpseudo_switch ", []),
- pp_temp(Dev, JTab),
- io:format(Dev, "[", []),
- pp_temp(Dev, Index),
- io:format(Dev, "]", []),
- case Labels of
- [] -> [];
- _ ->
- io:format(Dev, " #", []),
- pp_labels(Dev, Labels, Pre)
- end,
- io:format(Dev, "\n", []);
- #pseudo_tailcall{funv=FunV, arity=Arity, stkargs=StkArgs, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_tailcall ", []),
- pp_funv(Dev, FunV),
- io:format(Dev, "/~w (", [Arity]),
- pp_args(Dev, StkArgs),
- io:format(Dev, ") ~w\n", [Linkage]);
- #pseudo_tailcall_prepare{} ->
- io:format(Dev, "\tpseudo_tailcall_prepare\n", []);
- #smull{dstlo=DstLo, dsthi=DstHi, src1=Src1, src2=Src2} ->
- io:format(Dev, "\tsmull ", []),
- pp_temp(Dev, DstLo),
- io:format(Dev, ", ", []),
- pp_temp(Dev, DstHi),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src2),
- io:format(Dev, "\n", []);
- #store{stop=StOp, src=Src, am2=Am2} ->
- io:format(Dev, "\tstr~s ", [stop_suffix(StOp)]),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_am2(Dev, Am2),
- io:format(Dev, "\n", []);
- _ ->
- exit({?MODULE, pp_insn, I})
- end.
-
-to_hex(N) ->
- io_lib:format("~.16x", [N, "0x"]).
-
-pp_sdesc(Dev, Pre, #arm_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live}) ->
- pp_sdesc_exnlab(Dev, Pre, ExnLab),
- io:format(Dev, " ~s ~w [", [to_hex(FSize), Arity]),
- pp_sdesc_live(Dev, Live),
- io:format(Dev, "]", []).
-
-pp_sdesc_exnlab(Dev, _, []) -> io:format(Dev, " []", []);
-pp_sdesc_exnlab(Dev, Pre, ExnLab) -> io:format(Dev, " .~s_~w", [Pre, ExnLab]).
-
-pp_sdesc_live(_, {}) -> [];
-pp_sdesc_live(Dev, Live) -> pp_sdesc_live(Dev, Live, 1).
-
-pp_sdesc_live(Dev, Live, I) ->
- io:format(Dev, "~s", [to_hex(element(I, Live))]),
- if I < tuple_size(Live) ->
- io:format(Dev, ",", []),
- pp_sdesc_live(Dev, Live, I+1);
- true -> []
- end.
-
-pp_labels(Dev, [Label|Labels], Pre) ->
- io:format(Dev, " .~s_~w", [Pre, Label]),
- pp_labels(Dev, Labels, Pre);
-pp_labels(_, [], _) ->
- [].
-
-pp_fun(Dev, Fun) ->
- case Fun of
- #arm_mfa{m=M, f=F, a=A} ->
- io:format(Dev, "~w:~w/~w", [M, F, A]);
- #arm_prim{prim=Prim} ->
- io:format(Dev, "~w", [Prim])
- end.
-
-pp_funv(Dev, FunV) ->
- case FunV of
- #arm_temp{} ->
- pp_temp(Dev, FunV);
- Fun ->
- pp_fun(Dev, Fun)
- end.
-
-alu_op_name(Op) -> Op.
-
-cond_name(Cond) ->
- case Cond of
- 'al' -> "";
- _ -> Cond
- end.
-
-s_name(S) ->
- case S of
- true -> "s";
- false -> ""
- end.
-
-cmp_op_name(Op) -> Op.
-
-mov_op_name(Op) -> Op.
-
-ldop_name(LdOp) -> LdOp.
-
-stop_suffix(StOp) ->
- case StOp of
- 'str' -> "";
- 'strb' -> "b"
- end.
-
-imm8m_decode(Value, 0) ->
- Value;
-imm8m_decode(Value, Rot) ->
- (Value bsr (2 * Rot)) bor (Value bsl (2 * (16 - Rot))).
-
-pp_temp(Dev, Temp=#arm_temp{reg=Reg, type=Type}) ->
- case hipe_arm:temp_is_precoloured(Temp) of
- true ->
- Name =
-%%% case Type of
-%%% 'double' ->
-%%% hipe_arm_registers:reg_name_fpr(Reg);
-%%% _ ->
- hipe_arm_registers:reg_name_gpr(Reg)
-%%% end
- ,
- io:format(Dev, "~s", [Name]);
- false ->
- Tag =
- case Type of
-%%% double -> "f";
- tagged -> "t";
- untagged -> "u"
- end,
- io:format(Dev, "~s~w", [Tag, Reg])
- end.
-
-pp_hex(Dev, Value) -> io:format(Dev, "~s", [to_hex(Value)]).
-
-pp_imm(Dev, Value) ->
- if is_integer(Value) -> pp_hex(Dev, Value);
- true -> io:format(Dev, "~w", [Value])
- end.
-
-pp_am1(Dev, Am1) ->
- case Am1 of
- #arm_temp{} ->
- pp_temp(Dev, Am1);
- {Src,rrx} ->
- pp_temp(Dev, Src),
- io:format(Dev, ", rrx", []);
- {Src,ShiftOp,ShiftArg} ->
- pp_temp(Dev, Src),
- io:format(Dev, ", ~w ", [ShiftOp]),
- case ShiftArg of
- #arm_temp{} ->
- pp_temp(Dev, ShiftArg);
- Imm5 ->
- io:format(Dev, "#~w", [Imm5])
- end;
- {Imm8,Imm4} ->
- io:format(Dev, "#~s", [to_hex(imm8m_decode(Imm8, Imm4))])
- end.
-
-pp_am2(Dev, #am2{src=Src,sign=Sign,offset=Am2Offset}) ->
- io:format(Dev, "[", []),
- pp_temp(Dev, Src),
- io:format(Dev, ",~s", [sign_name(Sign)]),
- case Am2Offset of
- #arm_temp{} ->
- pp_temp(Dev, Am2Offset);
- {Src2,rrx} ->
- pp_temp(Dev, Src2),
- io:format(Dev, ", rrx", []);
- {Src2,ShiftOp,Imm5} ->
- pp_temp(Dev, Src2),
- io:format(Dev, ",~w #~w", [ShiftOp,Imm5]);
- Imm12 ->
- io:format(Dev, "#~w", [Imm12])
- end,
- io:format(Dev, "]", []).
-
-pp_am3(Dev, #am3{src=Src,sign=Sign,offset=Am3Offset}) ->
- io:format(Dev, "[", []),
- pp_temp(Dev, Src),
- io:format(Dev, ",~s", [sign_name(Sign)]),
- case Am3Offset of
- #arm_temp{} -> pp_temp(Dev, Am3Offset);
- Imm8 -> io:format(Dev, "~w", [Imm8])
- end,
- io:format(Dev, "]", []).
-
-sign_name(Sign) ->
- case Sign of
- '+' -> "";
- '-' -> "-"
- end.
-
-pp_arg(Dev, Arg) ->
- case Arg of
- #arm_temp{} ->
- pp_temp(Dev, Arg);
- _ ->
- pp_hex(Dev, Arg)
- end.
-
-pp_args(Dev, [A|As]) ->
- pp_arg(Dev, A),
- pp_comma_args(Dev, As);
-pp_args(_, []) ->
- [].
-
-pp_comma_args(Dev, [A|As]) ->
- io:format(Dev, ", ", []),
- pp_arg(Dev, A),
- pp_comma_args(Dev, As);
-pp_comma_args(_, []) ->
- [].
diff --git a/lib/hipe/arm/hipe_arm_ra.erl b/lib/hipe/arm/hipe_arm_ra.erl
deleted file mode 100644
index b360fc05c4..0000000000
--- a/lib/hipe/arm/hipe_arm_ra.erl
+++ /dev/null
@@ -1,54 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_ra).
--export([ra/2]).
-
-ra(CFG0, Options) ->
- %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG0)),
- {CFG1, _FPLiveness1, Coloring_fp, SpillIndex}
- = case proplists:get_bool(inline_fp, Options) of
-%% true ->
-%% FPLiveness0 = hipe_arm_specific_fp:analyze(CFG0, no_context),
-%% hipe_regalloc_loop:ra_fp(CFG0, FPLiveness0, Options,
-%% hipe_coalescing_regalloc,
-%% hipe_arm_specific_fp, no_context);
- false ->
- {CFG0,undefined,[],0}
- end,
- %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG1)),
- GPLiveness1 = hipe_arm_specific:analyze(CFG1, no_context),
- {CFG2, _GPLiveness2, Coloring}
- = case proplists:get_value(regalloc, Options, coalescing) of
- coalescing ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_coalescing_regalloc);
- optimistic ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_optimistic_regalloc);
- graph_color ->
- ra(CFG1, GPLiveness1, SpillIndex, Options,
- hipe_graph_coloring_regalloc);
- linear_scan ->
- hipe_arm_ra_ls:ra(CFG1, GPLiveness1, SpillIndex, Options);
- naive ->
- hipe_arm_ra_naive:ra(CFG1, GPLiveness1, Coloring_fp, Options);
- _ ->
- exit({unknown_regalloc_compiler_option,
- proplists:get_value(regalloc,Options)})
- end,
- %% hipe_arm_pp:pp(hipe_arm_cfg:linearise(CFG2)),
- hipe_arm_ra_finalise:finalise(CFG2, Coloring, Coloring_fp).
-
-ra(CFG, Liveness, SpillIndex, Options, RegAllocMod) ->
- hipe_regalloc_loop:ra(CFG, Liveness, SpillIndex, Options, RegAllocMod,
- hipe_arm_specific, no_context).
diff --git a/lib/hipe/arm/hipe_arm_ra_finalise.erl b/lib/hipe/arm/hipe_arm_ra_finalise.erl
deleted file mode 100644
index 80cd470708..0000000000
--- a/lib/hipe/arm/hipe_arm_ra_finalise.erl
+++ /dev/null
@@ -1,295 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_ra_finalise).
--export([finalise/3]).
--include("hipe_arm.hrl").
-
-finalise(CFG, TempMap, _FPMap0=[]) ->
- {_, SpillLimit} = hipe_gensym:var_range(arm),
- Map = mk_ra_map(TempMap, SpillLimit),
- hipe_arm_cfg:map_bbs(fun(_Lbl, BB) -> ra_bb(BB, Map) end, CFG).
-
-ra_bb(BB, Map) ->
- hipe_bb:code_update(BB, ra_code(hipe_bb:code(BB), Map, [])).
-
-ra_code([I|Insns], Map, Accum) ->
- ra_code(Insns, Map, ra_insn(I, Map, Accum));
-ra_code([], _Map, Accum) ->
- lists:reverse(Accum).
-
-ra_insn(I, Map, Accum) ->
- case I of
- #pseudo_move{} -> ra_pseudo_move(I, Map, Accum);
- _ -> [ra_insn_1(I, Map) | Accum]
- end.
-
-ra_insn_1(I, Map) ->
- case I of
- #alu{} -> ra_alu(I, Map);
- #cmp{} -> ra_cmp(I, Map);
- #load{} -> ra_load(I, Map);
- #ldrsb{} -> ra_ldrsb(I, Map);
- #move{} -> ra_move(I, Map);
- #pseudo_call{} -> ra_pseudo_call(I, Map);
- #pseudo_li{} -> ra_pseudo_li(I, Map);
- #pseudo_spill_move{} -> ra_pseudo_spill_move(I, Map);
- #pseudo_switch{} -> ra_pseudo_switch(I, Map);
- #pseudo_tailcall{} -> ra_pseudo_tailcall(I, Map);
- #smull{} -> ra_smull(I, Map);
- #store{} -> ra_store(I, Map);
- _ -> I
- end.
-
-ra_alu(I=#alu{dst=Dst,src=Src,am1=Am1}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewSrc = ra_temp(Src, Map),
- NewAm1 = ra_am1(Am1, Map),
- I#alu{dst=NewDst,src=NewSrc,am1=NewAm1}.
-
-ra_cmp(I=#cmp{src=Src,am1=Am1}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewAm1 = ra_am1(Am1, Map),
- I#cmp{src=NewSrc,am1=NewAm1}.
-
-ra_load(I=#load{dst=Dst,am2=Am2}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewAm2 = ra_am2(Am2, Map),
- I#load{dst=NewDst,am2=NewAm2}.
-
-ra_ldrsb(I=#ldrsb{dst=Dst,am3=Am3}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewAm3 = ra_am3(Am3, Map),
- I#ldrsb{dst=NewDst,am3=NewAm3}.
-
-ra_move(I=#move{dst=Dst,am1=Am1}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewAm1 = ra_am1(Am1, Map),
- I#move{dst=NewDst,am1=NewAm1}.
-
-ra_pseudo_call(I=#pseudo_call{funv=FunV}, Map) ->
- NewFunV = ra_funv(FunV, Map),
- I#pseudo_call{funv=NewFunV}.
-
-ra_pseudo_li(I=#pseudo_li{dst=Dst}, Map) ->
- NewDst = ra_temp(Dst, Map),
- I#pseudo_li{dst=NewDst}.
-
-ra_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, Map, Accum) ->
- NewDst = ra_temp(Dst, Map),
- NewSrc = ra_temp(Src, Map),
- case NewSrc#arm_temp.reg =:= NewDst#arm_temp.reg of
- true -> Accum;
- false -> [I#pseudo_move{dst=NewDst,src=NewSrc} | Accum]
- end.
-
-ra_pseudo_spill_move(I=#pseudo_spill_move{dst=Dst,temp=Temp,src=Src}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewTemp = ra_temp(Temp, Map),
- NewSrc = ra_temp(Src, Map),
- I#pseudo_spill_move{dst=NewDst, temp=NewTemp, src=NewSrc}.
-
-ra_pseudo_switch(I=#pseudo_switch{jtab=JTab,index=Index}, Map) ->
- NewJTab = ra_temp(JTab, Map),
- NewIndex = ra_temp(Index, Map),
- I#pseudo_switch{jtab=NewJTab,index=NewIndex}.
-
-ra_pseudo_tailcall(I=#pseudo_tailcall{funv=FunV,stkargs=StkArgs}, Map) ->
- NewFunV = ra_funv(FunV, Map),
- NewStkArgs = ra_args(StkArgs, Map),
- I#pseudo_tailcall{funv=NewFunV,stkargs=NewStkArgs}.
-
-ra_smull(I=#smull{dstlo=DstLo,dsthi=DstHi,src1=Src1,src2=Src2}, Map) ->
- NewDstLo = ra_temp(DstLo, Map),
- NewDstHi = ra_temp(DstHi, Map),
- NewSrc1 = ra_temp(Src1, Map),
- NewSrc2 = ra_temp(Src2, Map),
- I#smull{dstlo=NewDstLo,dsthi=NewDstHi,src1=NewSrc1,src2=NewSrc2}.
-
-ra_store(I=#store{src=Src,am2=Am2}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewAm2 = ra_am2(Am2, Map),
- I#store{src=NewSrc,am2=NewAm2}.
-
-%%% Tailcall stack arguments.
-
-ra_args([Arg|Args], Map) ->
- [ra_temp_or_imm(Arg, Map) | ra_args(Args, Map)];
-ra_args([], _) ->
- [].
-
-ra_temp_or_imm(Arg, Map) ->
- case hipe_arm:is_temp(Arg) of
- true ->
- ra_temp(Arg, Map);
- false ->
- Arg
- end.
-
-%%% FunV, Am, and Temp operands.
-
-ra_funv(FunV, Map) ->
- case FunV of
- #arm_temp{} -> ra_temp(FunV, Map);
- _ -> FunV
- end.
-
-ra_am1(Am1, Map) ->
- case Am1 of
- #arm_temp{} ->
- ra_temp(Am1, Map);
- {Src2,rrx} ->
- NewSrc2 = ra_temp(Src2, Map),
- {NewSrc2,rrx};
- {Src2,ShiftOp,ShiftArg} ->
- NewSrc2 = ra_temp(Src2, Map),
- NewArg =
- case ShiftArg of
- #arm_temp{} -> ra_temp(ShiftArg, Map);
- _ -> ShiftArg
- end,
- {NewSrc2,ShiftOp,NewArg};
- _ ->
- Am1
- end.
-
-ra_am2(Am2=#am2{src=Src2,offset=Offset}, Map) ->
- NewSrc2 = ra_temp(Src2, Map),
- NewOffset = ra_am2offset(Offset, Map),
- Am2#am2{src=NewSrc2,offset=NewOffset}.
-
-ra_am2offset(Offset, Map) ->
- case Offset of
- #arm_temp{} ->
- ra_temp(Offset, Map);
- {Src3,rrx} ->
- NewSrc3 = ra_temp(Src3, Map),
- {NewSrc3,rrx};
- {Src3,ShiftOp,Imm5} ->
- NewSrc3 = ra_temp(Src3, Map),
- {NewSrc3,ShiftOp,Imm5};
- _ ->
- Offset
- end.
-
-ra_am3(Am3=#am3{src=Src2,offset=Offset}, Map) ->
- NewSrc2 = ra_temp(Src2, Map),
- NewOffset = ra_am3offset(Offset, Map),
- Am3#am3{src=NewSrc2,offset=NewOffset}.
-
-ra_am3offset(Offset, Map) ->
- case Offset of
- #arm_temp{} -> ra_temp(Offset, Map);
- _ -> Offset
- end.
-
--ifdef(notdef). % for FP regalloc
-ra_temp_fp(Temp, FPMap) ->
- Reg = hipe_arm:temp_reg(Temp),
- case hipe_arm:temp_type(Temp) of
- 'double' ->
- case hipe_arm_registers:is_precoloured_fpr(Reg) of
- true -> Temp;
- _ -> ra_temp_common(Reg, Temp, FPMap)
- end
- end.
--endif.
-
-ra_temp(Temp, Map) ->
- Reg = hipe_arm:temp_reg(Temp),
- case hipe_arm:temp_type(Temp) of
- 'double' ->
- exit({?MODULE,ra_temp,Temp});
- _ ->
- case hipe_arm_registers:is_precoloured_gpr(Reg) of
- true -> Temp;
- _ -> ra_temp_common(Reg, Temp, Map)
- end
- end.
-
-ra_temp_common(Reg, Temp, Map) ->
- case gb_trees:lookup(Reg, Map) of
- {value,NewReg} -> Temp#arm_temp{reg=NewReg};
- _ -> Temp
- end.
-
-mk_ra_map(TempMap, SpillLimit) ->
- %% Build a partial map from pseudo to reg or spill.
- %% Spills are represented as pseudos with indices above SpillLimit.
- %% (I'd prefer to use negative indices, but that breaks
- %% hipe_arm_registers:is_precoloured/1.)
- %% The frame mapping proper is unchanged, since spills look just like
- %% ordinary (un-allocated) pseudos.
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit, is_precoloured_gpr),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- TempMap).
-
-conv_ra_maplet(MapLet = {From,To}, SpillLimit, IsPrecoloured) ->
- %% From should be a pseudo, or a hard reg mapped to itself.
- if is_integer(From), From =< SpillLimit ->
- case hipe_arm_registers:IsPrecoloured(From) of
- false -> [];
- _ ->
- case To of
- {reg, From} -> [];
- _ -> exit({?MODULE,conv_ra_maplet,MapLet})
- end
- end;
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of From check
- case To of
- {reg, NewReg} ->
- %% NewReg should be a hard reg, or a pseudo mapped
- %% to itself (formals are handled this way).
- if is_integer(NewReg) ->
- case hipe_arm_registers:IsPrecoloured(NewReg) of
- true -> [];
- _ -> if From =:= NewReg -> [];
- true ->
- exit({?MODULE,conv_ra_maplet,MapLet})
- end
- end;
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of NewReg check
- {From, NewReg};
- {spill, SpillIndex} ->
- %% SpillIndex should be >= 0.
- if is_integer(SpillIndex), SpillIndex >= 0 -> [];
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of SpillIndex check
- ToTempNum = SpillLimit+SpillIndex+1,
- MaxTempNum = hipe_gensym:get_var(arm),
- if MaxTempNum >= ToTempNum -> ok;
- true -> hipe_gensym:set_var(arm, ToTempNum)
- end,
- {From, ToTempNum};
- _ -> exit({?MODULE,conv_ra_maplet,MapLet})
- end.
-
--ifdef(notdef). % for FP regalloc
-mk_ra_map_fp(FPMap, SpillLimit) ->
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit,
- is_precoloured_fpr),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- FPMap).
--endif.
diff --git a/lib/hipe/arm/hipe_arm_ra_ls.erl b/lib/hipe/arm/hipe_arm_ra_ls.erl
deleted file mode 100644
index bbb75f9c55..0000000000
--- a/lib/hipe/arm/hipe_arm_ra_ls.erl
+++ /dev/null
@@ -1,49 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Linear Scan register allocator for ARM
-
--module(hipe_arm_ra_ls).
--export([ra/4]).
-
-ra(CFG, Liveness, SpillIndex, Options) ->
- SpillLimit = hipe_arm_specific:number_of_temporaries(CFG, no_context),
- alloc(CFG, Liveness, SpillIndex, SpillLimit, Options).
-
-alloc(CFG, Liveness, SpillIndex, SpillLimit, Options) ->
- {Coloring, _NewSpillIndex} =
- regalloc(
- CFG, Liveness,
- hipe_arm_registers:allocatable_gpr()--
- [hipe_arm_registers:temp3(),
- hipe_arm_registers:temp2(),
- hipe_arm_registers:temp1()],
- [hipe_arm_cfg:start_label(CFG)],
- SpillIndex, SpillLimit, Options,
- hipe_arm_specific, no_context),
- {NewCFG, _DidSpill} =
- hipe_arm_ra_postconditions:check_and_rewrite(
- CFG, Coloring, 'linearscan'),
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific, no_context),
- {SpillMap, _NewSpillIndex2} =
- hipe_spillmin:stackalloc(CFG, Liveness, [], SpillIndex, Options,
- hipe_arm_specific, no_context, TempMap),
- Coloring2 =
- hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), SpillMap),
- {NewCFG, Liveness, Coloring2}.
-
-regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options,
- TgtMod, TgtCtx) ->
- hipe_ls_regalloc:regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex,
- DontSpill, Options, TgtMod, TgtCtx).
diff --git a/lib/hipe/arm/hipe_arm_ra_naive.erl b/lib/hipe/arm/hipe_arm_ra_naive.erl
deleted file mode 100644
index e3fe9877ad..0000000000
--- a/lib/hipe/arm/hipe_arm_ra_naive.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_ra_naive).
--export([ra/4]).
-
--include("hipe_arm.hrl").
-
-ra(CFG, Liveness, _Coloring_fp, _Options) -> % -> {CFG, Liveness, Coloring}
- {NewCFG,_DidSpill} =
- hipe_arm_ra_postconditions:check_and_rewrite2(CFG, [], 'naive'),
- {NewCFG, Liveness, []}.
diff --git a/lib/hipe/arm/hipe_arm_ra_postconditions.erl b/lib/hipe/arm/hipe_arm_ra_postconditions.erl
deleted file mode 100644
index 23c305511f..0000000000
--- a/lib/hipe/arm/hipe_arm_ra_postconditions.erl
+++ /dev/null
@@ -1,283 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_ra_postconditions).
-
--export([check_and_rewrite/3, check_and_rewrite2/3]).
-
--include("hipe_arm.hrl").
-
-check_and_rewrite(CFG, Coloring, Allocator) ->
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_arm_specific, no_context),
- check_and_rewrite2(CFG, TempMap, Allocator).
-
-check_and_rewrite2(CFG, TempMap, Allocator) ->
- Strategy = strategy(Allocator),
- do_bbs(hipe_arm_cfg:labels(CFG), TempMap, Strategy, CFG, false).
-
-strategy(Allocator) ->
- case Allocator of
- 'normal' -> 'new';
- 'linearscan' -> 'fixed';
- 'naive' -> 'fixed'
- end.
-
-do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_arm_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0),
- CFG = hipe_arm_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
- do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
-do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap, Strategy) ->
- case I of
- #alu{} -> do_alu(I, TempMap, Strategy);
- #cmp{} -> do_cmp(I, TempMap, Strategy);
- #load{} -> do_load(I, TempMap, Strategy);
- #ldrsb{} -> do_ldrsb(I, TempMap, Strategy);
- #move{} -> do_move(I, TempMap, Strategy);
- #pseudo_call{} -> do_pseudo_call(I, TempMap, Strategy);
- #pseudo_li{} -> do_pseudo_li(I, TempMap, Strategy);
- #pseudo_move{} -> do_pseudo_move(I, TempMap, Strategy);
- #pseudo_spill_move{} -> do_pseudo_spill_move(I, TempMap, Strategy);
- #pseudo_switch{} -> do_pseudo_switch(I, TempMap, Strategy);
- #pseudo_tailcall{} -> do_pseudo_tailcall(I, TempMap, Strategy);
- #smull{} -> do_smull(I, TempMap, Strategy);
- #store{} -> do_store(I, TempMap, Strategy);
- _ -> {[I], false}
- end.
-
-%%% Fix relevant instruction types.
-
-do_alu(I=#alu{dst=Dst,src=Src,am1=Am1}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixSrc,NewSrc,DidSpill2} = fix_src1(Src, TempMap, Strategy),
- {FixAm1,NewAm1,DidSpill3} = fix_am1(Am1, TempMap, Strategy),
- NewI = I#alu{dst=NewDst,src=NewSrc,am1=NewAm1},
- {FixSrc ++ FixAm1 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_cmp(I=#cmp{src=Src,am1=Am1}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
- {FixAm1,NewAm1,DidSpill2} = fix_am1(Am1, TempMap, Strategy),
- NewI = I#cmp{src=NewSrc,am1=NewAm1},
- {FixSrc ++ FixAm1 ++ [NewI], DidSpill1 or DidSpill2}.
-
-do_load(I=#load{dst=Dst,am2=Am2}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixAm2,NewAm2,DidSpill2} = fix_am2(Am2, TempMap, Strategy),
- NewI = I#load{dst=NewDst,am2=NewAm2},
- {FixAm2 ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_ldrsb(I=#ldrsb{dst=Dst,am3=Am3}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixAm3,NewAm3,DidSpill2} = fix_am3(Am3, TempMap, Strategy),
- NewI = I#ldrsb{dst=NewDst,am3=NewAm3},
- {FixAm3 ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_move(I=#move{dst=Dst,am1=Am1}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixAm1,NewAm1,DidSpill2} = fix_am1(Am1, TempMap, Strategy),
- NewI = I#move{dst=NewDst,am1=NewAm1},
- {FixAm1 ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_pseudo_call(I=#pseudo_call{funv=FunV}, TempMap, Strategy) ->
- {FixFunV,NewFunV,DidSpill} = fix_funv(FunV, TempMap, Strategy),
- NewI = I#pseudo_call{funv=NewFunV},
- {FixFunV ++ [NewI], DidSpill}.
-
-do_pseudo_li(I=#pseudo_li{dst=Dst}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
- NewI = I#pseudo_li{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, TempMap, Strategy) ->
- %% Either Dst or Src (but not both) may be a pseudo temp.
- %% pseudo_move, pseudo_spill_move, and pseudo_tailcall
- %% are special cases: in all other instructions, all
- %% temps must be non-pseudos after register allocation.
- case temp_is_spilled(Dst, TempMap)
- andalso temp_is_spilled(Dst, TempMap)
- of
- true -> % Turn into pseudo_spill_move
- Temp = clone(Src, temp1(Strategy)),
- NewI = #pseudo_spill_move{dst=Dst, temp=Temp, src=Src},
- {[NewI], true};
- _ ->
- {[I], false}
- end.
-
-do_pseudo_spill_move(I = #pseudo_spill_move{temp=Temp}, TempMap, _Strategy) ->
- %% Temp is above the low water mark and must not have been spilled
- false = temp_is_spilled(Temp, TempMap),
- {[I], false}. % nothing to do
-
-do_pseudo_switch(I=#pseudo_switch{jtab=JTab,index=Index}, TempMap, Strategy) ->
- {FixJTab,NewJTab,DidSpill1} = fix_src1(JTab, TempMap, Strategy),
- {FixIndex,NewIndex,DidSpill2} = fix_src2(Index, TempMap, Strategy),
- NewI = I#pseudo_switch{jtab=NewJTab,index=NewIndex},
- {FixJTab ++ FixIndex ++ [NewI], DidSpill1 or DidSpill2}.
-
-do_pseudo_tailcall(I=#pseudo_tailcall{funv=FunV}, TempMap, Strategy) ->
- {FixFunV,NewFunV,DidSpill} = fix_funv(FunV, TempMap, Strategy),
- NewI = I#pseudo_tailcall{funv=NewFunV},
- {FixFunV ++ [NewI], DidSpill}.
-
-do_smull(I=#smull{dstlo=DstLo,dsthi=DstHi,src1=Src1,src2=Src2}, TempMap, Strategy) ->
- %% ARM requires that DstLo, DstHi, and Src1 are distinct.
- %% We furthermore require Src1 and Src2 to be different in the fixed strategy.
- {FixDstLo,NewDstLo,DidSpill1} = fix_dst(DstLo, TempMap, Strategy), % temp1
- {FixDstHi,NewDstHi,DidSpill2} = fix_dst2(DstHi, TempMap, Strategy), % temp3
- {FixSrc1,NewSrc1,DidSpill3} = fix_src2(Src1, TempMap, Strategy), % temp2
- {FixSrc2,NewSrc2,DidSpill4} = fix_src1(Src2, TempMap, Strategy), % temp1; temp3 would be OK
- NewI = I#smull{dstlo=NewDstLo,dsthi=NewDstHi,src1=NewSrc1,src2=NewSrc2},
- {FixSrc1 ++ FixSrc2 ++ [NewI | FixDstLo ++ FixDstHi],
- DidSpill1 or DidSpill2 or DidSpill3 or DidSpill4}.
-
-do_store(I=#store{src=Src,am2=Am2}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
- {FixAm2,NewAm2,DidSpill2} = fix_am2(Am2, TempMap, Strategy),
- NewI = I#store{src=NewSrc,am2=NewAm2},
- {FixSrc ++ FixAm2 ++ [NewI], DidSpill1 or DidSpill2}.
-
-%%% Fix Dst and Src operands.
-
-fix_funv(FunV, TempMap, Strategy) ->
- case FunV of
- #arm_temp{} -> fix_src3(FunV, TempMap, Strategy);
- _ -> {[], FunV, false}
- end.
-
-fix_am1(Am1, TempMap, Strategy) ->
- case Am1 of
- #arm_temp{} ->
- fix_src2(Am1, TempMap, Strategy);
- {Src2,rrx} ->
- {Fix,New,DidSpill} = fix_src2(Src2, TempMap, Strategy),
- {Fix, {New,rrx}, DidSpill};
- {Src2,ShiftOp,ShiftArg} ->
- {FixSrc2,NewSrc2,DidSpill1} = fix_src2(Src2, TempMap, Strategy),
- {FixArg,NewArg,DidSpill2} =
- case ShiftArg of
- #arm_temp{} -> fix_src3(ShiftArg, TempMap, Strategy);
- _ -> {[], ShiftArg, false}
- end,
- %% order matters: FixArg may clobber temp2/Src2
- {FixArg ++ FixSrc2, {NewSrc2,ShiftOp,NewArg}, DidSpill1 or DidSpill2};
- _ -> {[], Am1, false}
- end.
-
-fix_am2(Am2=#am2{src=Src2,offset=Offset}, TempMap, Strategy) ->
- {FixSrc2,NewSrc2,DidSpill1} = fix_src2(Src2, TempMap, Strategy),
- {FixOffset,NewOffset,DidSpill2} = fix_am2offset(Offset, TempMap, Strategy),
- NewAm2 = Am2#am2{src=NewSrc2,offset=NewOffset},
- %% order matters: FixOffset may clobber temp2/Src2
- {FixOffset ++ FixSrc2, NewAm2, DidSpill1 or DidSpill2}.
-
-fix_am2offset(Offset, TempMap, Strategy) ->
- case Offset of
- #arm_temp{} ->
- fix_src3(Offset, TempMap, Strategy);
- {Src3,rrx} ->
- {Fix,New,DidSpill} = fix_src3(Src3, TempMap, Strategy),
- {Fix, {New,rrx}, DidSpill};
- {Src3,ShiftOp,Imm5} ->
- {Fix,New,DidSpill} = fix_src3(Src3, TempMap, Strategy),
- {Fix, {New,ShiftOp,Imm5}, DidSpill};
- _ ->
- {[], Offset, false}
- end.
-
-fix_am3(Am3=#am3{src=Src2,offset=Offset}, TempMap, Strategy) ->
- {FixSrc2,NewSrc2,DidSpill1} = fix_src2(Src2, TempMap, Strategy),
- {FixOffset,NewOffset,DidSpill2} = fix_am3offset(Offset, TempMap, Strategy),
- NewAm3 = Am3#am3{src=NewSrc2,offset=NewOffset},
- %% order matters: FixOffset may clobber temp2/Src2
- {FixOffset ++ FixSrc2, NewAm3, DidSpill1 or DidSpill2}.
-
-fix_am3offset(Offset, TempMap, Strategy) ->
- case Offset of
- #arm_temp{} -> fix_src3(Offset, TempMap, Strategy);
- _ -> {[], Offset, false}
- end.
-
-fix_src1(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp1(Strategy)).
-
-temp1('new') -> [];
-temp1('fixed') -> hipe_arm_registers:temp1().
-
-fix_src2(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp2(Strategy)).
-
-temp2('new') -> [];
-temp2('fixed') -> hipe_arm_registers:temp2().
-
-fix_src3(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp3(Strategy)).
-
-temp3('new') -> [];
-temp3('fixed') -> hipe_arm_registers:temp3().
-
-fix_src(Src, TempMap, RegOpt) ->
- case temp_is_spilled(Src, TempMap) of
- true ->
- NewSrc = clone(Src, RegOpt),
- {[hipe_arm:mk_pseudo_move(NewSrc, Src)],
- NewSrc,
- true};
- _ ->
- {[], Src, false}
- end.
-
-fix_dst(Dst, TempMap, Strategy) ->
- fix_dst_common(Dst, TempMap, temp1(Strategy)).
-
-fix_dst2(Dst, TempMap, Strategy) -> % only used for smull's DstHi
- fix_dst_common(Dst, TempMap, temp3(Strategy)).
-
-fix_dst_common(Dst, TempMap, RegOpt) ->
- case temp_is_spilled(Dst, TempMap) of
- true ->
- NewDst = clone(Dst, RegOpt),
- {[hipe_arm:mk_pseudo_move(Dst, NewDst)], NewDst, true};
- _ ->
- {[], Dst, false}
- end.
-
-%%% Check if an operand is a pseudo-temp.
-
-temp_is_spilled(Temp, []) -> % special case for naive regalloc
- not(hipe_arm:temp_is_precoloured(Temp));
-temp_is_spilled(Temp, TempMap) ->
- case hipe_arm:temp_is_allocatable(Temp) of
- true ->
- Reg = hipe_arm:temp_reg(Temp),
- tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
- false -> true
- end.
-
-%%% Make a certain reg into a clone of Temp.
-
-clone(Temp, RegOpt) ->
- Type = hipe_arm:temp_type(Temp),
- case RegOpt of
- [] -> hipe_arm:mk_new_temp(Type);
- Reg -> hipe_arm:mk_temp(Reg, Type)
- end.
diff --git a/lib/hipe/arm/hipe_arm_registers.erl b/lib/hipe/arm/hipe_arm_registers.erl
deleted file mode 100644
index 59545c2e64..0000000000
--- a/lib/hipe/arm/hipe_arm_registers.erl
+++ /dev/null
@@ -1,207 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_registers).
-
--export([reg_name_gpr/1,
- first_virtual/0,
- is_precoloured_gpr/1,
- all_precoloured/0, % for coalescing
- return_value/0,
- temp1/0, % C callee-save, not parameter, may be allocatable
- temp2/0, % not parameter, must not be allocatable (frame)
- temp3/0, % not parameter, may be allocatable
- heap_pointer/0,
- stack_pointer/0,
- proc_pointer/0,
- lr/0,
- pc/0,
- %% heap_limit/0,
- %% fcalls/0,
- allocatable_gpr/0, % for coalescing
- is_fixed/1, % for graph coloring
- nr_args/0,
- arg/1,
- args/1,
- is_arg/1, % for linear scan
- call_clobbered/0,
- tailcall_clobbered/0,
- live_at_return/0
- ]).
-
--include("../rtl/hipe_literals.hrl").
-
--define(R0, 0).
--define(R1, 1).
--define(R2, 2).
--define(R3, 3).
--define(R4, 4).
--define(R5, 5).
--define(R6, 6).
--define(R7, 7).
--define(R8, 8).
--define(R9, 9).
--define(R10, 10).
--define(R11, 11).
--define(R12, 12).
--define(R13, 13). % XXX: see all_precoloured()
--define(R14, 14).
--define(R15, 15).
--define(LAST_PRECOLOURED, 15). % must handle both GPR and FPR ranges
-
--define(LR, ?R14).
-
--define(ARG0, ?R1).
--define(ARG1, ?R2).
--define(ARG2, ?R3).
--define(ARG3, ?R4).
--define(ARG4, ?R5).
--define(ARG5, ?R6).
-
--define(TEMP1, ?R8). % stores LR around inc_stack calls, must be C calleE-save
--define(TEMP2, ?R12).
--define(TEMP3, ?R7).
-
--define(RETURN_VALUE, ?R0).
--define(HEAP_POINTER, ?R9).
--define(STACK_POINTER, ?R10).
--define(PROC_POINTER, ?R11).
-
-reg_name_gpr(R) -> [$r | integer_to_list(R)].
-
-%%% Must handle both GPR and FPR ranges.
-first_virtual() -> ?LAST_PRECOLOURED + 1.
-
-%%% These two tests have the same implementation, but that's
-%%% not something we should cast in stone in the interface.
-is_precoloured_gpr(R) -> R =< ?LAST_PRECOLOURED.
-
-all_precoloured() ->
- %% XXX: R13 should be skipped as it never is used anywhere.
- %% Unfortunately, gaps in the list of precoloured registers
- %% cause the graph_color register allocator to create bogus
- %% assignments for those "registers", which in turn causes
- %% the "precoloured reg must map to itself" sanity check in
- %% the frame module to signal errors.
- [ ?R0, ?R1, ?R2, ?R3, ?R4, ?R5, ?R6, ?R7,
- ?R8, ?R9, ?R10, ?R11, ?R12, ?R13, ?R14, ?R15].
-
-return_value() -> ?RETURN_VALUE.
-
-temp1() -> ?TEMP1.
-temp2() -> ?TEMP2.
-temp3() -> ?TEMP3. % for base2 in storeix :-(
-
-heap_pointer() -> ?HEAP_POINTER.
-
-stack_pointer() -> ?STACK_POINTER.
-
-proc_pointer() -> ?PROC_POINTER.
-
-lr() -> ?LR.
-
-pc() -> ?R15.
-
-allocatable_gpr() ->
- %% r9, r10, and r11 are fixed global registers.
- %% r12 may be used by the frame module for large load/store offsets.
- %% r13 is reserved for C.
- %% r15 is the PC, and is not usable as a variable.
- [ ?R0, ?R1, ?R2, ?R3, ?R4, ?R5, ?R6, ?R7,
- ?R8, ?R14].
-
-%% Needed for hipe_graph_coloring_regalloc.
-%% Presumably true for Reg in AllPrecoloured \ Allocatable.
-is_fixed(Reg) ->
- case Reg of
- ?HEAP_POINTER -> true;
- ?STACK_POINTER -> true;
- ?PROC_POINTER -> true;
- %% The following cases are required for linear scan:
- %% it gets confused if it sees a register which is
- %% neither allocatable nor global (fixed or one of
- %% the scratch registers set aside for linear scan).
- ?R15 -> true;
- ?R13 -> true; % XXX: see all_precoloured()
- ?R12 -> true;
- _ -> false
- end.
-
-nr_args() -> ?ARM_NR_ARG_REGS.
-
-args(Arity) when is_integer(Arity) ->
- N = erlang:min(Arity, ?ARM_NR_ARG_REGS),
- args(N-1, []).
-
-args(-1, Rest) -> Rest;
-args(I, Rest) -> args(I-1, [arg(I) | Rest]).
-
-arg(N) ->
- if N < ?ARM_NR_ARG_REGS ->
- case N of
- 0 -> ?ARG0;
- 1 -> ?ARG1;
- 2 -> ?ARG2;
- 3 -> ?ARG3;
- 4 -> ?ARG4;
- 5 -> ?ARG5;
- _ -> exit({?MODULE, arg, N})
- end;
- true ->
- exit({?MODULE, arg, N})
- end.
-
-is_arg(R) ->
- case R of
- ?ARG0 -> ?ARM_NR_ARG_REGS > 0;
- ?ARG1 -> ?ARM_NR_ARG_REGS > 1;
- ?ARG2 -> ?ARM_NR_ARG_REGS > 2;
- ?ARG3 -> ?ARM_NR_ARG_REGS > 3;
- ?ARG4 -> ?ARM_NR_ARG_REGS > 4;
- ?ARG5 -> ?ARM_NR_ARG_REGS > 5;
- _ -> false
- end.
-
-%% Note: the fact that allocatable_gpr() is a subset of call_clobbered() is
-%% hard-coded in hipe_arm_defuse:insn_defs_all_gpr/1
-call_clobbered() -> % does the RA strip the type or not?
- [{?R0,tagged},{?R0,untagged},
- {?R1,tagged},{?R1,untagged},
- {?R2,tagged},{?R2,untagged},
- {?R3,tagged},{?R3,untagged},
- {?R4,tagged},{?R4,untagged},
- {?R5,tagged},{?R5,untagged},
- {?R6,tagged},{?R6,untagged},
- {?R7,tagged},{?R7,untagged},
- {?R8,tagged},{?R8,untagged},
- %% R9 is fixed (HP)
- %% R10 is fixed (NSP)
- %% R11 is fixed (P)
- {?R12,tagged},{?R12,untagged},
- %% R13 is reserved for C
- {?R14,tagged},{?R14,untagged}
- %% R15 is the non-allocatable PC
- ].
-
-tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}
- ,{?LR,tagged},{?LR,untagged}
- ].
-
-live_at_return() ->
- [%%{?LR,untagged},
- {?HEAP_POINTER,untagged},
- {?STACK_POINTER,untagged},
- {?PROC_POINTER,untagged}
- ].
diff --git a/lib/hipe/arm/hipe_arm_subst.erl b/lib/hipe/arm/hipe_arm_subst.erl
deleted file mode 100644
index 4ff245f414..0000000000
--- a/lib/hipe/arm/hipe_arm_subst.erl
+++ /dev/null
@@ -1,127 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_subst).
--export([insn_temps/2, insn_lbls/2]).
--include("hipe_arm.hrl").
-
-%% These should be moved to hipe_arm and exported
--type temp() :: #arm_temp{}.
--type shiftop() :: lsl | lsr | asr | ror.
--type imm4() :: 0..15.
--type imm5() :: 0..31.
--type imm8() :: 0..255.
--type am1() :: {imm8(),imm4()}
- | temp()
- | {temp(), rrx}
- | {temp(), shiftop(), imm5()}
- | {temp(), shiftop(), temp()}.
--type am2() :: #am2{}.
--type am3() :: #am3{}.
--type arg() :: temp() | integer().
--type funv() :: #arm_mfa{} | #arm_prim{} | temp().
--type label() :: non_neg_integer().
--type insn() :: tuple(). % for now
-
--type subst_fun() :: fun((temp()) -> temp()).
-
-%% @doc Maps over the temporaries in an instruction
--spec insn_temps(subst_fun(), insn()) -> insn().
-insn_temps(T, I) ->
- AM1 = fun(O) -> am1_temps(T, O) end,
- AM2 = fun(O) -> am2_temps(T, O) end,
- AM3 = fun(O) -> am3_temps(T, O) end,
- Arg = fun(O) -> arg_temps(T, O) end,
- case I of
- #alu {dst=D,src=L,am1=R} -> I#alu{dst=T(D),src=T(L),am1=AM1(R)};
- #cmp {src=L,am1=R} -> I#cmp {src=T(L),am1=AM1(R)};
- #load {dst=D,am2=S} -> I#load {dst=T(D),am2=AM2(S)};
- #ldrsb {dst=D,am3=S} -> I#ldrsb {dst=T(D),am3=AM3(S)};
- #move {dst=D,am1=S} -> I#move {dst=T(D),am1=AM1(S)};
- #pseudo_move{dst=D,src=S} -> I#pseudo_move {dst=T(D),src=T(S)};
- #store {src=S,am2=D} -> I#store {src=T(S),am2=AM2(D)};
- #b_label{} -> I;
- #comment{} -> I;
- #label{} -> I;
- #pseudo_bc{} -> I;
- #pseudo_blr{} -> I;
- #pseudo_call{funv=F} -> I#pseudo_call{funv=funv_temps(T, F)};
- #pseudo_call_prepare{} -> I;
- #pseudo_li{dst=D} -> I#pseudo_li{dst=T(D)};
- #pseudo_spill_move{dst=D,temp=U,src=S} ->
- I#pseudo_spill_move{dst=T(D),temp=T(U),src=T(S)};
- #pseudo_switch{jtab=J=#arm_temp{},index=Ix=#arm_temp{}} ->
- I#pseudo_switch{jtab=T(J),index=T(Ix)};
- #pseudo_tailcall{funv=F,stkargs=Stk} ->
- I#pseudo_tailcall{funv=funv_temps(T,F),stkargs=lists:map(Arg,Stk)};
- #pseudo_tailcall_prepare{} -> I;
- #smull{dstlo=DL,dsthi=DH,src1=L,src2=R} ->
- I#smull{dstlo=T(DL),dsthi=T(DH),src1=T(L),src2=T(R)}
- end.
-
--spec am1_temps(subst_fun(), am1()) -> am1().
-am1_temps(_SubstTemp, T={C,R}) when is_integer(C), is_integer(R) -> T;
-am1_temps(SubstTemp, T=#arm_temp{}) -> SubstTemp(T);
-am1_temps(SubstTemp, {T=#arm_temp{},rrx}) -> {SubstTemp(T),rrx};
-am1_temps(SubstTemp, {A=#arm_temp{},Op,B=#arm_temp{}}) when is_atom(Op) ->
- {SubstTemp(A),Op,SubstTemp(B)};
-am1_temps(SubstTemp, {T=#arm_temp{},Op,I}) when is_atom(Op), is_integer(I) ->
- {SubstTemp(T),Op,I}.
-
--spec am2_temps(subst_fun(), am2()) -> am2().
-am2_temps(SubstTemp, T=#am2{src=A=#arm_temp{},offset=O0}) ->
- O = case O0 of
- _ when is_integer(O0) -> O0;
- #arm_temp{} -> SubstTemp(O0);
- {B=#arm_temp{},rrx} -> {SubstTemp(B),rrx};
- {B=#arm_temp{},Op,I} when is_atom(Op), is_integer(I) ->
- {SubstTemp(B),Op,I}
- end,
- T#am2{src=SubstTemp(A),offset=O}.
-
--spec am3_temps(subst_fun(), am3()) -> am3().
-am3_temps(SubstTemp, T=#am3{src=A=#arm_temp{},offset=O0}) ->
- O = case O0 of
- _ when is_integer(O0) -> O0;
- #arm_temp{} -> SubstTemp(O0)
- end,
- T#am3{src=SubstTemp(A),offset=O}.
-
--spec funv_temps(subst_fun(), funv()) -> funv().
-funv_temps(_SubstTemp, M=#arm_mfa{}) -> M;
-funv_temps(_SubstTemp, P=#arm_prim{}) -> P;
-funv_temps(SubstTemp, T=#arm_temp{}) -> SubstTemp(T).
-
--spec arg_temps(subst_fun(), arg()) -> arg().
-arg_temps(_SubstTemp, Imm) when is_integer(Imm) -> Imm;
-arg_temps(SubstTemp, T=#arm_temp{}) -> SubstTemp(T).
-
--type lbl_subst_fun() :: fun((label()) -> label()).
-
-%% @doc Maps over the branch targets in an instruction
--spec insn_lbls(lbl_subst_fun(), insn()) -> insn().
-insn_lbls(SubstLbl, I) ->
- case I of
- #b_label{label=Label} ->
- I#b_label{label=SubstLbl(Label)};
- #pseudo_bc{true_label=T, false_label=F} ->
- I#pseudo_bc{true_label=SubstLbl(T), false_label=SubstLbl(F)};
- #pseudo_call{sdesc=Sdesc, contlab=Contlab} ->
- I#pseudo_call{sdesc=sdesc_lbls(SubstLbl, Sdesc),
- contlab=SubstLbl(Contlab)}
- end.
-
-sdesc_lbls(_SubstLbl, Sdesc=#arm_sdesc{exnlab=[]}) -> Sdesc;
-sdesc_lbls(SubstLbl, Sdesc=#arm_sdesc{exnlab=Exnlab}) ->
- Sdesc#arm_sdesc{exnlab=SubstLbl(Exnlab)}.
diff --git a/lib/hipe/arm/hipe_rtl_to_arm.erl b/lib/hipe/arm/hipe_rtl_to_arm.erl
deleted file mode 100644
index 59e0a79b0d..0000000000
--- a/lib/hipe/arm/hipe_rtl_to_arm.erl
+++ /dev/null
@@ -1,858 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_rtl_to_arm).
--export([translate/1]).
-
--include("../rtl/hipe_rtl.hrl").
-
-translate(RTL) ->
- hipe_gensym:init(arm),
- hipe_gensym:set_var(arm, hipe_arm_registers:first_virtual()),
- hipe_gensym:set_label(arm, hipe_gensym:get_label(rtl)),
- Map0 = vmap_empty(),
- {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),
- OldData = hipe_rtl:rtl_data(RTL),
- {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),
- {RegFormals,_} = split_args(Formals),
- Code =
- case RegFormals of
- [] -> Code0;
- _ -> [hipe_arm:mk_label(hipe_gensym:get_next_label(arm)) |
- move_formals(RegFormals, Code0)]
- end,
- IsClosure = hipe_rtl:rtl_is_closure(RTL),
- IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
- hipe_arm:mk_defun(hipe_rtl:rtl_fun(RTL),
- Formals,
- IsClosure,
- IsLeaf,
- Code,
- NewData,
- [],
- []).
-
-conv_insn_list([H|T], Map, Data) ->
- {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),
- %% io:format("~w \n ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),
- {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),
- {NewH ++ NewT, NewData2};
-conv_insn_list([], _, Data) ->
- {[], Data}.
-
-conv_insn(I, Map, Data) ->
- case I of
- #alu{} -> conv_alu(I, Map, Data);
- #alub{} -> conv_alub(I, Map, Data);
- #call{} -> conv_call(I, Map, Data);
- #comment{} -> conv_comment(I, Map, Data);
- #enter{} -> conv_enter(I, Map, Data);
- #goto{} -> conv_goto(I, Map, Data);
- #label{} -> conv_label(I, Map, Data);
- #load{} -> conv_load(I, Map, Data);
- #load_address{} -> conv_load_address(I, Map, Data);
- #load_atom{} -> conv_load_atom(I, Map, Data);
- #move{} -> conv_move(I, Map, Data);
- #return{} -> conv_return(I, Map, Data);
- #store{} -> conv_store(I, Map, Data);
- #switch{} -> conv_switch(I, Map, Data);
- _ -> exit({?MODULE,conv_insn,I})
- end.
-
-conv_alu(I, Map, Data) ->
- %% dst = src1 aluop src2
- {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),
- {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),
- {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),
- RtlAluOp = hipe_rtl:alu_op(I),
- S = false,
- I2 = mk_alu(S, Dst, Src1, RtlAluOp, Src2),
- {I2, Map2, Data}.
-
-conv_shift(RtlShiftOp) ->
- case RtlShiftOp of
- 'sll' -> 'lsl';
- 'srl' -> 'lsr';
- 'sra' -> 'asr'
- end.
-
-conv_arith(RtlAluOp) -> % RtlAluOp \ RtlShiftOp -> ArmArithOp
- case RtlAluOp of
- 'add' -> 'add';
- 'sub' -> 'sub';
- 'mul' -> 'mul';
- 'or' -> 'orr';
- 'and' -> 'and';
- 'xor' -> 'eor'
- end.
-
-commute_arithop(ArithOp) ->
- case ArithOp of
- 'sub' -> 'rsb';
- _ -> ArithOp
- end.
-
-conv_cmpop('add') -> 'cmn';
-conv_cmpop('sub') -> 'cmp';
-conv_cmpop('and') -> 'tst';
-conv_cmpop('xor') -> 'teq';
-conv_cmpop(_) -> none.
-
-cmpop_commutes('cmp') -> false;
-cmpop_commutes('cmn') -> true;
-cmpop_commutes('tst') -> true;
-cmpop_commutes('teq') -> true.
-
-mk_alu(S, Dst, Src1, RtlAluOp, Src2) ->
- case hipe_rtl:is_shift_op(RtlAluOp) of
- true ->
- mk_shift(S, Dst, Src1, conv_shift(RtlAluOp), Src2);
- false ->
- mk_arith(S, Dst, Src1, conv_arith(RtlAluOp), Src2)
- end.
-
-mk_shift(S, Dst, Src1, ShiftOp, Src2) ->
- case hipe_arm:is_temp(Src1) of
- true ->
- case hipe_arm:is_temp(Src2) of
- true ->
- mk_shift_rr(S, Dst, Src1, ShiftOp, Src2);
- _ ->
- mk_shift_ri(S, Dst, Src1, ShiftOp, Src2)
- end;
- _ ->
- case hipe_arm:is_temp(Src2) of
- true ->
- mk_shift_ir(S, Dst, Src1, ShiftOp, Src2);
- _ ->
- mk_shift_ii(S, Dst, Src1, ShiftOp, Src2)
- end
- end.
-
-mk_shift_ii(S, Dst, Src1, ShiftOp, Src2) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_shift_ri(S, Dst, Tmp, ShiftOp, Src2)).
-
-mk_shift_ir(S, Dst, Src1, ShiftOp, Src2) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_shift_rr(S, Dst, Tmp, ShiftOp, Src2)).
-
-mk_shift_ri(S, Dst, Src1, ShiftOp, 0)
- when ShiftOp =:= lsl; ShiftOp =:= lsr; ShiftOp =:= asr ->
- [hipe_arm:mk_move(S, Dst, Src1)];
-mk_shift_ri(S, Dst, Src1, ShiftOp, Src2)
- when is_integer(Src2), Src2 > 0, Src2 < 32 ->
- Am1 = {Src1,ShiftOp,Src2},
- [hipe_arm:mk_move(S, Dst, Am1)].
-
-mk_shift_rr(S, Dst, Src1, ShiftOp, Src2) ->
- Am1 = {Src1,ShiftOp,Src2},
- [hipe_arm:mk_move(S, Dst, Am1)].
-
-mk_arith(S, Dst, Src1, ArithOp, Src2) ->
- case hipe_arm:is_temp(Src1) of
- true ->
- case hipe_arm:is_temp(Src2) of
- true ->
- mk_arith_rr(S, Dst, Src1, ArithOp, Src2);
- _ ->
- mk_arith_ri(S, Dst, Src1, ArithOp, Src2)
- end;
- _ ->
- case hipe_arm:is_temp(Src2) of
- true ->
- mk_arith_ir(S, Dst, Src1, ArithOp, Src2);
- _ ->
- mk_arith_ii(S, Dst, Src1, ArithOp, Src2)
- end
- end.
-
-mk_arith_ii(S, Dst, Src1, ArithOp, Src2) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_arith_ri(S, Dst, Tmp, ArithOp, Src2)).
-
-mk_arith_ir(S, Dst, Src1, ArithOp, Src2) ->
- mk_arith_ri(S, Dst, Src2, commute_arithop(ArithOp), Src1).
-
-mk_arith_ri(S, Dst, Src1, ArithOp, Src2) ->
- case ArithOp of
- 'mul' -> % mul/smull only take reg/reg operands
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src2,
- mk_arith_rr(S, Dst, Src1, ArithOp, Tmp));
- _ -> % add/sub/orr/and/eor have reg/am1 operands
- {FixAm1,NewArithOp,Am1} = fix_aluop_imm(ArithOp, Src2),
- FixAm1 ++ [hipe_arm:mk_alu(NewArithOp, S, Dst, Src1, Am1)]
- end.
-
-mk_arith_rr(S, Dst, Src1, ArithOp, Src2) ->
- case {ArithOp,S} of
- {'mul',true} ->
- %% To check for overflow in 32x32->32 multiplication:
- %% smull Dst,TmpHi,Src1,Src2
- %% mov TmpSign,Dst,ASR #31
- %% cmp TmpSign,TmpHi
- %% [bne OverflowLabel]
- TmpHi = new_untagged_temp(),
- TmpSign = new_untagged_temp(),
- [hipe_arm:mk_smull(Dst, TmpHi, Src1, Src2),
- hipe_arm:mk_move(TmpSign, {Dst,'asr',31}),
- hipe_arm:mk_cmp('cmp', TmpSign, TmpHi)];
- _ ->
- [hipe_arm:mk_alu(ArithOp, S, Dst, Src1, Src2)]
- end.
-
-fix_aluop_imm(AluOp, Imm) -> % {FixAm1,NewAluOp,Am1}
- case hipe_arm:try_aluop_imm(AluOp, Imm) of
- {NewAluOp,Am1} -> {[], NewAluOp, Am1};
- [] ->
- Tmp = new_untagged_temp(),
- {mk_li(Tmp, Imm), AluOp, Tmp}
- end.
-
-conv_alub(I, Map, Data) ->
- %% dst = src1 aluop src2; if COND goto label
- {Src1, Map0} = conv_src(hipe_rtl:alub_src1(I), Map),
- {Src2, Map1} = conv_src(hipe_rtl:alub_src2(I), Map0),
- RtlAluOp = hipe_rtl:alub_op(I),
- RtlCond = hipe_rtl:alub_cond(I),
- HasDst = hipe_rtl:alub_has_dst(I),
- CmpOp = conv_cmpop(RtlAluOp),
- Cond0 = conv_alub_cond(RtlAluOp, RtlCond),
- case (not HasDst) andalso CmpOp =/= none of
- true ->
- I1 = mk_branch(Src1, CmpOp, Src2, Cond0,
- hipe_rtl:alub_true_label(I),
- hipe_rtl:alub_false_label(I),
- hipe_rtl:alub_pred(I)),
- {I1, Map1, Data};
- false ->
- {Dst, Map2} =
- case HasDst of
- false -> {new_untagged_temp(), Map1};
- true -> conv_dst(hipe_rtl:alub_dst(I), Map1)
- end,
- Cond =
- case {RtlAluOp,Cond0} of
- {'mul','vs'} -> 'ne'; % overflow becomes not-equal
- {'mul','vc'} -> 'eq'; % no-overflow becomes equal
- {'mul',_} -> exit({?MODULE,I});
- {_,_} -> Cond0
- end,
- I2 = mk_pseudo_bc(
- Cond,
- hipe_rtl:alub_true_label(I),
- hipe_rtl:alub_false_label(I),
- hipe_rtl:alub_pred(I)),
- S = true,
- I1 = mk_alu(S, Dst, Src1, RtlAluOp, Src2),
- {I1 ++ I2, Map2, Data}
- end.
-
-mk_branch(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred) ->
- case hipe_arm:is_temp(Src1) of
- true ->
- case hipe_arm:is_temp(Src2) of
- true ->
- mk_branch_rr(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred);
- _ ->
- mk_branch_ri(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred)
- end;
- _ ->
- case hipe_arm:is_temp(Src2) of
- true ->
- NewCond =
- case cmpop_commutes(CmpOp) of
- true -> Cond;
- false -> commute_cond(Cond)
- end,
- mk_branch_ri(Src2, CmpOp, Src1, NewCond, TrueLab, FalseLab, Pred);
- _ ->
- mk_branch_ii(Src1, CmpOp, Src2, Cond, TrueLab, FalseLab, Pred)
- end
- end.
-
-mk_branch_ii(Imm1, CmpOp, Imm2, Cond, TrueLab, FalseLab, Pred) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Imm1,
- mk_branch_ri(Tmp, CmpOp, Imm2, Cond,
- TrueLab, FalseLab, Pred)).
-
-mk_branch_ri(Src, CmpOp, Imm, Cond, TrueLab, FalseLab, Pred) ->
- {FixAm1,NewCmpOp,Am1} = fix_aluop_imm(CmpOp, Imm),
- FixAm1 ++ mk_branch_rr(Src, NewCmpOp, Am1, Cond, TrueLab, FalseLab, Pred).
-
-mk_branch_rr(Src, CmpOp, Am1, Cond, TrueLab, FalseLab, Pred) ->
- [hipe_arm:mk_cmp(CmpOp, Src, Am1) |
- mk_pseudo_bc(Cond, TrueLab, FalseLab, Pred)].
-
-conv_call(I, Map, Data) ->
- {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),
- {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),
- {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),
- ContLab = hipe_rtl:call_continuation(I),
- ExnLab = hipe_rtl:call_fail(I),
- Linkage = hipe_rtl:call_type(I),
- I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage),
- {I2, Map2, Data}.
-
-mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- case hipe_arm:is_prim(Fun) of
- true ->
- mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);
- false ->
- mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)
- end.
-
-mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->
- case hipe_arm:prim_prim(Prim) of
- %% no ARM-specific primops defined yet
- _ ->
- mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)
- end.
-
-mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- %% The backend does not support pseudo_calls without a
- %% continuation label, so we make sure each call has one.
- {RealContLab, Tail} =
- case mk_call_results(Dsts) of
- [] ->
- %% Avoid consing up a dummy basic block if the moves list
- %% is empty, as is typical for calls to suspend/0.
- %% This should be subsumed by a general "optimise the CFG"
- %% module, and could probably be removed.
- case ContLab of
- [] ->
- NewContLab = hipe_gensym:get_next_label(arm),
- {NewContLab, [hipe_arm:mk_label(NewContLab)]};
- _ ->
- {ContLab, []}
- end;
- Moves ->
- %% Change the call to continue at a new basic block.
- %% In this block move the result registers to the Dsts,
- %% then continue at the call's original continuation.
- NewContLab = hipe_gensym:get_next_label(arm),
- case ContLab of
- [] ->
- %% This is just a fallthrough
- %% No jump back after the moves.
- {NewContLab,
- [hipe_arm:mk_label(NewContLab) |
- Moves]};
- _ ->
- %% The call has a continuation. Jump to it.
- {NewContLab,
- [hipe_arm:mk_label(NewContLab) |
- Moves ++
- [hipe_arm:mk_b_label(ContLab)]]}
- end
- end,
- SDesc = hipe_arm:mk_sdesc(ExnLab, 0, length(Args), {}),
- CallInsn = hipe_arm:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage),
- {RegArgs,StkArgs} = split_args(Args),
- mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).
-
-mk_call_results([]) ->
- [];
-mk_call_results([Dst]) ->
- RV = hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged'),
- [hipe_arm:mk_pseudo_move(Dst, RV)];
-mk_call_results(Dsts) ->
- exit({?MODULE,mk_call_results,Dsts}).
-
-mk_push_args(StkArgs, Tail) ->
- case length(StkArgs) of
- 0 ->
- Tail;
- NrStkArgs ->
- [hipe_arm:mk_pseudo_call_prepare(NrStkArgs) |
- mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)]
- end.
-
-mk_store_args([Arg|Args], PrevOffset, Tail) ->
- Offset = PrevOffset - word_size(),
- {Src,FixSrc} =
- case hipe_arm:is_temp(Arg) of
- true ->
- {Arg, []};
- _ ->
- Tmp = new_tagged_temp(),
- {Tmp, mk_li(Tmp, Arg)}
- end,
- NewTail = hipe_arm:mk_store('str', Src, mk_sp(), Offset, 'new', Tail),
- mk_store_args(Args, Offset, FixSrc ++ NewTail);
-mk_store_args([], _, Tail) ->
- Tail.
-
-conv_comment(I, Map, Data) ->
- I2 = [hipe_arm:mk_comment(hipe_rtl:comment_text(I))],
- {I2, Map, Data}.
-
-conv_enter(I, Map, Data) ->
- {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),
- {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),
- I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)),
- {I2, Map1, Data}.
-
-mk_enter(Fun, Args, Linkage) ->
- Arity = length(Args),
- {RegArgs,StkArgs} = split_args(Args),
- move_actuals(RegArgs,
- [hipe_arm:mk_pseudo_tailcall_prepare(),
- hipe_arm:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]).
-
-conv_goto(I, Map, Data) ->
- I2 = [hipe_arm:mk_b_label(hipe_rtl:goto_label(I))],
- {I2, Map, Data}.
-
-conv_label(I, Map, Data) ->
- I2 = [hipe_arm:mk_label(hipe_rtl:label_name(I))],
- {I2, Map, Data}.
-
-conv_load(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),
- {Base1, Map1} = conv_src(hipe_rtl:load_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:load_offset(I), Map1),
- LoadSize = hipe_rtl:load_size(I),
- LoadSign = hipe_rtl:load_sign(I),
- I2 = mk_load(Dst, Base1, Base2, LoadSize, LoadSign),
- {I2, Map2, Data}.
-
-mk_load(Dst, Base1, Base2, LoadSize, LoadSign) ->
- case {LoadSize,LoadSign} of
- {byte,signed} ->
- case hipe_arm:is_temp(Base1) of
- true ->
- case hipe_arm:is_temp(Base2) of
- true ->
- mk_ldrsb_rr(Dst, Base1, Base2);
- _ ->
- mk_ldrsb_ri(Dst, Base1, Base2)
- end;
- _ ->
- case hipe_arm:is_temp(Base2) of
- true ->
- mk_ldrsb_ri(Dst, Base2, Base1);
- _ ->
- mk_ldrsb_ii(Dst, Base1, Base2)
- end
- end;
- _ ->
- LdOp =
- case LoadSize of
- byte -> 'ldrb';
- int32 -> 'ldr';
- word -> 'ldr'
- end,
- case hipe_arm:is_temp(Base1) of
- true ->
- case hipe_arm:is_temp(Base2) of
- true ->
- mk_load_rr(Dst, Base1, Base2, LdOp);
- _ ->
- mk_load_ri(Dst, Base1, Base2, LdOp)
- end;
- _ ->
- case hipe_arm:is_temp(Base2) of
- true ->
- mk_load_ri(Dst, Base2, Base1, LdOp);
- _ ->
- mk_load_ii(Dst, Base1, Base2, LdOp)
- end
- end
- end.
-
-mk_load_ii(Dst, Base1, Base2, LdOp) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Base1,
- mk_load_ri(Dst, Tmp, Base2, LdOp)).
-
-mk_load_ri(Dst, Base, Offset, LdOp) ->
- hipe_arm:mk_load(LdOp, Dst, Base, Offset, 'new', []).
-
-mk_load_rr(Dst, Base1, Base2, LdOp) ->
- Am2 = hipe_arm:mk_am2(Base1, '+', Base2),
- [hipe_arm:mk_load(LdOp, Dst, Am2)].
-
-mk_ldrsb_ii(Dst, Base1, Base2) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Base1,
- mk_ldrsb_ri(Dst, Tmp, Base2)).
-
-mk_ldrsb_ri(Dst, Base, Offset) when is_integer(Offset) ->
- {Sign,AbsOffset} =
- if Offset < 0 -> {'-', -Offset};
- true -> {'+', Offset}
- end,
- if AbsOffset =< 255 ->
- Am3 = hipe_arm:mk_am3(Base, Sign, AbsOffset),
- [hipe_arm:mk_ldrsb(Dst, Am3)];
- true ->
- Index = new_untagged_temp(),
- Am3 = hipe_arm:mk_am3(Base, Sign, Index),
- mk_li(Index, AbsOffset,
- [hipe_arm:mk_ldrsb(Dst, Am3)])
- end.
-
-mk_ldrsb_rr(Dst, Base1, Base2) ->
- Am3 = hipe_arm:mk_am3(Base1, '+', Base2),
- [hipe_arm:mk_ldrsb(Dst, Am3)].
-
-conv_load_address(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map),
- Addr = hipe_rtl:load_address_addr(I),
- Type = hipe_rtl:load_address_type(I),
- Src = {Addr,Type},
- I2 = [hipe_arm:mk_pseudo_li(Dst, Src)],
- {I2, Map0, Data}.
-
-conv_load_atom(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map),
- Src = hipe_rtl:load_atom_atom(I),
- I2 = [hipe_arm:mk_pseudo_li(Dst, Src)],
- {I2, Map0, Data}.
-
-conv_move(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0),
- I2 = mk_move(Dst, Src, []),
- {I2, Map1, Data}.
-
-mk_move(Dst, Src, Tail) ->
- case hipe_arm:is_temp(Src) of
- true -> [hipe_arm:mk_pseudo_move(Dst, Src) | Tail];
- _ -> mk_li(Dst, Src, Tail)
- end.
-
-conv_return(I, Map, Data) ->
- %% TODO: multiple-value returns
- {[Arg], Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map),
- I2 = mk_move(mk_rv(), Arg,
- [hipe_arm:mk_pseudo_blr()]),
- {I2, Map0, Data}.
-
-conv_store(I, Map, Data) ->
- {Base, Map0} = conv_src(hipe_rtl:store_base(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),
- {Offset, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),
- StoreSize = hipe_rtl:store_size(I),
- I2 = mk_store(Src, Base, Offset, StoreSize),
- {I2, Map2, Data}.
-
-mk_store(Src, Base, Offset, StoreSize) ->
- StOp =
- case StoreSize of
- byte -> 'strb';
- int32 -> 'str';
- word -> 'str'
- end,
- case hipe_arm:is_temp(Src) of
- true ->
- mk_store2(Src, Base, Offset, StOp);
- _ ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src,
- mk_store2(Tmp, Base, Offset, StOp))
- end.
-
-mk_store2(Src, Base, Offset, StOp) ->
- case hipe_arm:is_temp(Base) of
- true ->
- case hipe_arm:is_temp(Offset) of
- true ->
- mk_store_rr(Src, Base, Offset, StOp);
- _ ->
- mk_store_ri(Src, Base, Offset, StOp)
- end;
- false ->
- case hipe_arm:is_temp(Offset) of
- true ->
- mk_store_ri(Src, Offset, Base, StOp);
- _ ->
- mk_store_ii(Src, Base, Offset, StOp)
- end
- end.
-
-mk_store_ii(Src, Base, Offset, StOp) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Base,
- mk_store_ri(Src, Tmp, Offset, StOp)).
-
-mk_store_ri(Src, Base, Offset, StOp) ->
- hipe_arm:mk_store(StOp, Src, Base, Offset, 'new', []).
-
-mk_store_rr(Src, Base, Index, StOp) ->
- Am2 = hipe_arm:mk_am2(Base, '+', Index),
- [hipe_arm:mk_store(StOp, Src, Am2)].
-
-conv_switch(I, Map, Data) ->
- Labels = hipe_rtl:switch_labels(I),
- LMap = [{label,L} || L <- Labels],
- {NewData, JTabLab} =
- case hipe_rtl:switch_sort_order(I) of
- [] ->
- hipe_consttab:insert_block(Data, word, LMap);
- SortOrder ->
- hipe_consttab:insert_sorted_block(
- Data, word, LMap, SortOrder)
- end,
- %% no immediates allowed here
- {IndexR, Map1} = conv_dst(hipe_rtl:switch_src(I), Map),
- JTabR = new_untagged_temp(),
- I2 =
- [hipe_arm:mk_pseudo_li(JTabR, {JTabLab,constant}),
- hipe_arm:mk_pseudo_switch(JTabR, IndexR, Labels)],
- {I2, Map1, NewData}.
-
-%%% Create a conditional branch.
-
-mk_pseudo_bc(Cond, TrueLabel, FalseLabel, Pred) ->
- [hipe_arm:mk_pseudo_bc(Cond, TrueLabel, FalseLabel, Pred)].
-
-%%% Load an integer constant into a register.
-
-mk_li(Dst, Value) -> mk_li(Dst, Value, []).
-
-mk_li(Dst, Value, Tail) ->
- hipe_arm:mk_li(Dst, Value, Tail).
-
-%%% Convert an RTL condition code.
-
-conv_alub_cond(RtlAluOp, Cond) -> % may be unsigned, depends on aluop
- %% Note: ARM has a non-standard definition of the Carry flag:
- %% 'cmp', 'sub', and 'rsb' define Carry as the NEGATION of Borrow.
- %% This means that the mapping between C/Z combinations and
- %% conditions like "lower" and "higher" becomes non-standard.
- %% (See conv_branch_cond/1 which maps ltu to lo/carry-clear,
- %% while x86 maps ltu to b/carry-set.)
- %% Here in conv_alub_cond/2 it means that the mapping of unsigned
- %% conditions also has to consider the alu operator, since e.g.
- %% 'add' and 'sub' behave differently with regard to Carry.
- case {RtlAluOp, Cond} of % handle allowed alub unsigned conditions
- {'add', 'ltu'} -> 'hs'; % add+ltu == unsigned overflow == carry set == hs
- %% add more cases when needed
- {'sub', _} -> conv_branch_cond(Cond);
- _ -> conv_cond(Cond)
- end.
-
-conv_cond(Cond) -> % only signed
- case Cond of
- eq -> 'eq';
- ne -> 'ne';
- gt -> 'gt';
- ge -> 'ge';
- lt -> 'lt';
- le -> 'le';
- overflow -> 'vs';
- not_overflow -> 'vc'
- end.
-
-conv_branch_cond(Cond) -> % may be unsigned
- case Cond of
- gtu -> 'hi';
- geu -> 'hs';
- ltu -> 'lo';
- leu -> 'ls';
- _ -> conv_cond(Cond)
- end.
-
-%%% Commute an ARM condition code.
-
-commute_cond(Cond) -> % if x Cond y, then y commute_cond(Cond) x
- case Cond of
- 'eq' -> 'eq'; % ==, ==
- 'ne' -> 'ne'; % !=, !=
- 'gt' -> 'lt'; % >, <
- 'ge' -> 'le'; % >=, <=
- 'lt' -> 'gt'; % <, >
- 'le' -> 'ge'; % <=, >=
- 'hi' -> 'lo'; % >u, <u
- 'hs' -> 'ls'; % >=u, <=u
- 'lo' -> 'hi'; % <u, >u
- 'ls' -> 'hs'; % <=u, >=u
- %% vs/vc: n/a
- _ -> exit({?MODULE,commute_cond,Cond})
- end.
-
-%%% Split a list of formal or actual parameters into the
-%%% part passed in registers and the part passed on the stack.
-%%% The parameters passed in registers are also tagged with
-%%% the corresponding registers.
-
-split_args(Args) ->
- split_args(0, hipe_arm_registers:nr_args(), Args, []).
-
-split_args(I, N, [Arg|Args], RegArgs) when I < N ->
- Reg = hipe_arm_registers:arg(I),
- Temp = hipe_arm:mk_temp(Reg, 'tagged'),
- split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]);
-split_args(_, _, StkArgs, RegArgs) ->
- {RegArgs, StkArgs}.
-
-%%% Convert a list of actual parameters passed in
-%%% registers (from split_args/1) to a list of moves.
-
-move_actuals([{Src,Dst}|Actuals], Rest) ->
- move_actuals(Actuals, mk_move(Dst, Src, Rest));
-move_actuals([], Rest) ->
- Rest.
-
-%%% Convert a list of formal parameters passed in
-%%% registers (from split_args/1) to a list of moves.
-
-move_formals([{Dst,Src}|Formals], Rest) ->
- move_formals(Formals, [hipe_arm:mk_pseudo_move(Dst, Src) | Rest]);
-move_formals([], Rest) ->
- Rest.
-
-%%% Convert a 'fun' operand (MFA, prim, or temp)
-
-conv_fun(Fun, Map) ->
- case hipe_rtl:is_var(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- case hipe_rtl:is_reg(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- if is_atom(Fun) ->
- {hipe_arm:mk_prim(Fun), Map};
- true ->
- {conv_mfa(Fun), Map}
- end
- end
- end.
-
-%%% Convert an MFA operand.
-
-conv_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
- hipe_arm:mk_mfa(M, F, A).
-
-%%% Convert an RTL source operand (imm/var/reg).
-%%% Returns a temp or a naked integer.
-
-conv_src(Opnd, Map) ->
- case hipe_rtl:is_imm(Opnd) of
- true ->
- Value = hipe_rtl:imm_value(Opnd),
- if is_integer(Value) ->
- {Value, Map}
- end;
- false ->
- conv_dst(Opnd, Map)
- end.
-
-conv_src_list([O|Os], Map) ->
- {V, Map1} = conv_src(O, Map),
- {Vs, Map2} = conv_src_list(Os, Map1),
- {[V|Vs], Map2};
-conv_src_list([], Map) ->
- {[], Map}.
-
-%%% Convert an RTL destination operand (var/reg).
-
-conv_dst(Opnd, Map) ->
- {Name, Type} =
- case hipe_rtl:is_var(Opnd) of
- true ->
- {hipe_rtl:var_index(Opnd), 'tagged'};
- false ->
- case hipe_rtl:is_fpreg(Opnd) of
- true ->
- {hipe_rtl:fpreg_index(Opnd), 'double'};
- false ->
- {hipe_rtl:reg_index(Opnd), 'untagged'}
- end
- end,
- IsPrecoloured =
- case Type of
- 'double' -> false; %hipe_arm_registers:is_precoloured_fpr(Name);
- _ -> hipe_arm_registers:is_precoloured_gpr(Name)
- end,
- case IsPrecoloured of
- true ->
- {hipe_arm:mk_temp(Name, Type), Map};
- false ->
- case vmap_lookup(Map, Opnd) of
- {value, NewTemp} ->
- {NewTemp, Map};
- _ ->
- NewTemp = hipe_arm:mk_new_temp(Type),
- {NewTemp, vmap_bind(Map, Opnd, NewTemp)}
- end
- end.
-
-conv_dst_list([O|Os], Map) ->
- {Dst, Map1} = conv_dst(O, Map),
- {Dsts, Map2} = conv_dst_list(Os, Map1),
- {[Dst|Dsts], Map2};
-conv_dst_list([], Map) ->
- {[], Map}.
-
-conv_formals(Os, Map) ->
- conv_formals(hipe_arm_registers:nr_args(), Os, Map, []).
-
-conv_formals(N, [O|Os], Map, Res) ->
- Type =
- case hipe_rtl:is_var(O) of
- true -> 'tagged';
- _ -> 'untagged'
- end,
- Dst =
- if N > 0 -> hipe_arm:mk_new_temp(Type); % allocatable
- true -> hipe_arm:mk_new_nonallocatable_temp(Type)
- end,
- Map1 = vmap_bind(Map, O, Dst),
- conv_formals(N-1, Os, Map1, [Dst|Res]);
-conv_formals(_, [], Map, Res) ->
- {lists:reverse(Res), Map}.
-
-%%% Create a temp representing the stack pointer register.
-
-mk_sp() ->
- hipe_arm:mk_temp(hipe_arm_registers:stack_pointer(), 'untagged').
-
-%%% Create a temp representing the return value register.
-
-mk_rv() ->
- hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged').
-
-%%% new_untagged_temp -- conjure up an untagged scratch reg
-
-new_untagged_temp() ->
- hipe_arm:mk_new_temp('untagged').
-
-%%% new_tagged_temp -- conjure up a tagged scratch reg
-
-new_tagged_temp() ->
- hipe_arm:mk_new_temp('tagged').
-
-%%% Map from RTL var/reg operands to temps.
-
-vmap_empty() ->
- gb_trees:empty().
-
-vmap_lookup(Map, Key) ->
- gb_trees:lookup(Key, Map).
-
-vmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-word_size() ->
- 4.
diff --git a/lib/hipe/boot_ebin/.gitignore b/lib/hipe/boot_ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/hipe/boot_ebin/.gitignore
+++ /dev/null
diff --git a/lib/hipe/cerl/Makefile b/lib/hipe/cerl/Makefile
deleted file mode 100644
index 9835772ff8..0000000000
--- a/lib/hipe/cerl/Makefile
+++ /dev/null
@@ -1,114 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2020. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = cerl_to_icode cerl_hipeify cerl_cconv
-
-HRL_FILES= cerl_hipe_primops.hrl
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += +inline +warn_export_vars +warn_unused_import +warn_missing_spec #+warn_untyped_record
-ifneq ($(NATIVE_LIBS_ENABLED),yes)
-ERL_COMPILE_FLAGS += -Werror
-endif
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/cerl"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/cerl"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-$(EBIN)/cerl_cconv.beam: cerl_hipe_primops.hrl
-$(EBIN)/cerl_hipeify.beam: cerl_hipe_primops.hrl
-$(EBIN)/cerl_to_icode.beam: cerl_hipe_primops.hrl ../icode/hipe_icode_primops.hrl
diff --git a/lib/hipe/cerl/cerl_cconv.erl b/lib/hipe/cerl/cerl_cconv.erl
deleted file mode 100644
index 2cd0e261d5..0000000000
--- a/lib/hipe/cerl/cerl_cconv.erl
+++ /dev/null
@@ -1,774 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% @copyright 2000-2004 Richard Carlsson
-%% @author Richard Carlsson <carlsson.richard@gmail.com>
-%% @doc Closure conversion of Core Erlang modules. This is done as a
-%% step in the translation from Core Erlang down to HiPE Icode, and is
-%% very much tied to the calling conventions used in HiPE native code.
-%% @see cerl_to_icode
-
-%% Some information about function closures in Beam and HiPE:
-%%
-%% - In Beam, each fun-expression is lifted to a top-level function such
-%% that the arity of the new function is equal to the arity of the fun
-%% *plus* the number of free variables. The original fun-expression is
-%% replaced by a call to 'make_fun' which takes the *label* of the new
-%% function and the number of free variables as arguments (the arity
-%% of the fun can be found via the label). When a call is made through
-%% the closure, the free variables are extracted from the closure by
-%% the 'call_fun' operation and are placed in the X registers
-%% following the ones used for the normal parameters; then the call is
-%% made to the function label.
-%%
-%% - In HiPE (when compiling from Beam bytecode), the Beam-to-Icode
-%% translation rewrites the fun-functions (those referenced by
-%% 'make_fun' operations) so that the code expects only the normal
-%% parameters, plus *one* extra parameter containing the closure
-%% itself, and then immediately extracts the free variables from the
-%% closure - the code knows how many free variables it expects.
-%% However, the arity part of the function name is *not* changed;
-%% thus, the native code and the Beam code still use the same
-%% fun-table entry. The arity value used in native-code 'make_fun'
-%% operations should therefore be the same as in Beam, i.e., the sum
-%% of the number of parameters and the number of free variables.
-
--module(cerl_cconv).
-
--export([transform/2]).
--export([core_transform/2]).
-
--include("cerl_hipe_primops.hrl").
-
-%% A descriptor for top-level and letrec-bound functions. (Top-level
-%% functions always have an empty list of free variables.) The 'name'
-%% field is the name of the lifted function, and is thus unique over the
-%% whole module.
-
--record(function, {name :: {atom(), arity()}, free}).
-
-%% A record for holding fun-information (if such information is attached
-%% as an annotation on a fun, it should preferably be preserved).
-
--record(fun_info, {name :: atom(),
- id = 0 :: integer(),
- hash = 0 :: integer()}).
-
-%% @spec core_transform(Module::cerl_records(), Options::[term()]) ->
-%% cerl_records()
-%%
-%% @doc Transforms a module represented by records. See
-%% <code>transform/2</code> for details.
-%%
-%% <p>Use the compiler option <code>{core_transform, cerl_cconv}</code>
-%% to insert this function as a compilation pass.</p>
-%%
-%% @see transform/2
-
--spec core_transform(cerl:cerl(), [term()]) -> cerl:cerl().
-
-core_transform(M, Opts) ->
- cerl:to_records(transform(cerl:from_records(M), Opts)).
-
-
-%% @spec transform(Module::cerl(), Options::[term()]) -> cerl()
-%%
-%% cerl() = cerl:cerl()
-%%
-%% @doc Rewrites a Core Erlang module so that all fun-expressions
-%% (lambda expressions) in the code are in top level function
-%% definitions, and the operators of all `apply'-expressions are names
-%% of such top-level functions. The primitive operations `make_fun' and
-%% `call_fun' are inserted in the code to create and apply functional
-%% values; this transformation is known as "Closure Conversion"
-%%
-%% <p>See the module {@link cerl_to_icode} for details.</p>
-
--spec transform(cerl:c_module(), [term()]) -> cerl:c_module().
-
-transform(E, _Options) ->
- M = cerl:module_name(E),
- S0 = s__new(cerl:atom_val(M)),
- {Defs1, S1} = module_defs(cerl:module_defs(E), env__new(),
- ren__new(), S0),
- Defs2 = lists:reverse(s__get_defs(S1) ++ Defs1),
- cerl:update_c_module(E, M, cerl:module_exports(E),
- cerl:module_attrs(E), Defs2).
-
-%% Note that the environment is defined on the renamed variables.
-
-expr(E, Env, Ren, S0) ->
- case cerl:type(E) of
- literal ->
- {E, S0};
- var ->
- var(E, Env, Ren, S0);
- values ->
- {Es, S1} = expr_list(cerl:values_es(E), Env, Ren, S0),
- {cerl:update_c_values(E, Es), S1};
- cons ->
- {E1, S1} = expr(cerl:cons_hd(E), Env, Ren, S0),
- {E2, S2} = expr(cerl:cons_tl(E), Env, Ren, S1),
- {cerl:update_c_cons(E, E1, E2), S2};
- tuple ->
- {Es, S1} = expr_list(cerl:tuple_es(E), Env, Ren, S0),
- {cerl:update_c_tuple(E, Es), S1};
- 'let' ->
- {A, S1} = expr(cerl:let_arg(E), Env, Ren, S0),
- Vs = cerl:let_vars(E),
- {Vs1, Env1, Ren1} = bind_vars(Vs, Env, Ren),
- {B, S2} = expr(cerl:let_body(E), Env1, Ren1, S1),
- {cerl:update_c_let(E, Vs1, A, B), S2};
- seq ->
- {A, S1} = expr(cerl:seq_arg(E), Env, Ren, S0),
- {B, S2} = expr(cerl:seq_body(E), Env, Ren, S1),
- {cerl:update_c_seq(E, A, B), S2};
- apply ->
- apply_expr(E, Env, Ren, S0);
- call ->
- {M, S1} = expr(cerl:call_module(E), Env, Ren, S0),
- {N, S2} = expr(cerl:call_name(E), Env, Ren, S1),
- {As, S3} = expr_list(cerl:call_args(E), Env, Ren, S2),
- {cerl:update_c_call(E, M, N, As), S3};
- primop ->
- {As, S1} = expr_list(cerl:primop_args(E), Env, Ren, S0),
- N = cerl:primop_name(E),
- {cerl:update_c_primop(E, N, As), S1};
- 'case' ->
- {A, S1} = expr(cerl:case_arg(E), Env, Ren, S0),
- {Cs, S2} = expr_list(cerl:case_clauses(E), Env, Ren, S1),
- {cerl:update_c_case(E, A, Cs), S2};
- clause ->
- Vs = cerl:clause_vars(E),
- {_, Env1, Ren1} = bind_vars(Vs, Env, Ren),
- %% Visit patterns to rename variables.
- Ps = pattern_list(cerl:clause_pats(E), Env1, Ren1),
- {G, S1} = expr(cerl:clause_guard(E), Env1, Ren1, S0),
- {B, S2} = expr(cerl:clause_body(E), Env1, Ren1, S1),
- {cerl:update_c_clause(E, Ps, G, B), S2};
- 'fun' ->
- fun_expr(E, Env, Ren, S0);
- 'receive' ->
- {Cs, S1} = expr_list(cerl:receive_clauses(E), Env, Ren, S0),
- {T, S2} = expr(cerl:receive_timeout(E), Env, Ren, S1),
- {A, S3} = expr(cerl:receive_action(E), Env, Ren, S2),
- {cerl:update_c_receive(E, Cs, T, A), S3};
- 'try' ->
- {A, S1} = expr(cerl:try_arg(E), Env, Ren, S0),
- Vs = cerl:try_vars(E),
- {Vs1, Env1, Ren1} = bind_vars(Vs, Env, Ren),
- {B, S2} = expr(cerl:try_body(E), Env1, Ren1, S1),
- Evs = cerl:try_evars(E),
- {Evs1, Env2, Ren2} = bind_vars(Evs, Env, Ren),
- {H, S3} = expr(cerl:try_handler(E), Env2, Ren2, S2),
- {cerl:update_c_try(E, A, Vs1, B, Evs1, H), S3};
- 'catch' ->
- {B, S1} = expr(cerl:catch_body(E), Env, Ren, S0),
- {cerl:update_c_catch(E, B), S1};
- letrec ->
- {Env1, Ren1, S1} = letrec_defs(cerl:letrec_defs(E), Env,
- Ren, S0),
- expr(cerl:letrec_body(E), Env1, Ren1, S1);
- binary ->
- {Segs, S1} = expr_list(cerl:binary_segments(E), Env, Ren, S0),
- {cerl:update_c_binary(E, Segs),S1};
- bitstr ->
- {E1,S1} = expr(cerl:bitstr_val(E), Env, Ren, S0),
- {E2,S2} = expr(cerl:bitstr_size(E), Env, Ren, S1),
- E3 = cerl:bitstr_unit(E),
- E4 = cerl:bitstr_type(E),
- E5 = cerl:bitstr_flags(E),
- {cerl:update_c_bitstr(E, E1, E2, E3, E4, E5), S2}
- end.
-
-expr_list([E | Es], Env, Ren, S0) ->
- {E1, S1} = expr(E, Env, Ren, S0),
- {Es1, S2} = expr_list(Es, Env, Ren, S1),
- {[E1 | Es1], S2};
-expr_list([], _, _, S) ->
- {[], S}.
-
-pattern(E, Env, Ren) ->
- case cerl:type(E) of
- literal ->
- E;
- var ->
- cerl:update_c_var(E, ren__map(cerl:var_name(E), Ren));
- values ->
- Es = pattern_list(cerl:values_es(E), Env, Ren),
- cerl:update_c_values(E, Es);
- cons ->
- E1 = pattern(cerl:cons_hd(E), Env, Ren),
- E2 = pattern(cerl:cons_tl(E), Env, Ren),
- cerl:update_c_cons(E, E1, E2);
- tuple ->
- Es = pattern_list(cerl:tuple_es(E), Env, Ren),
- cerl:update_c_tuple(E, Es);
- binary ->
- Es = pattern_list(cerl:binary_segments(E), Env, Ren),
- cerl:update_c_binary(E, Es);
- bitstr ->
- E1 = pattern(cerl:bitstr_val(E), Env, Ren),
- E2 = pattern(cerl:bitstr_size(E), Env, Ren),
- E3 = cerl:bitstr_unit(E),
- E4 = cerl:bitstr_type(E),
- E5 = cerl:bitstr_flags(E),
- cerl:update_c_bitstr(E, E1, E2, E3, E4, E5);
- alias ->
- V = pattern(cerl:alias_var(E), Env, Ren),
- P = pattern(cerl:alias_pat(E), Env, Ren),
- cerl:update_c_alias(E, V, P)
- end.
-
-pattern_list([E | Es], Env, Ren) ->
- [pattern(E, Env, Ren) | pattern_list(Es, Env, Ren)];
-pattern_list([], _, _) ->
- [].
-
-%% First we set up the environment, binding the function names to the
-%% corresponding descriptors. (For the top level functions, we don't
-%% want to cause renaming.) After that, we can visit each function body
-%% and return the new function definitions and the final state.
-
-module_defs(Ds, Env, Ren, S) ->
- {Env1, S1} = bind_module_defs(Ds, Env, S),
- module_defs_1(Ds, [], Env1, Ren, S1).
-
-bind_module_defs([{V, _F} | Ds], Env, S) ->
- Name = cerl:var_name(V),
- check_function_name(Name, S),
- S1 = s__add_function_name(Name, S),
- Info = #function{name = Name, free = []},
- Env1 = env__bind(Name, Info, Env),
- bind_module_defs(Ds, Env1, S1);
-bind_module_defs([], Env, S) ->
- {Env, S}.
-
-%% Checking that top-level function names are not reused
-
-check_function_name(Name, S) ->
- case s__is_function_name(Name, S) of
- true ->
- error_msg("multiple definitions of function `~tw'.", [Name]),
- exit(error);
- false ->
- ok
- end.
-
-%% We must track which top-level function we are in, for name generation
-%% purposes.
-
-module_defs_1([{V, F} | Ds], Ds1, Env, Ren, S) ->
- S1 = s__enter_function(cerl:var_name(V), S),
- %% The parameters should never need renaming, but this is easiest.
- {Vs, Env1, Ren1} = bind_vars(cerl:fun_vars(F), Env, Ren),
- {B, S2} = expr(cerl:fun_body(F), Env1, Ren1, S1),
- F1 = cerl:update_c_fun(F, Vs, B),
- module_defs_1(Ds, [{V, F1} | Ds1], Env, Ren, S2);
-module_defs_1([], Ds, _, _, S) ->
- {Ds, S}.
-
-%% First we must create the new function names and set up the
-%% environment with descriptors for the letrec-bound functions.
-%%
-%% Since we never shadow variables, the free variables of any
-%% letrec-bound fun can always be referenced directly wherever the
-%% fun-variable itself is referenced - this is important when we create
-%% direct calls to lifted letrec-bound functions, and is the main reason
-%% why we do renaming. For example:
-%%
-%% 'f'/0 = fun () ->
-%% let X = 42 in
-%% letrec 'g'/1 = fun (Y) -> {X, Y} in
-%% let X = 17 in
-%% apply 'g'/1(X)
-%%
-%% will become something like
-%%
-%% 'f'/0 = fun () ->
-%% let X = 42 in
-%% let X1 = 17 in
-%% apply 'g'/2(X1, X)
-%% 'g'/2 = fun (Y, X) -> {X, Y}
-%%
-%% where the innermost X has been renamed so that the outermost X can be
-%% referenced in the call to the lifted function 'g'/2. (Renaming must
-%% of course also be applied also to letrec-bound function variables.)
-%%
-%% Furthermore, if some variable X occurs free in a fun 'f'/N, and 'f'/N
-%% it its turn occurs free in a fun 'g'/M, then we transitively count X
-%% as free in 'g'/M, even if it has no occurrence there. This allows us
-%% to rewrite code such as the following:
-%%
-%% 'f'/0 = fun () ->
-%% let X = 42 in
-%% letrec 'g'/1 = fun (Y) -> {X, Y}
-%% 'h'/1 = fun (Z) -> {'bar', apply 'g'/1(Z)}
-%% in let X = 17 in
-%% apply 'h'/1(X)
-%%
-%% into something like:
-%%
-%% 'f'/0 = fun () ->
-%% let X = 42 in
-%% let X1 = 17 in
-%% apply 'h'/2(X1, X)
-%% 'g'/2 = fun (Y, X) -> {X, Y}
-%% 'h'/2 = fun (Z, X) -> {'bar', apply 'g'/2(Z, X)}
-%%
-%% which uses only direct calls. The drawback is that if the occurrence
-%% of 'f'/N in 'g'/M instead would cause a closure to be created, then
-%% that closure could have been formed earlier (at the point where 'f'/N
-%% was defined), rather than passing on all the free variables of 'f'/N
-%% into 'g'/M. Since we must know the interface to 'g'/M (i.e., the
-%% total number of parameters) before we begin processing its body, and
-%% the interface depends on what we do to the body (and functions can be
-%% mutually recursive), this problem can only be solved by finding out
-%% _what_ we are going to do before we can even define the interfaces of
-%% the functions, by looking at _how_ variables are being referenced
-%% when we look for free variables. Currently, we don't do that.
-
-letrec_defs(Ds, Env, Ren, S) ->
- {Env1, Ren1, S1} = bind_letrec_defs(Ds, Env, Ren, S),
- {Env1, Ren1, lift_letrec_defs(Ds, Env1, Ren1, S1)}.
-
-%% Note: it is important that we store the *renamed* free variables for
-%% each function to be lifted.
-
-bind_letrec_defs(Ds, Env, Ren, S) ->
- bind_letrec_defs(Ds, free_in_defs(Ds, Env, Ren), Env, Ren, S).
-
-bind_letrec_defs([{V, _F} | Ds], Free, Env, Ren, S) ->
- Name = cerl:var_name(V),
- {Env1, Ren1, S1} = bind_letrec_fun(Name, Free, Env, Ren, S),
- bind_letrec_defs(Ds, Free, Env1, Ren1, S1);
-bind_letrec_defs([], _Free, Env, Ren, S) ->
- {Env, Ren, S}.
-
-bind_letrec_fun(Name = {_,A}, Free, Env, Ren, S) ->
- A1 = A + length(Free),
- {Name1, Ren1, S1} = rename_letrec_fun(Name, A1, Env, Ren, S),
- Info = #function{name = Name1, free = Free},
- {env__bind(Name1, Info, Env), Ren1, S1}.
-
-%% Creating a new name for the lifted function that is informative, is
-%% not in the environment, and is not already used for some other lifted
-%% function.
-
-rename_letrec_fun(Name, NewArity, Env, Ren, S) ->
- {New, S1} = new_letrec_fun_name(Name, NewArity, Env, S),
- {New, ren__add(Name, New, Ren), s__add_function_name(New, S1)}.
-
-new_letrec_fun_name({N,_}, Arity, Env, S) ->
- {FName, FArity} = s__get_function(S),
- Base = fun_name_base(FName, FArity)
- ++ "-letrec-" ++ atom_to_list(N) ++ "-",
- %% We try the base as name first. This will usually work.
- Name = {list_to_atom(Base), Arity},
- case env__is_defined(Name, Env) of
- true ->
- new_fun_name(Base, Arity, Env, S);
- false ->
- case s__is_function_name(Name, S) of
- true ->
- new_fun_name(Base, Arity, Env, S);
- false ->
- {Name, S}
- end
- end.
-
-%% Processing the actual functions of a letrec
-
-lift_letrec_defs([{V, F} | Ds], Env, Ren, S) ->
- Info = env__get(ren__map(cerl:var_name(V), Ren), Env),
- S1 = lift_letrec_fun(F, Info, Env, Ren, S),
- lift_letrec_defs(Ds, Env, Ren, S1);
-lift_letrec_defs([], _, _, S) ->
- S.
-
-%% The direct calling convention for letrec-defined functions is to pass
-%% the free variables as additional parameters. Note that the free
-%% variables (if any) are already in the environment when we get here.
-%% We only have to append them to the parameter list so that they are in
-%% scope in the lifted function; they are already renamed.
-%%
-%% It should not be possible for the original parameters to clash with
-%% the free ones (in that case they cannot be free), but we do the full
-%% bind-and-rename anyway, since it's easiest.
-
-lift_letrec_fun(F, Info, Env, Ren, S) ->
- {Vs, Env1, Ren1} = bind_vars(cerl:fun_vars(F), Env, Ren),
- {B, S1} = expr(cerl:fun_body(F), Env1, Ren1, S),
- Fs = [cerl:c_var(V) || V <- Info#function.free],
- F1 = cerl:c_fun(Vs ++ Fs, B),
- s__add_def(cerl:c_var(Info#function.name), F1, S1).
-
-%% This is a simple way of handling mutual recursion in a group of
-%% letrec-definitions: classify a variable as free in all the functions
-%% if it is free in any of them. (The preferred way would be to actually
-%% take the transitive closure for each function.)
-
-free_in_defs(Ds, Env, Ren) ->
- {Vs, Fs} = free_in_defs(Ds, [], [], Ren),
- closure_vars(ordsets:subtract(Fs, Vs), Env, Ren).
-
-free_in_defs([{V, F} | Ds], Vs, Free, Ren) ->
- Fs = cerl_trees:free_variables(F),
- free_in_defs(Ds, [ren__map(cerl:var_name(V), Ren) | Vs], Fs ++ Free,
- Ren);
-free_in_defs([], Vs, Free, _Ren) ->
- {ordsets:from_list(Vs), ordsets:from_list(Free)}.
-
-%% Replacing function variables with the free variables of the function
-
-closure_vars(Vs, Env, Ren) ->
- closure_vars(Vs, [], Env, Ren).
-
-closure_vars([V = {_, _} | Vs], As, Env, Ren) ->
- V1 = ren__map(V, Ren),
- case env__lookup(V1, Env) of
- {ok, #function{free = Vs1}} ->
- closure_vars(Vs, Vs1 ++ As, Env, Ren);
- _ ->
- closure_vars(Vs, As, Env, Ren)
- end;
-closure_vars([V | Vs], As, Env, Ren) ->
- closure_vars(Vs, [V | As], Env, Ren);
-closure_vars([], As, _Env, _Ren) ->
- ordsets:from_list(As).
-
-%% We use the no-shadowing strategy, renaming variables on the fly and
-%% only when necessary to uphold the invariant.
-
-bind_vars(Vs, Env, Ren) ->
- bind_vars(Vs, [], Env, Ren).
-
-bind_vars([V | Vs], Vs1, Env, Ren) ->
- Name = cerl:var_name(V),
- {Name1, Ren1} = rename_var(Name, Env, Ren),
- bind_vars(Vs, [cerl:update_c_var(V, Name1) | Vs1],
- env__bind(Name1, variable, Env), Ren1);
-bind_vars([], Vs, Env, Ren) ->
- {lists:reverse(Vs), Env, Ren}.
-
-rename_var(Name, Env, Ren) ->
- case env__is_defined(Name, Env) of
- false ->
- {Name, Ren};
- true ->
- New = env__new_name(Env),
- {New, ren__add(Name, New, Ren)}
- end.
-
-%% This handles variable references *except* in function application
-%% operator positions (see apply_expr/4).
-%%
-%% The Beam compiler annotates function-variable references with 'id'
-%% info, eventually transforming a direct reference such as "fun f/2"
-%% into a new fun-expression "fun (X1,X2) -> apply f/2(X1,X2)" for which
-%% the info is used to create the lifted function as for any other fun.
-%% We do the same thing for function-bound variables.
-
-var(V, Env, Ren, S) ->
- Name = ren__map(cerl:var_name(V), Ren),
- case lookup_var(Name, Env) of
- #function{name = F, free = Vs} ->
- {_, Arity} = F,
- Vs1 = make_vars(Arity),
- C = cerl:c_apply(cerl:c_var(F), Vs1),
- E = cerl:ann_c_fun(cerl:get_ann(V), Vs1, C),
- fun_expr_1(E, Vs, Env, Ren, S);
- variable ->
- {cerl:update_c_var(V, Name), S}
- end.
-
-lookup_var(V, Env) ->
- case env__lookup(V, Env) of
- {ok, X} ->
- X;
- error ->
- error_msg("unbound variable `~P'.", [V, 5]),
- exit(error)
- end.
-
-make_vars(N) when N > 0 ->
- [cerl:c_var(list_to_atom("X" ++ integer_to_list(N)))
- | make_vars(N - 1)];
-make_vars(0) ->
- [].
-
-%% All funs that are not bound by module or letrec definitions will be
-%% rewritten to create explicit closures using "make fun". We don't
-%% currently track ordinary let-bindings of funs, as in "let F = fun
-%% ... in ...apply F(...)...".
-%%
-%% Note that we (currently) follow the Beam naming convention, including
-%% the free variables in the arity of the name, even though the actual
-%% function typically expects a different number of parameters.
-
-fun_expr(F, Env, Ren, S) ->
- Free = closure_vars(cerl_trees:free_variables(F), Env, Ren),
- Vs = [cerl:c_var(V) || V <- Free],
- fun_expr_1(F, Vs, Env, Ren, S).
-
-fun_expr_1(F, Vs, Env, Ren, S) ->
- Arity = cerl:fun_arity(F) + length(Vs), % for the name only
- {Info, S1} = fun_info(F, Env, S),
- Name = {Info#fun_info.name, Arity},
- S2 = lift_fun(Name, F, Vs, Env, Ren, S1),
- {make_fun_primop(Name, Vs, Info, F, S2), S2}.
-
-make_fun_primop({Name, Arity}, Free, #fun_info{id = Id, hash = Hash},
- F, S) ->
- Module = s__get_module_name(S),
- cerl:update_c_primop(F, cerl:c_atom(?PRIMOP_MAKE_FUN),
- [cerl:c_atom(Module),
- cerl:c_atom(Name),
- cerl:c_int(Arity),
- cerl:c_int(Hash),
- cerl:c_int(Id),
- cerl:make_list(Free)]).
-
-%% Getting attached fun-info, if present; otherwise making it up.
-
-fun_info(E, Env, S) ->
- case lists:keyfind(id, 1, cerl:get_ann(E)) of
- {id, {Id, H, Name}} ->
- %% io:fwrite("Got fun-info: ~w: {~w,~w}.\n", [Name,Id,H]),
- {#fun_info{name = Name, id = Id, hash = H}, S};
- _ ->
- io:fwrite("Warning - fun not annotated: "
- "making up new name.\n"), % for now
- {{Name,_Arity}, S1} = new_fun_name(E, Env, S),
- {#fun_info{name = Name, id = 0, hash = 0}, S1}
- end.
-
-fun_name_base(FName, FArity) ->
- "-" ++ atom_to_list(FName) ++ "/" ++ integer_to_list(FArity).
-
-%% Generate a name for the new function, using a the same convention
-%% that is used by the Beam compiler.
-new_fun_name(F, Env, S) ->
- {FName, FArity} = s__get_function(S),
- Base = fun_name_base(FName, FArity) ++ "-fun-",
- Arity = cerl:fun_arity(F),
- new_fun_name(Base, Arity, Env, S).
-
-%% Creating a new function name that is not in the environment and is
-%% not already used for some other lifted function.
-
-new_fun_name(Base, Arity, Env, S) ->
- F = fun (N) ->
- {list_to_atom(Base ++ integer_to_list(N)), Arity}
- end,
- new_fun_name(Base, Arity, Env, S, F).
-
-new_fun_name(Base, Arity, Env, S, F) ->
- %% Note that repeated calls to env__new_function_name/2 will yield
- %% different names even though Env and F are the same.
- Name = env__new_function_name(F, Env),
- case s__is_function_name(Name, S) of
- true ->
- new_fun_name(Base, Arity, Env, S, F);
- false ->
- {Name, S}
- end.
-
-%% This lifts the fun to a new top-level function which uses the calling
-%% convention for closures, with the closure itself as the final
-%% parameter. Note that the free variables (if any) are already in the
-%% environment.
-%%
-%% It should not be possible for the original parameters to clash with
-%% the free ones (in that case they cannot be free), but we do the full
-%% bind-and-rename anyway, since it's easiest.
-
-lift_fun(Name, F, Free, Env, Ren, S) ->
- %% If the name is already in the list of top-level definitions, we
- %% assume we have already generated this function, and do not need
- %% to do it again (typically, this happens for 'fun f/n'-variables
- %% that have been duplicated before being rewritten to actual
- %% fun-expressions, and the name is taken from their annotations).
- %% Otherwise, we add the name to the list.
- case s__is_function_name(Name, S) of
- true ->
- S;
- false ->
- S1 = s__add_function_name(Name, S),
- lift_fun_1(Name, F, Free, Env, Ren, S1)
- end.
-
-lift_fun_1(Name, F, Free, Env, Ren, S) ->
- %% (The original parameters must be added to the environment before
- %% we generate the new variable for the closure parameter.)
- {Vs, Env1, Ren1} = bind_vars(cerl:fun_vars(F), Env, Ren),
- V = env__new_name(Env1),
- Env2 = env__bind(V, variable, Env1),
- {B, S1} = expr(cerl:fun_body(F), Env2, Ren1, S),
- %% We unpack all free variables from the closure upon entering.
- %% (Adding this to the body before we process it would introduce
- %% unnecessary, although harmless, renaming of the free variables.)
- Es = closure_elements(length(Free), cerl:c_var(V)),
- B1 = cerl:c_let(Free, cerl:c_values(Es), B),
- %% The closure itself is passed as the last argument. The new
- %% function is annotated as being a closure-call entry point.
- E = cerl:ann_c_fun([closure, {closure_orig_arity, cerl:fun_arity(F)}], Vs ++ [cerl:c_var(V)], B1),
- s__add_def(cerl:c_var(Name), E, S1).
-
-closure_elements(N, V) ->
- closure_elements(N, N + 1, V).
-
-closure_elements(0, _, _) -> [];
-closure_elements(N, M, V) ->
- [cerl:c_primop(cerl:c_atom(?PRIMOP_FUN_ELEMENT),
- [cerl:c_int(M - N), V])
- | closure_elements(N - 1, M, V)].
-
-
-%% Function applications must be rewritten depending on the
-%% operator. For a call to a known top-level function or letrec-bound
-%% function, we make a direct call, passing the free variables as extra
-%% parameters (we know they are in scope, since variables may not be
-%% shadowed). Otherwise, we create an "apply fun" primop call that
-%% expects a closure.
-
-apply_expr(E, Env, Ren, S) ->
- {As, S1} = expr_list(cerl:apply_args(E), Env, Ren, S),
- Op = cerl:apply_op(E),
- case cerl:is_c_var(Op) of
- true ->
- Name = ren__map(cerl:var_name(Op), Ren),
- case lookup_var(Name, Env) of
- #function{name = F, free = Vs} ->
- Vs1 = As ++ [cerl:c_var(V) || V <- Vs],
- {cerl:update_c_apply(E, cerl:c_var(F), Vs1), S1};
- variable ->
- apply_expr_1(E, Op, As, Env, Ren, S1)
- end;
- _ ->
- apply_expr_1(E, Op, As, Env, Ren, S1)
- end.
-
-%% Note that this primop call only communicates the necessary
-%% information to the core-to-icode stage, which rewrites it to use the
-%% real calling convention for funs.
-
-apply_expr_1(E, Op, As, Env, Ren, S) ->
- {Op1, S1} = expr(Op, Env, Ren, S),
- Call = cerl:update_c_primop(E, cerl:c_atom(?PRIMOP_APPLY_FUN),
- [Op1, cerl:make_list(As)]),
- {Call, S1}.
-
-
-%% ---------------------------------------------------------------------
-%% Environment
-
-env__new() ->
- rec_env:empty().
-
-env__bind(Key, Value, Env) ->
- rec_env:bind(Key, Value, Env).
-
-env__lookup(Key, Env) ->
- rec_env:lookup(Key, Env).
-
-env__get(Key, Env) ->
- rec_env:get(Key, Env).
-
-env__is_defined(Key, Env) ->
- rec_env:is_defined(Key, Env).
-
-env__new_name(Env) ->
- rec_env:new_key(Env).
-
-env__new_function_name(F, Env) ->
- rec_env:new_key(F, Env).
-
-
-%% ---------------------------------------------------------------------
-%% Renaming
-
-ren__new() ->
- dict:new().
-
-ren__add(Key, Value, Ren) ->
- dict:store(Key, Value, Ren).
-
-ren__map(Key, Ren) ->
- case dict:find(Key, Ren) of
- {ok, Value} ->
- Value;
- error ->
- Key
- end.
-
-
-%% ---------------------------------------------------------------------
-%% State
-
--record(state, {module :: module(),
- function :: {atom(), arity()} | 'undefined',
- names = sets:new() :: sets:set(), %% XXX: refine
- refs = dict:new() :: dict:dict(), %% XXX: refine
- defs = []}).
-
-s__new(Module) ->
- #state{module = Module}.
-
-s__add_function_name(Name, S) ->
- S#state{names = sets:add_element(Name, S#state.names)}.
-
-s__is_function_name(Name, S) ->
- sets:is_element(Name, S#state.names).
-
-s__get_module_name(S) ->
- S#state.module.
-
-s__enter_function(F, S) ->
- S#state{function = F}.
-
-s__get_function(S) ->
- S#state.function.
-
-s__add_def(V, F, S) ->
- S#state{defs = [{V, F} | S#state.defs]}.
-
-s__get_defs(S) ->
- S#state.defs.
-
-
-%% ---------------------------------------------------------------------
-%% Reporting
-
-%% internal_error_msg(S) ->
-%% internal_error_msg(S, []).
-
-%% internal_error_msg(S, Vs) ->
-%% error_msg(lists:concat(["Internal error: ", S]), Vs).
-
-%% error_msg(S) ->
-%% error_msg(S, []).
-
-error_msg(S, Vs) ->
- error_logger:error_msg(lists:concat([?MODULE, ": ", S, "\n"]), Vs).
-
-%% warning_msg(S) ->
-%% warning_msg(S, []).
-
-%% warning_msg(S, Vs) ->
-%% info_msg(lists:concat(["warning: ", S]), Vs).
-
-%% info_msg(S) ->
-%% info_msg(S, []).
-
-%% info_msg(S, Vs) ->
-%% error_logger:info_msg(lists:concat([?MODULE, ": ", S, "\n"]), Vs).
diff --git a/lib/hipe/cerl/cerl_hipe_primops.hrl b/lib/hipe/cerl/cerl_hipe_primops.hrl
deleted file mode 100644
index 6e4d830b61..0000000000
--- a/lib/hipe/cerl/cerl_hipe_primops.hrl
+++ /dev/null
@@ -1,77 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% @copyright 2000 Richard Carlsson
-%% @author Richard Carlsson <carlsson.richard@gmail.com>
-%% @doc Predefined Core Erlang primitive operations used by HiPE.
-
-%% These definitions give the names of Core Erlang primops recognized by
-%% HiPE. Many of them (e.g., 'not'/'and'/'or', and the type tests), are
-%% not primops on the Icode level, but are inline-expanded by the
-%% translation from Core Erlang to Icode, or are renamed/rewritten to a
-%% corresponding ICode primop; they only exist to help the translation.
-
-%%-define(PRIMOP_IDENTITY, identity). % arity 1
--define(PRIMOP_NOT, 'not'). % arity 1
--define(PRIMOP_AND, 'and'). % arity 2
--define(PRIMOP_OR, 'or'). % arity 2
--define(PRIMOP_XOR, 'xor'). % arity 2
--define(PRIMOP_ADD, '+'). % arity 2
--define(PRIMOP_SUB, '-'). % arity 2
--define(PRIMOP_NEG, neg). % arity 1
--define(PRIMOP_MUL, '*'). % arity 2
--define(PRIMOP_DIV, '/'). % arity 2
--define(PRIMOP_INTDIV, 'div'). % arity 2
--define(PRIMOP_REM, 'rem'). % arity 2
--define(PRIMOP_BAND, 'band'). % arity 2
--define(PRIMOP_BOR, 'bor'). % arity 2
--define(PRIMOP_BXOR, 'bxor'). % arity 2
--define(PRIMOP_BNOT, 'bnot'). % arity 1
--define(PRIMOP_BSL, 'bsl'). % arity 2
--define(PRIMOP_BSR, 'bsr'). % arity 2
--define(PRIMOP_EQ, '=='). % arity 2
--define(PRIMOP_NE, '/='). % arity 2
--define(PRIMOP_EXACT_EQ, '=:='). % arity 2
--define(PRIMOP_EXACT_NE, '=/='). % arity 2
--define(PRIMOP_LT, '<'). % arity 2
--define(PRIMOP_GT, '>'). % arity 2
--define(PRIMOP_LE, '=<'). % arity 2
--define(PRIMOP_GE, '>='). % arity 2
--define(PRIMOP_IS_ATOM, 'is_atom'). % arity 1
--define(PRIMOP_IS_BIGNUM, 'is_bignum'). % arity 1
--define(PRIMOP_IS_BINARY, 'is_binary'). % arity 1
--define(PRIMOP_IS_FIXNUM, 'is_fixnum'). % arity 1
--define(PRIMOP_IS_FLOAT, 'is_float'). % arity 1
--define(PRIMOP_IS_FUNCTION, 'is_function'). % arity 1
--define(PRIMOP_IS_INTEGER, 'is_integer'). % arity 1
--define(PRIMOP_IS_LIST, 'is_list'). % arity 1
--define(PRIMOP_IS_NUMBER, 'is_number'). % arity 1
--define(PRIMOP_IS_PID, 'is_pid'). % arity 1
--define(PRIMOP_IS_PORT, 'is_port'). % arity 1
--define(PRIMOP_IS_REFERENCE, 'is_reference'). % arity 1
--define(PRIMOP_IS_TUPLE, 'is_tuple'). % arity 1
--define(PRIMOP_IS_RECORD, 'is_record'). % arity 3
--define(PRIMOP_EXIT, exit). % arity 1
--define(PRIMOP_THROW, throw). % arity 1
--define(PRIMOP_ERROR, error). % arity 1,2
--define(PRIMOP_RETHROW, raise). % arity 2
--define(PRIMOP_RECEIVE_SELECT, receive_select). % arity 0
--define(PRIMOP_RECEIVE_NEXT, receive_next). % arity 0
--define(PRIMOP_ELEMENT, element). % arity 2
--define(PRIMOP_DSETELEMENT, dsetelement). % arity 3
--define(PRIMOP_MAKE_FUN, make_fun). % arity 6
--define(PRIMOP_APPLY_FUN, apply_fun). % arity 2
--define(PRIMOP_FUN_ELEMENT, closure_element). % arity 2
--define(PRIMOP_SET_LABEL, set_label). % arity 1
--define(PRIMOP_GOTO_LABEL, goto_label). % arity 1
--define(PRIMOP_REDUCTION_TEST, reduction_test). % arity 0
--define(PRIMOP_BS_CONTEXT_TO_BINARY, bs_context_to_binary). % arity 1
diff --git a/lib/hipe/cerl/cerl_hipeify.erl b/lib/hipe/cerl/cerl_hipeify.erl
deleted file mode 100644
index 137a54ba32..0000000000
--- a/lib/hipe/cerl/cerl_hipeify.erl
+++ /dev/null
@@ -1,648 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% @copyright 2000-2004 Richard Carlsson
-%% @author Richard Carlsson <carlsson.richard@gmail.com>
-%% @doc HiPE-ification of Core Erlang code. Prepares Core Erlang code
-%% for translation to ICode.
-%% @see cerl_to_icode
-
--module(cerl_hipeify).
-
--define(NO_UNUSED, true).
-
--export([transform/2]).
--ifndef(NO_UNUSED).
--export([core_transform/2]).
--endif.
-
--include("cerl_hipe_primops.hrl").
-
--record(ctxt, {class = expr}).
-
-
-%% @spec core_transform(Module::cerl_records(), Options::[term()]) ->
-%% cerl_records()
-%%
-%% @doc Transforms a module represented by records. See
-%% <code>transform/2</code> for details.
-%%
-%% <p>Use the compiler option <code>{core_transform,
-%% cerl_hipeify}</code> to insert this function as a compilation
-%% pass.</p>
-%%
-%% @see transform/2
-
--ifndef(NO_UNUSED).
-core_transform(M, Opts) ->
- cerl:to_records(transform(cerl:from_records(M), Opts)).
--endif. % NO_UNUSED
-%% @clear
-
-
-%% @spec transform(Module::cerl(), Options::[term()]) -> cerl()
-%%
-%% cerl() = cerl:cerl()
-%%
-%% @doc Rewrites a Core Erlang module to a form suitable for further
-%% translation to HiPE Icode. See module <code>cerl_to_icode</code> for
-%% details.
-%%
-%% @see cerl_to_icode
-%% @see cerl_cconv
-
--spec transform(cerl:c_module(), [term()]) -> cerl:c_module().
-
-transform(E, Opts) ->
- %% Start by closure converting the code
- module(cerl_cconv:transform(E, Opts), Opts).
-
-module(E, Opts) ->
- {Ds, Env, Ren} = add_defs(cerl:module_defs(E), env__new(),
- ren__new()),
- M = cerl:module_name(E),
- S0 = s__new(cerl:atom_val(M)),
- S = s__set_pmatch(proplists:get_value(pmatch, Opts, true), S0),
- {Ds1, _} = defs(Ds, true, Env, Ren, S),
- cerl:update_c_module(E, M, cerl:module_exports(E),
- cerl:module_attrs(E), Ds1).
-
-%% Note that the environment is defined on the renamed variables.
-
-expr(E0, Env, Ren, Ctxt, S0) ->
- %% Do peephole optimizations as we traverse the code.
- E = cerl_lib:reduce_expr(E0),
- case cerl:type(E) of
- literal ->
- {E, S0};
- var ->
- variable(E, Env, Ren, Ctxt, S0);
- values ->
- {Es, S1} = expr_list(cerl:values_es(E), Env, Ren, Ctxt, S0),
- {cerl:update_c_values(E, Es), S1};
- cons ->
- {E1, S1} = expr(cerl:cons_hd(E), Env, Ren, Ctxt, S0),
- {E2, S2} = expr(cerl:cons_tl(E), Env, Ren, Ctxt, S1),
- {cerl:update_c_cons(E, E1, E2), S2};
- tuple ->
- {Es, S1} = expr_list(cerl:tuple_es(E), Env, Ren, Ctxt, S0),
- {cerl:update_c_tuple(E, Es), S1};
- 'let' ->
- let_expr(E, Env, Ren, Ctxt, S0);
- seq ->
- {A, S1} = expr(cerl:seq_arg(E), Env, Ren, Ctxt, S0),
- {B, S2} = expr(cerl:seq_body(E), Env, Ren, Ctxt, S1),
- {cerl:update_c_seq(E, A, B), S2};
- apply ->
- {Op, S1} = expr(cerl:apply_op(E), Env, Ren, Ctxt, S0),
- {As, S2} = expr_list(cerl:apply_args(E), Env, Ren, Ctxt, S1),
- {cerl:update_c_apply(E, Op, As), S2};
- call ->
- {M, S1} = expr(cerl:call_module(E), Env, Ren, Ctxt, S0),
- {N, S2} = expr(cerl:call_name(E), Env, Ren, Ctxt, S1),
- {As, S3} = expr_list(cerl:call_args(E), Env, Ren, Ctxt, S2),
- {rewrite_call(E, M, N, As, S3), S3};
- primop ->
- {As, S1} = expr_list(cerl:primop_args(E), Env, Ren, Ctxt, S0),
- N = cerl:primop_name(E),
- {rewrite_primop(E, N, As, S1), S1};
- 'case' ->
- case_expr(E, Env, Ren, Ctxt, S0);
- 'fun' ->
- Vs = cerl:fun_vars(E),
- {Vs1, Env1, Ren1} = add_vars(Vs, Env, Ren),
- {B, S1} = expr(cerl:fun_body(E), Env1, Ren1, Ctxt, S0),
- {cerl:update_c_fun(E, Vs1, B), S1};
- 'receive' ->
- receive_expr(E, Env, Ren, Ctxt, S0);
- 'try' ->
- {A, S1} = expr(cerl:try_arg(E), Env, Ren, Ctxt, S0),
- Vs = cerl:try_vars(E),
- {Vs1, Env1, Ren1} = add_vars(Vs, Env, Ren),
- {B, S2} = expr(cerl:try_body(E), Env1, Ren1, Ctxt, S1),
- Evs = cerl:try_evars(E),
- {Evs1, Env2, Ren2} = add_vars(Evs, Env, Ren),
- {H, S3} = expr(cerl:try_handler(E), Env2, Ren2, Ctxt, S2),
- {cerl:update_c_try(E, A, Vs1, B, Evs1, H), S3};
- 'catch' ->
- catch_expr(E, Env, Ren, Ctxt, S0);
- letrec ->
- {Ds, Env1, Ren1} = add_defs(cerl:letrec_defs(E), Env, Ren),
- {Ds1, S1} = defs(Ds, false, Env1, Ren1, S0),
- {B, S2} = expr(cerl:letrec_body(E), Env1, Ren1, Ctxt, S1),
- {cerl:update_c_letrec(E, Ds1, B), S2};
- binary ->
- {Segs, S1} = expr_list(cerl:binary_segments(E), Env, Ren,
- Ctxt, S0),
- {cerl:update_c_binary(E, Segs), S1};
- bitstr ->
- {E1,S1} = expr(cerl:bitstr_val(E), Env, Ren, Ctxt, S0),
- {E2,S2} = expr(cerl:bitstr_size(E), Env, Ren, Ctxt, S1),
- E3 = cerl:bitstr_unit(E),
- E4 = cerl:bitstr_type(E),
- E5 = cerl:bitstr_flags(E),
- {cerl:update_c_bitstr(E, E1, E2, E3, E4, E5), S2}
- end.
-
-guard_expr(E, Env, Ren, Ctxt, S) ->
- expr(E, Env, Ren, Ctxt#ctxt{class = guard}, S).
-
-expr_list(Es, Env, Ren, Ctxt, S0) ->
- list(Es, Env, Ren, Ctxt, S0, fun expr/5).
-
-list([E | Es], Env, Ren, Ctxt, S0, F) ->
- {E1, S1} = F(E, Env, Ren, Ctxt, S0),
- {Es1, S2} = list(Es, Env, Ren, Ctxt, S1, F),
- {[E1 | Es1], S2};
-list([], _, _, _, S, _) ->
- {[], S}.
-
-pattern(E, Env, Ren) ->
- case cerl:type(E) of
- literal ->
- E;
- var ->
- cerl:update_c_var(E, ren__map(cerl:var_name(E), Ren));
- values ->
- Es = pattern_list(cerl:values_es(E), Env, Ren),
- cerl:update_c_values(E, Es);
- cons ->
- E1 = pattern(cerl:cons_hd(E), Env, Ren),
- E2 = pattern(cerl:cons_tl(E), Env, Ren),
- cerl:update_c_cons(E, E1, E2);
- tuple ->
- Es = pattern_list(cerl:tuple_es(E), Env, Ren),
- cerl:update_c_tuple(E, Es);
- alias ->
- V = pattern(cerl:alias_var(E), Env, Ren),
- P = pattern(cerl:alias_pat(E), Env, Ren),
- cerl:update_c_alias(E, V, P);
- binary ->
- Segs = pattern_list(cerl:binary_segments(E), Env, Ren),
- cerl:update_c_binary(E, Segs);
- bitstr ->
- E1 = pattern(cerl:bitstr_val(E), Env, Ren),
- E2 = pattern(cerl:bitstr_size(E), Env, Ren),
- E3 = cerl:bitstr_unit(E),
- E4 = cerl:bitstr_type(E),
- E5 = cerl:bitstr_flags(E),
- cerl:update_c_bitstr(E, E1, E2, E3, E4, E5)
- end.
-
-pattern_list(ExprList, Env, Ren) ->
- [pattern(E, Env, Ren) || E <- ExprList].
-
-%% Visit the function body of each definition. We insert an explicit
-%% reduction test at the start of each function.
-
-defs(Ds, Top, Env, Ren, S) ->
- defs(Ds, [], Top, Env, Ren, S).
-
-defs([{V, F} | Ds], Ds1, Top, Env, Ren, S0) ->
- S1 = case Top of
- true -> s__enter_function(cerl:var_name(V), S0);
- false -> S0
- end,
- {B, S2} = expr(cerl:fun_body(F), Env, Ren, #ctxt{}, S1),
- B1 = cerl:c_seq(cerl:c_primop(cerl:c_atom(?PRIMOP_REDUCTION_TEST), []),
- B),
- F1 = cerl:update_c_fun(F, cerl:fun_vars(F), B1),
- defs(Ds, [{V, F1} | Ds1], Top, Env, Ren, S2);
-defs([], Ds, _Top, _Env, _Ren, S) ->
- {lists:reverse(Ds), S}.
-
-case_expr(E, Env, Ren, Ctxt, S0) ->
- {A, S1} = expr(cerl:case_arg(E), Env, Ren, Ctxt, S0),
- {Cs, S2} = clause_list(cerl:case_clauses(E), Env, Ren, Ctxt, S1),
- case s__get_revisit(S2) of
- false ->
- {E1, Vs, S3} = pmatch(Cs, Env, Ren, Ctxt, S2),
- {cerl:c_let(Vs, A, E1), S3};
- true ->
- {cerl:c_case(A, Cs), S2}
- end.
-
-%% Note: There is an ordering problem with switch-clauses and pattern
-%% matching compilation. We must process any receive-clauses first,
-%% making the message queue operations explicit, before we can do
-%% pattern matching compilation. However, the latter can introduce new
-%% expressions - in particular new guards - which also need processing.
-%% Hence, we must process the clauses, then do pattern matching
-%% compilation, and then re-visit the resulting expression with pattern
-%% matching compilation disabled.
-
-pmatch(Cs, Env, _Ren, Ctxt, S0) ->
- {E, Vs} = case s__get_pmatch(S0) of
- true ->
- cerl_pmatch:clauses(Cs, Env);
- no_duplicates ->
- put('cerl_pmatch_duplicate_code', never),
- cerl_pmatch:clauses(Cs, Env);
- duplicate_all ->
- put('cerl_pmatch_duplicate_code', always),
- cerl_pmatch:clauses(Cs, Env);
- false ->
- Vs0 = new_vars(cerl:clause_arity(hd(Cs)), Env),
- {cerl:c_case(cerl:c_values(Vs0), Cs), Vs0}
- end,
- %% Revisit the resulting expression. Pass an empty renaming, since
- %% all variables in E have already been properly renamed and must
- %% not be renamed again by accident.
- {E1, S1} = expr(E, Env, ren__new(), Ctxt, s__set_revisit(true, S0)),
- {E1, Vs, s__set_revisit(false, S1)}.
-
-clause_list(Cs, Env, Ren, Ctxt, S) ->
- list(Cs, Env, Ren, Ctxt, S, fun clause/5).
-
-clause(E, Env, Ren, Ctxt, S0) ->
- Vs = cerl:clause_vars(E),
- {_, Env1, Ren1} = add_vars(Vs, Env, Ren),
- %% Visit patterns to rename variables.
- Ps = pattern_list(cerl:clause_pats(E), Env1, Ren1),
- {G, S1} = guard_expr(cerl:clause_guard(E), Env1, Ren1, Ctxt, S0),
- {B, S2} = expr(cerl:clause_body(E), Env1, Ren1, Ctxt, S1),
- {cerl:update_c_clause(E, Ps, G, B), S2}.
-
-%% We use the no-shadowing strategy, renaming variables on the fly and
-%% only when necessary to uphold the invariant.
-
-add_vars(Vs, Env, Ren) ->
- add_vars(Vs, [], Env, Ren).
-
-add_vars([V | Vs], Vs1, Env, Ren) ->
- Name = cerl:var_name(V),
- {Name1, Ren1} = rename(Name, Env, Ren),
- add_vars(Vs, [cerl:update_c_var(V, Name1) | Vs1],
- env__bind(Name1, variable, Env), Ren1);
-add_vars([], Vs, Env, Ren) ->
- {lists:reverse(Vs), Env, Ren}.
-
-rename(Name, Env, Ren) ->
- case env__is_defined(Name, Env) of
- false ->
- {Name, Ren};
- true ->
- New = env__new_name(Env),
- {New, ren__add(Name, New, Ren)}
- end.
-
-%% Setting up the environment for a list of letrec-bound definitions.
-
-add_defs(Ds, Env, Ren) ->
- add_defs(Ds, [], Env, Ren).
-
-add_defs([{V, F} | Ds], Ds1, Env, Ren) ->
- Name = cerl:var_name(V),
- {Name1, Ren1} =
- case env__is_defined(Name, Env) of
- false ->
- {Name, Ren};
- true ->
- {N, A} = Name,
- S = atom_to_list(N) ++ "_",
- F1 = fun (Num) ->
- {list_to_atom(S ++ integer_to_list(Num)), A}
- end,
- New = env__new_function_name(F1, Env),
- {New, ren__add(Name, New, Ren)}
- end,
- add_defs(Ds, [{cerl:update_c_var(V, Name1), F} | Ds1],
- env__bind(Name1, function, Env), Ren1);
-add_defs([], Ds, Env, Ren) ->
- {lists:reverse(Ds), Env, Ren}.
-
-%% We change remote calls to important built-in functions into primop
-%% calls. In some cases (e.g., for the boolean operators), this is
-%% mainly to allow the cerl_to_icode module to handle them more
-%% straightforwardly. In most cases however, it is simply because they
-%% are supposed to be represented as primop calls on the Icode level.
-
-rewrite_call(E, M, F, As, S) ->
- case cerl:is_c_atom(M) andalso cerl:is_c_atom(F) of
- true ->
- case call_to_primop(cerl:atom_val(M),
- cerl:atom_val(F),
- length(As))
- of
- {yes, ?PRIMOP_IS_RECORD} ->
- %% Needs additional testing
- [_, Tag, Arity] = As,
- case (cerl:is_c_atom(Tag) andalso
- cerl:is_c_int(Arity)) of
- true ->
- %% The primop might need further handling
- N1 = cerl:c_atom(?PRIMOP_IS_RECORD),
- E1 = cerl:update_c_primop(E, N1, As),
- rewrite_primop(E1, N1, As, S);
- false ->
- cerl:update_c_call(E, M, F, As)
- end;
- {yes, N} ->
- %% The primop might need further handling
- N1 = cerl:c_atom(N),
- E1 = cerl:update_c_primop(E, N1, As),
- rewrite_primop(E1, N1, As, S);
- no ->
- cerl:update_c_call(E, M, F, As)
- end;
- false ->
- cerl:update_c_call(E, M, F, As)
- end.
-
-call_to_primop(erlang, 'not', 1) -> {yes, ?PRIMOP_NOT};
-call_to_primop(erlang, 'and', 2) -> {yes, ?PRIMOP_AND};
-call_to_primop(erlang, 'or', 2) -> {yes, ?PRIMOP_OR};
-call_to_primop(erlang, 'xor', 2) -> {yes, ?PRIMOP_XOR};
-call_to_primop(erlang, '+', 2) -> {yes, ?PRIMOP_ADD};
-%%call_to_primop(erlang, '+', 1) -> {yes, ?PRIMOP_IDENTITY};
-call_to_primop(erlang, '-', 2) -> {yes, ?PRIMOP_SUB};
-call_to_primop(erlang, '-', 1) -> {yes, ?PRIMOP_NEG};
-call_to_primop(erlang, '*', 2) -> {yes, ?PRIMOP_MUL};
-call_to_primop(erlang, '/', 2) -> {yes, ?PRIMOP_DIV};
-call_to_primop(erlang, 'div', 2) -> {yes, ?PRIMOP_INTDIV};
-call_to_primop(erlang, 'rem', 2) -> {yes, ?PRIMOP_REM};
-call_to_primop(erlang, 'band', 2) -> {yes, ?PRIMOP_BAND};
-call_to_primop(erlang, 'bor', 2) -> {yes, ?PRIMOP_BOR};
-call_to_primop(erlang, 'bxor', 2) -> {yes, ?PRIMOP_BXOR};
-call_to_primop(erlang, 'bnot', 1) -> {yes, ?PRIMOP_BNOT};
-call_to_primop(erlang, 'bsl', 2) -> {yes, ?PRIMOP_BSL};
-call_to_primop(erlang, 'bsr', 2) -> {yes, ?PRIMOP_BSR};
-call_to_primop(erlang, '==', 2) -> {yes, ?PRIMOP_EQ};
-call_to_primop(erlang, '/=', 2) -> {yes, ?PRIMOP_NE};
-call_to_primop(erlang, '=:=', 2) -> {yes, ?PRIMOP_EXACT_EQ};
-call_to_primop(erlang, '=/=', 2) -> {yes, ?PRIMOP_EXACT_NE};
-call_to_primop(erlang, '<', 2) -> {yes, ?PRIMOP_LT};
-call_to_primop(erlang, '>', 2) -> {yes, ?PRIMOP_GT};
-call_to_primop(erlang, '=<', 2) -> {yes, ?PRIMOP_LE};
-call_to_primop(erlang, '>=', 2) -> {yes, ?PRIMOP_GE};
-call_to_primop(erlang, is_atom, 1) -> {yes, ?PRIMOP_IS_ATOM};
-call_to_primop(erlang, is_binary, 1) -> {yes, ?PRIMOP_IS_BINARY};
-call_to_primop(erlang, is_float, 1) -> {yes, ?PRIMOP_IS_FLOAT};
-call_to_primop(erlang, is_function, 1) -> {yes, ?PRIMOP_IS_FUNCTION};
-call_to_primop(erlang, is_integer, 1) -> {yes, ?PRIMOP_IS_INTEGER};
-call_to_primop(erlang, is_list, 1) -> {yes, ?PRIMOP_IS_LIST};
-call_to_primop(erlang, is_number, 1) -> {yes, ?PRIMOP_IS_NUMBER};
-call_to_primop(erlang, is_pid, 1) -> {yes, ?PRIMOP_IS_PID};
-call_to_primop(erlang, is_port, 1) -> {yes, ?PRIMOP_IS_PORT};
-call_to_primop(erlang, is_reference, 1) -> {yes, ?PRIMOP_IS_REFERENCE};
-call_to_primop(erlang, is_tuple, 1) -> {yes, ?PRIMOP_IS_TUPLE};
-call_to_primop(erlang, internal_is_record, 3) -> {yes, ?PRIMOP_IS_RECORD};
-call_to_primop(erlang, is_record, 3) -> {yes, ?PRIMOP_IS_RECORD};
-call_to_primop(erlang, element, 2) -> {yes, ?PRIMOP_ELEMENT};
-call_to_primop(erlang, exit, 1) -> {yes, ?PRIMOP_EXIT};
-call_to_primop(erlang, throw, 1) -> {yes, ?PRIMOP_THROW};
-call_to_primop(erlang, error, 1) -> {yes, ?PRIMOP_ERROR};
-call_to_primop(erlang, error, 2) -> {yes, ?PRIMOP_ERROR};
-call_to_primop(M, F, A) when is_atom(M), is_atom(F), is_integer(A) -> no.
-
-%% Also, some primops (introduced by Erlang to Core Erlang translation
-%% and possibly other stages) must be recognized and rewritten.
-
-rewrite_primop(E, N, As, S) ->
- case {cerl:atom_val(N), As} of
- {match_fail, [R]} ->
- M = s__get_module_name(S),
- {F, A} = s__get_function_name(S),
- Stack = cerl:abstract([{M, F, A}]),
- case cerl:type(R) of
- tuple ->
- %% Function clause failures have a special encoding
- %% as '{function_clause, Arg1, ..., ArgN}'.
- case cerl:tuple_es(R) of
- [X | Xs] ->
- case cerl:is_c_atom(X) of
- true ->
- case cerl:atom_val(X) of
- function_clause ->
- FStack = cerl:make_list(
- [cerl:c_tuple(
- [cerl:c_atom(M),
- cerl:c_atom(F),
- cerl:make_list(Xs)])]),
- match_fail(E, X, FStack);
- _ ->
- match_fail(E, R, Stack)
- end;
- false ->
- match_fail(E, R, Stack)
- end;
- _ ->
- match_fail(E, R, Stack)
- end;
- _ ->
- match_fail(E, R, Stack)
- end;
- _ ->
- cerl:update_c_primop(E, N, As)
- end.
-
-match_fail(E, R, Stack) ->
- cerl:update_c_primop(E, cerl:c_atom(?PRIMOP_ERROR), [R, Stack]).
-
-%% Simple let-definitions (of degree 1) in guard context are always
-%% inline expanded. This is allowable, since they cannot have side
-%% effects, and it makes it easy to generate good code for boolean
-%% expressions. It could cause repeated evaluations, but typically,
-%% local definitions within guards are used exactly once.
-
-let_expr(E, Env, Ren, Ctxt, S) ->
- if Ctxt#ctxt.class =:= guard ->
- case cerl:let_vars(E) of
- [V] ->
- {Name, Ren1} = rename(cerl:var_name(V), Env, Ren),
- Env1 = env__bind(Name, {expr, cerl:let_arg(E)}, Env),
- expr(cerl:let_body(E), Env1, Ren1, Ctxt, S);
- _ ->
- let_expr_1(E, Env, Ren, Ctxt, S)
- end;
- true ->
- let_expr_1(E, Env, Ren, Ctxt, S)
- end.
-
-let_expr_1(E, Env, Ren, Ctxt, S0) ->
- {A, S1} = expr(cerl:let_arg(E), Env, Ren, Ctxt, S0),
- Vs = cerl:let_vars(E),
- {Vs1, Env1, Ren1} = add_vars(Vs, Env, Ren),
- {B, S2} = expr(cerl:let_body(E), Env1, Ren1, Ctxt, S1),
- {cerl:update_c_let(E, Vs1, A, B), S2}.
-
-variable(E, Env, Ren, Ctxt, S) ->
- V = ren__map(cerl:var_name(E), Ren),
- if Ctxt#ctxt.class =:= guard ->
- case env__lookup(V, Env) of
- {ok, {expr, E1}} ->
- expr(E1, Env, Ren, Ctxt, S); % inline
- _ ->
- %% Since we don't track all bindings when we revisit
- %% guards, some names will not be in the environment.
- variable_1(E, V, S)
- end;
- true ->
- variable_1(E, V, S)
- end.
-
-variable_1(E, V, S) ->
- {cerl:update_c_var(E, V), S}.
-
-%% A catch-expression 'catch Expr' is rewritten as:
-%%
-%% try Expr
-%% of (V) -> V
-%% catch (T, V, E) ->
-%% letrec 'wrap'/1 = fun (V) -> {'EXIT', V}
-%% in case T of
-%% 'throw' when 'true' -> V
-%% 'exit' when 'true' -> 'wrap'/1(V)
-%% V when 'true' ->
-%% 'wrap'/1({V, erlang:get_stacktrace()})
-%% end
-
-catch_expr(E, Env, Ren, Ctxt, S) ->
- T = cerl:c_var('T'),
- V = cerl:c_var('V'),
- X = cerl:c_var('X'),
- W = cerl:c_var({wrap,1}),
- G = cerl:c_call(cerl:c_atom('erlang'),cerl:c_atom('get_stacktrace'),[]),
- Cs = [cerl:c_clause([cerl:c_atom('throw')], V),
- cerl:c_clause([cerl:c_atom('exit')], cerl:c_apply(W, [V])),
- cerl:c_clause([T], cerl:c_apply(W, [cerl:c_tuple([V,G])]))
- ],
- C = cerl:c_case(T, Cs),
- F = cerl:c_fun([V], cerl:c_tuple([cerl:c_atom('EXIT'), V])),
- H = cerl:c_letrec([{W,F}], C),
- As = cerl:get_ann(E),
- {B, S1} = expr(cerl:catch_body(E),Env, Ren, Ctxt, S),
- {cerl:ann_c_try(As, B, [V], V, [T,V,X], H), S1}.
-
-%% Receive-expressions are rewritten as follows:
-%%
-%% receive
-%% P1 when G1 -> B1
-%% ...
-%% Pn when Gn -> Bn
-%% after T -> A end
-%% becomes:
-%% receive
-%% M when 'true' ->
-%% case M of
-%% P1 when G1 -> do primop RECEIVE_SELECT B1
-%% ...
-%% Pn when Gn -> do primop RECEIVE_SELECT Bn
-%% Pn+1 when 'true' -> primop RECEIVE_NEXT()
-%% end
-%% after T -> A end
-
-receive_expr(E, Env, Ren, Ctxt, S0) ->
- case s__get_revisit(S0) of
- false ->
- Cs = receive_clauses(cerl:receive_clauses(E)),
- {Cs1, S1} = clause_list(Cs, Env, Ren, Ctxt, S0),
- {B, Vs, S2} = pmatch(Cs1, Env, Ren, Ctxt, S1),
- {T, S3} = expr(cerl:receive_timeout(E), Env, Ren, Ctxt, S2),
- {A, S4} = expr(cerl:receive_action(E), Env, Ren, Ctxt, S3),
- {cerl:update_c_receive(E, [cerl:c_clause(Vs, B)], T, A), S4};
- true ->
- %% we should never enter a receive-expression twice
- {E, S0}
- end.
-
-receive_clauses([C | Cs]) ->
- Call = cerl:c_primop(cerl:c_atom(?PRIMOP_RECEIVE_SELECT), []),
- B = cerl:c_seq(Call, cerl:clause_body(C)),
- C1 = cerl:update_c_clause(C, cerl:clause_pats(C),
- cerl:clause_guard(C), B),
- [C1 | receive_clauses(Cs)];
-receive_clauses([]) ->
- Call = cerl:c_primop(cerl:c_atom(?PRIMOP_RECEIVE_NEXT), []),
- V = cerl:c_var('X'), % any name is ok
- [cerl:c_clause([V], Call)].
-
-new_vars(N, Env) ->
- [cerl:c_var(V) || V <- env__new_names(N, Env)].
-
-%% ---------------------------------------------------------------------
-%% Environment
-
-env__new() ->
- rec_env:empty().
-
-env__bind(Key, Value, Env) ->
- rec_env:bind(Key, Value, Env).
-
-%% env__get(Key, Env) ->
-%% rec_env:get(Key, Env).
-
-env__lookup(Key, Env) ->
- rec_env:lookup(Key, Env).
-
-env__is_defined(Key, Env) ->
- rec_env:is_defined(Key, Env).
-
-env__new_name(Env) ->
- rec_env:new_key(Env).
-
-env__new_names(N, Env) ->
- rec_env:new_keys(N, Env).
-
-env__new_function_name(F, Env) ->
- rec_env:new_key(F, Env).
-
-%% ---------------------------------------------------------------------
-%% Renaming
-
-ren__new() ->
- dict:new().
-
-ren__add(Key, Value, Ren) ->
- dict:store(Key, Value, Ren).
-
-ren__map(Key, Ren) ->
- case dict:find(Key, Ren) of
- {ok, Value} ->
- Value;
- error ->
- Key
- end.
-
-%% ---------------------------------------------------------------------
-%% State
-
--type pmatch() :: 'true' | 'false' | 'no_duplicates' | 'duplicate_all'.
-
--record(state, {module :: module(),
- function :: {atom(), arity()} | 'undefined',
- pmatch = true :: pmatch(),
- revisit = false :: boolean()}).
-
-s__new(Module) ->
- #state{module = Module}.
-
-s__get_module_name(S) ->
- S#state.module.
-
-s__enter_function(F, S) ->
- S#state{function = F}.
-
-s__get_function_name(S) ->
- S#state.function.
-
-s__set_pmatch(V, S) ->
- S#state{pmatch = V}.
-
-s__get_pmatch(S) ->
- S#state.pmatch.
-
-s__set_revisit(V, S) ->
- S#state{revisit = V}.
-
-s__get_revisit(S) ->
- S#state.revisit.
diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl
deleted file mode 100644
index e37eae8a03..0000000000
--- a/lib/hipe/cerl/cerl_to_icode.erl
+++ /dev/null
@@ -1,2705 +0,0 @@
-%% -*- erlang-indent-level: 4 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% @copyright 2000-2006 Richard Carlsson
-%% @author Richard Carlsson <carlsson.richard@gmail.com>
-%% @doc Translation from Core Erlang to HiPE Icode.
-
-%% TODO: annotate Icode leaf functions as such.
-%% TODO: add a pass to remove unnecessary reduction tests
-%% TODO: generate branch prediction info?
-
--module(cerl_to_icode).
-
--define(NO_UNUSED, true).
-
--export([module/1, module/2]).
--ifndef(NO_UNUSED).
--export([function/3, function/4]).
--endif.
-
-%% Added in an attempt to suppress message by Dialyzer, but I run into
-%% an internal compiler error in the old inliner and commented it out.
-%% The inlining is performed manually instead :-( - Kostis
-%% -compile({inline, [{error_fun_value,1}]}).
-
-%% ---------------------------------------------------------------------
-%% Macros and records
-
-%% Icode primitive operation names
-
--include("../icode/hipe_icode_primops.hrl").
-
--define(OP_REDTEST, redtest).
--define(OP_CONS, cons).
--define(OP_TUPLE, mktuple).
--define(OP_ELEMENT, {erlang,element,2}). %% This has an MFA name
--define(OP_UNSAFE_HD, unsafe_hd).
--define(OP_UNSAFE_TL, unsafe_tl).
--define(OP_UNSAFE_ELEMENT(N), #unsafe_element{index=N}).
--define(OP_UNSAFE_SETELEMENT(N), #unsafe_update_element{index=N}).
--define(OP_CHECK_GET_MESSAGE, check_get_msg).
--define(OP_NEXT_MESSAGE, next_msg).
--define(OP_SELECT_MESSAGE, select_msg).
--define(OP_SET_TIMEOUT, set_timeout).
--define(OP_CLEAR_TIMEOUT, clear_timeout).
--define(OP_WAIT_FOR_MESSAGE, suspend_msg).
--define(OP_APPLY_FIXARITY(N), #apply_N{arity=N}).
--define(OP_MAKE_FUN(M, F, A, U, I), #mkfun{mfa={M,F,A}, magic_num=U, index=I}).
--define(OP_FUN_ELEMENT(N), #closure_element{n=N}).
--define(OP_BS_CONTEXT_TO_BINARY, {hipe_bs_primop,bs_context_to_binary}).
-
-%% Icode conditional tests
-
--define(TEST_EQ, '==').
--define(TEST_NE, '/=').
--define(TEST_EXACT_EQ, '=:=').
--define(TEST_EXACT_NE, '=/=').
--define(TEST_LT, '<').
--define(TEST_GT, '>').
--define(TEST_LE, '=<').
--define(TEST_GE, '>=').
--define(TEST_WAIT_FOR_MESSAGE_OR_TIMEOUT, suspend_msg_timeout).
-
-%% Icode type tests
-
--define(TYPE_ATOM(X), {atom, X}).
--define(TYPE_INTEGER(X), {integer, X}).
--define(TYPE_FIXNUM(X), {integer, X}). % for now
--define(TYPE_CONS, cons).
--define(TYPE_NIL, nil).
--define(TYPE_IS_N_TUPLE(N), {tuple, N}).
--define(TYPE_IS_ATOM, atom).
--define(TYPE_IS_BIGNUM, bignum).
--define(TYPE_IS_BINARY, binary).
--define(TYPE_IS_FIXNUM, fixnum).
--define(TYPE_IS_FLOAT, float).
--define(TYPE_IS_FUNCTION, function).
--define(TYPE_IS_INTEGER, integer).
--define(TYPE_IS_LIST, list).
--define(TYPE_IS_NUMBER, number).
--define(TYPE_IS_PID, pid).
--define(TYPE_IS_PORT, port).
--define(TYPE_IS_RECORD(Atom_, Size_), {record, Atom_, Size_}).
--define(TYPE_IS_REFERENCE, reference).
--define(TYPE_IS_TUPLE, tuple).
-
-%% Record definitions
-
--record('receive', {loop}).
--record(cerl_to_icode__var, {name}).
--record('fun', {label, vars}).
-
--record(ctxt, {final = false :: boolean(),
- effect = false :: boolean(),
- fail = [], % [] or fail-to label
- class = expr :: 'expr' | 'guard',
- line = 0 :: erl_anno:line(), % current line number
- 'receive' :: 'undefined' | #'receive'{}
- }).
-
-%% ---------------------------------------------------------------------
-%% Code
-
-%% @spec module(Module::cerl()) -> [{mfa(), icode()}]
-%% @equiv module(Module, [])
-
--spec module(cerl:c_module()) -> [{mfa(), hipe_icode:icode()}].
-
-module(E) ->
- module(E, []).
-
-%% @spec module(Module::cerl(), Options::[term()]) -> [{mfa(), icode()}]
-%%
-%% cerl() = cerl:c_module()
-%% icode() = hipe_icode:icode()
-%%
-%% @doc Transforms a Core Erlang module to linear HiPE Icode. The result
-%% is a list of Icode function definitions. Currently, no options are
-%% available.
-%%
-%% <p>This function first calls the {@link cerl_hipeify:transform/2}
-%% function on the module.</p>
-%%
-%% <p>Note: Except for the module name, which is included in the header
-%% of each Icode function definition, the remaining information (exports
-%% and attributes) associated with the module definition is not included
-%% in the resulting Icode.</p>
-%%
-%% @see function/4
-%% @see cerl_hipeify:transform/1
-
--spec module(cerl:c_module(), [term()]) -> [{mfa(), hipe_icode:icode()}].
-
-module(E, Options) ->
- module_1(cerl_hipeify:transform(E, Options), Options).
-
-module_1(E, Options) ->
- M = cerl:atom_val(cerl:module_name(E)),
- if is_atom(M) ->
- ok;
- true ->
- error_msg("bad module name: ~P.", [M, 5]),
- throw(error)
- end,
- S0 = init(M),
- S1 = s__set_pmatch(proplists:get_value(pmatch, Options), S0),
- S2 = s__set_bitlevel_binaries(proplists:get_value(
- bitlevel_binaries, Options), S1),
- {Icode, _} = lists:mapfoldl(fun function_definition/2,
- S2, cerl:module_defs(E)),
- Icode.
-
-%% For now, we simply assume that all function bodies should have degree
-%% one (i.e., return exactly one value). We clear the code ackumulator
-%% before we start compiling each function.
-
-function_definition({V, F}, S) ->
- S1 = s__set_code([], S),
- {Icode, S2} = function_1(cerl:var_name(V), F, 1, S1),
- {{icode_icode_name(Icode), Icode}, S2}.
-
-init(Module) ->
- reset_label_counter(),
- s__new(Module).
-
-%% @spec function(Module::atom(), Name::atom(), Function::cerl()) ->
-%% icode()
-%% @equiv function(Module, Name, Fun, 1)
-
--ifndef(NO_UNUSED).
-function(Module, Name, Fun) ->
- function(Module, Name, Fun, 1).
--endif. % NO_UNUSED
-%% @clear
-
-%% @spec function(Module::atom(), Name::{atom(), integer()},
-%% Fun::cerl(), Degree::integer()) -> icode()
-%%
-%% @doc Transforms a Core Erlang function to a HiPE Icode function
-%% definition. `Fun' must represent a fun-expression, which may not
-%% contain free variables. `Module' and `Name' specify the module and
-%% function name of the resulting Icode function. Note that the arity
-%% part of `Name' is not necessarily equivalent to the number of
-%% parameters of `Fun' (this can happen e.g., for lifted closure
-%% functions).
-%%
-%% <p>`Degree' specifies the number of values the function is expected
-%% to return; this is typically 1 (one); cf. {@link function/3}.</p>
-%%
-%% <p>Notes:
-%% <ul>
-%% <li>This function assumes that the code has been transformed into a
-%% very simple and explicit form, using the {@link cerl_hipeify}
-%% module.</li>
-%%
-%% <li>Several primops (see "`cerl_hipe_primops.hrl'") are
-%% detected by the translation and handled specially.</li>
-%%
-%% <li>Tail call optimization is handled, even when the call is
-%% "hidden" by let-definitions.</li>
-%%
-%% <li>It is assumed that all `primop' calls in the code represent
-%% Icode primops or macro instructions, and that all inter-module
-%% calls (both calls to statically named functions, and dynamic
-%% meta-calls) represent <em>actual</em> inter-module calls - not
-%% primitive or built-in operations.</li>
-%%
-%% <li>The following special form:
-%% ```case Test of
-%% 'true' when 'true' -> True
-%% 'false' when 'true' -> False
-%% end'''
-%% is recognized as an if-then-else switch where `Test' is known
-%% to always yield 'true' or 'false'. Efficient jumping code is
-%% generated for such expressions, in particular if nested. Note that
-%% there must be exactly two clauses; order is not important.</li>
-%%
-%% <li>Compilation of clauses is simplistic. No pattern matching
-%% compilation or similar optimizations is done at this stage. Guards
-%% that are `true' or `false' are recognized as trivially true/false;
-%% for all other guards, code will be generated. Catch-all clauses
-%% (with `true' guard and variable-only patterns) are detected, and
-%% any following clauses are discarded.</li>
-%% </ul></p>
-%%
-%% <p><b>Important</b>: This function does not handle occurrences of
-%% fun-expressions in the body of `Fun', nor `apply'-expressions whose
-%% operators are not locally bound function variables. These must be
-%% transformed away before this function is called, by closure
-%% conversion ({@link cerl_cconv}) using the `make_fun' and `call_fun'
-%% primitive operations to create and apply functional values.</p>
-%%
-%% <p>`receive'-expressions are expected to have a particular
-%% form:
-%% <ul>
-%% <li>There must be exactly one clause, with the atom
-%% `true' as guard, and only a single variable as pattern.
-%% The variable will be bound to a message in the mailbox, and can be
-%% referred to in the clause body.</li>
-%%
-%% <li>In the body of that clause, all paths must execute one of the
-%% primitive operations `receive_select/0' or
-%% `receive_next/0' before another
-%% `receive'-statement might be executed.
-%% `receive_select/0' always returns, but without a value,
-%% while `receive_next/0' never returns, either causing
-%% the nearest surrounding receive-expression to be re-tried with the
-%% next message in the input queue, or timing out.</li>
-%% </ul></p>
-%%
-%% @see function/3
-
--include("cerl_hipe_primops.hrl").
-
-%% Main translation function:
-
--ifndef(NO_UNUSED).
-function(Module, Name, Fun, Degree) ->
- S = init(Module),
- {Icode, _} = function_1(Name, Fun, Degree, S),
- Icode.
--endif. % NO_UNUSED
-%% @clear
-
-function_1(Name, Fun, Degree, S) ->
- reset_var_counter(),
- LowV = max_var(),
- LowL = max_label(),
- %% Create input variables for the function parameters, and a list of
- %% target variables for the result of the function.
- Args = cerl:fun_vars(Fun),
- IcodeArity = length(Args),
- Vs = make_vars(IcodeArity),
- Vs1 = make_vars(IcodeArity), % input variable temporaries
- Ts = make_vars(Degree),
-
- %% Initialise environment and context.
- Env = bind_vars(Args, Vs, env__new()),
- %% TODO: if the function returns no values, we can use effect mode
- Ctxt = #ctxt{final = true, effect = false},
- %% Each basic block must begin with a label. Note that we
- %% immediately transfer the input parameters to local variables, for
- %% our self-recursive calling convention.
- Start = new_label(),
- Local = new_label(),
- S1 = add_code([icode_label(Start)]
- ++ make_moves(Vs, Vs1)
- ++ [icode_label(Local)],
- s__set_function(Name, S)),
- S2 = expr(cerl:fun_body(Fun), Ts, Ctxt, Env,
- s__set_local_entry({Local, Vs}, S1)),
-
- %% This creates an Icode function definition. The ranges of used
- %% variables and labels below should be nonempty. Note that the
- %% input variables for the Icode function are `Vs1', which will be
- %% transferred to `Vs' (see above).
- HighV = new_var(), % assure nonempty range
- HighL = max_label(),
- Closure = lists:member(closure, cerl:get_ann(Fun)),
- Module = s__get_module(S2),
- Code = s__get_code(S2),
- Function = icode_icode(Module, Name, Vs1, Closure, Code,
- {LowV, HighV}, {LowL, HighL}),
- if Closure ->
- {_, OrigArity} =
- lists:keyfind(closure_orig_arity, 1, cerl:get_ann(Fun)),
- {hipe_icode:icode_closure_arity_update(Function,
- OrigArity),
- S2};
- true -> {Function, S2}
- end.
-
-%% ---------------------------------------------------------------------
-%% Main expression handler
-
-expr(E, Ts, Ctxt, Env, S0) ->
- %% Insert source code position information
- case get_line(cerl:get_ann(E)) of
- none ->
- expr_1(E, Ts, Ctxt, Env, S0);
- Line when Line > Ctxt#ctxt.line ->
- Txt = "Line: " ++ integer_to_list(Line),
- S1 = add_code([icode_comment(Txt)], S0),
- expr_1(E, Ts, Ctxt#ctxt{line = Line}, Env, S1);
- _ ->
- expr_1(E, Ts, Ctxt, Env, S0)
- end.
-
-expr_1(E, Ts, Ctxt, Env, S) ->
- case cerl:type(E) of
- var ->
- expr_var(E, Ts, Ctxt, Env, S);
- literal ->
- expr_literal(E, Ts, Ctxt, S);
- values ->
- expr_values(E, Ts, Ctxt, Env, S);
- tuple ->
- %% (The unit tuple `{}' is a literal, handled above.)
- expr_tuple(E, Ts, Ctxt, Env, S);
- cons ->
- expr_cons(E, Ts, Ctxt, Env, S);
- 'let' ->
- expr_let(E, Ts, Ctxt, Env, S);
- seq ->
- expr_seq(E, Ts, Ctxt, Env, S);
- apply ->
- expr_apply(E, Ts, Ctxt, Env, S);
- call ->
- expr_call(E, Ts, Ctxt, Env, S);
- primop ->
- expr_primop(E, Ts, Ctxt, Env, S);
- 'case' ->
- expr_case(E, Ts, Ctxt, Env, S);
- 'receive' ->
- expr_receive(E, Ts, Ctxt, Env, S);
- 'try' ->
- expr_try(E, Ts, Ctxt, Env, S);
- binary ->
- expr_binary(E, Ts, Ctxt, Env, S);
- letrec ->
- expr_letrec(E, Ts, Ctxt, Env, S);
- 'fun' ->
- error_msg("cannot handle fun-valued expressions; "
- "must be closure converted."),
- throw(error)
- end.
-
-%% This is for when we need new target variables for all of the
-%% expressions in the list, and evaluate them for value in a
-%% non-tail-call context.
-
-expr_list(Es, Ctxt, Env, S) ->
- Ctxt1 = Ctxt#ctxt{effect = false, final = false},
- lists:mapfoldl(fun (E0, S0) ->
- V = make_var(),
- {V, expr(E0, [V], Ctxt1, Env, S0)}
- end,
- S, Es).
-
-%% This is for when we already have the target variables. It is expected
-%% that each expression in the list has degree one, so the result can be
-%% assigned to the corresponding variable.
-
-exprs([E | Es], [V | Vs], Ctxt, Env, S) ->
- S1 = expr(E, [V], Ctxt, Env, S),
- exprs(Es, Vs, Ctxt, Env, S1);
-exprs([], [], _Ctxt, _Env, S) ->
- S;
-exprs([], _, _Ctxt, _Env, S) ->
- warning_low_degree(),
- S;
-exprs(_, [], _Ctxt, _Env, _S) ->
- error_high_degree(),
- throw(error).
-
-get_line([L | _As]) when is_integer(L) ->
- L;
-get_line([_ | As]) ->
- get_line(As);
-get_line([]) ->
- none.
-
-
-%% ---------------------------------------------------------------------
-%% Variables
-
-expr_var(_E, _Ts, #ctxt{effect = true}, _Env, S) ->
- S;
-expr_var(E, Ts, Ctxt, Env, S) ->
- Name = cerl:var_name(E),
- case env__lookup(Name, Env) of
- error ->
- %% Either an undefined variable or an attempt to use a local
- %% function name as a value.
- case Name of
- {N,A} when is_atom(N), is_integer(A) ->
- %% error_fun_value(Name);
- error_msg("cannot handle fun-values outside call context; "
- "must be closure converted: ~P.",
- [Name, 5]),
- throw(error);
- _ ->
- error_msg("undefined variable: ~P.", [Name, 5]),
- throw(error)
- end;
- {ok, #cerl_to_icode__var{name = V}} ->
- case Ctxt#ctxt.final of
- false ->
- glue([V], Ts, S);
- true ->
- add_return([V], S)
- end;
- {ok, #'fun'{}} ->
- %% A letrec-defined function name, used as a value.
- %% error_fun_value(Name)
- error_msg("cannot handle fun-values outside call context; "
- "must be closure converted: ~P.",
- [Name, 5]),
- throw(error)
- end.
-
-%% The function has been inlined manually above to suppress message by Dialyzer
-%% error_fun_value(Name) ->
-%% error_msg("cannot handle fun-values outside call context; "
-%% "must be closure converted: ~P.",
-%% [Name, 5]),
-%% throw(error).
-
-%% ---------------------------------------------------------------------
-%% This handles all constants, both atomic and compound:
-
-expr_literal(_E, _Ts, #ctxt{effect = true}, S) ->
- S;
-expr_literal(E, [V] = Ts, Ctxt, S) ->
- Code = [icode_move(V, icode_const(cerl:concrete(E)))],
- maybe_return(Ts, Ctxt, add_code(Code, S));
-expr_literal(E, Ts, _Ctxt, _S) ->
- error_degree_mismatch(length(Ts), E),
- throw(error).
-
-%% ---------------------------------------------------------------------
-%% Multiple value aggregate <X1,...,Xn>
-
-expr_values(E, Ts, #ctxt{effect = true} = Ctxt, Env, S) ->
- {_, S1} = exprs(cerl:values_es(E), Ts, Ctxt#ctxt{final = false},
- Env, S),
- S1;
-expr_values(E, Ts, Ctxt, Env, S) ->
- S1 = exprs(cerl:values_es(E), Ts, Ctxt#ctxt{final = false}, Env, S),
- maybe_return(Ts, Ctxt, S1).
-
-%% ---------------------------------------------------------------------
-%% Nonconstant tuples
-
-expr_tuple(E, _Ts, #ctxt{effect = true} = Ctxt, Env, S) ->
- {_Vs, S1} = expr_list(cerl:tuple_es(E), Ctxt, Env, S),
- S1;
-expr_tuple(E, [_V] = Ts, Ctxt, Env, S) ->
- {Vs, S1} = expr_list(cerl:tuple_es(E), Ctxt, Env, S),
- add_code(make_op(?OP_TUPLE, Ts, Vs, Ctxt), S1);
-expr_tuple(E, Ts, _Ctxt, _Env, _S) ->
- error_degree_mismatch(length(Ts), E),
- throw(error).
-
-%% ---------------------------------------------------------------------
-%% Nonconstant cons cells
-
-expr_cons(E, _Ts, #ctxt{effect = true} = Ctxt, Env, S) ->
- {_Vs, S1} = expr_list([cerl:cons_hd(E), cerl:cons_tl(E)], Ctxt, Env, S),
- S1;
-expr_cons(E, [_V] = Ts, Ctxt, Env, S) ->
- {Vs, S1} = expr_list([cerl:cons_hd(E), cerl:cons_tl(E)], Ctxt, Env, S),
- add_code(make_op(?OP_CONS, Ts, Vs, Ctxt), S1);
-expr_cons(E, Ts, _Ctxt, _Env, _S) ->
- error_degree_mismatch(length(Ts), E),
- throw(error).
-
-%% ---------------------------------------------------------------------
-%% Let-expressions
-
-%% We want to make sure we are not easily tricked by expressions hidden
-%% in contexts like "let X = Expr in X"; this should not destroy tail
-%% call properties.
-
-expr_let(E, Ts, Ctxt, Env, S) ->
- F = fun (BF, CtxtF, EnvF, SF) -> expr(BF, Ts, CtxtF, EnvF, SF) end,
- expr_let_1(E, F, Ctxt, Env, S).
-
-expr_let_1(E, F, Ctxt, Env, S) ->
- E1 = cerl_lib:reduce_expr(E),
- case cerl:is_c_let(E1) of
- true ->
- expr_let_2(E1, F, Ctxt, Env, S);
- false ->
- %% Redispatch the new expression.
- F(E1, Ctxt, Env, S)
- end.
-
-expr_let_2(E, F, Ctxt, Env, S) ->
- Vars = cerl:let_vars(E),
- Vs = make_vars(length(Vars)),
- S1 = expr(cerl:let_arg(E), Vs,
- Ctxt#ctxt{effect = false, final = false}, Env, S),
- Env1 = bind_vars(Vars, Vs, Env),
- F(cerl:let_body(E), Ctxt, Env1, S1).
-
-%% ---------------------------------------------------------------------
-%% Sequencing
-
-%% To compile a sequencing operator, we generate code for effect only
-%% for the first expression (the "argument") and then use the
-%% surrounding context for the second expression (the "body"). Note that
-%% we always create a new dummy target variable; this is necessary for
-%% many ICode operations, even if the result is not used.
-
-expr_seq(E, Ts, Ctxt, Env, S) ->
- F = fun (BF, CtxtF, EnvF, SF) -> expr(BF, Ts, CtxtF, EnvF, SF) end,
- expr_seq_1(E, F, Ctxt, Env, S).
-
-expr_seq_1(E, F, Ctxt, Env, S) ->
- Ctxt1 = Ctxt#ctxt{effect = true, final = false},
- S1 = expr(cerl:seq_arg(E), [make_var()], Ctxt1, Env, S),
- F(cerl:seq_body(E), Ctxt, Env, S1).
-
-%% ---------------------------------------------------------------------
-%% Binaries
-
--record(sz_var, {code, sz}).
--record(sz_const, {code, sz}).
-
-expr_binary(E, [V]=Ts, Ctxt, Env, S) ->
- Offset = make_reg(),
- Base = make_reg(),
- Segs = cerl:binary_segments(E),
- S1 = case do_size_code(Segs, S, Env, Ctxt) of
- #sz_const{code = S0, sz = Size} ->
- Primop = {hipe_bs_primop, {bs_init, Size, 0}},
- add_code([icode_call_primop([V, Base, Offset], Primop, [])],
- S0);
- #sz_var{code = S0, sz = SizeVar} ->
- Primop = {hipe_bs_primop, {bs_init, 0}},
- add_code([icode_call_primop([V, Base, Offset],
- Primop, [SizeVar])],
- S0)
- end,
- Vars = make_vars(length(Segs)),
- S2 = binary_segments(Segs, Vars, Ctxt, Env, S1, false, Base, Offset),
- S3 = case s__get_bitlevel_binaries(S2) of
- true ->
- POp = {hipe_bs_primop, bs_final},
- add_code([icode_call_primop([V], POp, [V, Offset])], S2);
- false ->
- S2
- end,
- maybe_return(Ts, Ctxt, S3).
-
-do_size_code(Segs, S, Env, Ctxt) ->
- case do_size_code(Segs, S, Env, cerl:c_int(0), [], []) of
- {[], [], Const, S1} ->
- #sz_const{code = S1, sz = ((cerl:concrete(Const) + 7) div 8)};
- {Pairs, Bins, Const, S1} ->
- V1 = make_var(),
- S2 = add_code([icode_move(V1, icode_const(cerl:int_val(Const)))], S1),
- {S3, SizeVar} = create_size_code(Pairs, Bins, Ctxt, V1, S2),
- #sz_var{code = S3, sz = SizeVar}
- end.
-
-do_size_code([Seg|Rest], S, Env, Const, Pairs, Bins) ->
- Size = cerl:bitstr_size(Seg),
- Unit = cerl:bitstr_unit(Seg),
- Val = cerl:bitstr_val(Seg),
- case calculate_size(Unit, Size, false, Env, S) of
- {all,_, _, S} ->
- Binary = make_var(),
- S1 = expr(Val, [Binary], #ctxt{final=false}, Env, S),
- do_size_code(Rest, S1, Env, Const, Pairs, [{all,Binary}|Bins]);
- {NewVal, [], S, _} ->
- do_size_code(Rest, S, Env, add_val(NewVal, Const), Pairs, Bins);
- {UnitVal, [Var], S1, _} ->
- do_size_code(Rest, S1, Env, Const, [{UnitVal,Var}|Pairs], Bins)
- end;
-do_size_code([], S, _Env, Const, Pairs, Bins) ->
- {Pairs, Bins, Const, S}.
-
-add_val(NewVal, Const) ->
- cerl:c_int(NewVal + cerl:concrete(Const)).
-
-create_size_code([{UnitVal, Var}|Rest], Bins, Ctxt, Old, S0) ->
- Dst = make_var(),
- S = make_bs_add(UnitVal, Old, Var, Dst, Ctxt, S0),
- create_size_code(Rest, Bins, Ctxt, Dst, S);
-create_size_code([], Bins, Ctxt, Old, S0) ->
- Dst = make_var(),
- S = make_bs_bits_to_bytes(Old, Dst, Ctxt, S0),
- create_size_code(Bins, Ctxt, Dst, S).
-
-create_size_code([{all,Bin}|Rest], Ctxt, Old, S0) ->
- Dst = make_var(),
- S = make_binary_size(Old, Bin, Dst, Ctxt, S0),
- create_size_code(Rest, Ctxt, Dst, S);
-create_size_code([], _Ctxt, Dst, S) ->
- {S, Dst}.
-
-make_bs_add(Unit, Old, Var, Dst, #ctxt{fail=FL, class=guard}, S0) ->
- SL1 = new_label(),
- SL2 = new_label(),
- SL3 = new_label(),
- Temp = make_var(),
- add_code([icode_if('>=', [Var, icode_const(0)], SL1, FL),
- icode_label(SL1),
- icode_guardop([Temp], '*', [Var, icode_const(Unit)], SL2, FL),
- icode_label(SL2),
- icode_guardop([Dst], '+', [Temp, Old], SL3, FL),
- icode_label(SL3)], S0);
-make_bs_add(Unit, Old, Var, Dst, _Ctxt, S0) ->
- SL = new_label(),
- FL = new_label(),
- Temp = make_var(),
- add_code([icode_if('>=', [Var, icode_const(0)], SL, FL),
- icode_label(FL),
- icode_fail([icode_const(badarg)], error),
- icode_label(SL),
- icode_call_primop([Temp], '*', [Var, icode_const(Unit)]),
- icode_call_primop([Dst], '+', [Temp, Old])], S0).
-
-make_bs_bits_to_bytes(Old, Dst, #ctxt{fail=FL, class=guard}, S0) ->
- SL = new_label(),
- add_code([icode_guardop([Dst], 'bsl', [Old, icode_const(3)], SL, FL),
- icode_label(SL)], S0);
-make_bs_bits_to_bytes(Old, Dst, _Ctxt, S0) ->
- add_code([icode_call_primop([Dst], 'bsl', [Old, icode_const(3)])], S0).
-
-make_binary_size(Old, Bin, Dst, #ctxt{fail=FL, class=guard}, S0) ->
- SL1 = new_label(),
- SL2 = new_label(),
- add_code([icode_guardop([Dst], {erlang, byte_size, 1}, [Bin], SL1, FL),
- icode_label(SL1),
- icode_guardop([Dst], '+', [Old, Dst], SL2, FL),
- icode_label(SL2)], S0);
-make_binary_size(Old, Bin, Dst, _Ctxt, S0) ->
- add_code([icode_call_primop([Dst], {erlang, byte_size, 1}, [Bin]),
- icode_call_primop([Dst], '+', [Old, Dst])], S0).
-
-binary_segments(SegList, TList, Ctxt=#ctxt{}, Env, S, Align, Base,
- Offset) ->
- case do_const_segs(SegList, TList, S, Align, Base, Offset) of
- {[Seg|Rest], [T|Ts], S1} ->
- {S2, NewAlign} = bitstr(Seg, [T], Ctxt, Env, S1, Align,
- Base, Offset),
- binary_segments(Rest, Ts, Ctxt, Env, S2, NewAlign, Base, Offset);
- {[], [], S1} ->
- S1
- end.
-
-do_const_segs(SegList, TList, S, _Align, Base, Offset) ->
- case get_segs(SegList, TList, [], 0, {[], SegList, TList}) of
- {[], SegList, TList} ->
- {SegList, TList, S};
- {ConstSegs, RestSegs, RestT} ->
- String = create_string(ConstSegs, <<>>, 0),
- Name = {bs_put_string, String, length(String)},
- Primop = {hipe_bs_primop, Name},
- {RestSegs, RestT,
- add_code([icode_call_primop([Offset], Primop, [Base, Offset])],
- S)}
- end.
-
-get_segs([Seg|Rest], [_|RestT], Acc, AccSize, BestPresent) ->
- Size = cerl:bitstr_size(Seg),
- Unit = cerl:bitstr_unit(Seg),
- Val = cerl:bitstr_val(Seg),
- case allowed(Size, Unit, Val, AccSize) of
- {true, NewAccSize} ->
- case Acc of
- [] ->
- get_segs(Rest, RestT, [Seg|Acc], NewAccSize, BestPresent);
- _ ->
- get_segs(Rest, RestT, [Seg|Acc], NewAccSize,
- {lists:reverse([Seg|Acc]), Rest, RestT})
- end;
- {possible, NewAccSize} ->
- get_segs(Rest, RestT, [Seg|Acc], NewAccSize, BestPresent);
- false ->
- BestPresent
- end;
-get_segs([], [], _Acc, _AccSize, Best) ->
- Best.
-
-
-create_string([Seg|Rest], Bin, TotalSize) ->
- Size = cerl:bitstr_size(Seg),
- Unit = cerl:bitstr_unit(Seg),
- NewSize = cerl:int_val(Size) * cerl:int_val(Unit),
- LitVal = cerl:concrete(cerl:bitstr_val(Seg)),
- LiteralFlags = cerl:bitstr_flags(Seg),
- FlagVal = translate_flags(LiteralFlags, []),
- NewTotalSize = NewSize + TotalSize,
- Pad = (8 - NewTotalSize rem 8) rem 8,
- NewBin = case cerl:concrete(cerl:bitstr_type(Seg)) of
- integer ->
- case {FlagVal band 2, FlagVal band 4} of
- {2, 4} ->
- <<Bin:TotalSize/binary-unit:1,
- LitVal:NewSize/integer-little-signed, 0:Pad>>;
- {0, 4} ->
- <<Bin:TotalSize/binary-unit:1,
- LitVal:NewSize/integer-signed, 0:Pad>>;
- {2, 0} ->
- <<Bin:TotalSize/binary-unit:1,
- LitVal:NewSize/integer-little, 0:Pad>>;
- {0, 0} ->
- <<Bin:TotalSize/binary-unit:1,
- LitVal:NewSize/integer, 0:Pad>>
- end;
- float ->
- case FlagVal band 2 of
- 2 ->
- <<Bin:TotalSize/binary-unit:1,
- LitVal:NewSize/float-little, 0:Pad>>;
- 0 ->
- <<Bin:TotalSize/binary-unit:1,
- LitVal:NewSize/float, 0:Pad>>
- end
- end,
- create_string(Rest, NewBin, NewTotalSize);
-
-create_string([], Bin, _Size) ->
- binary_to_list(Bin).
-
-allowed(Size, Unit, Val, AccSize) ->
- case {cerl:is_c_int(Size), cerl:is_literal(Val)} of
- {true, true} ->
- NewAccSize = cerl:int_val(Size) * cerl:int_val(Unit) + AccSize,
- case NewAccSize rem 8 of
- 0 ->
- {true, NewAccSize};
- _ ->
- {possible, NewAccSize}
- end;
- _ ->
- false
- end.
-
-bitstr(E, Ts, Ctxt, Env, S, Align, Base, Offset) ->
- Size = cerl:bitstr_size(E),
- Unit = cerl:bitstr_unit(E),
- LiteralFlags = cerl:bitstr_flags(E),
- Val = cerl:bitstr_val(E),
- Type = cerl:concrete(cerl:bitstr_type(E)),
- S0 = expr(Val, Ts, Ctxt#ctxt{final = false, effect = false}, Env, S),
- ConstInfo = get_const_info(Val, Type),
- Flags = translate_flags(LiteralFlags, Align),
- SizeInfo = calculate_size(Unit, Size, false, Env, S0),
- bitstr_gen_op(Ts, Ctxt, SizeInfo, ConstInfo, Type, Flags, Base, Offset).
-
-bitstr_gen_op([V], #ctxt{fail=FL, class=guard}, SizeInfo, ConstInfo,
- Type, Flags, Base, Offset) ->
- SL = new_label(),
- case SizeInfo of
- {all, NewUnit, NewAlign, S1} ->
- Type = binary,
- Name = {bs_put_binary_all, NewUnit, Flags},
- Primop = {hipe_bs_primop, Name},
- {add_code([icode_guardop([Offset], Primop,
- [V, Base, Offset], SL, FL),
- icode_label(SL)], S1), NewAlign};
- {NewUnit, NewArgs, S1, NewAlign} ->
- Args = [V|NewArgs] ++ [Base, Offset],
- Name =
- case Type of
- integer ->
- {bs_put_integer, NewUnit, Flags, ConstInfo};
- float ->
- {bs_put_float, NewUnit, Flags, ConstInfo};
- binary ->
- {bs_put_binary, NewUnit, Flags}
- end,
- Primop = {hipe_bs_primop, Name},
- {add_code([icode_guardop([Offset], Primop, Args, SL, FL),
- icode_label(SL)], S1), NewAlign}
- end;
-bitstr_gen_op([V], _Ctxt, SizeInfo, ConstInfo, Type, Flags, Base,
- Offset) ->
- case SizeInfo of
- {all, NewUnit, NewAlign, S} ->
- Type = binary,
- Name = {bs_put_binary_all, NewUnit, Flags},
- Primop = {hipe_bs_primop, Name},
- {add_code([icode_call_primop([Offset], Primop,
- [V, Base, Offset])], S),
- NewAlign};
- {NewUnit, NewArgs, S, NewAlign} ->
- Args = [V|NewArgs] ++ [Base, Offset],
- Name =
- case Type of
- integer ->
- {bs_put_integer, NewUnit, Flags, ConstInfo};
- float ->
- {bs_put_float, NewUnit, Flags, ConstInfo};
- binary ->
- {bs_put_binary, NewUnit, Flags}
- end,
- Primop = {hipe_bs_primop, Name},
- {add_code([icode_call_primop([Offset], Primop, Args)], S),
- NewAlign}
- end.
-
-%% ---------------------------------------------------------------------
-%% Apply-expressions
-
-%% Note that the arity of the called function only depends on the length
-%% of the argument list; the arity stated by the function name is
-%% ignored.
-
-expr_apply(E, Ts, Ctxt, Env, S) ->
- Op = cerl_lib:reduce_expr(cerl:apply_op(E)),
- {Vs, S1} = expr_list(cerl:apply_args(E), Ctxt, Env, S),
- case cerl:is_c_var(Op) of
- true ->
- case cerl:var_name(Op) of
- {N, A} = V when is_atom(N), is_integer(A) ->
- case env__lookup(V, Env) of
- error ->
- %% Assumed to be a function in the
- %% current module; we don't check.
- add_local_call(V, Vs, Ts, Ctxt, S1);
- {ok, #'fun'{label = L, vars = Vs1}} ->
- %% Call to a local letrec-bound function.
- add_letrec_call(L, Vs1, Vs, Ctxt, S1);
- {ok, #cerl_to_icode__var{}} ->
- error_msg("cannot call via variable; must "
- "be closure converted: ~P.",
- [V, 5]),
- throw(error)
- end;
- _ ->
- error_nonlocal_application(Op),
- throw(error)
- end;
- false ->
- error_nonlocal_application(Op),
- throw(error)
- end.
-
-%% ---------------------------------------------------------------------
-%% Call-expressions
-
-%% Unless we know the module and function names statically, we have to
-%% go through the meta-call operator for a static number of arguments.
-
-expr_call(E, Ts, Ctxt, Env, S) ->
- Module = cerl_lib:reduce_expr(cerl:call_module(E)),
- Name = cerl_lib:reduce_expr(cerl:call_name(E)),
- case cerl:is_c_atom(Module) and cerl:is_c_atom(Name) of
- true ->
- M = cerl:atom_val(Module),
- F = cerl:atom_val(Name),
- {Vs, S1} = expr_list(cerl:call_args(E), Ctxt, Env, S),
- add_code(make_call(M, F, Ts, Vs, Ctxt), S1);
- false ->
- Args = cerl:call_args(E),
- N = length(Args),
- {Vs, S1} = expr_list([Module, Name | Args], Ctxt, Env, S),
- add_code(make_op(?OP_APPLY_FIXARITY(N), Ts, Vs, Ctxt), S1)
- end.
-
-%% ---------------------------------------------------------------------
-%% Primop calls
-
-%% Core Erlang primop calls are generally mapped directly to Icode
-%% primop calls, with a few exceptions (listed above), which are
-%% expanded inline, sometimes depending on context. Note that primop
-%% calls do not have specialized tail-call forms.
-
-expr_primop(E, Ts, Ctxt, Env, S) ->
- Name = cerl:atom_val(cerl:primop_name(E)),
- As = cerl:primop_args(E),
- Arity = length(As),
- expr_primop_0(Name, Arity, As, E, Ts, Ctxt, Env, S).
-
-expr_primop_0(Name, Arity, As, E, Ts, #ctxt{effect = true} = Ctxt, Env,
- S) ->
- case is_safe_op(Name, Arity) of
- true ->
- %% Just drop the operation; cf. 'expr_values(...)'.
- {_, S1} = expr_list(As, Ctxt, Env, S),
- S1;
- false ->
- expr_primop_1(Name, Arity, As, E, Ts,
- Ctxt#ctxt{effect = false}, Env, S)
- end;
-expr_primop_0(Name, Arity, As, E, Ts, Ctxt, Env, S) ->
- expr_primop_1(Name, Arity, As, E, Ts, Ctxt, Env, S).
-
-%% Some primops must be caught before their arguments are visited.
-
-expr_primop_1(?PRIMOP_MAKE_FUN, 6, As, _E, Ts, Ctxt, Env, S) ->
- primop_make_fun(As, Ts, Ctxt, Env, S);
-expr_primop_1(?PRIMOP_APPLY_FUN, 2, As, _E, Ts, Ctxt, Env, S) ->
- primop_apply_fun(As, Ts, Ctxt, Env, S);
-expr_primop_1(?PRIMOP_FUN_ELEMENT, 2, As, _E, Ts, Ctxt, Env, S) ->
- primop_fun_element(As, Ts, Ctxt, Env, S);
-expr_primop_1(?PRIMOP_DSETELEMENT, 3, As, _E, Ts, Ctxt, Env, S) ->
- primop_dsetelement(As, Ts, Ctxt, Env, S);
-expr_primop_1(?PRIMOP_RECEIVE_SELECT, 0, _As, _E, Ts, Ctxt, _Env, S) ->
- primop_receive_select(Ts, Ctxt, S);
-expr_primop_1(?PRIMOP_RECEIVE_NEXT, 0, _As, _E, _Ts, Ctxt, _Env, S) ->
- primop_receive_next(Ctxt, S);
-%%expr_primop_1(?PRIMOP_IDENTITY, 1, [A], _E, Ts, Ctxt, Env, S) ->
-%% expr(A, Ts, Ctxt, Env, S); % used for unary plus
-expr_primop_1(?PRIMOP_NEG, 1, [A], _, Ts, Ctxt, Env, S) ->
- E = cerl:c_primop(cerl:c_atom('-'), [cerl:c_int(0), A]),
- expr_primop(E, Ts, Ctxt, Env, S);
-expr_primop_1(?PRIMOP_GOTO_LABEL, 1, [A], _, _Ts, _Ctxt, _Env, S) ->
- primop_goto_label(A, S);
-expr_primop_1(?PRIMOP_REDUCTION_TEST, 0, [], _, _Ts, Ctxt, _Env, S) ->
- primop_reduction_test(Ctxt, S);
-expr_primop_1(Name, Arity, As, E, Ts, Ctxt, Env, S) ->
- case is_pure_op_aux(Name, Arity) of
- true ->
- boolean_expr(E, Ts, Ctxt, Env, S);
- false ->
- {Vs, S1} = expr_list(As, Ctxt, Env, S),
- expr_primop_2(Name, Arity, Vs, Ts, Ctxt, S1)
- end.
-
-expr_primop_2(?PRIMOP_ELEMENT, 2, Vs, Ts, Ctxt, S) ->
- add_code(make_op(?OP_ELEMENT, Ts, Vs, Ctxt), S);
-expr_primop_2(?PRIMOP_BS_CONTEXT_TO_BINARY, 1, Vs, Ts, Ctxt, S) ->
- add_code(make_op(?OP_BS_CONTEXT_TO_BINARY, Ts, Vs, Ctxt), S);
-expr_primop_2(?PRIMOP_EXIT, 1, [V], _Ts, Ctxt, S) ->
- add_exit(V, Ctxt, S);
-expr_primop_2(?PRIMOP_THROW, 1, [V], _Ts, Ctxt, S) ->
- add_throw(V, Ctxt, S);
-expr_primop_2(?PRIMOP_ERROR, 1, [V], _Ts, Ctxt, S) ->
- add_error(V, Ctxt, S);
-expr_primop_2(?PRIMOP_ERROR, 2, [V, F], _Ts, Ctxt, S) ->
- add_error(V, F, Ctxt, S);
-expr_primop_2(?PRIMOP_RETHROW, 2, [E, V], _Ts, Ctxt, S) ->
- add_rethrow(E, V, Ctxt, S);
-expr_primop_2(Name, _Arity, Vs, Ts, Ctxt, S) ->
- %% Other ops are assumed to be recognized by the backend.
- add_code(make_op(Name, Ts, Vs, Ctxt), S).
-
-%% All of M, F, and A must be literals with the right types.
-%% V must represent a proper list.
-
-primop_make_fun([M, F, A, H, I, V] = As, [_T] = Ts, Ctxt, Env, S) ->
- case cerl:is_c_atom(M) and
- cerl:is_c_atom(F) and
- cerl:is_c_int(A) and
- cerl:is_c_int(H) and
- cerl:is_c_int(I) and
- cerl:is_c_list(V) of
- true ->
- Module = cerl:atom_val(M),
- Name = cerl:atom_val(F),
- Arity = cerl:int_val(A),
- Hash = cerl:int_val(H),
- Index = cerl:int_val(I),
- {Vs, S1} = expr_list(cerl:list_elements(V),
- Ctxt, Env, S),
- add_code(make_op(?OP_MAKE_FUN(Module, Name, Arity,
- Hash, Index),
- Ts, Vs, Ctxt),
- S1);
- false ->
- error_primop_badargs(?PRIMOP_MAKE_FUN, As),
- throw(error)
- end.
-
-%% V must represent a proper list.
-
-primop_apply_fun([F, V] = As, [_T] = Ts, Ctxt, Env, S) ->
- case cerl:is_c_list(V) of
- true ->
- %% Note that the closure itself is passed as the last value.
- {Vs, S1} = expr_list(cerl:list_elements(V) ++ [F],
- Ctxt, Env, S),
- case Ctxt#ctxt.final of
- false ->
- add_code([icode_call_fun(Ts, Vs)], S1);
- true ->
- add_code([icode_enter_fun(Vs)], S1)
- end;
- false ->
- error_primop_badargs(?PRIMOP_APPLY_FUN, As),
- throw(error)
- end.
-
-primop_fun_element([N, F] = As, Ts, Ctxt, Env, S) ->
- case cerl:is_c_int(N) of
- true ->
- V = make_var(),
- S1 = expr(F, [V], Ctxt#ctxt{final = false, effect = false},
- Env, S),
- add_code(make_op(?OP_FUN_ELEMENT(cerl:int_val(N)),
- Ts, [V], Ctxt),
- S1);
- false ->
- error_primop_badargs(?PRIMOP_FUN_ELEMENT, As),
- throw(error)
- end.
-
-primop_goto_label(A, S) ->
- {Label,S1} = s__get_label(A, S),
- add_code([icode_goto(Label)], S1).
-
-is_goto(E) ->
- case cerl:type(E) of
- primop ->
- Name = cerl:atom_val(cerl:primop_name(E)),
- As = cerl:primop_args(E),
- Arity = length(As),
- case {Name, Arity} of
- {?PRIMOP_GOTO_LABEL, 1} ->
- true;
- _ ->
- false
- end;
- _ ->
- false
- end.
-
-primop_reduction_test(Ctxt, S) ->
- add_code(make_op(?OP_REDTEST, [], [], Ctxt), S).
-
-primop_dsetelement([N | As1] = As, Ts, Ctxt, Env, S) ->
- case cerl:is_c_int(N) of
- true ->
- {Vs, S1} = expr_list(As1, Ctxt, Env, S),
- add_code(make_op(?OP_UNSAFE_SETELEMENT(cerl:int_val(N)),
- Ts, Vs, Ctxt),
- S1);
- false ->
- error_primop_badargs(?PRIMOP_DSETELEMENT, As),
- throw(error)
- end.
-
-%% ---------------------------------------------------------------------
-%% Try-expressions:
-
-%% We want to rewrite trivial things like `try A of X -> B catch ...',
-%% where A is safe, into a simple let-binding `let X = A in B', avoiding
-%% unnecessary try-blocks. (The `let' might become further simplified.)
-
-expr_try(E, Ts, Ctxt, Env, S) ->
- F = fun (BF, CtxtF, EnvF, SF) -> expr(BF, Ts, CtxtF, EnvF, SF) end,
- expr_try_1(E, F, Ctxt, Env, S).
-
-expr_try_1(E, F, Ctxt, Env, S) ->
- A = cerl:try_arg(E),
- case is_safe_expr(A) of
- true ->
- E1 = cerl:c_let(cerl:try_vars(E), A, cerl:try_body(E)),
- expr_let_1(E1, F, Ctxt, Env, S);
- false ->
- expr_try_2(E, F, Ctxt, Env, S)
- end.
-
-%% TODO: maybe skip begin_try/end_try and just use fail-labels...
-
-expr_try_2(E, F, Ctxt, Env, S) ->
- Cont = new_continuation_label(Ctxt),
- Catch = new_label(),
- Next = new_label(),
- S1 = add_code([icode_begin_try(Catch,Next),icode_label(Next)], S),
- Vars = cerl:try_vars(E),
- Vs = make_vars(length(Vars)),
- Ctxt1 = Ctxt#ctxt{final = false},
- S2 = expr(cerl:try_arg(E), Vs, Ctxt1, Env, S1),
- Env1 = bind_vars(Vars, Vs, Env),
- S3 = add_code([icode_end_try()], S2),
- S4 = F(cerl:try_body(E), Ctxt, Env1, S3),
- S5 = add_continuation_jump(Cont, Ctxt, S4),
- EVars = cerl:try_evars(E),
- EVs = make_vars(length(EVars)),
- Env2 = bind_vars(EVars, EVs, Env),
- S6 = add_code([icode_label(Catch), icode_begin_handler(EVs)], S5),
- S7 = F(cerl:try_handler(E), Ctxt, Env2, S6),
- add_continuation_label(Cont, Ctxt, S7).
-
-%% ---------------------------------------------------------------------
-%% Letrec-expressions (local goto-labels)
-
-%% We only handle letrec-functions as continuations. The fun-bodies are
-%% always compiled in the same context as the main letrec-body. Note
-%% that we cannot propagate "advanced" contexts like boolean-compilation
-%% into the letrec body like we do for ordinary lets or seqs, since the
-%% context for an individual local function would be depending on the
-%% contexts of its call sites.
-
-expr_letrec(E, Ts, Ctxt, Env, S) ->
- Ds = cerl:letrec_defs(E),
- Env1 = add_defs(Ds, Env),
- S1 = expr(cerl:letrec_body(E), Ts, Ctxt, Env1, S),
- Next = new_continuation_label(Ctxt),
- S2 = add_continuation_jump(Next, Ctxt, S1),
- S3 = defs(Ds, Ts, Ctxt, Env1, S2),
- add_continuation_label(Next, Ctxt, S3).
-
-add_defs([{V, _F} | Ds], Env) ->
- {_, A} = cerl:var_name(V),
- Vs = make_vars(A),
- L = new_label(),
- Env1 = bind_fun(V, L, Vs, Env),
- add_defs(Ds, Env1);
-add_defs([], Env) ->
- Env.
-
-defs([{V, F} | Ds], Ts, Ctxt, Env, S) ->
- Name = cerl:var_name(V),
- #'fun'{label = L, vars = Vs} = env__get(Name, Env),
- S1 = add_code([icode_label(L)], S),
- Env1 = bind_vars(cerl:fun_vars(F), Vs, Env),
- S2 = expr(cerl:fun_body(F), Ts, Ctxt, Env1, S1),
- defs(Ds, Ts, Ctxt, Env, S2);
-defs([], _Ts, _Ctxt, _Env, S) ->
- S.
-
-%% ---------------------------------------------------------------------
-%% Receive-expressions
-
-%% There may only be exactly one clause, which must be a trivial
-%% catch-all with exactly one (variable) pattern. Each message will be
-%% read from the mailbox and bound to the pattern variable; the body of
-%% the clause must do the switching and call either of the primops
-%% `receive_select/0' or `receive_next/0'.
-
-expr_receive(E, Ts, Ctxt, Env, S) ->
- F = fun (BF, CtxtF, EnvF, SF) -> expr(BF, Ts, CtxtF, EnvF, SF) end,
- expr_receive_1(E, F, Ctxt, Env, S).
-
-expr_receive_1(E, F, Ctxt, Env, S) ->
- case cerl:receive_clauses(E) of
- [C] ->
- case cerl:clause_pats(C) of
- [_] ->
- case cerl_clauses:is_catchall(C) of
- true ->
- expr_receive_2(C, E, F, Ctxt, Env, S);
- false ->
- error_msg("receive-expression clause "
- "must be a catch-all."),
- throw(error)
- end;
- _ ->
- error_msg("receive-expression clause must "
- "have exactly one pattern."),
- throw(error)
- end;
- _ ->
- error_msg("receive-expressions must have "
- "exactly one clause."),
- throw(error)
- end.
-
-%% There are a number of primitives to do the work involved in receiving
-%% messages:
-%%
-%% if-tests: suspend_msg_timeout()
-%%
-%% primops: V = check_get_msg()
-%% select_msg()
-%% next_msg()
-%% set_timeout(T)
-%% clear_timeout()
-%% suspend_msg()
-%%
-%% `check_get_msg' tests if the mailbox is empty or not, and if not it
-%% reads the message currently pointed to by the implicit message pointer.
-%% `select_msg' removes the current message from the mailbox, resets the
-%% message pointer and clears any timeout. `next_msg' advances the
-%% message pointer but does nothing else. `set_timeout(T)' sets up the
-%% timeout mechanism *unless it is already set*. `suspend_msg' suspends
-%% until a message has arrived and does not check for timeout. The test
-%% `suspend_msg_timeout' suspends the process and upon resuming
-%% execution selects the `true' branch if a message has arrived and the
-%% `false' branch otherwise. `clear_timeout' resets the message pointer
-%% when a timeout has occurred (the name is somewhat misleading).
-%%
-%% Note: the receiving of a message must be performed so that the
-%% message pointer is always reset when the receive is done; thus, all
-%% paths must go through either `select_msg' or `clear_timeout'.
-
-%% Recall that the `final' and `effect' context flags distribute over
-%% the clauses *and* the timeout action (but not over the
-%% timeout-expression, which is always executed for its value).
-
-%% This is the code we generate for a full receive:
-%%
-%% Loop: check_get_msg(Match, Wait)
-%% Wait: set_timeout
-%% suspend_msg_timeout(Loop, Timeout)
-%% Timeout: clear_timeout
-%% TIMEOUT-ACTION
-%% goto Next
-%% Match: RECEIVE-CLAUSES(Loop, Next)
-%% Next: ...
-%%
-%% For a receive with infinity timout, we generate
-%%
-%% Wait: suspend_msg
-%% goto Loop
-%%
-%% For a receive with zero timout, we generate
-%%
-%% Wait: clear_timeout
-%% TIMEOUT-ACTION
-%% goto Next
-
-expr_receive_2(C, E, F, Ctxt, Env, S0) ->
- Expiry = cerl_lib:reduce_expr(cerl:receive_timeout(E)),
- After = case cerl:is_literal(Expiry) of
- true ->
- cerl:concrete(Expiry);
- false ->
- undefined
- end,
- T = make_var(), % T will hold the timeout value
- %% It would be harmless to generate code for `infinity', but we
- %% might as well avoid it if we can.
- S1 = if After =:= 'infinity' -> S0;
- true ->
- expr(Expiry, [T],
- Ctxt#ctxt{final = false, effect = false},
- Env, S0)
- end,
-
- %% This is the top of the receive-loop, which checks if the
- %% mailbox is empty, and otherwise reads the next message.
- Loop = new_label(),
- Wait = new_label(),
- Match = new_label(),
- V = make_var(),
- S2 = add_code([icode_label(Loop),
- icode_call_primop([V], ?OP_CHECK_GET_MESSAGE, [],
- Match, Wait),
- icode_label(Wait)], S1),
-
- %% The wait-for-message section looks a bit different depending on
- %% whether we actually need to set a timer or not.
- Ctxt0 = #ctxt{},
- S3 = case After of
- 'infinity' ->
- %% Only wake up when we get new messages, and never
- %% execute the expiry body.
- add_code(make_op(?OP_WAIT_FOR_MESSAGE, [], [], Ctxt0)
- ++ [icode_goto(Loop)], S2);
- 0 ->
- %% Zero limit - reset the message pointer (this is what
- %% "clear timeout" does) and execute the expiry body.
- add_code(make_op(?OP_CLEAR_TIMEOUT, [], [], Ctxt0),
- S2);
- _ ->
- %% Other value - set the timer (if it is already set,
- %% nothing is changed) and wait for a message or
- %% timeout. Reset the message pointer upon timeout.
- Timeout = new_label(),
- add_code(make_op(?OP_SET_TIMEOUT, [], [T], Ctxt0)
- ++ [make_if(?TEST_WAIT_FOR_MESSAGE_OR_TIMEOUT,
- [], Loop, Timeout),
- icode_label(Timeout)]
- ++ make_op(?OP_CLEAR_TIMEOUT, [], [], Ctxt0),
- S2)
- end,
-
- %% We never generate code for the expiry body if the timeout value
- %% is 'infinity' (and thus we know that it will not be used), mainly
- %% because in this case it is possible (and legal) for the expiry
- %% body to not have the expected degree. (Typically, it produces a
- %% single constant value such as 'true', while the clauses may be
- %% producing 2 or more values.)
- Next = new_continuation_label(Ctxt),
- S4 = if After =:= 'infinity' -> S3;
- true ->
- add_continuation_jump(Next, Ctxt,
- F(cerl:receive_action(E), Ctxt,
- Env, S3))
- end,
-
- %% When we compile the primitive operations that select the current
- %% message or loop to try the next message (see the functions
- %% 'primop_receive_next' and 'primop_receive_select'), we will use
- %% the receive-loop label in the context (i.e., that of the nearest
- %% enclosing receive expression).
- Ctxt1 = Ctxt#ctxt{'receive' = #'receive'{loop = Loop}},
-
- %% The pattern variable of the clause will be mapped to `V', which
- %% holds the message, so it can be accessed in the clause body:
- S5 = clauses([C], F, [V], Ctxt1, Env,
- add_code([icode_label(Match)], S4)),
- add_continuation_label(Next, Ctxt, S5).
-
-%% Primops supporting "expanded" receive-expressions on the Core level:
-
-primop_receive_next(#ctxt{'receive' = R} = Ctxt, S0) ->
- case R of
- #'receive'{loop = Loop} ->
- %% Note that this has the same "problem" as the fail
- %% instruction (see the 'add_fail' function), namely, that
- %% it unexpectedly ends a basic block. The solution is the
- %% same - add a dummy label if necessary.
- S1 = add_code(make_op(?OP_NEXT_MESSAGE, [], [], #ctxt{})
- ++ [icode_goto(Loop)], S0),
- add_new_continuation_label(Ctxt, S1);
- _ ->
- error_not_in_receive(?PRIMOP_RECEIVE_NEXT),
- throw(error)
- end.
-
-primop_receive_select(Ts, #ctxt{'receive' = R} = Ctxt, S) ->
- case R of
- #'receive'{} ->
- add_code(make_op(?OP_SELECT_MESSAGE, Ts, [], Ctxt), S);
- _ ->
- error_not_in_receive(?PRIMOP_RECEIVE_SELECT),
- throw(error)
- end.
-
-%% ---------------------------------------------------------------------
-%% Case expressions
-
-%% Typically, pattern matching compilation has split all switches into
-%% separate groups of tuples, integers, atoms, etc., where each such
-%% switch over a group of constructors is protected by a type test.
-%% Thus, it is straightforward to generate switch instructions. (If no
-%% pattern matching compilation has been done, we don't care about
-%% efficiency anyway, so we don't spend any extra effort here.)
-
-expr_case(E, Ts, Ctxt, Env, S) ->
- F = fun (BF, CtxtF, EnvF, SF) -> expr(BF, Ts, CtxtF, EnvF, SF) end,
- expr_case_1(E, F, Ctxt, Env, S).
-
-expr_case_1(E, F, Ctxt, Env, S) ->
- Cs = cerl:case_clauses(E),
- A = cerl:case_arg(E),
- case cerl_lib:is_bool_switch(Cs) of
- true ->
- %% An if-then-else with a known boolean argument
- {True, False} = cerl_lib:bool_switch_cases(Cs),
- bool_switch(A, True, False, F, Ctxt, Env, S);
- false ->
- Vs = make_vars(cerl:clause_arity(hd(Cs))),
- Ctxt1 = Ctxt#ctxt{final = false, effect = false},
- S1 = expr(A, Vs, Ctxt1, Env, S),
- expr_case_2(Vs, Cs, F, Ctxt, Env, S1)
- end.
-
-%% Switching on a value
-
-expr_case_2(Vs, Cs, F, Ctxt, Env, S1) ->
- case is_constant_switch(Cs) of
- true ->
- switch_val_clauses(Cs, F, Vs, Ctxt, Env, S1);
- false ->
- case is_tuple_switch(Cs) of
- true ->
- switch_tuple_clauses(Cs, F, Vs, Ctxt, Env, S1);
- false ->
- case is_binary_switch(Cs, S1) of
- true ->
- switch_binary_clauses(Cs, F, Vs, Ctxt, Env, S1);
- false ->
- clauses(Cs, F, Vs, Ctxt, Env, S1)
- end
- end
- end.
-
-%% Check if a list of clauses represents a switch over a number (more
-%% than 1) of constants (integers or atoms), or tuples (whose elements
-%% are all variables)
-
-is_constant_switch(Cs) ->
- is_switch(Cs, fun (P) -> (cerl:type(P) =:= literal) andalso
- (is_integer(cerl:concrete(P))
- orelse is_atom(cerl:concrete(P))) end).
-
-is_tuple_switch(Cs) ->
- is_switch(Cs, fun (P) -> cerl:is_c_tuple(P) andalso
- all_vars(cerl:tuple_es(P)) end).
-
-is_binary_switch(Cs, S) ->
- case s__get_pmatch(S) of
- False when False =:= false; False =:= undefined ->
- false;
- Other when Other =:= duplicate_all; Other =:= no_duplicates; Other =:= true->
- is_binary_switch1(Cs, 0)
- end.
-
-is_binary_switch1([C|Cs], N) ->
- case cerl:clause_pats(C) of
- [P] ->
- case cerl:is_c_binary(P) of
- true ->
- is_binary_switch1(Cs, N + 1);
- false ->
- %% The final clause may be a catch-all.
- Cs =:= [] andalso N > 0 andalso cerl:type(P) =:= var
- end;
- _ ->
- false
- end;
-is_binary_switch1([], N) ->
- N > 0.
-
-all_vars([E | Es]) ->
- case cerl:is_c_var(E) of
- true -> all_vars(Es);
- false -> false
- end;
-all_vars([]) -> true.
-
-is_switch(Cs, F) ->
- is_switch(Cs, F, 0).
-
-is_switch([C | Cs], F, N) ->
- case cerl_lib:is_simple_clause(C) of
- true ->
- [P] = cerl:clause_pats(C),
- case F(P) of
- true ->
- is_switch(Cs, F, N + 1);
- false ->
- %% The final clause may be a catch-all.
- Cs =:= [] andalso N > 1 andalso cerl:type(P) =:= var
- end;
- false -> false
- end;
-is_switch([], _F, N) ->
- N > 1.
-
-switch_val_clauses(Cs, F, Vs, Ctxt, Env, S) ->
- switch_clauses(Cs, F, Vs, Ctxt, Env,
- fun (P) -> cerl:concrete(P) end,
- fun icode_switch_val/4,
- fun val_clause_body/9,
- S).
-
-val_clause_body(_N, _V, C, F, Next, _Fail, Ctxt, Env, S) ->
- clause_body(C, F, Next, Ctxt, Env, S).
-
-switch_tuple_clauses(Cs, F, Vs, Ctxt, Env, S) ->
- switch_clauses(Cs, F, Vs, Ctxt, Env,
- fun (P) -> cerl:tuple_arity(P) end,
- fun icode_switch_tuple_arity/4,
- fun tuple_clause_body/9,
- S).
-
-tuple_clause_body(N, V, C, F, Next, Fail, Ctxt, Env, S0) ->
- Vs = make_vars(N),
- S1 = tuple_elements(Vs, V, S0),
- Es = cerl:tuple_es(hd(cerl:clause_pats(C))),
- {Env1, S2} = patterns(Es, Vs, Fail, Env, S1),
- clause_body(C, F, Next, Ctxt, Env1, S2).
-
-switch_clauses(Cs, F, [V], Ctxt, Env, GetVal, Switch, Body, S0) ->
- Cs1 = [switch_clause(C, GetVal) || C <- Cs],
- Cases = [{Val, L} || {Val, L, _} <- Cs1],
- Default = [C || {default, C} <- Cs1],
- Fail = new_label(),
- S1 = add_code([Switch(V, Fail, length(Cases), Cases)], S0),
- Next = new_continuation_label(Ctxt),
- S3 = case Default of
- [] -> add_default_case(Fail, Ctxt, S1);
- [C] ->
- %% Bind the catch-all variable (this always succeeds)
- {Env1, S2} = patterns(cerl:clause_pats(C), [V], Fail,
- Env, S1),
- clause_body(C, F, Next, Ctxt, Env1,
- add_code([icode_label(Fail)], S2))
- end,
- S4 = switch_cases(Cs1, V, F, Next, Fail, Ctxt, Env, Body, S3),
- add_continuation_label(Next, Ctxt, S4).
-
-switch_clause(C, F) ->
- [P] = cerl:clause_pats(C),
- L = new_label(),
- case cerl:type(P) of
- var -> {default, C};
- _ -> {icode_const(F(P)), L, C}
- end.
-
-switch_binary_clauses(Cs, F, Vs, Ctxt, Env, S) ->
- {Bins, Default} = get_binary_clauses(Cs),
- Fail = new_label(),
- Next = new_continuation_label(Ctxt),
- S1 = binary_match(Bins, F, Vs, Next, Fail, Ctxt, Env, S),
- S2 = case Default of
- [] -> add_default_case(Fail, Ctxt, S1);
- [C] ->
- clause_body(C, F, Next, Ctxt, Env,
- add_code([icode_label(Fail)], S1))
- end,
- add_continuation_label(Next, Ctxt, S2).
-
-get_binary_clauses(Cs) ->
- get_binary_clauses(Cs, []).
-
-get_binary_clauses([C|Cs], Acc) ->
- [P] = cerl:clause_pats(C),
- case cerl:is_c_binary(P) of
- true ->
- get_binary_clauses(Cs, [C|Acc]);
- false ->
- {lists:reverse(Acc),[C]}
- end;
-get_binary_clauses([], Acc) ->
- {lists:reverse(Acc),[]}.
-
-switch_cases([{N, L, C} | Cs], V, F, Next, Fail, Ctxt, Env, Body, S0) ->
- S1 = add_code([icode_label(L)], S0),
- S2 = Body(icode_const_val(N), V, C, F, Next, Fail, Ctxt, Env, S1),
- switch_cases(Cs, V, F, Next, Fail, Ctxt, Env, Body, S2);
-switch_cases([_ | Cs], V, F, Next, Fail, Ctxt, Env, Body, S) ->
- switch_cases(Cs, V, F, Next, Fail, Ctxt, Env, Body, S);
-switch_cases([], _V, _F, _Next, _Fail, _Ctxt, _Env, _Body, S) ->
- S.
-
-%% Recall that the `final' and `effect' context flags distribute over
-%% the clause bodies.
-
-clauses(Cs, F, Vs, Ctxt, Env, S) ->
- Next = new_continuation_label(Ctxt),
- S1 = clauses_1(Cs, F, Vs, undefined, Next, Ctxt, Env, S),
- add_continuation_label(Next, Ctxt, S1).
-
-clauses_1([C | Cs], F, Vs, Fail, Next, Ctxt, Env, S) ->
- case cerl_clauses:is_catchall(C) of
- true ->
- %% The fail label will not actually be used in this case.
- clause(C, F, Vs, Fail, Next, Ctxt, Env, S);
- false ->
- %% The previous `Fail' is not used here.
- Fail1 = new_label(),
- S1 = clause(C, F, Vs, Fail1, Next, Ctxt, Env, S),
- S2 = add_code([icode_label(Fail1)], S1),
- clauses_1(Cs, F, Vs, Fail1, Next, Ctxt, Env, S2)
- end;
-clauses_1([], _F, _Vs, Fail, _Next, Ctxt, _Env, S) ->
- if Fail =:= undefined ->
- L = new_label(),
- add_default_case(L, Ctxt, S);
- true ->
- add_code([icode_goto(Fail)], S) % use existing label
- end.
-
-%% The exact behaviour if all clauses fail is undefined; we generate an
-%% 'internal_error' exception if this happens, which is safe and will
-%% not get in the way of later analyses. (Continuing execution after the
-%% `case', as in a C `switch' statement, would add a new possible path
-%% to the program, which could destroy program properties.) Note that
-%% this code is only generated if some previous stage has created a
-%% switch over clauses without a final catch-all; this could be both
-%% legal and non-redundant, e.g. if the last clause does pattern
-%% matching to extract components of a (known) constructor. The
-%% generated default-case code *should* be unreachable, but we need it
-%% in order to have a safe fail-label.
-
-add_default_case(L, Ctxt, S) ->
- S1 = add_code([icode_label(L)], S),
- add_error(icode_const(internal_error), Ctxt, S1).
-
-clause(C, F, Vs, Fail, Next, Ctxt, Env, S) ->
- G = cerl:clause_guard(C),
- case cerl_clauses:eval_guard(G) of
- {value, true} ->
- {Env1, S1} = patterns(cerl:clause_pats(C), Vs, Fail, Env,
- S),
- clause_body(C, F, Next, Ctxt, Env1, S1);
- {value, false} ->
- add_code([icode_goto(Fail)], S);
- _ ->
- {Env1, S1} = patterns(cerl:clause_pats(C), Vs, Fail, Env,
- S),
- Succ = new_label(),
- Ctxt1 = Ctxt#ctxt{final = false,
- fail = Fail,
- class = guard},
- S2 = boolean(G, Succ, Fail, Ctxt1, Env1, S1),
- S3 = add_code([icode_label(Succ)], S2),
- clause_body(C, F, Next, Ctxt, Env1, S3)
- end.
-
-clause_body(C, F, Next, Ctxt, Env, S) ->
- %% This check is inserted as a goto is always final
- case is_goto(cerl:clause_body(C)) of
- true ->
- F(cerl:clause_body(C), Ctxt, Env, S);
- false ->
- S1 = F(cerl:clause_body(C), Ctxt, Env, S),
- add_continuation_jump(Next, Ctxt, S1)
- end.
-
-patterns([P | Ps], [V | Vs], Fail, Env, S) ->
- {Env1, S1} = pattern(P, V, Fail, Env, S),
- patterns(Ps, Vs, Fail, Env1, S1);
-patterns([], [], _, Env, S) ->
- {Env, S}.
-
-pattern(P, V, Fail, Env, S) ->
- case cerl:type(P) of
- var ->
- {bind_var(P, V, Env), S};
- alias ->
- {Env1, S1} = pattern(cerl:alias_pat(P), V,
- Fail, Env, S),
- {bind_var(cerl:alias_var(P), V, Env1), S1};
- literal ->
- {Env, literal_pattern(P, V, Fail, S)};
- cons ->
- cons_pattern(P, V, Fail, Env, S);
- tuple ->
- tuple_pattern(P, V, Fail, Env, S);
- binary ->
- binary_pattern(P, V, Fail, Env, S)
- end.
-
-literal_pattern(P, V, Fail, S) ->
- L = new_label(),
- S1 = literal_pattern_1(P, V, Fail, L, S),
- add_code([icode_label(L)], S1).
-
-literal_pattern_1(P, V, Fail, Next, S) ->
- case cerl:concrete(P) of
- X when is_atom(X) ->
- add_code([make_type([V], ?TYPE_ATOM(X), Next, Fail)],
- S);
- X when is_integer(X) ->
- add_code([make_type([V], ?TYPE_INTEGER(X), Next, Fail)],
- S);
- X when is_float(X) ->
- V1 = make_var(),
- L = new_label(),
- %% First doing an "is float" test here might allow later
- %% stages to use a specialized equality test.
- add_code([make_type([V], ?TYPE_IS_FLOAT, L, Fail),
- icode_label(L),
- icode_move(V1, icode_const(X)),
- make_if(?TEST_EQ, [V, V1], Next, Fail)],
- S);
- [] ->
- add_code([make_type([V], ?TYPE_NIL, Next, Fail)], S);
- X ->
- %% Compound constants are compared with the generic exact
- %% equality test.
- V1 = make_var(),
- add_code([icode_move(V1, icode_const(X)),
- make_if(?TEST_EXACT_EQ, [V, V1], Next, Fail)],
- S)
- end.
-
-cons_pattern(P, V, Fail, Env, S) ->
- V1 = make_var(),
- V2 = make_var(),
- Next = new_label(),
- Ctxt = #ctxt{},
- S1 = add_code([make_type([V], ?TYPE_CONS, Next, Fail),
- icode_label(Next)]
- ++ make_op(?OP_UNSAFE_HD, [V1], [V], Ctxt)
- ++ make_op(?OP_UNSAFE_TL, [V2], [V], Ctxt),
- S),
- patterns([cerl:cons_hd(P), cerl:cons_tl(P)], [V1, V2],
- Fail, Env, S1).
-
-tuple_pattern(P, V, Fail, Env, S) ->
- Es = cerl:tuple_es(P),
- N = length(Es),
- Vs = make_vars(N),
- Next = new_label(),
- S1 = add_code([make_type([V], ?TYPE_IS_N_TUPLE(N), Next, Fail),
- icode_label(Next)],
- S),
- S2 = tuple_elements(Vs, V, S1),
- patterns(Es, Vs, Fail, Env, S2).
-
-tuple_elements(Vs, V, S) ->
- tuple_elements(Vs, V, #ctxt{}, 1, S).
-
-tuple_elements([V1 | Vs], V0, Ctxt, N, S) ->
- Code = make_op(?OP_UNSAFE_ELEMENT(N), [V1], [V0], Ctxt),
- tuple_elements(Vs, V0, Ctxt, N + 1, add_code(Code, S));
-tuple_elements([], _, _, _, S) ->
- S.
-
-binary_pattern(P, V, Fail, Env, S) ->
- L1 = new_label(),
- Segs = cerl:binary_segments(P),
- Arity = length(Segs),
- Vars = make_vars(Arity),
- MS = make_var(),
- Primop1 = {hipe_bs_primop, {bs_start_match,0}},
- S1 = add_code([icode_guardop([MS], Primop1, [V], L1, Fail),
- icode_label(L1)],S),
- {Env1,S2} = bin_seg_patterns(Segs, Vars, MS, Fail, Env, S1, false),
- L2 = new_label(),
- Primop2 = {hipe_bs_primop, {bs_test_tail, 0}},
- {Env1, add_code([icode_guardop([], Primop2, [MS], L2, Fail),
- icode_label(L2)], S2)}.
-
-bin_seg_patterns([Seg|Rest], [T|Ts], MS, Fail, Env, S, Align) ->
- {{NewEnv, S1}, NewAlign} = bin_seg_pattern(Seg, T, MS, Fail, Env, S, Align),
- bin_seg_patterns(Rest, Ts, MS, Fail, NewEnv, S1, NewAlign);
-
-bin_seg_patterns([], [], _MS, _Fail, Env, S, _Align) ->
- {Env, S}.
-
-bin_seg_pattern(P, V, MS, Fail, Env, S, Align) ->
- L = new_label(),
- Size = cerl:bitstr_size(P),
- Unit = cerl:bitstr_unit(P),
- Type = cerl:concrete(cerl:bitstr_type(P)),
- LiteralFlags = cerl:bitstr_flags(P),
- T = cerl:bitstr_val(P),
- Flags = translate_flags(LiteralFlags, Align),
- case calculate_size(Unit, Size, false, Env, S) of
- {all, NewUnit, NewAlign, S0} ->
- Type = binary,
- Name = {bs_get_binary_all_2, NewUnit, Flags},
- Primop = {hipe_bs_primop, Name},
- S1 = add_code([icode_guardop([V,MS], Primop, [MS], L, Fail),
- icode_label(L)], S0),
- {pattern(T, V, Fail, Env, S1), NewAlign};
- {NewUnit, Args, S0, NewAlign} ->
- Name =
- case Type of
- integer ->
- {bs_get_integer, NewUnit, Flags};
- float ->
- {bs_get_float, NewUnit, Flags};
- binary ->
- {bs_get_binary, NewUnit, Flags}
- end,
- Primop = {hipe_bs_primop, Name},
- S1 = add_code([icode_guardop([V,MS], Primop, [MS|Args], L, Fail),
- icode_label(L)], S0),
- {pattern(T, V, Fail, Env, S1), NewAlign}
- end.
-
-%% ---------------------------------------------------------------------
-%% Boolean expressions
-
-%% This generates code for a boolean expression (such as "primop
-%% 'and'(X, Y)") in a normal expression context, when an actual `true'
-%% or `false' value is to be computed. We set up a default fail-label
-%% for generating a `badarg' error, unless we are in a guard.
-
-boolean_expr(E, [V], Ctxt=#ctxt{class = guard}, Env, S) ->
- {Code, True, False} = make_bool_glue(V),
- S1 = boolean(E, True, False, Ctxt, Env, S),
- add_code(Code, S1);
-boolean_expr(E, [V] = Ts, Ctxt, Env, S) ->
- {Code, True, False} = make_bool_glue(V),
- Fail = new_label(),
- Cont = new_continuation_label(Ctxt),
- Ctxt1 = Ctxt#ctxt{final = false, effect = false, fail = Fail},
- S1 = boolean(E, True, False, Ctxt1, Env, S),
- S2 = maybe_return(Ts, Ctxt, add_code(Code, S1)),
- S3 = add_continuation_jump(Cont, Ctxt, S2),
- S4 = add_code([icode_label(Fail)], S3),
- S5 = add_error(icode_const(badarg), Ctxt, S4), % can add dummy label
- S6 = add_continuation_jump(Cont, Ctxt, S5), % avoid empty basic block
- add_continuation_label(Cont, Ctxt, S6);
-boolean_expr(_, [], _Ctxt, _Env, _S) ->
- error_high_degree(),
- throw(error);
-boolean_expr(_, _, _Ctxt, _Env, _S) ->
- error_low_degree(),
- throw(error).
-
-%% This is for when we expect a boolean result in jumping code context,
-%% but are not sure what the expression will produce, or we know that
-%% the result is not a boolean and we just want error handling.
-
-expect_boolean_value(E, True, False, Ctxt, Env, S) ->
- V = make_var(),
- S1 = expr(E, [V], Ctxt#ctxt{final = false}, Env, S),
- case Ctxt#ctxt.fail of
- [] ->
- %% No fail-label set - this means we are *sure* that the
- %% result can only be 'true' or 'false'.
- add_code([make_type([V], ?TYPE_ATOM(true), True, False)],
- S1);
- Fail ->
- Next = new_label(),
- add_code([make_type([V], ?TYPE_ATOM(true), True, Next),
- icode_label(Next),
- make_type([V], ?TYPE_ATOM(false), False, Fail)],
- S1)
- end.
-
-%% This generates code for a case-switch with exactly one 'true' branch
-%% and one 'false' branch, and no other branches (not even a catch-all).
-%% Note that E must be guaranteed to produce a boolean value for such a
-%% switch to have been generated.
-
-bool_switch(E, TrueExpr, FalseExpr, F, Ctxt, Env, S) ->
- Cont = new_continuation_label(Ctxt),
- True = new_label(),
- False = new_label(),
- Ctxt1 = Ctxt#ctxt{final = false, effect = false},
- S1 = boolean(E, True, False, Ctxt1, Env, S),
- S2 = add_code([icode_label(True)], S1),
- S3 = F(TrueExpr, Ctxt, Env, S2),
- S4 = add_continuation_jump(Cont, Ctxt, S3),
- S5 = add_code([icode_label(False)], S4),
- S6 = F(FalseExpr, Ctxt, Env, S5),
- add_continuation_label(Cont, Ctxt, S6).
-
-%% This generates jumping code for booleans. If the fail-label is set,
-%% it tells where to go in case a value turns out not to be a boolean.
-
-%% In strict boolean expressions, we set a flag to be checked if
-%% necessary after both branches have been evaluated. An alternative
-%% would be to duplicate the code for the second argument, for each
-%% value ('true' or 'false') of the first argument.
-
-%% (Note that subexpressions are checked repeatedly to see if they are
-%% safe - this is quadratic, but I don't expect booleans to be very
-%% deeply nested.)
-
-%% Note that 'and', 'or' and 'xor' are strict (like all primops)!
-
-boolean(E0, True, False, Ctxt, Env, S) ->
- E = cerl_lib:reduce_expr(E0),
- case cerl:type(E) of
- literal ->
- case cerl:concrete(E) of
- true ->
- add_code([icode_goto(True)], S);
- false ->
- add_code([icode_goto(False)], S);
- _ ->
- expect_boolean_value(E, True, False, Ctxt, Env, S)
- end;
- values ->
- case cerl:values_es(E) of
- [E1] ->
- boolean(E1, True, False, Ctxt, Env, S);
- _ ->
- error_msg("degree mismatch - expected boolean: ~P",
- [E, 10]),
- throw(error)
- end;
- primop ->
- Name = cerl:atom_val(cerl:primop_name(E)),
- As = cerl:primop_args(E),
- Arity = length(As),
- case {Name, Arity} of
- {?PRIMOP_NOT, 1} ->
- %% `not' simply switches true and false labels.
- [A] = As,
- boolean(A, False, True, Ctxt, Env, S);
- {?PRIMOP_AND, 2} ->
- strict_and(As, True, False, Ctxt, Env, S);
- {?PRIMOP_OR, 2} ->
- strict_or(As, True, False, Ctxt, Env, S);
- {?PRIMOP_XOR, 2} ->
- %% `xor' always needs to evaluate both arguments
- strict_xor(As, True, False, Ctxt, Env, S);
- _ ->
- case is_comp_op(Name, Arity) of
- true ->
- comparison(Name, As, True, False, Ctxt, Env,
- S);
- false ->
- case is_type_test(Name, Arity) of
- true ->
- type_test(Name, As, True, False,
- Ctxt, Env, S);
- false ->
- expect_boolean_value(E, True, False,
- Ctxt, Env, S)
- end
- end
- end;
- 'case' ->
- %% Propagate boolean handling into clause bodies.
- %% (Note that case switches assume fallthrough code in the
- %% clause bodies, so we must add a dummy label as needed.)
- F = fun (BF, CtxtF, EnvF, SF) ->
- SF1 = boolean(BF, True, False, CtxtF, EnvF, SF),
- add_new_continuation_label(CtxtF, SF1)
- end,
- S1 = expr_case_1(E, F, Ctxt, Env, S),
- %% Add a final goto if necessary, to compensate for the
- %% final continuation label of the case-expression. This
- %% should be unreachable, so the value does not matter.
- add_continuation_jump(False, Ctxt, S1);
- seq ->
- %% Propagate boolean handling into body.
- F = fun (BF, CtxtF, EnvF, SF) ->
- boolean(BF, True, False, CtxtF, EnvF, SF)
- end,
- expr_seq_1(E, F, Ctxt, Env, S);
- 'let' ->
- %% Propagate boolean handling into body. Note that we have
- %% called 'cerl_lib:reduce_expr/1' above.
- F = fun (BF, CtxtF, EnvF, SF) ->
- boolean(BF, True, False, CtxtF, EnvF, SF)
- end,
- expr_let_1(E, F, Ctxt, Env, S);
- 'try' ->
- case Ctxt#ctxt.class of
- guard ->
- %% This *must* be a "protected" guard expression on
- %% the form "try E of X -> X catch <...> -> 'false'"
- %% (we could of course test if the handler body is
- %% the atom 'false', etc.).
- Ctxt1 = Ctxt#ctxt{fail = False},
- boolean(cerl:try_arg(E), True, False, Ctxt1, Env, S);
- _ ->
- %% Propagate boolean handling into the handler and body
- %% (see propagation into case switches for comparison)
- F = fun (BF, CtxtF, EnvF, SF) ->
- boolean(BF, True, False, CtxtF, EnvF, SF)
- end,
- S1 = expr_try_1(E, F, Ctxt, Env, S),
- add_continuation_jump(False, Ctxt, S1)
- end;
- _ ->
- %% This handles everything else, including cases that are
- %% known to not return a boolean.
- expect_boolean_value(E, True, False, Ctxt, Env, S)
- end.
-
-strict_and([A, B], True, False, Ctxt, Env, S) ->
- V = make_var(),
- {Glue, True1, False1} = make_bool_glue(V),
- S1 = boolean(A, True1, False1, Ctxt, Env, S),
- S2 = add_code(Glue, S1),
- Test = new_label(),
- S3 = boolean(B, Test, False, Ctxt, Env, S2),
- add_code([icode_label(Test),
- make_bool_test(V, True, False)],
- S3).
-
-strict_or([A, B], True, False, Ctxt, Env, S) ->
- V = make_var(),
- {Glue, True1, False1} = make_bool_glue(V),
- S1 = boolean(A, True1, False1, Ctxt, Env, S),
- S2 = add_code(Glue, S1),
- Test = new_label(),
- S3 = boolean(B, True, Test, Ctxt, Env, S2),
- add_code([icode_label(Test),
- make_bool_test(V, True, False)],
- S3).
-
-strict_xor([A, B], True, False, Ctxt, Env, S) ->
- V = make_var(),
- {Glue, True1, False1} = make_bool_glue(V),
- S1 = boolean(A, True1, False1, Ctxt, Env, S),
- S2 = add_code(Glue, S1),
- Test1 = new_label(),
- Test2 = new_label(),
- S3 = boolean(B, Test1, Test2, Ctxt, Env, S2),
- add_code([icode_label(Test1),
- make_bool_test(V, False, True),
- icode_label(Test2),
- make_bool_test(V, True, False)],
- S3).
-
-%% Primitive comparison operations are inline expanded as conditional
-%% branches when part of a boolean expression, rather than made into
-%% primop or guardop calls. Note that Without type information, we
-%% cannot reduce equality tests like `Expr == true' to simply `Expr'
-%% (and `Expr == false' to `not Expr'), because we are not sure that
-%% Expr will yield a boolean - if it does not, the result of the
-%% comparison should be `false'.
-
-comparison(Name, As, True, False, Ctxt, Env, S) ->
- {Vs, S1} = expr_list(As, Ctxt, Env, S),
- Test = comp_test(Name),
- add_code([make_if(Test, Vs, True, False)], S1).
-
-comp_test(?PRIMOP_EQ) -> ?TEST_EQ;
-comp_test(?PRIMOP_NE) -> ?TEST_NE;
-comp_test(?PRIMOP_EXACT_EQ) -> ?TEST_EXACT_EQ;
-comp_test(?PRIMOP_EXACT_NE) -> ?TEST_EXACT_NE;
-comp_test(?PRIMOP_LT) -> ?TEST_LT;
-comp_test(?PRIMOP_GT) -> ?TEST_GT;
-comp_test(?PRIMOP_LE) -> ?TEST_LE;
-comp_test(?PRIMOP_GE) -> ?TEST_GE.
-
-type_test(?PRIMOP_IS_RECORD, [T, A, N], True, False, Ctxt, Env, S) ->
- is_record_test(T, A, N, True, False, Ctxt, Env, S);
-type_test(Name, [A], True, False, Ctxt, Env, S) ->
- V = make_var(),
- S1 = expr(A, [V], Ctxt#ctxt{final = false, effect = false}, Env, S),
- Test = type_test(Name),
- add_code([make_type([V], Test, True, False)], S1).
-
-%% It turned out to be easiest to generate Icode directly for this.
-is_record_test(T, A, N, True, False, Ctxt, Env, S) ->
- case cerl:is_c_atom(A) andalso cerl:is_c_int(N)
- andalso (cerl:concrete(N) > 0) of
- true ->
- V = make_var(),
- Ctxt1 = Ctxt#ctxt{final = false, effect = false},
- S1 = expr(T, [V], Ctxt1, Env, S),
- Atom = cerl:concrete(A),
- Size = cerl:concrete(N),
- add_code([make_type([V], ?TYPE_IS_RECORD(Atom, Size), True, False)],
- S1);
- false ->
- error_primop_badargs(?PRIMOP_IS_RECORD, [T, A, N]),
- throw(error)
- end.
-
-type_test(?PRIMOP_IS_ATOM) -> ?TYPE_IS_ATOM;
-type_test(?PRIMOP_IS_BIGNUM) -> ?TYPE_IS_BIGNUM;
-type_test(?PRIMOP_IS_BINARY) -> ?TYPE_IS_BINARY;
-type_test(?PRIMOP_IS_FIXNUM) -> ?TYPE_IS_FIXNUM;
-type_test(?PRIMOP_IS_FLOAT) -> ?TYPE_IS_FLOAT;
-type_test(?PRIMOP_IS_FUNCTION) -> ?TYPE_IS_FUNCTION;
-type_test(?PRIMOP_IS_INTEGER) -> ?TYPE_IS_INTEGER;
-type_test(?PRIMOP_IS_LIST) -> ?TYPE_IS_LIST;
-type_test(?PRIMOP_IS_NUMBER) -> ?TYPE_IS_NUMBER;
-type_test(?PRIMOP_IS_PID) -> ?TYPE_IS_PID;
-type_test(?PRIMOP_IS_PORT) -> ?TYPE_IS_PORT;
-type_test(?PRIMOP_IS_REFERENCE) -> ?TYPE_IS_REFERENCE;
-type_test(?PRIMOP_IS_TUPLE) -> ?TYPE_IS_TUPLE.
-
-is_comp_op(?PRIMOP_EQ, 2) -> true;
-is_comp_op(?PRIMOP_NE, 2) -> true;
-is_comp_op(?PRIMOP_EXACT_EQ, 2) -> true;
-is_comp_op(?PRIMOP_EXACT_NE, 2) -> true;
-is_comp_op(?PRIMOP_LT, 2) -> true;
-is_comp_op(?PRIMOP_GT, 2) -> true;
-is_comp_op(?PRIMOP_LE, 2) -> true;
-is_comp_op(?PRIMOP_GE, 2) -> true;
-is_comp_op(Op, A) when is_atom(Op), is_integer(A) -> false.
-
-is_bool_op(?PRIMOP_AND, 2) -> true;
-is_bool_op(?PRIMOP_OR, 2) -> true;
-is_bool_op(?PRIMOP_XOR, 2) -> true;
-is_bool_op(?PRIMOP_NOT, 1) -> true;
-is_bool_op(Op, A) when is_atom(Op), is_integer(A) -> false.
-
-is_type_test(?PRIMOP_IS_ATOM, 1) -> true;
-is_type_test(?PRIMOP_IS_BIGNUM, 1) -> true;
-is_type_test(?PRIMOP_IS_BINARY, 1) -> true;
-is_type_test(?PRIMOP_IS_FIXNUM, 1) -> true;
-is_type_test(?PRIMOP_IS_FLOAT, 1) -> true;
-is_type_test(?PRIMOP_IS_FUNCTION, 1) -> true;
-is_type_test(?PRIMOP_IS_INTEGER, 1) -> true;
-is_type_test(?PRIMOP_IS_LIST, 1) -> true;
-is_type_test(?PRIMOP_IS_NUMBER, 1) -> true;
-is_type_test(?PRIMOP_IS_PID, 1) -> true;
-is_type_test(?PRIMOP_IS_PORT, 1) -> true;
-is_type_test(?PRIMOP_IS_REFERENCE, 1) -> true;
-is_type_test(?PRIMOP_IS_TUPLE, 1) -> true;
-is_type_test(?PRIMOP_IS_RECORD, 3) -> true;
-is_type_test(Op, A) when is_atom(Op), is_integer(A) -> false.
-
-
-%% ---------------------------------------------------------------------
-%% Utility functions
-
-bind_var(V, Name, Env) ->
- env__bind(cerl:var_name(V), #cerl_to_icode__var{name = Name}, Env).
-
-bind_vars([V | Vs], [X | Xs], Env) ->
- bind_vars(Vs, Xs, bind_var(V, X, Env));
-bind_vars([], [], Env) ->
- Env.
-
-bind_fun(V, L, Vs, Env) ->
- env__bind(cerl:var_name(V), #'fun'{label = L, vars = Vs}, Env).
-
-add_code(Code, S) ->
- s__add_code(Code, S).
-
-%% This inserts code when necessary for assigning the targets in the
-%% first list to those in the second.
-
-glue([V1 | Vs1], [V2 | Vs2], S) ->
- if V1 =:= V2 ->
- S;
- true ->
- glue(Vs1, Vs2, add_code([icode_move(V2, V1)], S))
- end;
-glue([], [], S) ->
- S;
-glue([], _, S) ->
- warning_low_degree(),
- S;
-glue(_, [], _) ->
- error_high_degree(),
- throw(error).
-
-make_moves([V1 | Vs1], [V2 | Vs2]) ->
- [icode_move(V1, V2) | make_moves(Vs1, Vs2)];
-make_moves([], []) ->
- [].
-
-%% If the context signals `final', we generate a return instruction,
-%% otherwise nothing happens.
-
-maybe_return(Ts, Ctxt, S) ->
- case Ctxt#ctxt.final of
- false ->
- S;
- true ->
- add_return(Ts, S)
- end.
-
-add_return(Ts, S) ->
- add_code([icode_return(Ts)], S).
-
-new_continuation_label(Ctxt) ->
- case Ctxt#ctxt.final of
- false ->
- new_label();
- true ->
- undefined
- end.
-
-add_continuation_label(Label, Ctxt, S) ->
- case Ctxt#ctxt.final of
- false ->
- add_code([icode_label(Label)], S);
- true ->
- S
- end.
-
-add_continuation_jump(Label, Ctxt, S) ->
- case Ctxt#ctxt.final of
- false ->
- add_code([icode_goto(Label)], S);
- true ->
- S
- end.
-
-%% This is used to insert a new dummy label (if necessary) when
-%% a block is ended suddenly; cf. add_fail.
-add_new_continuation_label(Ctxt, S) ->
- add_continuation_label(new_continuation_label(Ctxt), Ctxt, S).
-
-add_local_call({Name, _Arity} = V, Vs, Ts, Ctxt, S) ->
- Module = s__get_module(S),
- case Ctxt#ctxt.final of
- false ->
- add_code([icode_call_local(Ts, Module, Name, Vs)], S);
- true ->
- Self = s__get_function(S),
- if V =:= Self ->
- %% Self-recursive tail call:
- {Label, Vs1} = s__get_local_entry(S),
- add_code(make_moves(Vs1, Vs) ++ [icode_goto(Label)],
- S);
- true ->
- add_code([icode_enter_local(Module, Name, Vs)], S)
- end
- end.
-
-%% Note that this has the same "problem" as the fail instruction (see
-%% the 'add_fail' function), namely, that it unexpectedly ends a basic
-%% block. The solution is the same - add a dummy label if necessary.
-
-add_letrec_call(Label, Vs1, Vs, Ctxt, S) ->
- S1 = add_code(make_moves(Vs1, Vs) ++ [icode_goto(Label)], S),
- add_new_continuation_label(Ctxt, S1).
-
-add_exit(V, Ctxt, S) ->
- add_fail([V], exit, Ctxt, S).
-
-add_throw(V, Ctxt, S) ->
- add_fail([V], throw, Ctxt, S).
-
-add_error(V, Ctxt, S) ->
- add_fail([V], error, Ctxt, S).
-
-add_error(V, F, Ctxt, S) ->
- add_fail([V, F], error, Ctxt, S).
-
-add_rethrow(E, V, Ctxt, S) ->
- add_fail([E, V], rethrow, Ctxt, S).
-
-%% Failing is special, because it can "suddenly" end the basic block,
-%% even though the context was expecting the code to fall through, for
-%% instance when you have a call to 'exit(X)' that is not in a tail call
-%% context. In those cases a dummy label must therefore be added after
-%% the fail instruction, to start a new (but unreachable) basic block.
-
-add_fail(Vs, Class, Ctxt, S0) ->
- S1 = add_code([icode_fail(Vs, Class)], S0),
- add_new_continuation_label(Ctxt, S1).
-
-%% We must add continuation- and fail-labels if we are in a guard context.
-
-make_op(Name, Ts, As, Ctxt) ->
- case Ctxt#ctxt.final of
- false ->
- case Ctxt#ctxt.class of
- guard ->
- Next = new_label(),
- [icode_guardop(Ts, Name, As, Next, Ctxt#ctxt.fail),
- icode_label(Next)];
- _ ->
- [icode_call_primop(Ts, Name, As)]
- end;
- true ->
- [icode_enter_primop(Name, As)]
- end.
-
-make_call(M, F, Ts, As, Ctxt) ->
- case Ctxt#ctxt.final of
- false ->
- case Ctxt#ctxt.class of
- guard ->
- Next = new_label(),
- [icode_call_remote(Ts, M, F, As, Next,
- Ctxt#ctxt.fail, true),
- icode_label(Next)];
- _ ->
- [icode_call_remote(Ts, M, F, As)]
- end;
- true ->
- %% A final call can't be in a guard anyway
- [icode_enter_remote(M, F, As)]
- end.
-
-%% Recognize useless tests that always go to the same label. This often
-%% happens as an artefact of the translation.
-
-make_if(_, _, Label, Label) ->
- icode_goto(Label);
-make_if(Test, As, True, False) ->
- icode_if(Test, As, True, False).
-
-make_type(_, _, Label, Label) ->
- icode_goto(Label);
-make_type(Vs, Test, True, False) ->
- icode_type(Vs, Test, True, False).
-
-%% Creating glue code with true/false target labels for assigning a
-%% corresponding 'true'/'false' value to a specific variable. Used as
-%% glue between boolean jumping code and boolean values.
-
-make_bool_glue(V) ->
- make_bool_glue(V, true, false).
-
-make_bool_glue(V, T, F) ->
- False = new_label(),
- True = new_label(),
- Next = new_label(),
- Code = [icode_label(False),
- icode_move(V, icode_const(F)),
- icode_goto(Next),
- icode_label(True),
- icode_move(V, icode_const(T)),
- icode_label(Next)],
- {Code, True, False}.
-
-make_bool_test(V, True, False) ->
- make_type([V], ?TYPE_ATOM(true), True, False).
-
-%% Checking if an expression is safe
-
-is_safe_expr(E) ->
- cerl_lib:is_safe_expr(E, fun function_check/2).
-
-function_check(safe, {Name, Arity}) ->
- is_safe_op(Name, Arity);
-function_check(safe, {Module, Name, Arity}) ->
- erl_bifs:is_safe(Module, Name, Arity);
-function_check(pure, {Name, Arity}) ->
- is_pure_op(Name, Arity);
-function_check(pure, {Module, Name, Arity}) ->
- erl_bifs:is_pure(Module, Name, Arity);
-function_check(_, _) ->
- false.
-
-%% There are very few really safe operations (sigh!). If we have type
-%% information, several operations could be rewritten into specialized
-%% safe versions, such as '+'/2 -> add_integer/2.
-
-is_safe_op(N, A) ->
- is_comp_op(N, A) orelse is_type_test(N, A).
-
-is_pure_op(?PRIMOP_ELEMENT, 2) -> true;
-is_pure_op(?PRIMOP_MAKE_FUN, 6) -> true;
-is_pure_op(?PRIMOP_FUN_ELEMENT, 2) -> true;
-is_pure_op(?PRIMOP_ADD, 2) -> true;
-is_pure_op(?PRIMOP_SUB, 2) -> true;
-is_pure_op(?PRIMOP_NEG, 1) -> true;
-is_pure_op(?PRIMOP_MUL, 2) -> true;
-is_pure_op(?PRIMOP_DIV, 2) -> true;
-is_pure_op(?PRIMOP_INTDIV, 2) -> true;
-is_pure_op(?PRIMOP_REM, 2) -> true;
-is_pure_op(?PRIMOP_BAND, 2) -> true;
-is_pure_op(?PRIMOP_BOR, 2) -> true;
-is_pure_op(?PRIMOP_BXOR, 2) -> true;
-is_pure_op(?PRIMOP_BNOT, 1) -> true;
-is_pure_op(?PRIMOP_BSL, 2) -> true;
-is_pure_op(?PRIMOP_BSR, 2) -> true;
-is_pure_op(?PRIMOP_EXIT, 1) -> true;
-is_pure_op(?PRIMOP_THROW, 1) -> true;
-is_pure_op(?PRIMOP_ERROR, 1) -> true;
-is_pure_op(?PRIMOP_ERROR, 2) -> true;
-is_pure_op(?PRIMOP_RETHROW, 2) -> true;
-is_pure_op(N, A) -> is_pure_op_aux(N, A).
-
-is_pure_op_aux(N, A) ->
- is_bool_op(N, A) orelse is_comp_op(N, A) orelse is_type_test(N, A).
-
-translate_flags(Flags, Align) ->
- translate_flags1(cerl:concrete(Flags), Align).
-
-translate_flags1([A|Rest], Align) ->
- case A of
- signed ->
- 4 + translate_flags1(Rest, Align);
- little ->
- 2 + translate_flags1(Rest, Align);
- native ->
- case hipe_rtl_arch:endianess() of
- little ->
- 2 + translate_flags1(Rest, Align);
- big ->
- translate_flags1(Rest, Align)
- end;
- _ ->
- translate_flags1(Rest, Align)
- end;
-translate_flags1([], Align) ->
- case Align of
- 0 ->
- 1;
- _ ->
- 0
- end.
-
-get_const_info(Val, integer) ->
- case {cerl:is_c_var(Val), cerl:is_c_int(Val)} of
- {true, _} ->
- var;
- {_, true} ->
- pass;
- _ ->
- fail
- end;
-get_const_info(Val, float) ->
- case {cerl:is_c_var(Val), cerl:is_c_float(Val)} of
- {true, _} ->
- var;
- {_, true} ->
- pass;
- _ ->
- fail
- end;
-get_const_info(_Val, _Type) ->
- [].
-
-calculate_size(Unit, Var, Align, Env, S) ->
- case cerl:is_c_atom(Var) of
- true ->
- {cerl:atom_val(Var), cerl:concrete(Unit), Align, S};
- false ->
- case cerl:is_c_int(Var) of
- true ->
- NewVal = cerl:concrete(Var) * cerl:concrete(Unit),
- NewAlign =
- case Align of
- false ->
- false
- %% Currently, all uses of the function are
- %% with "Aligned == false", and this case
- %% is commented out to shut up Dialyzer.
- %% _ ->
- %% (NewVal+Align) band 7
- end,
- {NewVal, [], S, NewAlign};
- false ->
- NewSize = make_var(),
- S1 = expr(Var, [NewSize], #ctxt{final=false}, Env, S),
- NewAlign =
- case cerl:concrete(Unit) band 7 of
- 0 ->
- Align;
- _ ->
- false
- end,
- {cerl:concrete(Unit), [NewSize], S1, NewAlign}
- end
- end.
-
-
-%% ---------------------------------------------------------------------
-%% Environment (abstract datatype)
-
-env__new() ->
- rec_env:empty().
-
-env__bind(Key, Val, Env) ->
- rec_env:bind(Key, Val, Env).
-
-env__lookup(Key, Env) ->
- rec_env:lookup(Key, Env).
-
-env__get(Key, Env) ->
- rec_env:get(Key, Env).
-
-%% env__new_integer_keys(N, Env) ->
-%% rec_env:new_keys(N, Env).
-
-
-%% ---------------------------------------------------------------------
-%% State (abstract datatype)
-
--record(state, {module, function, local, labels=gb_trees:empty(),
- code = [], pmatch=true, bitlevel_binaries=false}).
-
-s__new(Module) ->
- #state{module = Module}.
-
-s__get_module(S) ->
- S#state.module.
-
-s__set_function(Name, S) ->
- S#state{function = Name}.
-
-s__get_function(S) ->
- S#state.function.
-
-s__set_local_entry(Info, S) ->
- S#state{local = Info}.
-
-s__get_local_entry(S) ->
- S#state.local.
-
-%% Generated code is kept in reverse order, to make adding fast.
-
-s__set_code(Code, S) ->
- S#state{code = lists:reverse(Code)}.
-
-s__get_code(S) ->
- lists:reverse(S#state.code).
-
-s__add_code(Code, S) ->
- S#state{code = lists:reverse(Code, S#state.code)}.
-
-s__get_label(Ref, S) ->
- Labels = S#state.labels,
- case gb_trees:lookup(Ref, Labels) of
- none ->
- Label = new_label(),
- S1 = S#state{labels=gb_trees:enter(Ref, Label, Labels)},
- {Label, S1};
- {value, Label} ->
- {Label,S}
- end.
-
-s__set_pmatch(V, S) ->
- S#state{pmatch = V}.
-
-s__get_pmatch(S) ->
- S#state.pmatch.
-
-s__set_bitlevel_binaries(true, S) ->
- S#state{bitlevel_binaries = true};
-s__set_bitlevel_binaries(_, S) ->
- S#state{bitlevel_binaries = false}.
-
-s__get_bitlevel_binaries(S) ->
- S#state.bitlevel_binaries.
-%% ---------------------------------------------------------------------
-%%% Match label State
-
-%-record(mstate,{labels=gb_trees:empty()}).
-
-%get_correct_label(Alias, MState=#mstate{labels=Labels}) ->
-% case gb_trees:lookup(Alias, Labels) of
-% none ->
-% LabelName=new_label(),
-% {LabelName, MState#mstate{labels=gb_trees:insert(Alias, LabelName, Labels)}};
-% {value, LabelName} ->
-% {LabelName, MState}
-% end.
-
-
-%% ---------------------------------------------------------------------
-%% General utilities
-
-reset_var_counter() ->
- hipe_gensym:set_var(0).
-
-reset_label_counter() ->
- hipe_gensym:set_label(0).
-
-new_var() ->
- hipe_gensym:get_next_var().
-
-new_label() ->
- hipe_gensym:get_next_label().
-
-max_var() ->
- hipe_gensym:get_var().
-
-max_label() ->
- hipe_gensym:get_label().
-
-make_var() ->
- icode_var(new_var()).
-
-make_vars(N) when N > 0 ->
- [make_var() | make_vars(N - 1)];
-make_vars(0) ->
- [].
-
-make_reg() ->
- icode_reg(new_var()).
-
-
-%% ---------------------------------------------------------------------
-%% ICode interface
-
-icode_icode(M, {F, A}, Vs, Closure, C, V, L) ->
- MFA = {M, F, A},
- hipe_icode:mk_icode(MFA, Vs, Closure, false, C, V, L).
-
-icode_icode_name(Icode) ->
- hipe_icode:icode_fun(Icode).
-
-icode_comment(S) -> hipe_icode:mk_comment(S).
-
-icode_var(V) -> hipe_icode:mk_var(V).
-
-icode_reg(V) -> hipe_icode:mk_reg(V).
-
-icode_label(L) -> hipe_icode:mk_label(L).
-
-icode_move(V, D) -> hipe_icode:mk_move(V, D).
-
-icode_const(X) -> hipe_icode:mk_const(X).
-
-icode_const_val(X) -> hipe_icode:const_value(X).
-
-icode_call_local(Ts, M, N, Vs) ->
- hipe_icode:mk_call(Ts, M, N, Vs, local).
-
-icode_call_remote(Ts, M, N, Vs) ->
- hipe_icode:mk_call(Ts, M, N, Vs, remote).
-
-icode_call_remote(Ts, M, N, Vs, Cont, Fail, Guard) ->
- hipe_icode:mk_call(Ts, M, N, Vs, remote, Cont, Fail, Guard).
-
-icode_enter_local(M, N, Vs) ->
- hipe_icode:mk_enter(M, N, Vs, local).
-
-icode_enter_remote(M, N, Vs) ->
- hipe_icode:mk_enter(M, N, Vs, remote).
-
-icode_call_fun(Ts, Vs) ->
- icode_call_primop(Ts, call_fun, Vs).
-
-icode_enter_fun(Vs) ->
- icode_enter_primop(enter_fun, Vs).
-
-icode_begin_try(L,Cont) -> hipe_icode:mk_begin_try(L,Cont).
-
-icode_end_try() -> hipe_icode:mk_end_try().
-
-icode_begin_handler(Ts) -> hipe_icode:mk_begin_handler(Ts).
-
-icode_goto(L) -> hipe_icode:mk_goto(L).
-
-icode_return(Ts) -> hipe_icode:mk_return(Ts).
-
-icode_fail(Vs, C) -> hipe_icode:mk_fail(Vs, C).
-
-icode_guardop(Ts, Name, As, Succ, Fail) ->
- hipe_icode:mk_guardop(Ts, Name, As, Succ, Fail).
-
-icode_call_primop(Ts, Name, As) -> hipe_icode:mk_primop(Ts, Name, As).
-
-icode_call_primop(Ts, Name, As, Succ, Fail) ->
- hipe_icode:mk_primop(Ts, Name, As, Succ, Fail).
-
-icode_enter_primop(Name, As) -> hipe_icode:mk_enter_primop(Name, As).
-
-icode_if(Test, As, True, False) ->
- hipe_icode:mk_if(Test, As, True, False).
-
-icode_type(Test, As, True, False) ->
- hipe_icode:mk_type(Test, As, True, False).
-
-icode_switch_val(Arg, Fail, Length, Cases) ->
- hipe_icode:mk_switch_val(Arg, Fail, Length, Cases).
-
-icode_switch_tuple_arity(Arg, Fail, Length, Cases) ->
- SortedCases = lists:keysort(1, Cases), %% imitate BEAM compiler - Kostis
- hipe_icode:mk_switch_tuple_arity(Arg, Fail, Length, SortedCases).
-
-
-%% ---------------------------------------------------------------------
-%% Error reporting
-
-error_not_in_receive(Name) ->
- error_msg("primitive operation `~w' missing receive-context.",
- [Name]).
-
-low_degree() ->
- "degree of expression less than expected.".
-
-warning_low_degree() ->
- warning_msg(low_degree()).
-
-error_low_degree() ->
- error_msg(low_degree()).
-
-error_high_degree() ->
- error_msg("degree of expression greater than expected.").
-
-error_degree_mismatch(N, E) ->
- error_msg("expression does not have expected degree (~w): ~P.",
- [N, E, 10]).
-
-error_nonlocal_application(Op) ->
- error_msg("application operator not a local function: ~P.",
- [Op, 10]).
-
-error_primop_badargs(Op, As) ->
- error_msg("bad arguments to `~w' operation: ~P.",
- [Op, As, 15]).
-
-%% internal_error_msg(S) ->
-%% internal_error_msg(S, []).
-
-%% internal_error_msg(S, Vs) ->
-%% error_msg(lists:concat(["Internal error: ", S]), Vs).
-
-error_msg(S) ->
- error_msg(S, []).
-
-error_msg(S, Vs) ->
- error_logger:error_msg(lists:concat([?MODULE, ": ", S, "\n"]), Vs).
-
-warning_msg(S) ->
- warning_msg(S, []).
-
-warning_msg(S, Vs) ->
- info_msg(lists:concat(["warning: ", S]), Vs).
-
-%% info_msg(S) ->
-%% info_msg(S, []).
-
-info_msg(S, Vs) ->
- error_logger:info_msg(lists:concat([?MODULE, ": ", S, "\n"]), Vs).
-
-
-%% --------------------------------------------------------------------------
-%% Binary stuff
-
-binary_match([Clause|Clauses], F, [V], Next, Fail, Ctxt, Env, S) ->
- Guard = cerl:clause_guard(Clause),
- Body = cerl:clause_body(Clause),
- [Pat] = cerl:clause_pats(Clause),
- {FL,S1} = s__get_label(translate_label_primop(Guard),S),
- {Env1,S2} = binary_pattern(Pat,V,FL,Env,S1),
- S3 = F(Body, Ctxt, Env1, S2),
- S4 = add_continuation_jump(Next, Ctxt, S3),
- S5 = add_code([icode_label(FL)], S4),
- binary_match(Clauses, F, [V], Next, Fail, Ctxt, Env, S5);
-binary_match([], _F, _, _Next, Fail, _Ctxt, _Env, S) ->
- add_code([icode_goto(Fail)], S).
-
-translate_label_primop(LabelPrimop) ->
- ?PRIMOP_SET_LABEL = cerl:atom_val(cerl:primop_name(LabelPrimop)),
- [Ref] = cerl:primop_args(LabelPrimop),
- Ref.
-
-
diff --git a/lib/hipe/doc/Makefile b/lib/hipe/doc/Makefile
deleted file mode 100644
index 1015ca78eb..0000000000
--- a/lib/hipe/doc/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2006-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-SHELL=/bin/sh
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-clean:
- -rm -f *.html edoc-info stylesheet.css erlang.png
-
-distclean: clean
-realclean: clean
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
diff --git a/lib/hipe/doc/html/.gitignore b/lib/hipe/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/hipe/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/hipe/doc/overview.edoc b/lib/hipe/doc/overview.edoc
deleted file mode 100644
index 0016478a8a..0000000000
--- a/lib/hipe/doc/overview.edoc
+++ /dev/null
@@ -1,9 +0,0 @@
-
- HiPE overview page
-
-@title The HiPE Compiler
-
-@author The HiPE group <hipe@it.uu.se> [http://www.it.uu.se/research/group/hipe/]
-
-@doc This is the online documentation for the HiPE native code compiler.
-The user interface is provided by the module {@link hipe}.
diff --git a/lib/hipe/doc/pdf/.gitignore b/lib/hipe/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/hipe/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/hipe/doc/src/HiPE_app.xml b/lib/hipe/doc/src/HiPE_app.xml
deleted file mode 100644
index 592ba0b313..0000000000
--- a/lib/hipe/doc/src/HiPE_app.xml
+++ /dev/null
@@ -1,198 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE appref SYSTEM "appref.dtd">
-
-<appref>
- <header>
- <copyright>
- <year>1997</year><year>2020</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>HiPE</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date></date>
- <rev></rev>
- <file>hipe.xml</file>
- </header>
- <app>HiPE</app>
- <appsummary>The HiPE Application</appsummary>
- <description>
- <note>
- <p>
- HiPE and execution of HiPE compiled code only have limited support by
- the OTP team at Ericsson. The OTP team only does limited maintenance
- of HiPE and does not actively develop HiPE. HiPE is mainly supported
- by the HiPE team at Uppsala University.
- </p>
- </note>
- <p>
- The normal way to native-compile an Erlang module using HiPE is to include the atom native
- in the Erlang compiler options, as in:</p>
- <pre>
- 1> <input>c(my_module, [native]).</input></pre>
- <p>Options to the HiPE compiler are then passed as follows:</p>
- <pre>
- 1> <input>c(my_module, [native,{hipe,Options}]).</input></pre>
- <p>For on-line help in the Erlang shell, call <c>hipe:help()</c>.
- Details on HiPE compiler options are given by <c>hipe:help_options()</c>.</p>
- </description>
- <section>
- <title>Feature Limitations</title>
- <p>
- The HiPE compiler is in general compliant with the normal BEAM compiler,
- with respect to semantic behavior. There are however features in the BEAM compiler
- and the runtime system that have limited or no support for HiPE compiled modules.
- </p>
- <taglist>
- <tag>Binary matching</tag>
- <item><p>The HiPE compiler will crash on modules containing binary
- matching.</p>
- </item>
- <tag>try/catch</tag>
- <item><p>The HiPE compiler will crash on modules containing 'try' or
- 'catch'.</p>
- </item>
-
- <tag>Stack traces</tag>
- <item><p>Stack traces returned from <c>try</c>/<c>catch</c> or as part of <c>'EXIT'</c> terms
- can look incomplete if HiPE compiled functions are involved. Typically a stack trace
- will contain only BEAM compiled functions or only HiPE compiled functions, depending
- on where the exception was raised.</p>
- <p>Source code line numbers in stack traces are also not supported by HiPE compiled functions.</p>
- </item>
-
- <tag>Tracing</tag>
- <item><p>Erlang call trace is not supported by HiPE. Calling
- <seemfa marker="erts:erlang#trace_pattern/3"><c>erlang:trace_pattern({M,F,A}, ...)</c></seemfa>
- does not have any effect on HiPE compiled modules.</p>
- </item>
-
- <tag>NIFs</tag>
- <item><p>Modules compiled with HiPE cannot call <seemfa marker="erts:erlang#load_nif/2">
- <c>erlang:load_nif/2</c></seemfa> to load NIFs.</p>
- </item>
-
- <tag>-on_load</tag>
- <item><p>Modules compiled with HiPE cannot use
- <seeguide marker="system/reference_manual:code_loading#on_load"><c>-on_load()</c></seeguide>
- directives.</p>
- </item>
- </taglist>
-
- </section>
- <section>
- <title>Performance Limitations</title>
- <p>
- The HiPE compiler does in general produce faster code than the
- BEAM compiler. There are however some situation when HiPE
- compiled code will perform worse than BEAM code.
- </p>
- <taglist>
- <tag>Mode switches</tag>
- <item><p>Every time a process changes from executing code in a
- HiPE compiled module to a BEAM compiled module (or vice versa),
- it will do a mode switch. This involves a certain amount of
- CPU overhead which can have a negative net impact if the
- process is switching back and forth without getting enough done in
- each mode.</p>
- </item>
-
- <tag>Optimization for <c>receive</c> with unique references</tag>
- <item>
- <p>
- The BEAM compiler can do an optimization when a receive
- statement is only waiting for messages containing a reference
- created before the receive. All messages that existed in the
- queue when the reference was created will be bypassed, as they
- cannot possibly contain the reference. HiPE currently has an
- optimization similar this, but it is not guaranteed to
- bypass all messages. In the worst case scenario, it cannot
- bypass any messages at all.
- </p>
- <p>
- An example of this is when <c>gen_server:call()</c> waits for
- the reply message.
- </p>
- </item>
-
- <tag>Garbage collection after BIFs</tag>
- <item>
- <p>
- The condition for determining whether a garbage collection
- is needed or not has changed in later releases. HiPE has not
- been updated regarding this which may cause premature garbage
- collections after BIF calls.
- </p>
- </item>
-
- </taglist>
- </section>
- <section>
- <title>Stability Issues</title>
- <taglist>
- <tag>Not checking reduction count on function returns</tag>
- <item>
- <p>
- BEAM checks the reduction count and schedules out the executing
- process if needed both when calling a function and when returning
- from a function call that was not called using a tail call.
- HiPE only checks the reduction count when calling a function.
- </p>
- <p>
- The runtime system might need to schedule out a process
- in order to reclaim memory. If the process isn't scheduled
- out soon after the process has entered this state, memory
- consumption will quickly grow. Maintaining this state is also
- quite expensive performance wise.
- </p>
- <p>
- Processes executing code that performs large recursions and
- produce data after returning from recursive calls may have to
- be scheduled out when returning from a function call. Since
- HiPE does not check reductions on returns, processes executing
- such HiPE compiled code may cause huge peaks in memory
- consumption as well as severe performance degradation.
- </p>
- </item>
-
- <tag>Not bumping appropriate amount of reductions in <c>receive</c> statements</tag>
- <item>
- <p>
- The process signaling improvements made in ERTS version
- 10.0 moved potentially significant amounts of work into the
- receive statement from other places. In order to account for
- this work, the reduction count should be bumped on the
- executing process. Reductions are not bumped when entering
- the <c>receive</c> statement from HiPE compiled code.
- </p>
- </item>
- </taglist>
- </section>
- <section>
- <title>SEE ALSO</title>
- <p>
- <seeerl marker="stdlib:c">c(3)</seeerl>,
- <seeerl marker="compiler:compile">compile(3)</seeerl>
- </p>
- </section>
-
-</appref>
-
diff --git a/lib/hipe/doc/src/Makefile b/lib/hipe/doc/src/Makefile
deleted file mode 100644
index ddebe3c415..0000000000
--- a/lib/hipe/doc/src/Makefile
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2006-2018. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(HIPE_VSN)
-APPLICATION=hipe
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES =
-
-XML_PART_FILES = HiPE_app.xml
-XML_CHAPTER_FILES = notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
-
-include $(ERL_TOP)/make/doc.mk
diff --git a/lib/hipe/doc/src/book.xml b/lib/hipe/doc/src/book.xml
deleted file mode 100644
index 7c594f12ad..0000000000
--- a/lib/hipe/doc/src/book.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2006</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>HiPE</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <pagetext></pagetext>
- <preamble>
- </preamble>
- <pagetext>HiPE</pagetext>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
-</book>
-
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
deleted file mode 100644
index 600aabaebb..0000000000
--- a/lib/hipe/doc/src/notes.xml
+++ /dev/null
@@ -1,2028 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2006</year><year>2020</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>HiPE Release Notes</title>
- <prepared>otp_appnotes</prepared>
- <docno>nil</docno>
- <date>nil</date>
- <rev>nil</rev>
- <file>notes.xml</file>
- </header>
- <p>This document describes the changes made to HiPE.</p>
-
-<section><title>Hipe 4.0.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fixed a warning issued when building the <c>hipe</c>
- application.</p>
- <p>
- Own Id: OTP-16737</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 4.0</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>Fixed a rare miss-compilation of tuple matching.</p>
- <p>
- Own Id: OTP-16470</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The deprecated <c>erlang:get_stacktrace/0</c> BIF now
- returns an empty list instead of a stacktrace. To
- retrieve the stacktrace, use the extended try/catch
- syntax that was introduced in OTP 21.
- <c>erlang:get_stacktrace/0</c> is scheduled for removal
- in OTP 24.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-16484</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.19.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>HiPE can again handle modules with <c>catch</c> and
- <c>try</c> constructs.</p>
- <p>
- Own Id: OTP-16418</p>
- </item>
- <item>
- <p>When the return value for try/catch was ignored, the
- native code compiler could crash.</p>
- <p>
- Own Id: OTP-16475 Aux Id: ERL-1175 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.19.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Correct the range type of <c>erlang:is_record/3</c>.
- </p>
- <p>
- Own Id: OTP-16323</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.19.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>The HiPE compiler would badly miscompile certain
- try/catch expressions, so it will now refuse to compile
- modules containing try or catch.</p> <p>As a consequence
- of this, <c>dialyzer</c> will no longer compile key
- modules to native code.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-15949</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.19</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Add function <c>hipe:erllvm_is_supported</c> to check for
- the presences of a suitable version of the LLVM tool
- chain as well as supported hardware architecture. The old
- <c>hipe:llvm_support_available</c> has been removed.</p>
- <p>
- Own Id: OTP-15385 Aux Id: PR-1986 </p>
- </item>
- <item>
- <p>
- Fix hipe LLVM for FreeBSD and other non-linux unix to use
- /tmp/ instead of /dev/shm/.</p>
- <p>
- Own Id: OTP-15386 Aux Id: PR-1963 </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>In OTP 22, HiPE (the native code compiler) is not
- fully functional. The reasons for this are:</p>
- <p>There are new BEAM instructions for binary matching
- that the HiPE native code compiler does not support.</p>
- <p>The new optimizations in the Erlang compiler create
- new combination of instructions that HiPE currently does
- not handle correctly.</p>
- <p>If erlc is invoked with the <c>+native</c> option, and
- if any of the new binary matching instructions are used,
- the compiler will issue a warning and produce a BEAM file
- without native code.</p>
- <p>
- Own Id: OTP-15596</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.18.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fix a bug in the handling of the <c>Key</c> argument
- of <c>lists:{keysearch, keyfind, keymember}</c>. </p>
- <p>
- Own Id: OTP-15570</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.18.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The code was updated to avoid causing a dialyzer
- warning because of a tightened spec for
- <c>beam_lib:info/1</c>.</p>
- <p>
- Own Id: OTP-15482</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.18.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Improved documentation.</p>
- <p>
- Own Id: OTP-15190</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.18</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Optimize <c>receive</c> statements that are only waiting
- for messages containing a reference created before the
- receive. All messages that existed in the queue when the
- reference was created will be bypassed, as they cannot
- possibly contain the reference. This optimization has
- existed for vanilla BEAM since OTP R14.</p>
- <p>
- Own Id: OTP-14785 Aux Id: PR-1632 </p>
- </item>
- <item>
- <p>
- Add validation pass to hipe compiler to detect internal
- errors causing primop calls that may trigger an unsafe GC
- at run-time. The pass can be disabled with option
- <c>no_verify_gcsafe</c>.</p>
- <p>
- Own Id: OTP-14900 Aux Id: PR-1685, PR-1621 </p>
- </item>
- <item>
- <p>
- Make hipe compiled code work on x86_64 (amd64) with OS
- security feature PIE, where executable code can be loaded
- into a random location. Old behavior, if hipe was
- enabled, was to disable PIE build options for the VM.</p>
- <p>
- Own Id: OTP-14903</p>
- </item>
- <item>
- <p>
- Inline more type test BIFs; <c>is_number</c>,
- <c>is_bitstring</c>, <c>is_map</c>.</p>
- <p>
- Own Id: OTP-14941 Aux Id: PR-1718 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.17.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix HiPE bug for binary constructs like
- <c>&lt;&lt;X/utf8&gt;&gt;</c> which could in rare cases
- cause faulty results or VM crash.</p>
- <p>
- This fix affects both the <c>hipe</c> compiler and
- <c>erts</c> runtime in an <em>incompatible</em> way. Old
- hipe compiled files need to be recompiled to load and run
- properly as native.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-14850 Aux Id: PR-1664 </p>
- </item>
- <item>
- <p>The BEAM compiler chooses not to perform tailcall
- optimisations for some calls in tail position, for
- example to some built-in functions. However, when the
- ErLLVM HiPE backend is used, LLVM may choose to perform
- tailcall optimisation on these calls, breaking the
- expected semantics.</p>
- <p>To preserve the precise semantics exhibited by BEAM,
- the 'notail' marker, present in LLVM since version 3.8,
- is added to call instructions that BEAM has not turned
- into tail calls, which inhibits LLVM from performing
- tail-call optimisation in turn.</p>
- <p>
- Own Id: OTP-14886</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.17</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix bug for hipe compiled code using
- <c>&lt;&lt;X/utf32&gt;&gt;</c> binary construction that
- could cause faulty result or even VM crash.</p>
- <p>
- On architectures other than x86_64, code need to be
- recompiled to benefit from this fix.</p>
- <p>
- Own Id: OTP-14740</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Added documentation about limitations of hipe compared to
- beam compiled code.</p>
- <p>
- Own Id: OTP-14767</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.16.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fix a bug regarding map types that caused Dialyzer to
- go into an infinite loop. A consequence of the fix is
- that compound map keys such as maps and tuples sometimes
- are handled with less precision than before. </p>
- <p>
- Own Id: OTP-14572 Aux Id: seq13319 </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- General Unicode improvements.</p>
- <p>
- Own Id: OTP-14462</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.16</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix hipe compiler flags <c>o0</c> and <c>o1</c> that have
- previously been ignored by mistake.</p>
- <p>
- Own Id: OTP-13862 Aux Id: PR-1154 </p>
- </item>
- <item>
- <p>
- Fix LLVM backend to not convert all remote calls to own
- module, like <c>?MODULE:foo()</c>, into local calls.</p>
- <p>
- Own Id: OTP-13983</p>
- </item>
- <item>
- <p>
- Hipe optional LLVM backend does require LLVM version 3.9
- or later as older versions forced strong dependencies on
- erts internals structures.</p>
- <p>
- Own Id: OTP-14238</p>
- </item>
- <item>
- <p>
- Fix a bug that has been seen causing failed loading of
- hipe compiled modules on NetBSD due to unaligned data
- pointers.</p>
- <p>
- Own Id: OTP-14302 Aux Id: ERL-376, PR-1386 </p>
- </item>
- <item>
- <p>
- Fix miscompilation bug in hipe that could cause wrong
- function clause to be called from non-tail calls, where
- the return value is unused, if the right function clause
- is only reachable from those non-tail calls.</p>
- <p>
- Own Id: OTP-14306 Aux Id: ERL-278, PR-1392 </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Improve hipe compilation time for large functions.</p>
- <p>
- Own Id: OTP-13810 Aux Id: PR-1124 </p>
- </item>
- <item>
- <p>Replaced usage of deprecated symbolic <seetype
- marker="erts:erlang#time_unit"><c>time
- unit</c></seetype> representations.</p>
- <p>
- Own Id: OTP-13831 Aux Id: OTP-13735 </p>
- </item>
- <item>
- <p>
- Speed up hipe compile time register allocation for larger
- function.</p>
- <p>
- Own Id: OTP-13879</p>
- </item>
- <item>
- <p>
- Various code generation improvements.</p>
- <p>
- Own Id: OTP-14261 Aux Id: PR-1360 </p>
- </item>
- <item>
- <p>
- Improve hipe compiler to generate code with better CPU
- register utilization at runtime by the use of 'Live Range
- Splitting' techniques.</p>
- <p>
- Own Id: OTP-14293 Aux Id: PR-1380 </p>
- </item>
- <item>
- <p>
- Allow HiPE to run on VM built with
- <c>--enable-m32-build</c>.</p>
- <p>
- Own Id: OTP-14330 Aux Id: PR-1397 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.15.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fix a bug concerning parameterized opaque types. </p>
- <p>
- Own Id: OTP-14130</p>
- </item>
- <item>
- <p>
- Fixed xml issues in old release notes</p>
- <p>
- Own Id: OTP-14269</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.15.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix flow control bug in hipe compiler that may cause
- compile time crash.</p>
- <p>
- Own Id: OTP-13965 Aux Id: PR-1253 </p>
- </item>
- <item>
- <p>
- Fix bug in native compilation of bitstring pattern
- matching causing erroneous runtime matching result. The
- bug only affects code containing constant-valued segments
- whose size is expressed in bits; it is triggered when the
- pattern matching against these segments fails (i.e., when
- the next clause needs to be tried).</p>
- <p>
- Own Id: OTP-14005</p>
- </item>
- <item>
- <p>
- Workaround in HiPE LLVM backend for a bug in LLVM 3.9.
- The bug could cause LLVM-compiled modules to be rejected
- during loading with a badarg exception in
- hipe_bifs:enter_sdecs/1, but also cause corruption or
- segmentation faults i runtime.</p>
- <p>
- Own Id: OTP-14027 Aux Id: ERL-292, PR-1237 </p>
- </item>
- <item>
- <p>
- Fix a bug in HiPE LLVM backend involving incorrect type
- tests of atoms sometimes causing incorrect behaviour or
- even segfaults.</p>
- <p>
- Own Id: OTP-14028 Aux Id: PR-1237 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.15.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fixed various hipe compiler backend bugs affecting mostly
- ARM and SPARC.</p>
- <p>
- Own Id: OTP-13846 Aux Id: PR-1146 </p>
- </item>
- <item>
- <p>
- Fixed some Dialyzer warnings and code cleanup for the
- Sparc compiler backend.</p>
- <p>
- Own Id: OTP-13861 Aux Id: PR-1148 </p>
- </item>
- <item>
- <p> Fix erl_bif_types opaque bug. </p>
- <p>
- Own Id: OTP-13878 Aux Id: PR-1161, ERL-249 </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Fix erl_types opaque match order</p>
- <p>
- Own Id: OTP-13876</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.15.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- HiPE compiler crashed, during compilation, in some cases
- that involved inlining of float operations on complicated
- control flow graphs.</p>
- <p>
- Own Id: OTP-13407 Aux Id: PR-984 </p>
- </item>
- <item>
- <p>
- Various fixes and improvements to the HiPE LLVM backend.</p>
- <list> <item>Add support for LLVM 3.7 and 3.8 in the
- HiPE/LLVM x86_64 backend</item> <item>Reinstate support
- for the LLVM backend on x86 (works OK for LLVM 3.5 to 3.7
- -- LLVM 3.8 has a bug that prevents it from generating
- correct native code on x86)</item> </list>
- <p>
- Own Id: OTP-13626</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Elimination of <c>maps:is_key/2</c> calls to HiPE</p>
- <p>
- Own Id: OTP-13625 Aux Id: PR-1069 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.15</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix pretty printing of Core Maps</p>
- <p>
- Literal maps could cause Dialyzer to crash when pretty
- printing the results.</p>
- <p>
- Own Id: OTP-13238</p>
- </item>
- <item>
- <p>
- Dialyzer warnings removed.</p>
- <p>
- Own Id: OTP-13379</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Fix HiPE ErLLVM code generation for pattern matching with
- UTF binaries.</p>
- <p>
- Own Id: OTP-13269</p>
- </item>
- <item>
- <p>
- Fix various binary construction inconsistencies for hipe
- compiled code.</p> <list> <item>Passing bad field sizes to
- binary constructions would throw <c>badarith</c> rather
- than <c>badarg</c>. Worse, in guards, when the unit size
- of the field was 1, the exception would leak rather than
- failing the function clause match.</item> <item>Passing
- bignums as field sizes to binary constructions would
- always fail (and always with <c>badarg</c>).</item>
- <item>A bug in bs_init_bits that cased binary
- constructions to fail with system_limit if they were at
- least 1/8th of the actual limit.</item> <item>Compiler
- crashes when matches against an integer literal whose
- size fits an unsigned word, but not a signed word or
- matches against an integer literal that whose size is
- larger than the largest allowed bignum.</item> <item>Very
- large binary constructions that should fail with
- system_limit could instead fail with <c>badarg</c> or
- even succeed with a faulty result.</item> <item>Add
- missing check for unit size match when inserting a
- binary. For example, a faulty expression like
- <c>&lt;&lt;&lt;&lt;1:7&gt;&gt;/binary&gt;&gt;</c> would
- succeed.</item> </list>
- <p>
- Own Id: OTP-13272</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.14</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix hipe bug causing segfaults when native code
- constructs binaries starting with a zero-length integer
- field.</p>
- <p>
- Own Id: OTP-13048</p>
- </item>
- <item>
- <p>
- Reintroduce the <c>erlang:make_fun/3</c> BIF in
- erl_bif_types.</p>
- <p>
- Own Id: OTP-13068</p>
- </item>
- <item>
- <p>
- In certain cases of matching with very big binaries, the
- HiPE compiler generated code that would fail the match,
- even in cases that the matching was successful. The
- problem was more quite noticeable on 32-bit platforms.</p>
- <p>
- Own Id: OTP-13092</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- mikpe/hipe_x86_signal-musl-support</p>
- <p>
- Own Id: OTP-13159</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.13</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fix bugs concerning <c>erlang:abs/1</c>. </p>
- <p>
- Own Id: OTP-12948</p>
- </item>
- <item>
- <p> Fix a bug concerning <c>lists:keydelete/3</c> with
- union and opaque types. </p>
- <p>
- Own Id: OTP-12949</p>
- </item>
- <item>
- <p>
- A beam file compiled by hipe for an incompatible runtime
- system was sometimes not rejected by the loader, which
- could lead to vm crash. This fix will also allow the same
- hipe compiler to be used by both normal and debug-built
- vm.</p>
- <p>
- Own Id: OTP-12962</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- New function <c>hipe:erts_checksum/0</c> which returns a
- value identifying the target runtime system for the
- compiler. Used by dialyzer for its beam cache directory.</p>
- <p>
- Own Id: OTP-12963 Aux Id: OTP-12962, OTP-12964 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.12</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fix a minor bug in the handling of opaque types. </p>
- <p>
- Own Id: OTP-12666</p>
- </item>
- <item>
- <p>
- Fix hipe bug when matching a "writable" binary. The bug
- has been seen to sometimes cause a failed binary matching
- of a correct utf8 character, but other symptoms are also
- possible.</p>
- <p>
- Own Id: OTP-12667</p>
- </item>
- <item>
- <p>
- Optimizations and code cleanup in hipe code loader.</p>
- <p>
- Own Id: OTP-12816</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Improved error handling when memory allocation for HiPE
- code fails.</p>
- <p>
- Own Id: OTP-12448</p>
- </item>
- <item>
- <p>
- Allow use of complete interface of cerl_pmatch module</p>
- <p>
- Own Id: OTP-12794</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.11.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix HiPE for ARM when Erlang VM is compiled for Thumb
- execution mode. This was a problem on e.g. Ubuntu which
- configures its system GCC to generate Thumb by default.</p>
- <p>
- Own Id: OTP-12405</p>
- </item>
- <item>
- <p>
- Reduced lock contention of dynamic function lookups (like
- apply) from hipe compiled code.</p>
- <p>
- Own Id: OTP-12557</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Fix two bugs in HiPE compiler regarding floating-points,
- both leading to crash during compilation. The
- target-specific code generators failed to handle integer
- to floating-point conversion instructions with constant
- operands. The middle-end could use an incorrect
- representation for copies between floating-point
- registers.</p>
- <p>
- Own Id: OTP-12413</p>
- </item>
- <item>
- <p>
- Improved error handling when memory allocation for HiPE
- code fails.</p>
- <p>
- Own Id: OTP-12448</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.11.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fixed internal elf_format hrl file to contain valid
- erlang</p>
- <p>
- Own Id: OTP-12322</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.11.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> The pretty-printing of bitstrings has been corrected.
- </p>
- <p>
- Own Id: OTP-12015</p>
- </item>
- <item>
- <p> A bug concerning <c>is_record/2,3</c> has been fixed,
- as well as some cases where Dialyzer could crash due to
- reaching system limits. </p>
- <p>
- Own Id: OTP-12018</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.11</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- A Dialyzer crash involving analysis of Map types has now
- been fixed.</p>
- <p>
- Own Id: OTP-11947</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Handle Maps instructions get_map_elements, put_map_assoc,
- put_map_exact in HiPE compiler.</p>
- <p>
- Own Id: OTP-11900</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.10.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix compilation with 'no_remove_comments' (Thanks to
- Johannes Weißl)</p>
- <p>
- Own Id: OTP-11564</p>
- </item>
- <item>
- <p>
- Application upgrade (appup) files are corrected for the
- following applications: </p>
- <p>
- <c>asn1, common_test, compiler, crypto, debugger,
- dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
- inets, observer, odbc, os_mon, otp_mibs, parsetools,
- percept, public_key, reltool, runtime_tools, ssh,
- syntax_tools, test_server, tools, typer, webtool, wx,
- xmerl</c></p>
- <p>
- A new test utility for testing appup files is added to
- test_server. This is now used by most applications in
- OTP.</p>
- <p>
- (Thanks to Tobias Schlager)</p>
- <p>
- Own Id: OTP-11744</p>
- </item>
- <item>
- <p>
- There is now a test suite for the Hipe application</p>
- <p>
- Own Id: OTP-11748</p>
- </item>
- <item>
- <p>
- Support for a LLVM backend has been added in HiPE</p>
- <p>
- Own Id: OTP-11801</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The pre-defined types <c>array/0</c>, <c>dict/0</c>,
- <c>digraph/0</c>, <c>gb_set/0</c>, <c>gb_tree/0</c>,
- <c>queue/0</c>, <c>set/0</c>, and <c>tid/0</c> have been
- deprecated. They will be removed in Erlang/OTP 18.0. </p>
- <p> Instead the types <c>array:array/0</c>,
- <c>dict:dict/0</c>, <c>digraph:graph/0</c>,
- <c>gb_set:set/0</c>, <c>gb_tree:tree/0</c>,
- <c>queue:queue/0</c>, <c>sets:set/0</c>, and
- <c>ets:tid/0</c> can be used. (Note: it has always been
- necessary to use <c>ets:tid/0</c>.) </p> <p> It is
- allowed in Erlang/OTP 17.0 to locally re-define the types
- <c>array/0</c>, <c>dict/0</c>, and so on. </p> <p> New
- types <c>array:array/1</c>, <c>dict:dict/2</c>,
- <c>gb_sets:set/1</c>, <c>gb_trees:tree/2</c>,
- <c>queue:queue/1</c>, and <c>sets:set/1</c> have been
- added. </p> <p> A compiler option,
- <c>nowarn_deprecated_type</c>, has been introduced. By
- including the attribute </p> <c>
- -compile(nowarn_deprecated_type).</c> <p> in an Erlang
- source file, warnings about deprecated types can be
- avoided in Erlang/OTP 17.0. </p> <p> The option can also
- be given as a compiler flag: </p> <c> erlc
- +nowarn_deprecated_type file.erl</c>
- <p>
- Own Id: OTP-10342</p>
- </item>
- <item>
- <p>
- EEP43: New data type - Maps</p>
- <p>
- With Maps you may for instance:</p>
- <taglist>
- <tag/> <item><c>M0 = #{ a =&gt; 1, b =&gt; 2}, % create
- associations</c></item>
- <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item>
- <tag/><item><c>M2 = M1#{ "hi" =&gt;
- "hello"}, % add new associations</c></item>
- <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2.
- % match keys with values</c></item>
- </taglist>
- <p>
- For information on how to use Maps please see Map Expressions in the
- <seeguide marker="system/reference_manual:expressions#map_expressions">
- Reference Manual</seeguide>.</p>
- <p>
- The current implementation is without the following
- features:</p>
- <taglist>
- <tag/><item>No variable keys</item>
- <tag/><item>No single value access</item>
- <tag/><item>No map comprehensions</item>
- </taglist>
- <p>
- Note that Maps is <em>experimental</em> during OTP 17.0.</p>
- <p>
- Own Id: OTP-11616</p>
- </item>
- <item>
- <p> Parameterized opaque types have been introduced. </p>
- <p>
- Own Id: OTP-11625</p>
- </item>
- <item>
- <p>
- Add support for the compilation of the is_map/1 and
- map_size/1 guards to native code.</p>
- <p>
- Own Id: OTP-11831</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.10.2.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fixed a dialyzer crash when using remote types in the
- tail position of a maybe_improper_list/2 type. Thanks to
- Kostis Sagonas</p>
- <p>
- Own Id: OTP-11374</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.10.2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The encoding of the <c>notes.xml</c> file has been
- changed from latin1 to utf-8 to avoid future merge
- problems.</p>
- <p>
- Own Id: OTP-11310</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.10.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Fix the title of hipe_app documentation page. Thanks to
- Loïc Hoguin.</p>
- <p>
- Own Id: OTP-10904</p>
- </item>
- <item>
- <p>
- Fix native code compiler crash involving bs_match_string.
- Thanks to Kostis Sagonas.</p>
- <p>
- Own Id: OTP-10985</p>
- </item>
- <item>
- <p>
- Loosen the assumptions of code that handles escaping
- functions. Thanks to Kostis Sagonas</p>
- <p>
- Own Id: OTP-11031</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.10.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Bug fixed in hipe to where it did not allow unicode code
- points 16#FFFE and 16#FFFF in bit syntax in natively
- compiled modules.</p>
- <p>
- Own Id: OTP-10867</p>
- </item>
- <item>
- <p>
- Fix bug in hipe compiled code related to the handling of
- <c>is_number/1</c>. (Thanks to Sebastian Egner and
- Johannes Weißl for minimal test code and Kostis for quick
- patch)</p>
- <p>
- Own Id: OTP-10897</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> The type <c>ascii_string()</c> in the <c>base64</c>
- module has been corrected. The type
- <c>file:file_info()</c> has been cleaned up. The type
- <c>file:fd()</c> has been made opaque in the
- documentation. </p>
- <p>
- Own Id: OTP-10624 Aux Id: kunagi-352 [263] </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Support for Unicode has been implemented. </p>
- <p>
- Own Id: OTP-10302</p>
- </item>
- <item>
- <p>Where necessary a comment stating encoding has been
- added to Erlang files. The comment is meant to be removed
- in Erlang/OTP R17B when UTF-8 becomes the default
- encoding. </p>
- <p>
- Own Id: OTP-10630</p>
- </item>
- <item>
- <p>
- Update .gitignore (lib/hipe/boot_ebin). Thanks to Tuncer
- Ayaz.</p>
- <p>
- Own Id: OTP-10705</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.9.3</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- A faulty spec for process_info/2 could cause false
- dialyzer warnings. The spec is corrected.</p>
- <p>
- Own Id: OTP-10584</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.9.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Correct handling of type names in contracts. Fix
- crash related to contract checking. Do not rewrite
- unchanged PLT. </p>
- <p>
- Own Id: OTP-10083</p>
- </item>
- <item>
- <p>
- Changes in comments and minor code cleanups</p>
- <p>
- Thanks to Kostis Sagonas.</p>
- <p>
- Own Id: OTP-10230</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Remove all code, documentation, options and diagnostic
- functions which were related to the experimental hybrid
- heap implementation.</p>
- <p>
- Own Id: OTP-10105</p>
- </item>
- <item>
- <p> Bugs in <c>erl_types:t_inf()</c> (HiPE) and in
- <c>dialyzer_dataflow</c> (Dialyzer) have been fixed. </p>
- <p>
- Own Id: OTP-10191</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.9.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- References to <c>is_constant/1</c> (which was removed in
- the R12 release) has been removed from documentation and
- code.</p>
- <p>
- Own Id: OTP-6454 Aux Id: seq10407 </p>
- </item>
- <item>
- <p>
- Fixed a discrepancy in compile_info</p>
- <p>
- The BEAM disassembler used the atom 'none' to signify the
- absence of a compile_info chunk in a .beam file. This
- clashed with the type declaration of the compile_info
- field of a #beam_file{} record as containing a list. Now
- [] signifies the absence of this chunk. This simplifies
- the code and avoids a dialyzer warning.</p>
- <p>
- Own Id: OTP-9917</p>
- </item>
- <item>
- <p>
- Make dialyzer recognize the process_flag option sensitive
- add missing specs to documentation (Thanks to Tobias
- Schlager)</p>
- <p>
- Own Id: OTP-9923</p>
- </item>
- <item>
- <p>
- Remove hipe_ceach from hipe.app.src to fix
- reltool-generated release startup. (Thanks to Tim
- Stewart)</p>
- <p>
- Own Id: OTP-9939</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <list> <item><p>No warnings for underspecs with remote
- types</p></item> <item><p> Fix crash in Typer</p></item>
- <item><p>Fix Dialyzer's warning for its own
- code</p></item> <item><p>Fix Dialyzer's warnings in
- HiPE</p></item> <item><p>Add file/line info in a
- particular Dialyzer crash</p></item> <item><p>Update
- inets test results</p></item> </list>
- <p>
- Own Id: OTP-9758</p>
- </item>
- <item>
- <list> <item><p>Correct callback spec in application
- module</p></item> <item><p>Refine warning about callback
- specs with extra ranges</p></item> <item><p>Cleanup
- autoimport compiler directives</p></item> <item><p>Fix
- Dialyzer's warnings in typer</p></item> <item><p>Fix
- Dialyzer's warning for its own code</p></item>
- <item><p>Fix bug in Dialyzer's behaviours
- analysis</p></item> <item><p>Fix crash in
- Dialyzer</p></item> <item><p>Variable substitution was
- not generalizing any unknown variables.</p></item>
- </list>
- <p>
- Own Id: OTP-9776</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Possible to run HiPE without floating point exceptions
- (FPE). Useful on platforms that lack reliable FPE. Slower
- float operations compared to HiPE with FPE.</p>
- <p>
- Own Id: OTP-9724</p>
- </item>
- <item>
- <p>
- HiPE compiler: The possibility to compile and load
- selected functions from a module has been removed.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-9751</p>
- </item>
- <item>
- <p>
- <c>filename:find_src/1,2</c> will now work on stripped
- BEAM files (reported by Per Hedeland). The HiPE compiler
- will also work on stripped BEAM files. The BEAM compiler
- will no longer include compilation options given in the
- source code itself in <c>M:module_info(compile)</c>
- (because those options will be applied anyway if the
- module is re-compiled).</p>
- <p>
- Own Id: OTP-9752</p>
- </item>
- <item>
- <p> Optimize <c>erl_types:t_unify()</c>. </p>
- <p>
- Own Id: OTP-9768</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.8.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Clean up hipe.hrl.src (Thanks to Tuncer Ayaz)</p>
- <p>
- Own Id: OTP-9511</p>
- </item>
- <item>
- <p>
- Fix bug with binary pattern matching of floats of
- variable size</p>
- <p>
- Pattern matching of floats with variable size
- (&lt;&lt;F:S/float&gt;&gt;) did always fail. Judging from
- similar code for ints, this bug is simply a typo.(Thanks
- to Paul Guyot)</p>
- <p>
- Own Id: OTP-9556</p>
- </item>
- <item>
- <p>
- Quote atoms if necessary in types</p>
- <p>
- Atoms in some occurrences were not correctly quoted when
- formatted to strings, for instance by the typer program
- (Thanks to Tomas Abrahamsson)</p>
- <p>
- Update Dialyzer's reference results</p>
- <p>
- Own Id: OTP-9560</p>
- </item>
- <item>
- <p>
- Fix typer's crash for nonexisting files Remove unused
- macro Fix bug in dataflow Decrease tuple arity limit This
- fixes a memory related crash.</p>
- <p>
- Own Id: OTP-9597</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Types for several BIFs have been extended/corrected. Also
- the types for types for <c>lists:keyfind/3</c>,
- <c>lists:keysearch/3</c>, and <c>lists:keyemember/3</c>
- have been corrected. The incorrect/incomplete types could
- cause false dialyzer warnings.</p>
- <p>
- Own Id: OTP-9496</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix hipe bug causing minor heap corruption related to
- binary matching. The bug has not been confirmed as the
- cause of any actual fault symptom.</p>
- <p>
- Own Id: OTP-9182</p>
- </item>
- <item>
- <p>
- Enable HiPE by default when compiling for PPC64</p>
- <p>
- Own Id: OTP-9198</p>
- </item>
- <item>
- <p>
- Fix handling of &lt;&lt;_:N,_:_*M&gt;&gt; type
- expressions Fix the argument of
- erlang:list_to_bitstring/1 Remove unneeded function
- 'sequence/2' Same functionality provided by
- string:join/2.</p>
- <p>
- Own Id: OTP-9277</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix erroneous fail info of a hipe_bs_primop</p>
- <p>
- Own Id: OTP-9036</p>
- </item>
- <item>
- <p>
- The change fixes a bug in the translation of 'bs_add'
- BEAM instruction to HiPE's Icode representation. When
- these instructions appeared in a guard context the
- previous translation was obviously buggy.</p>
- <p>
- Own Id: OTP-9044</p>
- </item>
- <item>
- <p>
- Sanitize the specs of the code module</p>
- <p>
- After the addition of unicode_binary() to the
- file:filename() type, dialyzer started complaining about
- erroneous or incomplete specs in some functions of the
- 'code' module. The culprit was hard-coded information in
- erl_bif_types for functions of this module, which were
- not updated. Since these functions have proper specs
- these days and code duplication (pun intended) is never a
- good idea, their type information was removed from
- erl_bif_types.</p>
- <p>
- While doing this, some erroneous comments were fixed in
- the code module and also made sure that the code now runs
- without dialyzer warnings even when the
- -Wunmatched_returns option is used.</p>
- <p>
- Some cleanups were applied to erl_bif_types too.</p>
- <p>
- Own Id: OTP-9100</p>
- </item>
- <item>
- <p>
- Fix bug in the simplification of inexact comparisons</p>
- <p>
- On 31/1/2011 Paul Guyot reported a bug in the native code
- compilation of inexact equality/inequality tests between
- floats and integers. The relevant test was:</p>
- <p>
- f(X) -&gt; Y = X / 2, Y == 0.</p>
- <p>
- and hipe erroneously evaluated the calls f(0) and f(0.0)
- to 'false'.</p>
- <p>
- The culprit was in the simplification code of the Icode
- range analysis which used an erroneous test (lists:any/1
- instead of lists:all/1).</p>
- <p>
- Own Id: OTP-9101</p>
- </item>
- <item>
- <p>
- Document exiting and garbage_collecting process statuses</p>
- <p>
- Own Id: OTP-9102</p>
- </item>
- <item>
- <p>
- Remove hipe constants pool</p>
- <p>
- Hipe constants used to be allocated within a single,
- fixed-size pool for interaction with the garbage
- collector. However, the garbage collector no longer
- depends on constants being allocated within a single
- pool, and the fixed size of the pool both meant
- unnecessary allocations on most deployments and crashes
- on deployments requiring more constants.</p>
- <p>
- The code was simplified to directly invoke erts_alloc.
- Debugging and undocumented function
- hipe_bifs:show_literals/0 was removed (it returned true
- and output text to the console), and debugging and
- undocumented function hipe_bifs:constants_size/0 was
- rewritten with a global to count the size of allocated
- constants.</p>
- <p>
- Own Id: OTP-9128</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.8.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Several type specifications for standard libraries were
- wrong in the R14B01 release. This is now corrected. The
- corrections concern types in re,io,filename and the
- module erlang itself.</p>
- <p>
- Own Id: OTP-9008</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Compiler warnings were eliminated.</p>
- <p>
- Own Id: OTP-8855</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.7</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>The HiPE compiler could crash when compiling certain
- modules (the bug has been latent, and been exposed by new
- optimizations introduced in the BEAM compiler in R14A).
- (Thanks to Mikael Pettersson.)</p>
- <p>
- Own Id: OTP-8800</p>
- </item>
- <item>
- <p>
- hipe:load/1 was broken. (Thanks to Paul Guyot.)</p>
- <p>
- Own Id: OTP-8802</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.6</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p><c>receive</c> statements that can only read out a
- newly created reference are now specially optimized so
- that it will execute in constant time regardless of the
- number of messages in the receive queue for the process.
- That optimization will benefit calls to
- <c>gen_server:call()</c>. (See <c>gen:do_call/4</c> for
- an example of a receive statement that will be
- optimized.)</p>
- <p>
- Own Id: OTP-8623</p>
- </item>
- <item>
- <p>
- Various changes to dialyzer-related files for R14.</p>
- <p>
- - Dialyzer properly supports the new attribute
- -export_type and checks that remote types only refer to
- exported types. A warning is produced if some
- files/applications refer to types defined in modules
- which are neither in the PLT nor in the analyzed
- applications.</p>
- <p>
- - Support for detecting data races involving whereis/1
- and unregister/1.</p>
- <p>
- - More precise identification of the reason(s) why a
- record construction violates the types declared for its
- fields.</p>
- <p>
- - Fixed bug in the handling of the 'or' guard.</p>
- <p>
- - Better handling of the erlang:element/2 BIF.</p>
- <p>
- - Complete handling of Erlang BIFs.</p>
- <p>
- Own Id: OTP-8699</p>
- </item>
- <item>
- <p><c>eprof</c> has been reimplemented with support in
- the Erlang virtual machine and is now both faster (i.e.
- slows down the code being measured less) and scales much
- better. In measurements we saw speed-ups compared to the
- old eprof ranging from 6 times (for sequential code that
- only uses one scheduler/core) up to 84 times (for
- parallel code that uses 8 cores).</p>
- <p>Note: The API for the <c>eprof</c> has been cleaned up
- and extended. See the documentation.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-8706</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.5</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The documentation is now possible to build in an open
- source environment after a number of bugs are fixed and
- some features are added in the documentation build
- process. </p>
- <p>- The arity calculation is updated.</p>
- <p>- The module prefix used in the function names for
- bif's are removed in the generated links so the links
- will look like
- "http://www.erlang.org/doc/man/erlang.html#append_element-2"
- instead of
- "http://www.erlang.org/doc/man/erlang.html#erlang:append_element-2".</p>
- <p>- Enhanced the menu positioning in the html
- documentation when a new page is loaded.</p>
- <p>- A number of corrections in the generation of man
- pages (thanks to Sergei Golovan)</p>
- <p>- The legal notice is taken from the xml book file so
- OTP's build process can be used for non OTP
- applications.</p>
- <p>
- Own Id: OTP-8343</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.4</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The documentation is now built with open source tools
- (xsltproc and fop) that exists on most platforms. One
- visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201</p>
- </item>
- <item>
- <p>
- Misc updates.</p>
- <p>
- Own Id: OTP-8301</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Various small bugs (one involving the handling of large
- binaries) were corrected and some additions to its
- functionality and/or code cleanups were done.</p>
- <p>
- Own Id: OTP-8189</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Miscellaneous updates.</p>
- <p>
- Own Id: OTP-8038</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.7.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Minor updates and bug fixes.</p>
- <p>
- Own Id: OTP-7958</p>
- </item>
- </list>
- </section>
-
-</section>
-
-
-<section><title>Hipe 3.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Miscellaneous updates.</p>
- <p>
- Own Id: OTP-7877</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.6.9</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The <c>--disable-hipe</c> option for the
- <c>configure</c> will now completely disable the hipe
- run-time in the emulator, as is the expected
- behaviour.</p>
- <p>
- Own Id: OTP-7631</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.6.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Minor updates.</p>
- <p>
- Own Id: OTP-7522</p>
- </item>
- </list>
- </section>
-
-</section>
-
-
-<section><title>Hipe 3.6.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Minor changes.</p>
- <p>
- Own Id: OTP-7388</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.6.6</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>A fix for an #include problem which caused the FP
- exception test to fail unnecessarily on
- debian/glibc-2.7/x86 systems.</p>
- <p>Added SIGFPE loop detection to the FP exception test.
- This prevents the test from looping indefinitely, which
- could happen when the CPU is supported (so we can enable
- FP exceptions on it) but the OS isn't (so we can't write
- a proper SIGFPE handler). x86 on an unsupported OS is
- known to have had this problem.</p>
- <p>
- Own Id: OTP-7254</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- HiPE now also supports little-endian ARM processors.</p>
- <p>
- Own Id: OTP-7255</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Hipe 3.6.5</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- HIPE: Corrected the choice of interface to the send/3 and
- setnode/3 BIFs for native-compiled code. Using the
- incorrect interface could, in unusual circumstances, lead
- to random runtime errors.</p>
- <p>
- Own Id: OTP-7067</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The HiPE compiler's SPARC backend has been rewritten,
- improving its correctness and long-term maintainability.</p>
- <p>
- Own Id: OTP-7133</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section>
- <title>Hipe 3.6.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own Id: OTP-6689</p>
- </item>
- <item>
- <p>Miscellanous updates.</p>
- <p>Own Id: OTP-6738</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Hipe 3.6.2</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Miscellanous improvements.</p>
- <p>Own Id: OTP-6577</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Hipe 3.6.1.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Dialyzer could fail to analyze certain beam files that
- used try/catch.</p>
- <p>Own Id: OTP-6449 Aux Id: seq10563 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Hipe 3.6.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>HiPE runtime system:</p>
- <p>* added notes about supported systems to README</p>
- <p>* support 32-bit x86 on FreeBSD</p>
- <p>* autoenable HiPE on FreeBSD (32-bit x86) and Solaris
- (64-bit x86)</p>
- <p>* updated x86 runtime system to support glibc-2.5</p>
- <p>* work around probable gcc-4.1.1 bug affecting the x86
- runtime system</p>
- <p>HiPE compiler:</p>
- <p>* improved performance of integer multiplications on
- all platforms</p>
- <p>* corrected a code optimisation error in R11B-2 that
- broke some bsl/bsr operations on all platforms</p>
- <p>* corrected a type error in the ARM backend which
- could cause the compiler to crash</p>
- <p>* corrected an error in the SPARC backend's naive
- register allocator which could throw the compiler into an
- infinite loop</p>
- <p>Own Id: OTP-6423</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Hipe 3.6.0</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Support for native code on Solaris 10/AMD64.</p>
- <p>Support for native code on FreeBSD/AMD64.</p>
- <p>Native code now handles external funs (<c><![CDATA[fun M:F/A]]></c>). Native code can now also apply so-called
- tuple-funs (<c><![CDATA[{M,F}]]></c>). (Tuple funs are NOT
- recommended for new code; they are deprecated and will be
- removed in some future release.)</p>
- <p>Own Id: OTP-6305</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>Hipe 3.5.6</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Improved compilation of receives for the SMP runtime
- system.</p>
- <p>Improved code quality in HiPE compiler on ARM.</p>
- <p>Fix bug in handling of re-raised exceptions in
- try-catch.</p>
- <p>(HiPE loader) When native code is incompatible with
- the current runtime system, fall back to loading the BEAM
- code.</p>
- <p>Own Id: OTP-6127</p>
- </item>
- </list>
- </section>
- </section>
-</chapter>
-
diff --git a/lib/hipe/doc/src/ref_man.xml b/lib/hipe/doc/src/ref_man.xml
deleted file mode 100644
index 05af6b0c4f..0000000000
--- a/lib/hipe/doc/src/ref_man.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>1996</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>HiPE</title>
- <prepared></prepared>
- <docno></docno>
- <date>1997-06-04</date>
- <rev>1.3.1</rev>
- <file>ref_man.xml</file>
- </header>
- <description>
- </description>
- <xi:include href="HiPE_app.xml"/>
-</application>
-
diff --git a/lib/hipe/ebin/.gitignore b/lib/hipe/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/hipe/ebin/.gitignore
+++ /dev/null
diff --git a/lib/hipe/flow/Makefile b/lib/hipe/flow/Makefile
deleted file mode 100644
index d883eecf36..0000000000
--- a/lib/hipe/flow/Makefile
+++ /dev/null
@@ -1,113 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = hipe_bb hipe_dominators hipe_gen_cfg
-
-
-HRL_FILES=
-INC_FILES= cfg.inc ebb.inc liveness.inc
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars +warn_missing_spec +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/flow"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(INC_FILES) "$(RELSYSDIR)/flow"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-$(EBIN)/hipe_bb.beam: hipe_bb.hrl
-$(EBIN)/hipe_dominators.beam: cfg.hrl
-$(EBIN)/hipe_gen_cfg.beam: cfg.hrl cfg.inc ../main/hipe.hrl
diff --git a/lib/hipe/flow/cfg.hrl b/lib/hipe/flow/cfg.hrl
deleted file mode 100644
index 8d0f8855bb..0000000000
--- a/lib/hipe/flow/cfg.hrl
+++ /dev/null
@@ -1,48 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%============================================================================
-%% File : cfg.hrl
-%% Author : Kostis Sagonas <kostis@it.uu.se>
-%% Purpose : Contains typed record declarations for the CFG data structures
-%%============================================================================
-
--type cfg_lbl() :: non_neg_integer().
-
-%%
-%% This is supposed to be local but appears here for the time being
-%% just so that it is used below
-%%
--record(cfg_info, {'fun' :: mfa(),
- start_label :: cfg_lbl(),
- %% TODO: merge is_closure and closure_arity into one field
- is_closure :: boolean(),
- closure_arity = none :: 'none' | arity(),
- is_leaf :: boolean(),
- params :: list(), %% XXX: refine
- info = [] :: list()}). %% seems not needed; take out??
--type cfg_info() :: #cfg_info{}.
-
-%%
-%% Data is a triple with a dict of constants, a list of labels and an integer
-%%
--type cfg_data() :: {dict:dict(), [cfg_lbl()], non_neg_integer()}.
-
-%%
-%% The following is to be used by other modules
-%%
--record(cfg, {table = gb_trees:empty() :: gb_trees:tree(),
- info :: cfg_info(),
- data :: cfg_data()}).
--type cfg() :: #cfg{}.
diff --git a/lib/hipe/flow/cfg.inc b/lib/hipe/flow/cfg.inc
deleted file mode 100644
index 17342d3b60..0000000000
--- a/lib/hipe/flow/cfg.inc
+++ /dev/null
@@ -1,1013 +0,0 @@
-%% -*- Erlang -*-
-%% -*- erlang-indent-level: 2 -*-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% CONTROL FLOW GRAPHS
-%%
-%% Construct and manipulate the control flow graph of a function (program?).
-%%
-%% Exports:
-%% ~~~~~~~~
-%% init(Code) - makes a CFG out of code.
-%% bb(CFG, Label) - returns the basic block named 'Label' from the CFG.
-%% bb_add(CFG, Label, NewBB) - makes NewBB the basic block associated
-%% with Label.
-%% map_bbs(Fun, CFG) - map over all code without changing control flow.
-%% fold_bbs(Fun, Acc, CFG) - fold over the basic blocks in a CFG.
-%% succ(Map, Label) - returns a list of successors of basic block 'Label'.
-%% pred(Map, Label) - returns the predecessors of basic block 'Label'.
-%% fallthrough(CFG, Label) - returns fall-through successor of basic
-%% block 'Label' (or 'none').
-%% conditional(CFG, Label) - returns conditional successor (or 'none')
-%% start_label(CFG) - returns the label of the entry basic block.
-%% params(CFG) - returns the list of parameters to the CFG.
-%% labels(CFG) - returns a list of labels of all basic blocks in the CFG.
-%% postorder(CFG) - returns a list of labels in postorder.
-%% reverse_postorder(CFG) - returns a list of labels in reverse postorder.
-%% cfg_to_linear(CFG) - converts CFG to linearized code.
-%% remove_trivial_bbs(CFG) - removes empty BBs or BBs with only a goto.
-%% remove_unreachable_code(CFG) - removes unreachable BBs.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% TODO:
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=====================================================================
-%% The following are ugly as hell, but what else can I do???
-%%=====================================================================
-
--ifdef(GEN_CFG).
--define(PRED_NEEDED,true).
--endif.
-
--ifdef(ICODE_CFG).
--define(CLOSURE_ARITY_NEEDED,true).
--define(INFO_NEEDED,true).
--define(PARAMS_NEEDED,true).
--define(PARAMS_UPDATE_NEEDED,true).
--define(PRED_NEEDED,true).
--define(REMOVE_TRIVIAL_BBS_NEEDED,true).
--define(REMOVE_UNREACHABLE_CODE,true).
--define(START_LABEL_UPDATE_NEEDED,true).
--define(CFG_CAN_HAVE_PHI_NODES,true).
--endif.
-
--ifdef(RTL_CFG).
--define(PREORDER,true).
--define(FIND_NEW_LABEL_NEEDED,true).
--define(INFO_NEEDED,true).
--define(PARAMS_NEEDED,true).
--define(PARAMS_UPDATE_NEEDED,true).
--define(PRED_NEEDED,true).
--define(REMOVE_TRIVIAL_BBS_NEEDED,true).
--define(REMOVE_UNREACHABLE_CODE,true).
--define(START_LABEL_UPDATE_NEEDED,true).
--define(CFG_CAN_HAVE_PHI_NODES,true).
--endif.
-
--ifdef(SPARC_CFG).
--define(BREADTH_ORDER,true). % for linear scan
--define(PARAMS_NEEDED,true).
--define(START_LABEL_UPDATE_NEEDED,true).
--define(MAP_FOLD_NEEDED,true).
--endif.
-
-%%=====================================================================
-
--ifdef(START_LABEL_UPDATE_NEEDED).
--export([start_label_update/2]).
--endif.
-
--ifdef(BREADTH_ORDER).
--export([breadthorder/1]).
--endif.
-
--compile(inline).
-
-%%=====================================================================
-%%
-%% Interface functions that MUST be implemented in the including file:
-%%
-%% linear_to_cfg(LinearCode) -> CFG, constructs the cfg.
-%% is_label(Instr) -> boolean(), true if instruction is a label.
-%% label_name(Instr) -> term(), the name of a label.
-%% branch_successors(Instr) -> [term()], the successors of a branch.
-%% fails_to(Instr) -> [term()], the fail-successors of an instruction.
-%% is_branch(Instr) -> boolean(), true if instruction is a branch.
-%% is_comment(Instr) -> boolean(),
-%% true if instruction is a comment, used by remove dead code.
-%% is_goto(Instr) -> boolean(),
-%% true if instruction is a pure goto, used by remove dead code.
-%% redirect_jmp(Jmp, ToOld, ToNew) -> NewJmp,
-%% redirect_ops(Labels, CFG, Map) -> CFG.
-%% Rewrite instructions with labels in operands to use
-%% the new label as given by map.
-%% Use find_new_label(OldLab,Map) to get the new label.
-%% (See hipe_sparc_cfg for example)
-%% pp(CFG) -> ok, do some nifty output.
-%% cfg_to_linear(CFG) -> LinearCode, linearizes the code of CFG
-%% mk_goto(Label) -> instruction
-%% is_phi(Instr) -> boolean(), true if the instruction is a phi-instruction.
-%% phi_remove_pred(PhiInstr, Pred) -> NewPhi,
-%% Removes the predecessor Pred from the phi instruction.
-%% highest_var(Code) -> term(),
-%% Returns the highest variable used or defined in the code.
-%%
-%%=====================================================================
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Primitives (not all of these are exported)
-%%
-
--spec start_label(cfg()) -> cfg_lbl().
-start_label(CFG) -> (CFG#cfg.info)#cfg_info.start_label.
-
--ifndef(GEN_CFG).
--spec start_label_update(cfg(), cfg_lbl()) -> cfg().
-start_label_update(CFG, NewStartLabel) ->
- Info = CFG#cfg.info,
- CFG#cfg{info = Info#cfg_info{start_label = NewStartLabel}}.
-
--spec function(cfg()) -> mfa().
-function(CFG) -> (CFG#cfg.info)#cfg_info.'fun'.
-
--spec is_closure(cfg()) -> boolean().
-is_closure(CFG) -> (CFG#cfg.info)#cfg_info.is_closure.
-
--spec is_leaf(cfg()) -> boolean().
-is_leaf(CFG) -> (CFG#cfg.info)#cfg_info.is_leaf.
-
-mk_empty_cfg(Fun, StartLbl, Data, Closure, Leaf, Params) ->
- Info = #cfg_info{'fun' = Fun,
- start_label = StartLbl,
- is_closure = Closure,
- is_leaf = Leaf,
- params = Params},
- #cfg{table = gb_trees:empty(), data = Data, info = Info}.
-
-data(CFG) -> CFG#cfg.data.
--endif. % GEN_CFG
-
--ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
--spec update_data(cfg(), cfg_data()) -> cfg().
-update_data(CFG, D) ->
- CFG#cfg{data = D}.
--endif.
-
--ifdef(PARAMS_NEEDED).
-params(CFG) -> (CFG#cfg.info)#cfg_info.params.
--endif.
-
--ifdef(PARAMS_UPDATE_NEEDED).
-params_update(CFG, NewParams) ->
- Info = CFG#cfg.info,
- CFG#cfg{info = Info#cfg_info{params = NewParams}}.
--endif.
-
--ifdef(CLOSURE_ARITY_NEEDED).
--spec closure_arity(cfg()) -> arity().
-closure_arity(CFG) ->
- Info = CFG#cfg.info,
- Info#cfg_info.closure_arity.
-
--spec closure_arity_update(cfg(), arity()) -> cfg().
-closure_arity_update(CFG, Arity) ->
- Info = CFG#cfg.info,
- CFG#cfg{info = Info#cfg_info{closure_arity = Arity}}.
--endif.
-
-%% %% Don't forget to do a start_label_update if necessary.
-%% update_code(CFG, NewCode) ->
-%% take_bbs(NewCode, CFG).
-
--ifdef(INFO_NEEDED).
-info(CFG) -> (CFG#cfg.info)#cfg_info.info.
-%% info_add(CFG, A) ->
-%% As = info(CFG),
-%% Info = CFG#cfg.info,
-%% CFG#cfg{info = Info#cfg_info{info = [A|As]}}.
-info_update(CFG, I) ->
- Info = CFG#cfg.info,
- CFG#cfg{info = Info#cfg_info{info = I}}.
--endif.
-
-%%=====================================================================
--ifndef(GEN_CFG).
-
--spec other_entrypoints(cfg()) -> [cfg_lbl()].
-%% @doc Returns a list of labels that are referred to from the data section.
-
-other_entrypoints(CFG) ->
- hipe_consttab:referred_labels(data(CFG)).
-
-%% is_entry(Lbl, CFG) ->
-%% Lbl =:= start_label(CFG) orelse
-%% lists:member(Lbl, other_entrypoints(CFG)).
-
-%% @spec bb(CFG::cfg(), Label::cfg_lbl()) -> basic_block()
-%% @doc Returns the basic block of the CFG which begins at the Label.
-bb(CFG, Label) ->
- HT = CFG#cfg.table,
- case gb_trees:lookup(Label, HT) of
- {value, {Block,_Succ,_Pred}} ->
- Block;
- none ->
- not_found
- end.
-
-%% Remove duplicates from a list. The first instance (in left-to-right
-%% order) of an element is kept, remaining instances are removed.
--spec remove_duplicates([cfg_lbl()]) -> [cfg_lbl()].
-remove_duplicates(List) ->
- remove_duplicates(List, []).
-
--spec remove_duplicates([cfg_lbl()], [cfg_lbl()]) -> [cfg_lbl()].
-remove_duplicates([H|T], Acc) ->
- NewAcc =
- case lists:member(H, Acc) of
- false -> [H|Acc];
- true -> Acc
- end,
- remove_duplicates(T, NewAcc);
-remove_duplicates([], Acc) ->
- lists:reverse(Acc).
-
-
--ifdef(RTL_CFG). %% this could be CFG_CAN_HAVE_PHI_NODES
- %% if Icode also starts using this function
-
-%% @spec bb_insert_between(CFG::cfg(),
-%% Label::cfg_lbl(), NewBB::basic_block(),
-%% Pred::cfg_lbl(), Succ::cfg_lbl()) -> cfg()
-%%
-%% @doc Insert the new basic block with label Label in the edge from
-%% Pred to Succ
-
-bb_insert_between(CFG, Label, NewBB, Pred, Succ) ->
- Last = hipe_bb:last(NewBB),
- %% Asserts that NewBB ends in a label
- true = is_branch(Last),
- %% Asserts that the only Successor of NewBB is Succ
- [Succ] = remove_duplicates(branch_successors(Last)),
- HT = CFG#cfg.table,
- %% Asserts that Label does not exist in the CFG
- none = gb_trees:lookup(Label, HT),
- %% Updates the predecessor of NewBB
- {value, {PBB, PSucc, PPred}} = gb_trees:lookup(Pred, HT),
- NewPSucc = [Label|lists:delete(Succ, PSucc)],
- PLast = hipe_bb:last(PBB),
- PButLast = hipe_bb:butlast(PBB),
- NewPBB = hipe_bb:code_update(PBB, PButLast++[redirect_jmp(PLast, Succ, Label)]),
- HT1 = gb_trees:update(Pred, {NewPBB,NewPSucc,PPred}, HT),
- %% Updates the successor of NewBB
- {value, {SBB, SSucc, SPred}} = gb_trees:lookup(Succ, HT1),
- NewSPred = [Label|lists:delete(Pred, SPred)],
- SCode = hipe_bb:code(SBB),
- NewSCode = redirect_phis(SCode, Pred, Label, []),
- NewSBB = hipe_bb:code_update(SBB, NewSCode),
- HT2 = gb_trees:update(Succ, {NewSBB,SSucc,NewSPred}, HT1),
- %% Enters NewBB into the CFG
- HT3 = gb_trees:insert(Label, {NewBB,[Succ],[Pred]}, HT2),
- CFG#cfg{table = HT3}.
-
-redirect_phis([], _OldPred, _NewPred, Acc) ->
- lists:reverse(Acc);
-redirect_phis([I|Rest], OldPred, NewPred, Acc) ->
- case is_phi(I) of
- true ->
- Phi = phi_redirect_pred(I, OldPred, NewPred),
- redirect_phis(Rest, OldPred, NewPred, [Phi|Acc]);
- false ->
- redirect_phis(Rest, OldPred, NewPred, [I|Acc])
- end.
-
--endif.
-
-%% @spec bb_add(CFG::cfg(), Label::cfg_lbl(), NewBB::basic_block()) -> cfg()
-%% @doc Adds a new basic block to a CFG (or updates an existing block).
-bb_add(CFG, Label, NewBB) ->
- %% Asserting that the NewBB is a legal basic block
- Last = assert_bb(NewBB),
- %% The order of the elements from branch_successors/1 is
- %% significant. It determines the basic block order when the CFG is
- %% converted to linear form. That order may have been tuned for
- %% branch prediction purposes.
- Succ = remove_duplicates(branch_successors(Last)),
- HT = CFG#cfg.table,
- {OldSucc, OldPred} = case gb_trees:lookup(Label, HT) of
- {value, {_Block, OSucc, OPred}} ->
- {OSucc, OPred};
- none ->
- {[], []}
- end,
- %% Change this block to contain new BB and new successors, but keep
- %% the old predecessors which will be updated in the following steps
- HT1 = gb_trees:enter(Label, {NewBB, Succ, OldPred}, HT),
- %% Add this block as predecessor to its new successors
- HT2 = lists:foldl(fun (P, HTAcc) ->
- add_pred(HTAcc, P, Label)
- end,
- HT1, Succ -- OldSucc),
- %% Remove this block as predecessor of its former successors
- HT3 = lists:foldl(fun (S, HTAcc) ->
- remove_pred(HTAcc, S, Label)
- end,
- HT2, OldSucc -- Succ),
- CFG#cfg{table = HT3}.
-
--ifdef(MAP_FOLD_NEEDED).
--spec map_bbs(fun((cfg_lbl(), hipe_bb:bb()) -> hipe_bb:bb()), cfg()) -> cfg().
-%% @doc Map over the code in a CFG without changing any control flow.
-map_bbs(Fun, CFG = #cfg{table=HT0}) ->
- HT = gb_trees:map(
- fun(Lbl, {OldBB, OldSucc, OldPred}) ->
- NewBB = Fun(Lbl, OldBB),
- %% Assert preconditions
- NewLast = assert_bb(NewBB),
- OldSucc = remove_duplicates(branch_successors(NewLast)),
- {NewBB, OldSucc, OldPred}
- end, HT0),
- CFG#cfg{table=HT}.
-
--spec fold_bbs(fun((cfg_lbl(), hipe_bb:bb(), Acc) -> Acc), Acc, cfg()) -> Acc.
-%% @doc Fold over the basic blocks in a CFG in unspecified order.
-fold_bbs(Fun, InitAcc, #cfg{table=HT}) ->
- gb_trees_fold(fun(Lbl, {BB, _, _}, Acc) -> Fun(Lbl, BB, Acc) end,
- InitAcc, HT).
-
-gb_trees_fold(Fun, InitAcc, Tree) ->
- gb_trees_fold_1(Fun, InitAcc, gb_trees:iterator(Tree)).
-
-gb_trees_fold_1(Fun, InitAcc, Iter0) ->
- case gb_trees:next(Iter0) of
- none -> InitAcc;
- {Key, Value, Iter} ->
- gb_trees_fold_1(Fun, Fun(Key, Value, InitAcc), Iter)
- end.
--endif. % MAP_FOLD_NEEDED
-
-assert_bb(BB) ->
- assert_bb_is(hipe_bb:code(BB)).
-
-assert_bb_is([Last]) ->
- true = is_branch(Last),
- Last;
-assert_bb_is([I|Is]) ->
- false = is_branch(I),
- false = is_label(I),
- assert_bb_is(Is).
-
-remove_pred(HT, FromL, PredL) ->
- case gb_trees:lookup(FromL, HT) of
- {value, {Block, Succ, Preds}} ->
- Code = hipe_bb:code(Block),
- NewCode = remove_pred_from_phis(PredL, Code),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- gb_trees:update(FromL, {NewBlock,Succ,lists:delete(PredL,Preds)}, HT);
- none ->
- HT
- end.
-
-add_pred(HT, ToL, PredL) ->
- case gb_trees:lookup(ToL, HT) of
- {value,{Block,Succ,Preds}} ->
- gb_trees:update(ToL, {Block,Succ,[PredL|lists:delete(PredL,Preds)]}, HT);
- none ->
- gb_trees:insert(ToL, {[],[],[PredL]}, HT)
- end.
-
-%% find_highest_label(CFG) ->
-%% Labels = labels(CFG),
-%% lists:foldl(fun(X, Acc) -> erlang:max(X, Acc) end, 0, Labels).
-%%
-%% find_highest_var(CFG) ->
-%% Labels = labels(CFG),
-%% Fun = fun(X, Max) ->
-%% Code = hipe_bb:code(bb(CFG, X)),
-%% NewMax = highest_var(Code),
-%% erlang:max(Max, NewMax)
-%% end,
-%% lists:foldl(Fun, 0, Labels).
-
--ifdef(CFG_CAN_HAVE_PHI_NODES).
-%% phi-instructions in a removed block's successors must be aware of
-%% the change.
-remove_pred_from_phis(Label, List = [I|Left]) ->
- case is_phi(I) of
- true ->
- NewI = phi_remove_pred(I, Label),
- [NewI | remove_pred_from_phis(Label, Left)];
- false ->
- List
- end;
-remove_pred_from_phis(_Label, []) ->
- [].
--else.
-%% this is used for code representations like those of back-ends which
-%% do not have phi-nodes.
-remove_pred_from_phis(_Label, Code) ->
- Code.
--endif.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Constructs a CFG from a list of instructions.
-%%
-
-take_bbs([], CFG) ->
- CFG;
-take_bbs(Xs, CFG) ->
- Lbl = hd(Xs),
- case is_label(Lbl) of
- true ->
- case take_bb(tl(Xs), []) of
- {Code, Rest} ->
- NewCFG = bb_add(CFG, label_name(Lbl), hipe_bb:mk_bb(Code)),
- take_bbs(Rest, NewCFG)
- end;
- false ->
- erlang:error({?MODULE,"basic block doesn't start with a label",Xs})
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Take_bb returns:
-%% - {Code, Rest}.
-%% * Code is a list of all the instructions.
-%% * Rest is the remainder of the instructions
-
-take_bb([], Code) ->
- {lists:reverse(Code), []};
-take_bb([X, Y|Xs], Code) ->
- case is_label(X) of
- true -> %% Empty block fallthrough
- {[mk_goto(label_name(X))], [X,Y|Xs]};
- false ->
- case is_branch(X) of
- true ->
- case is_label(Y) of
- true ->
- {lists:reverse([X|Code]), [Y|Xs]};
- false ->
- %% This should not happen...
- %% move the problem to the next BB.
- {lists:reverse([X|Code]), [Y|Xs]}
- end;
- false -> %% X not branch
- case is_label(Y) of
- true ->
- {lists:reverse([mk_goto(label_name(Y)),X|Code]), [Y|Xs]};
- false ->
- take_bb([Y|Xs], [X|Code])
- end
- end
- end;
-take_bb([X], []) ->
- case is_label(X) of
- true ->
- %% We don't want the CFG to just end with a label...
- %% We loop forever instead...
- {[X,mk_goto(label_name(X))],[]};
- false ->
- {[X],[]}
- end;
-take_bb([X], Code) ->
- case is_label(X) of
- true ->
- %% We don't want the CFG to just end with a label...
- %% We loop for ever instead...
- {lists:reverse(Code),[X,mk_goto(label_name(X))]};
- false ->
- {lists:reverse([X|Code]),[]}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Functions for extracting the names of the basic blocks in various
-%% orders.
-%%
-
-labels(CFG) ->
- HT = CFG#cfg.table,
- gb_trees:keys(HT).
-
-postorder(CFG) ->
- lists:reverse(reverse_postorder(CFG)).
-
-reverse_postorder(CFG) ->
- Start = start_label(CFG),
- {Ordering, _Visited} =
- depth_search([Start|other_entrypoints(CFG)], none_visited(), CFG, []),
- Ordering.
-
-depth_search([N|Ns], Visited, CFG, Acc) ->
- case is_visited(N, Visited) of
- true ->
- depth_search(Ns, Visited, CFG, Acc);
- false ->
- {Order, Vis} = depth_search(succ(CFG, N), visit(N, Visited), CFG, Acc),
- depth_search(Ns, Vis, CFG, [N|Order])
- end;
-depth_search([], Visited, _, Ordering) ->
- {Ordering, Visited}.
-
--ifdef(PREORDER).
-preorder(CFG) ->
- Start = start_label(CFG),
- {Ordering, _Visited} =
- preorder_search([Start|other_entrypoints(CFG)], none_visited(), CFG, []),
- lists:reverse(Ordering).
-
-preorder_search([N|Ns], Visited, CFG, Acc) ->
- case is_visited(N, Visited) of
- true ->
- preorder_search(Ns, Visited, CFG, Acc);
- false ->
- {Order, Vis} =
- preorder_search(succ(CFG, N), visit(N, Visited), CFG, [N|Acc]),
- preorder_search(Ns, Vis, CFG, Order)
- end;
-preorder_search([], Visited, _, Ordering) ->
- {Ordering,Visited}.
--endif. % PREORDER
-
--ifdef(BREADTH_ORDER).
-breadthorder(CFG) ->
- lists:reverse(reverse_breadthorder(CFG)).
-
-reverse_breadthorder(CFG) ->
- Start = start_label(CFG),
- {Vis, RBO1} = breadth_list([Start], none_visited(), CFG, []),
- {_Vis1, RBO2} = breadth_list(other_entrypoints(CFG), Vis, CFG, RBO1),
- RBO2.
-
-breadth_list([X|Xs], Vis, CFG, BO) ->
- case is_visited(X, Vis) of
- true ->
- breadth_list(Xs, Vis, CFG, BO);
- false ->
- breadth_list(Xs ++ succ(CFG, X), visit(X, Vis), CFG, [X|BO])
- end;
-breadth_list([], Vis, _CFG, BO) ->
- {Vis, BO}.
--endif.
-
--spec none_visited() -> gb_sets:set().
-none_visited() ->
- gb_sets:empty().
-
-visit(X, Vis) ->
- gb_sets:add(X, Vis).
-
-is_visited(X, Vis) ->
- gb_sets:is_member(X, Vis).
-
--endif. % GEN_CFG
-
-%%---------------------------------------------------------------------
-
-succ(SuccMap, Label) ->
- HT = SuccMap#cfg.table,
- case gb_trees:lookup(Label, HT) of
- {value, {_Block,Succ,_Pred}} ->
- Succ;
- none ->
- erlang:error({"successor not found", Label, SuccMap})
- end.
-
--ifdef(PRED_NEEDED).
-pred(Map, Label) ->
- HT = Map#cfg.table,
- case gb_trees:lookup(Label, HT) of
- {value, {_Block,_Succ,Pred}} ->
- Pred;
- none ->
- erlang:error({"predecessor not found", Label, Map})
- end.
--endif. % PRED_NEEDED
-
--ifndef(GEN_CFG).
-fallthrough(CFG, Label) ->
- HT = CFG#cfg.table,
- case gb_trees:lookup(Label, HT) of
- {value, {_Block, Succ, _}} ->
- case Succ of
- [X|_] -> X;
- _ -> none
- end;
- none ->
- erlang:error({"fallthrough label not found", Label})
- end.
-
-conditional(CFG, Label) ->
- HT = CFG#cfg.table,
- {value,{_Block,Succ,_}} = gb_trees:lookup(Label, HT),
- case Succ of
- [] -> none;
- [_] -> none;
- [_|Labels] -> Labels
- end.
--endif. % GEN_CFG
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Linearize the code in a CFG. Returns a list of instructions.
-%%
-
--ifdef(GEN_CFG).
--else.
-linearize_cfg(CFG) ->
- Start = start_label(CFG),
- Vis = none_visited(),
- {Vis0, NestedCode} = lin_succ(Start, CFG, Vis),
- BlocksInData = hipe_consttab:referred_labels(data(CFG)),
- AllCode = lin_other_entries(NestedCode, CFG, BlocksInData, Vis0),
- lists:flatten(AllCode).
-
-lin_succ(none, _CFG, Vis) ->
- {Vis, []};
-lin_succ([Label|Labels], CFG, Vis) ->
- {Vis1, Code1} = lin_succ(Label, CFG, Vis),
- {Vis2, Code2} = lin_succ(Labels, CFG, Vis1),
- {Vis2, [Code1,Code2]};
-lin_succ([], _CFG, Vis) ->
- {Vis, []};
-lin_succ(Label, CFG, Vis) ->
- case is_visited(Label, Vis) of
- true ->
- {Vis, []}; % already visited
- false ->
- Vis0 = visit(Label, Vis),
- case bb(CFG, Label) of
- not_found ->
- erlang:error({?MODULE, "No basic block with label", Label});
- BB ->
- Fallthrough = fallthrough(CFG, Label),
- Cond = conditional(CFG, Label),
- LblInstr = mk_label(Label),
- {Vis1, Code1} = lin_succ(Fallthrough, CFG, Vis0),
- {Vis2, Code2} = lin_succ(Cond, CFG, Vis1),
- {Vis2, [[LblInstr|hipe_bb:code(BB)], Code1, Code2]}
- end
- end.
-
-lin_other_entries(Code, _CFG, [], _Vis) ->
- Code;
-lin_other_entries(Code, CFG, [E|Es], Vis) ->
- {Vis0, MoreCode} = lin_succ(E, CFG, Vis),
- lin_other_entries([Code, MoreCode], CFG, Es, Vis0).
--endif.
-
--ifdef(FIND_NEW_LABEL_NEEDED).
-find_new_label(Old, Map) ->
- forward(Old, Map).
--endif.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Remove empty BBs.
-%%
-%% Removes basic blocks containing only a goto to another BB.
-%% Branches to removed blocks are updated to the successor of the
-%% removed block.
-%% Loads (or other operations) on the label of the BB are also
-%% updated. So are any references from the data section.
-%%
-
--ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
-
--spec remove_trivial_bbs(cfg()) -> cfg().
-remove_trivial_bbs(CFG) ->
- ?opt_start_timer("Merge BBs"),
- CFG0 = merge_bbs(rewrite_trivial_branches(CFG)),
- ?opt_stop_timer("Merge BBs"),
- %% pp(CFG0),
- ?opt_start_timer("FindDead"),
- {NewMap, CFG1} = remap(labels(CFG0), rd_map_new(), CFG0),
- ?opt_stop_timer("FindDead"),
- ?opt_start_timer("Labels"),
- Labels = labels(CFG1),
- ?opt_stop_timer("Labels"),
- ?opt_start_timer("RedirectBranches"),
- CFG2 = redirect_branches(NewMap, CFG1),
- ?opt_stop_timer("RedirectBranches"),
- ?opt_start_timer("RedirectOps"),
- CFG3 = redirect_ops(Labels, CFG2, NewMap),
- ?opt_stop_timer("RedirectOps"),
- ?opt_start_timer("RedirectData"),
- CFG4 = redirect_data(CFG3, NewMap),
- ?opt_stop_timer("RedirectData"),
- ?opt_start_timer("RedirectStart"),
- CFG5 = redirect_start(CFG4, NewMap),
- ?opt_stop_timer("RedirectStart"),
- %% pp(CFG5),
- CFG5.
-
-redirect_start(CFG, Map) ->
- Start = start_label(CFG),
- case forward(Start, Map) of
- Start -> CFG;
- NewStart ->
- start_label_update(CFG, NewStart)
- end.
-
-redirect_data(CFG, Map) ->
- Data = data(CFG),
- NewData = hipe_consttab:update_referred_labels(Data, rd_succs(Map)),
- update_data(CFG, NewData).
-
-redirect_branches(Map, CFG) ->
- lists:foldl(fun ({From,{newsuccs,Redirects}}, CFGAcc) ->
- lists:foldl(
- fun({ToOld,ToNew}, CFG1) ->
- case bb(CFG1, From) of
- not_found ->
- CFG1;
- _ ->
- To = forward(ToNew, Map),
- redirect(CFG1, From, ToOld, To)
- end
- end,
- CFGAcc,
- Redirects);
- (_, CFGAcc) -> CFGAcc
- end,
- CFG,
- gb_trees:to_list(Map)).
-
-redirect(CFG, From, ToOld, ToNew) ->
- BB = bb(CFG, From),
- LastInstr = hipe_bb:last(BB),
- NewLastInstr = redirect_jmp(LastInstr, ToOld, ToNew),
- NewBB = hipe_bb:mk_bb(hipe_bb:butlast(BB) ++ [NewLastInstr]),
- bb_add(CFG, From, NewBB).
-
-bb_remove(CFG, Label) ->
- HT = CFG#cfg.table,
- case gb_trees:lookup(Label, HT) of
- {value, {_Block, Succ, _Preds}} ->
- %% Remove this block as a pred from all successors.
- HT1 = lists:foldl(fun (S,HTAcc) ->
- remove_pred(HTAcc, S, Label)
- end,
- HT, Succ),
- CFG#cfg{table = gb_trees:delete(Label, HT1)};
- none ->
- CFG
- end.
-
-remap([L|Rest], Map, CFG) ->
- case is_empty(bb(CFG, L)) of
- true ->
- case succ(CFG, L) of
- [L] -> %% This is an empty (infinite) self loop. Leave it.
- remap(Rest, Map, CFG);
- [SuccL] ->
- CFG1 = bb_remove(CFG, L),
- NewMap = remap_to_succ(L, SuccL, Map, CFG),
- remap(Rest, NewMap, CFG1)
- end;
- false ->
- remap(Rest, Map, CFG)
- end;
-remap([], Map, CFG) ->
- {Map, CFG}.
-
-remap_to_succ(L, SuccL, Map, PredMap) ->
- insert_remap(L, forward(SuccL,Map), pred(PredMap,L), Map).
-
-%% Find the proxy for a BB
-forward(L, Map) ->
- case gb_trees:lookup(L, Map) of
- {value, {dead, To}} ->
- forward(To, Map); %% Hope this terminates.
- _ -> L
- end.
-
-%% A redirection map contains mappings from labels to
-%% none -> this BB is not affected by the remapping.
-%% {dead,To} -> this BB is dead, To is the new proxy.
-%% {newsuccs,[{X,Y}|...]} -> The successor X is redirected to Y.
-
-rd_map_new() -> gb_trees:empty().
-
-rd_succs(M) ->
- lists:foldl(fun ({From,{dead,To}}, Acc) -> [{From,forward(To,M)}|Acc];
- (_, Acc) -> Acc
- end,
- [],
- gb_trees:to_list(M)).
-
-add_redirectedto(L, From, To, Map) ->
- case gb_trees:lookup(L, Map) of
- {value, {newsuccs, NS}} ->
- gb_trees:update(L,{newsuccs,[{From,To}|lists:keydelete(From,1,NS)]},Map);
- {value, {dead, _}} -> Map;
- none ->
- gb_trees:insert(L, {newsuccs, [{From, To}]}, Map)
- end.
-
-insert_remap(L, ToL, Preds, Map) ->
- Map2 = gb_trees:enter(L, {dead, ToL}, Map),
- lists:foldl(fun (Pred, AccMap) ->
- add_redirectedto(Pred, L, ToL, AccMap)
- end,
- Map2,
- Preds).
-
-is_empty(BB) ->
- is_empty_bb(hipe_bb:code(BB)).
-
-is_empty_bb([I]) ->
- is_goto(I); %% A BB with just a 'goto' is empty.
-is_empty_bb([I|Is]) ->
- case is_comment(I) of
- true ->
- is_empty_bb(Is);
- false ->
- false
- end;
-is_empty_bb([]) ->
- true.
-
-
-%% Rewrite all pure branches with one successor to goto:s
-
--spec rewrite_trivial_branches(cfg()) -> cfg().
-rewrite_trivial_branches(CFG) ->
- rewrite_trivial_branches(postorder(CFG), CFG).
-
-rewrite_trivial_branches([L|Left], CFG) ->
- BB = bb(CFG, L),
- Last = hipe_bb:last(BB),
- case is_goto(Last) of
- true ->
- rewrite_trivial_branches(Left, CFG);
- false ->
- case is_pure_branch(Last) of
- false ->
- rewrite_trivial_branches(Left, CFG);
- true ->
- case succ(CFG, L) of
- [Successor] ->
- Head = hipe_bb:butlast(BB),
- NewBB = hipe_bb:mk_bb(Head ++ [mk_goto(Successor)]),
- NewCFG = bb_add(CFG, L, NewBB),
- rewrite_trivial_branches(Left, NewCFG);
- _ ->
- rewrite_trivial_branches(Left, CFG)
- end
- end
- end;
-rewrite_trivial_branches([], CFG) ->
- CFG.
-
-
-%% Go through the CFG and find pairs of BBs that can be merged to one BB.
-%% They are of the form:
-%%
-%% L
-%% |
-%% Successor
-%%
-%% That is, the block L has only one successor (Successor) and that
-%% successor has no other predecessors than L.
-%%
-%% Note: calls might end a basic block
-
-merge_bbs(CFG) ->
- lists:foldl(fun merge_successor/2, CFG, postorder(CFG)).
-
-%% If L fulfills the requirements, merge it with its successor.
-merge_successor(L, CFG) ->
- %% Get the BB L (If it still exists).
- case bb(CFG, L) of
- not_found -> CFG;
- BB ->
- StartLabel = start_label(CFG),
- Last = hipe_bb:last(BB),
- %% Note: Cannot use succ/2 since the instruction can have more than
- %% one successor that are the same label.
- case {branch_successors(Last), fails_to(Last)} of
- {[Successor],[Successor]} ->
- %% The single successor is the fail-label; don't merge.
- CFG;
- {[Successor],_} when Successor =/= StartLabel ->
- %% Make sure the succesor only have this block as predecessor.
- case [L] =:= pred(CFG, Successor) of
- true ->
- %% Remove the goto or remap fall-through in BB and merge the BBs
- NewCode = merge(BB, bb(CFG, Successor), Successor),
- NewBB = hipe_bb:mk_bb(NewCode),
- bb_add(bb_remove(CFG, Successor), L, NewBB);
- false ->
- CFG
- end;
- _ ->
- %% Not exactly one successor or tried to merge with the
- %% entry point
- CFG
- end
- end.
-
-%% Merge BB and BB2
-merge(BB, BB2, BB2_Label) ->
- Head = hipe_bb:butlast(BB),
- Last = hipe_bb:last(BB),
- Tail = hipe_bb:code(BB2),
- case is_goto(Last) of
- true ->
- %% Just ignore the goto.
- Head ++ Tail;
- false ->
- %% The last instr is not a goto,
- %% e.g. a call with only fall-through
- %% Remove the fall-through with the []-label.
- Head ++ [redirect_jmp(Last, BB2_Label, [])|Tail]
- end.
-
--endif. % REMOVE_TRIVIAL_BBS_NEEDED
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Remove unreachable BBs.
-%%
-%% A BB is unreachable if it cannot be reached by any path from the
-%% start label of the function.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--ifdef(REMOVE_UNREACHABLE_CODE).
-
--spec remove_unreachable_code(cfg()) -> cfg().
-
-remove_unreachable_code(CFG) ->
- Start = start_label(CFG),
- %% No unreachable block will make another block reachable, so no fixpoint
- %% looping is required
- Reachable = find_reachable([], [Start], CFG, #{Start=>[]}),
- case [L || L <- labels(CFG), not maps:is_key(L, Reachable)] of
- [] -> CFG;
- Remove ->
- HT0 = CFG#cfg.table,
- HT1 = lists:foldl(fun gb_trees:delete/2, HT0, Remove),
- ReachableP = fun(Lbl) -> maps:is_key(Lbl, Reachable) end,
- HT = gb_trees:map(fun(_,B)->prune_preds(B, ReachableP)end, HT1),
- CFG#cfg{table=HT}
- end.
-
-find_reachable([], [], _CFG, Acc) -> Acc;
-find_reachable([Succ|Succs], Left, CFG, Acc) ->
- case Acc of
- #{Succ := _} -> find_reachable(Succs, Left, CFG, Acc);
- #{} -> find_reachable(Succs, [Succ|Left], CFG, Acc#{Succ => []})
- end;
-find_reachable([], [Label|Left], CFG, Acc) ->
- find_reachable(succ(CFG, Label), Left, CFG, Acc).
-
-%% Batch prune unreachable predecessors. Asymptotically faster than deleting
-%% unreachable blocks one at a time with bb_remove, at least when
-%% CFG_CAN_HAVE_PHI_NODES is undefined. Otherwise a phi_remove_preds might be
-%% needed to achieve that.
-prune_preds(B={Block, Succ, Preds}, ReachableP) ->
- case lists:partition(ReachableP, Preds) of
- {_, []} -> B;
- {NewPreds, Unreach} ->
- NewCode = remove_preds_from_phis(Unreach, hipe_bb:code(Block)),
- {hipe_bb:code_update(Block, NewCode), Succ, NewPreds}
- end.
-
--ifdef(CFG_CAN_HAVE_PHI_NODES).
-remove_preds_from_phis(_, []) -> [];
-remove_preds_from_phis(Preds, List=[I|Left]) ->
- case is_phi(I) of
- false -> List;
- true ->
- NewI = lists:foldl(fun(L,IA)->phi_remove_pred(IA,L)end,
- I, Preds),
- [NewI | remove_preds_from_phis(Preds, Left)]
- end.
--else.
-remove_preds_from_phis(_, Code) -> Code.
--endif.
-
--endif. %% -ifdef(REMOVE_UNREACHABLE_CODE)
diff --git a/lib/hipe/flow/ebb.inc b/lib/hipe/flow/ebb.inc
deleted file mode 100644
index e4b7fd0efb..0000000000
--- a/lib/hipe/flow/ebb.inc
+++ /dev/null
@@ -1,244 +0,0 @@
-%% -*- Erlang -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% IDENTIFIES THE EXTENDED BASIC BLOCKS OF A CFG
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--export([cfg/1,
- %% dag/2,
- type/1,
- node_label/1,
- node_successors/1
- ]).
--ifdef(DEBUG_EBB).
--export([pp/1]).
--endif.
-
--define(cfg, ?CFG).
-
-%%--------------------------------------------------------------------
-%% The extended basic block datatype
-%%
-%% An EBB is identified with the label of the root node.
-%% It's a tree
-%%
-%% EBB := {ebb_node, Label, [EBB]}
-%% | {ebb_leaf, SuccesorLabel}
-%%--------------------------------------------------------------------
-
--type ebb() :: ebb_node()
- | ebb_leaf().
-
--record(ebb_node, {label :: icode_lbl(), successors :: [ebb()]}).
--type ebb_node() :: #ebb_node{}.
-
--record(ebb_leaf, {successor :: icode_lbl()}).
--type ebb_leaf() :: #ebb_leaf{}.
-
-%%--------------------------------------------------------------------
-%% Returns a list of extended basic blocks.
-%%--------------------------------------------------------------------
-
--spec cfg(cfg()) -> [ebb()].
-
-cfg(CFG) ->
- Start = ?cfg:start_label(CFG),
- Labels = ?cfg:reverse_postorder(CFG),
- Roots = [Start],
- Blocks = Labels -- Roots,
- Visited = new_visited(),
- build_all_ebb(Roots, Blocks, Visited, CFG).
-
-new_visited() ->
- gb_sets:empty().
-visited(L, Visited) ->
- gb_sets:is_member(L, Visited).
-visit(L, Visited) ->
- gb_sets:add(L, Visited).
-
-build_all_ebb(Roots, Blocks, Visited, CFG) ->
- build_all_ebb(Roots, Blocks, Visited, CFG, []).
-
-build_all_ebb([], [], _, _CFG, Ebbs) ->
- lists:reverse(Ebbs);
-build_all_ebb([], [BlockLeft|BlocksLeft], Visited, CFG, Ebbs) ->
- case visited(BlockLeft, Visited) of
- true ->
- build_all_ebb([], BlocksLeft, Visited, CFG, Ebbs);
- false ->
- build_all_ebb([BlockLeft], BlocksLeft, Visited, CFG, Ebbs)
- end;
-build_all_ebb([Root|Roots], Blocks, Visited, CFG, Ebbs) ->
- {Ebb, NewVisited} = build_ebb(Root, Visited, CFG),
- build_all_ebb(Roots, Blocks, NewVisited, CFG, [Ebb|Ebbs]).
-
-%%
-%% Build the extended basic block with Lbl as its root.
-%%
-
-build_ebb(Lbl, Visited, CFG) ->
- build_ebb(Lbl, Visited,
- fun (NodeL, NewVisited) -> {NodeL, NewVisited} end,
- [], CFG).
-
-build_ebb(Lbl, Visited, MkFun, EBBs, CFG) ->
- Succ = ?cfg:succ(CFG, Lbl),
- add_succ(Succ, visit(Lbl, Visited), Lbl, MkFun, EBBs, CFG).
-
-add_succ([], Visited, Node, MkFun, EBBs, _CFG) ->
- MkFun(mk_node(Node, lists:reverse(EBBs)), Visited);
-add_succ([Lbl|Lbls], Visited, Node, MkFun, EBBs, CFG) ->
- case [visited(Lbl, Visited)|?cfg:pred(CFG, Lbl)] of
- [false,_] ->
- build_ebb(Lbl, Visited,
- fun (NewEbb, Visited0) ->
- add_succ(Lbls, Visited0, Node, MkFun, [NewEbb|EBBs], CFG)
- end, [], CFG);
- _ ->
- add_succ(Lbls, Visited, Node, MkFun, [mk_leaf(Lbl)|EBBs], CFG)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Generate a list of dags.
-%%
-
-%% dag(EBBs, CFG) ->
-%% Start = ?cfg:start_label(CFG),
-%% Roots = [Start],
-%% Edges = all_adges(EBBs, Roots),
-%% start_dag(Roots, Edges, []).
-%%
-%% start_dag([], _Edges, _Visit) ->
-%% [];
-%% start_dag([Root|Roots], Edges, Visit) ->
-%% case lists:member(Root, Visit) of
-%% true ->
-%% start_dag(Roots, Edges, Visit);
-%% false ->
-%% {Dag, Roots0, Visit0} =
-%% fill_dag(Root, [Root], Edges, Roots, [Root|Visit]),
-%% [lists:reverse(Dag) | start_dag(Roots0, Edges, Visit0)]
-%% end.
-%%
-%% fill_dag(Lbl, Dag, Edges, Roots, Visit) ->
-%% Succ = find_succ(Lbl, Edges),
-%% add_dag_succ(Succ, Dag, Edges, Roots, Visit).
-%%
-%% add_dag_succ([], Dag, _Edges, Roots, Visit) ->
-%% {Dag, Roots, Visit};
-%% add_dag_succ([S|Ss], Dag, Edges, Roots, Visit) ->
-%% {Dag0, Roots0, Visit0} = add_dag_succ(Ss, Dag, Edges, Roots, Visit),
-%% Pred = find_pred(S, Edges),
-%% case all_in(Pred, Dag0) of
-%% true ->
-%% fill_dag(S, [S|Dag0], Edges, Roots0, [S|Visit0]);
-%% false ->
-%% {Dag0, [S|Roots], Visit0}
-%% end.
-%%
-%% find_succ(_Lbl, []) ->
-%% [];
-%% find_succ(Lbl, [{Lbl, Succ}|Edges]) ->
-%% [Succ | find_succ(Lbl, Edges)];
-%% find_succ(Lbl, [_|Edges]) ->
-%% find_succ(Lbl, Edges).
-%%
-%% find_pred(_Lbl, []) ->
-%% [];
-%% find_pred(Lbl, [{Pred, Lbl}|Edges]) ->
-%% [Pred | find_pred(Lbl, Edges)];
-%% find_pred(Lbl, [_|Edges]) ->
-%% find_pred(Lbl, Edges).
-%%
-%% all_edges([], _Roots) ->
-%% [];
-%% all_edges([EBB|EBBs], Roots) ->
-%% succ_edges(node_label(EBB), ebb_successors(EBB), EBBs, Roots).
-%%
-%% succ_edges(Lbl, [], EBBs, Roots) ->
-%% case lists:member(Lbl, Roots) of
-%% true ->
-%% [{start, Lbl} | all_edges(EBBs, Roots)];
-%% false ->
-%% all_edges(EBBs, Roots)
-%% end;
-%% succ_edges(Lbl, [S|Ss], EBBs, Roots) ->
-%% [{Lbl, S} | succ_edges(Lbl, Ss, EBBs, Roots)].
-%%
-%% all_in([], _List) ->
-%% true;
-%% all_in([X|Xs], List) ->
-%% lists:member(X, List) andalso all_in(Xs, List).
-%%
-%% find_ebb(Lbl, [EBB|EBBs]) ->
-%% case node_label(EBB) of
-%% Lbl ->
-%% EBB;
-%% _ ->
-%% find_ebb(Lbl, EBBs)
-%% end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--spec mk_node(icode_lbl(), [ebb()]) -> ebb_node().
-mk_node(Label, Successors) -> #ebb_node{label=Label, successors=Successors}.
-
--spec node_label(#ebb_node{}) -> icode_lbl().
-node_label(#ebb_node{label=Label}) -> Label.
-
--spec node_successors(#ebb_node{}) -> [ebb()].
-node_successors(#ebb_node{successors=Successors}) -> Successors.
-
--spec mk_leaf(icode_lbl()) -> ebb_leaf().
-mk_leaf(NextEbb) -> #ebb_leaf{successor=NextEbb}.
-%% leaf_next(Leaf) -> Leaf#ebb_leaf.successor.
-
--spec type(ebb_node()) -> 'node' ; (ebb_leaf()) -> 'leaf'.
-type(#ebb_node{}) -> node;
-type(#ebb_leaf{}) -> leaf.
-
-%% ebb_successors(EBB) ->
-%% ordsets:from_list(ebb_successors0(EBB)).
-%%
-%% ebb_successors0(#ebb_leaf{successor=NextEBB}) ->
-%% [NextEBB];
-%% ebb_successors0(#ebb_node{successors=SuccessorNodes}) ->
-%% lists:append(lists:map(fun ebb_successors0/1, SuccessorNodes)).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Prettyprint a list of extended basic blocks
-%%
-
--ifdef(DEBUG_EBB).
-
-pp(EBBs) ->
- lists:map(fun(E) -> pp(E, 0) end, EBBs).
-
-pp(EBB, Indent) ->
- io:format([$~]++integer_to_list(Indent)++[$c],[$ ]),
- case type(EBB) of
- node ->
- io:format("~w~n", [node_label(EBB)]),
- lists:map(fun(E) -> pp(E, Indent+3) end, node_successors(EBB));
- leaf ->
- io:format("* -> ~w~n", [leaf_next(EBB)])
- end.
-
--endif.
diff --git a/lib/hipe/flow/hipe_bb.erl b/lib/hipe/flow/hipe_bb.erl
deleted file mode 100644
index f4dad59e61..0000000000
--- a/lib/hipe/flow/hipe_bb.erl
+++ /dev/null
@@ -1,78 +0,0 @@
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Basic Block Module
-%%
-%% Exports:
-%% ~~~~~~~~
-%% mk_bb(Code) - construct a basic block.
-%% code(BB) - returns the code.
-%% code_update(BB, NewCode) - replace the code in a basic block.
-%% last(BB) - returns the last instruction.
-%% butlast(BB) - returns the code with the last instruction removed.
-%%
-
--module(hipe_bb).
-
--export([mk_bb/1,
- code/1,
- code_update/2,
- is_bb/1,
- last/1,
- butlast/1]).
-
--include("hipe_bb.hrl").
-
--export_type([bb/0]).
-
-%%
-%% Constructs a basic block.
-%% Returns a basic block: {bb, Code}
-%% * Code is a list of instructions
-
--spec mk_bb([_]) -> bb().
-
-mk_bb(Code) ->
- #bb{code=Code}.
-
--spec is_bb(_) -> boolean().
-
-is_bb(#bb{}) -> true;
-is_bb(_) -> false.
-
--spec code_update(bb(), [_]) -> bb().
-
-code_update(BB, Code) ->
- BB#bb{code = Code}.
-
--spec code(bb()) -> [_].
-
-code(#bb{code = Code}) ->
- Code.
-
--spec last(bb()) -> _.
-
-last(#bb{code = Code}) ->
- lists:last(Code).
-
--spec butlast(bb()) -> [_].
-
-butlast(#bb{code = Code}) ->
- butlast_1(Code).
-
-butlast_1([X|Xs]) -> butlast_1(Xs,X).
-
-butlast_1([X|Xs],Y) -> [Y|butlast_1(Xs,X)];
-butlast_1([],_) -> [].
diff --git a/lib/hipe/flow/hipe_bb.hrl b/lib/hipe/flow/hipe_bb.hrl
deleted file mode 100644
index 5cb5c1b370..0000000000
--- a/lib/hipe/flow/hipe_bb.hrl
+++ /dev/null
@@ -1,25 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%-------------------------------------------------------------------
-%%% File : bb.hrl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Description : Typed record declaration for basic blocks
-%%%
-%%% Created : 20 Dec 2007 by Per Gustafsson <pergu@it.uu.se>
-%%%-------------------------------------------------------------------
-
--record(bb, {code=[] :: [_]}).
-
--type bb() :: #bb{}.
diff --git a/lib/hipe/flow/hipe_dominators.erl b/lib/hipe/flow/hipe_dominators.erl
deleted file mode 100644
index 749edd4f72..0000000000
--- a/lib/hipe/flow/hipe_dominators.erl
+++ /dev/null
@@ -1,712 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%------------------------------------------------------------------------
-%% File : hipe_dominators.erl
-%% Author : Christoffer Vikström <chvi3471@student.uu.se>
-%% Daniel Deogun <dade4543@student.uu.se>
-%% Jesper Bengtsson <jebe8371@student.uu.se>
-%% Created : 18 Mar 2002
-%%
-%% @doc
-%% Contains utilities for creating and manipulating dominator trees
-%% and dominance frontiers from a CFG.
-%% @end
-%%------------------------------------------------------------------------
--module(hipe_dominators).
-
--export([domTree_create/1,
- domTree_getChildren/2,
- domTree_dominates/3,
- domFrontier_create/2,
- domFrontier_get/2]).
-
--export_type([domTree/0]).
-
--include("cfg.hrl").
-
-%%========================================================================
-%%
-%% CODE FOR CREATING AND MANIPULATING DOMINATOR TREES.
-%%
-%%========================================================================
-
--record(workDataCell, {dfnum = 0 :: non_neg_integer(),
- dfparent = none :: 'none' | cfg_lbl(),
- semi = none :: 'none' | cfg_lbl(),
- ancestor = none :: 'none' | cfg_lbl(),
- best = none :: 'none' | cfg_lbl(),
- samedom = none :: 'none' | cfg_lbl(),
- bucket = [] :: [cfg_lbl()]}).
-
--record(domTree, {root :: cfg_lbl(),
- size = 0 :: non_neg_integer(),
- nodes = gb_trees:empty() :: gb_trees:tree()}).
--opaque domTree() :: #domTree{}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_create/1
-%% Purpose : Creates a complete dominator tree given a CFG.
-%% Arguments : CFG - a Control Flow Graph representation
-%% Returns : A dominator tree
-%%>----------------------------------------------------------------------<
-
--spec domTree_create(cfg()) -> domTree().
-
-domTree_create(CFG) ->
- {WorkData, DFS, N} = dfs(CFG),
- DomTree = domTree_empty(hipe_gen_cfg:start_label(CFG)),
- {DomData, WorkData2} = getIdoms(CFG, DomTree, WorkData, N, DFS),
- finalize(WorkData2, DomData, 1, N, DFS).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_empty/0
-%% Purpose : Creates an empty dominator tree.
-%% Arguments : The root node
-%% Returns : A dominator tree
-%%>----------------------------------------------------------------------<
-
-domTree_empty(Node) ->
- #domTree{root = Node}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_createNode/2
-%% Purpose : Creates a new node and inserts it into the dominator tree.
-%% Arguments : Node - The new node
-%% DomTree - The target dominator tree
-%% Returns : A dominator tree
-%%>----------------------------------------------------------------------<
-
-domTree_createNode(Node, DomTree) ->
- DomTree2 = domTree_setNodes(DomTree,
- gb_trees:enter(Node, {none,[]},
- domTree_getNodes(DomTree))),
- domTree_incSize(DomTree2).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_getNode/2
-%% Purpose : Returns a specific node in the dominator tree.
-%% Arguments : Node - The new node
-%% DomTree - The target dominator tree
-%% Returns : Node
-%%>----------------------------------------------------------------------<
-
-domTree_getNode(Node, DomTree) ->
- gb_trees:lookup(Node, domTree_getNodes(DomTree)).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_getNodes/1
-%% Purpose : Retrieves the nodes from a dominator tree.
-%% Arguments : DomTree - The target dominator tree
-%% Returns : A map containing the nodes of the dominator tree.
-%%>----------------------------------------------------------------------<
-
-domTree_getNodes(#domTree{nodes=Nodes}) -> Nodes.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_setNodes/2
-%% Purpose : Replaces the set of nodes in a dominator tree with a
-%% new set of nodes.
-%% Arguments : Nodes - The new set of nodes
-%% DomTree - The target dominator tree
-%% Returns : DomTree
-%%>----------------------------------------------------------------------<
-
-domTree_setNodes(DomTree, Nodes) -> DomTree#domTree{nodes = Nodes}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_setSize/2
-%% Purpose : Sets the size of the dominator tree, i.e. the number of
-%% nodes in it.
-%% Arguments : Size - The new size of the target dominator tree
-%% DomTree - The target dominator tree
-%% Returns : A dominator tree
-%%>----------------------------------------------------------------------<
-
-domTree_setSize(DomTree, Size) -> DomTree#domTree{size = Size}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_incSize/1
-%% Purpose : Increases the size of the dominator tree with one.
-%% Arguments : DomTree - The target dominator tree
-%% Returns : DomTree
-%%>----------------------------------------------------------------------<
-
-domTree_incSize(DomTree) ->
- Size = domTree_getSize(DomTree),
- domTree_setSize(DomTree, Size + 1).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : get IDom/2
-%% Purpose : Retrieves the immediate dominators of a node in the
-%% dominator tree.
-%% Arguments : Node - The new node
-%% DomTree - The target dominator tree
-%% Returns : The immediate dominator
-%%>----------------------------------------------------------------------<
-
-domTree_getIDom(Node, DomTree) ->
- case domTree_getNode(Node, DomTree) of
- {value, {IDom, _}} ->
- IDom;
- none ->
- []
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : getChildren/2
-%% Purpose : Retrieves the children of a node in the dominator tree.
-%% Arguments : Node - The new node
-%% DomTree - The target dominator tree
-%% Returns : [children]
-%%>----------------------------------------------------------------------<
-
--spec domTree_getChildren(cfg_lbl(), domTree()) -> [cfg_lbl()].
-
-domTree_getChildren(Node, DomTree) ->
- case domTree_getNode(Node, DomTree) of
- {value, {_, Children}} ->
- Children;
- none ->
- []
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_getSize/1
-%% Purpose : Retrieves the size of a dominator tree.
-%% Arguments : DomTree - The target dominator tree
-%% Returns : A number denoting the size of the dominator tree
-%%>----------------------------------------------------------------------<
-
-domTree_getSize(#domTree{size=Size}) -> Size.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_getRoot/2
-%% Purpose : Retrieves the number of the root node in the dominator tree.
-%% Arguments : DomTree - The target dominator tree
-%% Returns : Number
-%%>----------------------------------------------------------------------<
-
-domTree_getRoot(#domTree{root=Root}) -> Root.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_addChild/3
-%% Purpose : Inserts a new node as a child to another node in the
-%% dominator tree.
-%% Arguments : Node - The old node that should get a new child
-%% Child - The new child node
-%% DomTree - The target dominator tree
-%% Returns : DomTree
-%%>----------------------------------------------------------------------<
-
-domTree_addChild(Node, Child, DomTree) ->
- {IDom, Children} = case domTree_getNode(Node, DomTree) of
- {value, Tuple} ->
- Tuple;
- none ->
- {none, []}
- end,
- Nodes = case lists:member(Child, Children) of
- true ->
- domTree_getNodes(DomTree);
- false ->
- gb_trees:enter(Node, {IDom, [Child|Children]},
- domTree_getNodes(DomTree))
- end,
- domTree_setNodes(DomTree, Nodes).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : setIDom/3
-%% Purpose : Sets the immediate domminator of a node in the domminator tree.
-%% Arguments : Node - The node whose immediate domminator we are seting
-%% IDom - The immediate domminator
-%% DomTree - The target dominator tree
-%% Returns : DomTree
-%% Notes : Is used to build the dominator tree.
-%%>----------------------------------------------------------------------<
-
-setIDom(Node, IDom, DomTree) ->
- DomTree1 = case domTree_getNode(Node, DomTree) of
- none ->
- domTree_createNode(Node, DomTree);
- _ ->
- DomTree
- end,
- DomTree2 = domTree_addChild(IDom, Node, DomTree1),
- {value, {_, Children}} = domTree_getNode(Node, DomTree2),
- domTree_setNodes(DomTree2,
- gb_trees:enter(Node, {IDom, Children},
- domTree_getNodes(DomTree2))).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : lookup
-%% Purpose : This function is used as a wrapper for the lookup function.
-%% The function retrieves a particular element (defined by
-%% Field) stored in a workDataCell in the table (defined by
-%% Table).
-%% Arguments : Field - Value defined in the workDataCell record
-%% Key - Value used as a key in the table
-%% Table - Table storing workDataCells
-%% Returns : A value defined in the workDataCell record
-%%>----------------------------------------------------------------------<
-
-lookup({Field, Key}, Table) when is_integer(Key) ->
- WD = lookup_table(Key, Table),
- case Field of
- ancestor -> WD#workDataCell.ancestor;
- best -> WD#workDataCell.best;
- bucket -> WD#workDataCell.bucket;
- dfnum -> WD#workDataCell.dfnum;
- dfparent -> WD#workDataCell.dfparent;
- samedom -> WD#workDataCell.samedom;
- semi -> WD#workDataCell.semi
- end.
-
-lookup_table(Key, Table) when is_integer(Key) ->
- case gb_trees:lookup(Key, Table) of
- {value, Data} ->
- Data;
- none ->
- #workDataCell{}
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : update
-%% Purpose : This function is used as a wrapper for the update function
-%% The main purpose of the update function is therefore
-%% change a particular cell in the table (Table) to the
-%% value given as an argument (Value).
-%% Arguments : Key - Value used as a key in the table
-%% Field - Value defined in the workDataCell record.
-%% Value - The new value that should replace the old in the table
-%% Table - Table storing workDataCells
-%% Returns : NewTable
-%%>----------------------------------------------------------------------<
-
-update(Key, {Field, Value}, Table) ->
- gb_trees:enter(Key, updateCell(Value, Field, lookup_table(Key, Table)), Table);
-update(Key, List, Table) ->
- gb_trees:enter(Key, update(List, lookup_table(Key, Table)), Table).
-
-update([{Field, Value} | T], WD) ->
- update(T, updateCell(Value, Field, WD));
-update([], WD) -> WD.
-
-updateCell(Value, Field, WD) ->
- case Field of
- dfnum -> WD#workDataCell{dfnum = Value};
- dfparent -> WD#workDataCell{dfparent= Value};
- semi -> WD#workDataCell{semi = Value};
- ancestor -> WD#workDataCell{ancestor= Value};
- best -> WD#workDataCell{best = Value};
- samedom -> WD#workDataCell{samedom = Value};
- bucket -> WD#workDataCell{bucket = Value}
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : dfs/1
-%% Purpose : The main purpose of this function is to traverse the CFG in
-%% a depth first order. It is also used to initialize certain
-%% elements defined in a workDataCell.
-%% Arguments : CFG - a Control Flow Graph representation
-%% Returns : A table (WorkData) and the total number of elements in
-%% the CFG.
-%%>----------------------------------------------------------------------<
-
-dfs(CFG) ->
- {WorkData, DFS, N} = dfs(CFG, hipe_gen_cfg:start_label(CFG),
- none, 1, gb_trees:empty(), gb_trees:empty()),
- {WorkData, DFS, N-1}.
-
-dfs(CFG, Node, Parent, N, WorkData, DFS) ->
- case lookup({dfnum, Node}, WorkData) of
- 0 ->
- WorkData2 = update(Node, [{dfnum, N}, {dfparent, Parent},
- {semi, Node}, {best, Node}], WorkData),
- DFS2 = gb_trees:enter(N, Node, DFS),
- dfsTraverse(hipe_gen_cfg:succ(CFG, Node), CFG, Node,
- N + 1, WorkData2, DFS2);
- _ -> {WorkData, DFS, N}
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : dfsTraverse/6
-%% Purpose : This function acts as a help function for the dfs algorithm
-%% in the sence that it traverses a list of nodes given by the
-%% CFG.
-%% Arguments : Node - The first element in the node list
-%% SuccLst - The remainder of the node list
-%% CFG - Control Flow Graph representation
-%% Parent - Node representing the parent of the Node defined
-%% above.
-%% N - The total number of processed nodes.
-%% WorkData - Table consisting of workDataCells
-%% Returns : An updated version of the table (WorkData) and the
-%% total number of nodes processed.
-%%>----------------------------------------------------------------------<
-
-dfsTraverse([Node|T], CFG, Parent, N, WorkData, DFS) ->
- {WorkData2, DFS2, N2} = dfs(CFG, Node, Parent, N, WorkData, DFS),
- dfsTraverse(T, CFG, Parent, N2, WorkData2, DFS2);
-dfsTraverse([], _, _, N, WorkData, DFS) -> {WorkData, DFS, N}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : getIdoms/6
-%% Purpose : The purpose of this function is to compute the immediate
-%% dominators. This is accomplished by traversing the CFG nodes
-%% by their depth first number in a bottom up manner. That is,
-%% the nodes are processed in a backward order (highest to
-%% lowest number).
-%% Arguments : CFG - Control Flow Graph representation
-%% DomData - Table consisting of domTree cells
-%% WorkData - Table consisting of workDataCells
-%% Index - The index used for retrieving the node to be
-%% processed
-%% Returns : An updated version of the tables DomData and WorkData
-%%>----------------------------------------------------------------------<
-
-getIdoms(CFG, DomData, WorkData, Index, DFS)
- when is_integer(Index), Index > 1 ->
- Node = lookup_table(Index, DFS),
- PredLst = hipe_gen_cfg:pred(CFG, Node),
- Par = lookup({dfparent, Node}, WorkData),
- DfNumN = lookup({dfnum, Node}, WorkData),
- {S, WorkData2} = getSemiDominator(PredLst, DfNumN, Par, WorkData),
- WorkData3 = update(Node, {semi, S}, WorkData2),
- OldBucket = lookup({bucket, S}, WorkData3),
- WorkData4 = update(S, {bucket, [Node | OldBucket]}, WorkData3),
- WorkData5 = linkTrees(Par, Node, WorkData4),
- {WorkData6, DomData2} = filterBucket(lookup({bucket, Par}, WorkData5),
- Par, WorkData5, DomData),
- WorkData7 = update(Par, {bucket, []}, WorkData6),
- getIdoms(CFG, DomData2, WorkData7, Index - 1, DFS);
-getIdoms(_, DomData, WorkData, 1, _) ->
- {DomData, WorkData}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : getSemiDominator/4
-%% Purpose : The main purpose of this algorithm is to compute the semi
-%% dominator of the node Node based on the Semidominator Theorem
-%% Arguments : Preds - The list of predecessors of the node Node
-%% Node - Node in the CFG
-%% S - Parent of node Node (depth first parent)
-%% WorkData - Table consisting of workDataCells
-%% Returns : A tuple containing the semidominator and an updated version
-%% of the table WorkData.
-%%>----------------------------------------------------------------------<
-
-getSemiDominator([Pred|Preds], DfNumChild, S, WorkData) ->
- {Sp, WorkData3} =
- case lookup({dfnum, Pred}, WorkData) =< DfNumChild of
- true ->
- {Pred, WorkData};
- false ->
- {AncLowSemi, WorkData2} = getAncestorWithLowestSemi(Pred, WorkData),
- {lookup({semi, AncLowSemi}, WorkData2), WorkData2}
- end,
- S2 = case lookup({dfnum, Sp}, WorkData3) < lookup({dfnum, S}, WorkData3) of
- true -> Sp;
- false -> S
- end,
- getSemiDominator(Preds, DfNumChild, S2, WorkData3);
-getSemiDominator([], _, S, WorkData) ->
- {S, WorkData}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : getAncestorWithLowestSemi/2
-%% Purpose : The main purpose of this function is to retrieve the ancestor
-%% of a node with the lowest depth first number (semi). The
-%% function is also using path compression, i.e. it remembers the
-%% best node (the one with the lowest semi number) and hence the
-%% algorithm is only processing the minimal number of nodes.
-%% Arguments : Node - Node in the tree
-%% WorkData - Table consisting of workDataCells
-%% Returns : A node (the one with the lowest semi) and an updated version
-%% of the table WorkData.
-%%>----------------------------------------------------------------------<
-
-getAncestorWithLowestSemi(Node, WorkData) ->
- Best = lookup({best, Node}, WorkData),
- case lookup({ancestor, Node}, WorkData) of
- none -> {Best, WorkData};
- A ->
- case lookup({ancestor, A}, WorkData) of
- none ->
- {Best, WorkData};
- _ ->
- {B, WorkData2} = getAncestorWithLowestSemi(A, WorkData),
- AncA = lookup({ancestor, A}, WorkData2),
- WorkData3 = update(Node, {ancestor, AncA}, WorkData2),
- DfSemiB = lookup({dfnum, lookup({semi, B}, WorkData3)}, WorkData3),
- BestN = lookup({best, Node}, WorkData3),
- SemiB = lookup({semi, BestN}, WorkData3),
- DfSemiBestN = lookup({dfnum, SemiB}, WorkData3),
- case DfSemiB < DfSemiBestN of
- true ->
- {B, update(Node, {best, B}, WorkData3)};
- false ->
- {BestN, WorkData3}
- end
- end
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : linkTrees/3
-%% Purpose : The main purpose of this function is to combine two trees
-%% into one (accomplished by setting the ancestor for node
-%% Node to Parent). The algorithm is also updating the best field
-%% in the workDataCell for node Node to the value of itself.
-%% Arguments : Parent - The parent of the node Node.
-%% Node - The node to process
-%% WorkData - Table consisting of workDataCells
-%% Returns : An updated version of table WorkData
-%%>----------------------------------------------------------------------<
-
-linkTrees(Parent, Node, WorkData) ->
- update(Node, [{ancestor, Parent}, {best, Node}], WorkData).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : filterBucket/4
-%% Purpose : The purpose of this algorith is to compute the dominator of
-%% the node Node by utilizing the first clause of the Dominator
-%% Theorem. If the first clause of the theorem doesn't apply
-%% then the computation of that particular node is deferred to
-%% a later stage (see finalize).
-%% Arguments : Nodes - The list of CFG nodes that need to be computed.
-%% Parent - The parent of the nodes in the list Nodes
-%% WorkData - Table consisting of workDataCells
-%% DomData - Table consisting of domTree cells.
-%% Returns : An updated version of the tables WorkData and DomData
-%%>----------------------------------------------------------------------<
-
-filterBucket([Node|Nodes], Parent, WorkData, DomData) ->
- {Y, WorkData2} = getAncestorWithLowestSemi(Node, WorkData),
- {WorkData3, DomData2} =
- case lookup({semi, Y}, WorkData2) =:= lookup({semi, Node}, WorkData2) of
- true -> {WorkData2, setIDom(Node, Parent, DomData)};
- false -> {update(Node, {samedom, Y}, WorkData2), DomData}
- end,
- filterBucket(Nodes, Parent, WorkData3, DomData2);
-filterBucket([], _, WorkData, DomData) ->
- {WorkData, DomData}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : finalize/5
-%% Purpose : This algorithm finishes up the second clause of the Dominator
-%% Theorem. Hence, the main purpose of this function is therefore
-%% to update the dominator tree with the nodes that were deferred
-%% in the filterBucket algorithm.
-%% Arguments : WorkData - Table consisting of workDataCells
-%% DomData - Table consisting of domTree cells
-%% N - The index used for retrieving the node to be
-%% processed
-%% Max - Maximum node index
-%% Returns : An updated version of the table DomData
-%%>----------------------------------------------------------------------<
-
-finalize(WorkData, DomData, N, Max, DFS) when N =< Max ->
- Node = lookup_table(N, DFS),
- case lookup({samedom, Node}, WorkData) of
- none ->
- finalize(WorkData, DomData, N + 1, Max, DFS);
- SameDomN ->
- case domTree_getIDom(SameDomN, DomData) of
- IdomSameDomN when is_integer(IdomSameDomN) ->
- DomData2 = setIDom(Node, IdomSameDomN, DomData),
- finalize(WorkData, DomData2, N + 1, Max, DFS)
- end
- end;
-finalize(_, DomData, _, _, _) ->
- DomData.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domTree_dominates/3
-%% Purpose : checks wheter Node1 dominates Node2 with respect to the
-%% dominator tree DomTree
-%% Arguments : Node1 the possible dominator, Node2 which might be dominated
-%% and DomTree - the target dominator tree.
-%% Notes : Relies on lists:any to return false when the a list is empty
-%%>----------------------------------------------------------------------<
-
--spec domTree_dominates(cfg_lbl(), cfg_lbl(), domTree()) -> boolean().
-
-domTree_dominates(Node1, Node1, _DomTree) ->
- true;
-domTree_dominates(Node1, Node2, DomTree) ->
- Children = domTree_getChildren(Node1, DomTree),
- lists:any(fun(X) -> domTree_dominates(X, Node2, DomTree) end, Children).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : pp/1
-%% Purpose : Pretty Printing a dominator tree.
-%% Arguments : DomTree - the target dominator tree.
-%% Notes : Uses pp/2 and pp_children to perform its task.
-%%>----------------------------------------------------------------------<
-
--ifdef(DEBUG).
-
-domTree_pp(DomTree) ->
- io:format("Domtree:\nRoot: ~w\nSize: ~w\n", [domTree_getRoot(DomTree),
- domTree_getSize(DomTree)]),
- domTree_pp(domTree_getRoot(DomTree), DomTree).
-
-domTree_pp(N, DomTree) ->
- case domTree_getNode(N, DomTree) of
- {value, {IDom, Children}} ->
- io:format("Node: ~w\n\tIDom: ~w\n\tChildren: ~w\n\n",
- [N, IDom, Children]),
- domTree_pp_children(Children, DomTree);
- none ->
- failed
- end.
-
-domTree_pp_children([Child|T], DomTree) ->
- domTree_pp(Child, DomTree),
- domTree_pp_children(T, DomTree);
-domTree_pp_children([], _) ->
- ok.
-
--endif. %% DEBUG
-
-%%========================================================================
-%%
-%% CODE FOR CREATING AND MANIPULATING DOMINANCE FRONTIERS.
-%%
-%%========================================================================
-
--type domFrontier() :: gb_trees:tree().
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domFrontier_create
-%% Purpose : This function calculates the Dominance Frontiers given
-%% a CFG and a Dominator Tree.
-%% Arguments : SuccMap - The successor map of the CFG we are working with.
-%% DomTree - The dominance tree of the CFG.
-%% Notes : DomTree must actually be the dominance tree of the CFG.
-%%>----------------------------------------------------------------------<
-
--spec domFrontier_create(cfg(), domTree()) -> domFrontier().
-
-domFrontier_create(SuccMap, DomTree) ->
- df_create(domTree_getRoot(DomTree), SuccMap, DomTree, df__empty()).
-
-df_create(Node, SuccMap, DomTree, DF) ->
- Children = domTree_getChildren(Node, DomTree),
- Succ = hipe_gen_cfg:succ(SuccMap, Node),
- DF1 = checkIDomList(Succ, Node, DomTree, DF),
- makeDFChildren(Children, Node, SuccMap, DomTree, DF1).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : domFrontier_get
-%% Purpose : This function returns the Dominance Frontier for Node.
-%% Arguments : Node - The node whose Dominance Frontier we request
-%% DF - The Dominance Frontier structure
-%% Returns :
-%%>----------------------------------------------------------------------<
-
--spec domFrontier_get(cfg_lbl(), domFrontier()) -> [cfg_lbl()].
-
-domFrontier_get(Node, DF) ->
- case gb_trees:lookup(Node, DF) of
- {value, List} -> List;
- none -> []
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : df__empty
-%% Purpose : This function creates an empty instance of the Dominance
-%% Frontiers (DF) structure.
-%%>----------------------------------------------------------------------<
-
-df__empty() ->
- gb_trees:empty().
-
-%%>----------------------------------------------------------------------<
-%% Procedure : df__add
-%% Purpose : This function adds Node to N in DF.
-%% Arguments : N - The value being inserted
-%% Node - The node getting the value
-%% DF - The Dominance Frontiers
-%% Returns : DF
-%% Notes : If Node already exists at position N, it is not added again.
-%%>----------------------------------------------------------------------<
-
-df__add_to_node(N, Node, DF) ->
- case gb_trees:lookup(N, DF) of
- {value, DFList} ->
- case lists:member(Node, DFList) of
- true ->
- DF;
- false ->
- gb_trees:update(N, [Node|DFList], DF)
- end;
- none ->
- gb_trees:insert(N, [Node], DF)
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : makeDFChildren
-%% Purpose : This function calculates the dominance frontiers of the
-%% children of the parent and adds the nodes in these
-%% dominance frontiers who are not immediate dominantors of
-%% the parent to parents dominance frontier.
-%% Arguments : ChildList - The list of children that the function traverses
-%% Parent - The parent of the children
-%% SuccMap - The successor map of the CFG
-%% DomTree - The dominantor tree of the CFG
-%% DF - The dominance frontiers so far
-%%>----------------------------------------------------------------------<
-
-makeDFChildren([Child|T], Parent, SuccMap, DomTree, DF) ->
- DF1 = df_create(Child, SuccMap, DomTree, DF),
- DF2 = checkIDomList(domFrontier_get(Child, DF1), Parent, DomTree, DF1),
- makeDFChildren(T, Parent, SuccMap, DomTree, DF2);
-makeDFChildren([], _, _, _, DF) ->
- DF.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : checIDomList
-%% Purpose : Adds all the nodes in the list to the parents dominance
-%% frontier who do not have parent as immediate dominator.
-%% Arguments : NodeList - The list of nodes that the function traverses
-%% Parent - The parent of the nodes
-%% DomTree - Our dominator tree
-%% DF - The dominance frontiers so far
-%%>----------------------------------------------------------------------<
-
-checkIDomList([Node|T], Parent, DomTree, DF) ->
- DF1 = checkIDom(Node, Parent, DomTree, DF),
- checkIDomList(T, Parent, DomTree, DF1);
-checkIDomList([], _, _, DF) ->
- DF.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : checkIdom
-%% Purpose : Adds Node1 to Node2's dominance frontier if Node2 is not
-%% Node1's immediate dominator.
-%% Arguments : Node1 - a node
-%% Node2 - another node
-%% DomTree - the dominator tree
-%% DF - the dominance frontier so far
-%%>----------------------------------------------------------------------<
-
-checkIDom(Node1, Node2, DomTree, DF) ->
- case domTree_getIDom(Node1, DomTree) of
- Node2 ->
- DF;
- none ->
- DF;
- _ ->
- df__add_to_node(Node2, Node1, DF)
- end.
diff --git a/lib/hipe/flow/hipe_gen_cfg.erl b/lib/hipe/flow/hipe_gen_cfg.erl
deleted file mode 100644
index cc3a1b5b73..0000000000
--- a/lib/hipe/flow/hipe_gen_cfg.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_gen_cfg).
-
--export([start_label/1,
- succ/2,
- pred/2
- ]).
-
-%%-define(DO_ASSERT, true).
--define(GEN_CFG, true). % needed for cfg.inc
-
--include("../main/hipe.hrl").
--include("cfg.hrl").
-
--spec succ(cfg(), cfg_lbl()) -> [cfg_lbl()].
--spec pred(cfg(), cfg_lbl()) -> [cfg_lbl()].
-
--include("cfg.inc").
diff --git a/lib/hipe/flow/liveness.inc b/lib/hipe/flow/liveness.inc
deleted file mode 100644
index 3e9d7b3c96..0000000000
--- a/lib/hipe/flow/liveness.inc
+++ /dev/null
@@ -1,329 +0,0 @@
-%% -*- Erlang -*-
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% LIVENESS ANALYSIS
-%%
-%% Exports:
-%% ~~~~~~~
-%% analyze(CFG) - returns a liveness analysis of CFG.
-%% liveout(Liveness, Label) - returns a set of variables that are live at
-%% exit from basic block named Label.
-%% livein(Liveness, Label) - returns a set of variables that are live at
-%% entry to the basic block named Label.
-%% livein_from_liveout(Instructions, LiveOut) - Given a list of instructions
-%% and a liveout-set, returns a set of variables live at the
-%% first instruction.
-%%
-
--export([analyze/1,
- livein/2]).
--ifdef(LIVEOUT_NEEDED).
--export([liveout/2]).
--endif.
--ifdef(PRETTY_PRINT).
--export([pp/1]).
--endif.
-%%-export([livein_from_liveout/2]).
--ifdef(DEBUG_LIVENESS).
--export([annotate_liveness/2]).
--endif.
-
--include("../flow/cfg.hrl").
--include("../main/hipe.hrl").
-
--opaque liveness() :: map().
--export_type([liveness/0]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface functions that MUST be implemented in the including file
-%%
-%% cfg_bb(CFG, L) -> BasicBlock, extract a basic block from a cfg.
-%% cfg_postorder(CFG) -> [Labels], the labels of the cfg in postorder
-%% cfg_succ(CFG, L) -> [Labels],
-%% uses(Instr) ->
-%% defines(Instr) ->
-%%
-%% Plus the following, if basic block annotations are needed
-%%
-%% cfg_labels(CFG) ->
-%% cfg_bb_add(CFG, L, NewBB) ->
-%% mk_comment(Text) ->
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The generic liveness analysis
-%%
-
--spec analyze(cfg()) -> liveness().
-
--ifdef(HIPE_LIVENESS_CALC_LARGEST_LIVESET).
-analyze(CFG) ->
- PO = cfg_postorder(CFG),
- InitLiveness = liveness_init(init(cfg_labels(CFG), CFG)),
- _Max = case get(hipe_largest_liveset) of
- undefined ->
- put(hipe_largest_liveset, 0),
- 0;
- LL -> LL
- end,
- Res = merry_go_around(PO, InitLiveness,0),
- case get(hipe_largest_liveset) > _Max of
- true ->
- io:format("Largest liveset: ~w \n", [get(hipe_largest_liveset)]);
- _ -> ok
- end,
- Res.
-
--else.
-
-analyze(CFG) ->
- PO = cfg_postorder(CFG),
- InitLiveness = liveness_init(init(PO, CFG)),
- Res = merry_go_around(PO, InitLiveness, 0),
- Res.
--endif.
-
-%%
-%% The fixpoint iteration
-%%
-
-merry_go_around(Labels, Liveness, Count) ->
- case doit_once(Labels, Liveness, 0) of
- {NewLiveness, 0} ->
- %% io:format("Iterations ~w~n", [Count]),
- NewLiveness;
- {NewLiveness, _Changed} ->
- merry_go_around(Labels, NewLiveness, Count+1)
- end.
-
-%%
-%% One iteration
-%%
-
--ifdef(HIPE_LIVENESS_CALC_LARGEST_LIVESET).
-doit_once([], Liveness, Changed) ->
- {Liveness, Changed};
-doit_once([L|Ls], Liveness, Changed) ->
- LiveOut = liveout(Liveness, L),
- Kill = ordsets:subtract(LiveOut, kill(L, Liveness)),
- LiveIn = ordsets:union(Kill, gen(L,Liveness)),
- {NewLiveness, ChangedP} = update_livein(L, LiveIn, Liveness),
- Le = length(LiveIn),
- Max = get(hipe_largest_liveset),
- if Le > Max -> put(hipe_largest_liveset, Le);
- true -> true
- end,
- doit_once(Ls, NewLiveness, Changed+ChangedP).
-
--else.
-
-doit_once([], Liveness, Changed) ->
- {Liveness, Changed};
-doit_once([L|Ls], Liveness, Changed) ->
- LiveOut = liveout(Liveness, L),
- Kill = ordsets:subtract(LiveOut, kill(L, Liveness)),
- LiveIn = ordsets:union(Kill, gen(L,Liveness)),
- {NewLiveness, ChangedP} = update_livein(L, LiveIn, Liveness),
- doit_once(Ls, NewLiveness, Changed+ChangedP).
--endif.
-
-%% %%
-%% %% Given a list of instructions and liveout, calculates livein
-%% %%
-%% livein_from_liveout(List, LiveOut) when is_list(List) ->
-%% livein_from_liveout_1(lists:reverse(List), gb_sets:from_list(LiveOut));
-%% livein_from_liveout(Instr, LiveOut) ->
-%% livein_from_liveout_1([Instr], gb_sets:from_list(LiveOut)).
-%%
-%% livein_from_liveout_1([], LiveOut) ->
-%% gb_sets:to_list(LiveOut);
-%% livein_from_liveout_1([I|Is], LiveOut) ->
-%% Def = defines(I),
-%% Use = uses(I),
-%% DefSet = gb_sets:from_list(Def),
-%% UseSet = gb_sets:from_list(Use),
-%% LiveIn = gb_sets:union(gb_sets:difference(LiveOut, DefSet), UseSet),
-%% Le = gb_sets:size(LiveIn),
-%% Max = get(hipe_largest_liveset),
-%% if Le > Max -> put(hipe_largest_liveset, Le);
-%% true -> true
-%% end,
-%% livein_from_liveout_1(Is, LiveIn).
-
-%%
-%% updates liveness for a basic block
-%% - returns: {NewLiveness, ChangedP}
-%% - ChangedP is 0 if the new LiveIn is equal to the old one
-%% otherwise it's 1.
-%%
-
-update_livein(Label, NewLiveIn, Liveness) ->
- {GK, LiveIn, Successors} = liveness_lookup(Label, Liveness),
- NewLiveness = liveness_update(Label, {GK, NewLiveIn, Successors}, Liveness),
- if LiveIn =:= NewLiveIn ->
- {NewLiveness, 0};
- true ->
- {NewLiveness, 1}
- end.
-
-
-%%
-%% LiveOut for a block is the union of the successors LiveIn
-%%
--spec liveout(liveness(), _) -> [_].
-
-liveout(Liveness, L) ->
- Succ = successors(L, Liveness),
- case Succ of
- [] -> % special case if no successors
- liveout_no_succ();
- _ ->
- liveout1(Succ, Liveness)
- end.
-
-liveout1(Labels, Liveness) ->
- liveout1(Labels, Liveness, ordsets:new()).
-
-liveout1([], _Liveness, Live) ->
- Live;
-liveout1([L|Ls], Liveness,Live) ->
- liveout1(Ls, Liveness, ordsets:union(livein(Liveness, L), Live)).
-
-successors(L, Liveness) ->
- {_GK, _LiveIn, Successors} = liveness_lookup(L, Liveness),
- Successors.
-
--spec livein(liveness(), _) -> [_].
-
-livein(Liveness, L) ->
- {_GK, LiveIn, _Successors} = liveness_lookup(L, Liveness),
- LiveIn.
-
-kill(L, Liveness) ->
- {{_Gen, Kill}, _LiveIn, _Successors} = liveness_lookup(L, Liveness),
- Kill.
-
-gen(L, Liveness) ->
- {{Gen, _Kill}, _LiveIn, _Successors} = liveness_lookup(L, Liveness),
- Gen.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% init returns a list of: {Label, {{Gen, Kill}, LiveIn, Successors}}
-%% - Label is the name of the basic block.
-%% - Gen is the set of varables that are used by this block.
-%% - Kill is the set of varables that are defined by this block.
-%% - LiveIn is the set of variables that are alive at entry to the
-%% block (initially empty).
-%% - Successors is a list of the successors to the block.
-
-init([], _) ->
- [];
-init([L|Ls], CFG) ->
- BB = cfg_bb(CFG, L),
- Code = hipe_bb:code(BB),
- Succ = cfg_succ(CFG, L),
- Transfer = make_bb_transfer(Code, Succ),
- [{L, {Transfer, ordsets:new(), Succ}} | init(Ls, CFG)].
-
-
-make_bb_transfer([], _Succ) ->
- {ordsets:new(), ordsets:new()}; % {Gen, Kill}
-make_bb_transfer([I|Is], Succ) ->
- {Gen, Kill} = make_bb_transfer(Is, Succ),
- InstrGen = ordsets:from_list(uses(I)),
- InstrKill = ordsets:from_list(defines(I)),
- Gen1 = ordsets:subtract(Gen, InstrKill),
- Gen2 = ordsets:union(Gen1, InstrGen),
- Kill1 = ordsets:union(Kill, InstrKill),
- Kill2 = ordsets:subtract(Kill1, InstrGen),
- {Gen2, Kill2}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Annotate each basic block with liveness info
-%%
-
--ifdef(DEBUG_LIVENESS).
-
-annotate_liveness(CFG, Liveness) ->
- Labels = cfg_labels(CFG),
- annotate_liveness_bb(Labels, CFG, Liveness).
-
-annotate_liveness_bb([], CFG, _Liveness) ->
- CFG;
-annotate_liveness_bb([L|Ls], CFG, Liveness) ->
- BB = cfg_bb(CFG, L),
- Code0 = hipe_bb:code(BB),
- LiveIn = strip(livein(Liveness, L)),
- LiveOut = strip(liveout(Liveness, L)),
- Code = [mk_comment({live_in, LiveIn}),
- mk_comment({live_out, LiveOut})
- | Code0],
- NewBB = hipe_bb:code_update(BB, Code),
- NewCFG = cfg_bb_add(CFG, L, NewBB),
- annotate_liveness_bb(Ls, NewCFG, Liveness).
-
-strip([]) ->
- [];
-strip([{_,Y}|Xs]) ->
- [Y|strip(Xs)].
-
--endif. % DEBUG_LIVENESS
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
--compile({inline, [liveness_lookup/2, liveness_update/3]}).
-
-liveness_init(List) ->
- maps:from_list(List).
-
-liveness_lookup(Label, Liveness) ->
- maps:get(Label, Liveness).
-liveness_update(Label, Val, Liveness) ->
- maps:update(Label, Val, Liveness).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% pp/1 pretty prints liveness information for a CFG
-%%
-
--ifdef(PRETTY_PRINT).
-
--spec pp(cfg()) -> 'ok'.
-pp(Cfg) ->
- Liveness = analyze(Cfg),
- Labels = cfg_labels(Cfg),
- ok = print_blocks(Labels, Liveness, Cfg).
-
-print_blocks([Lbl|Rest], Liveness, Cfg) ->
- io:format("~nLivein:", []),
- pp_liveness_info(livein(Liveness, Lbl)),
- io:format("Label ~w:~n" , [Lbl]),
- pp_block(Lbl, Cfg),
- io:format("Liveout:", []),
- pp_liveness_info(liveout(Liveness, Lbl)),
- print_blocks(Rest, Liveness, Cfg);
-print_blocks([], _Liveness, _Cfg) ->
- ok.
-
--endif. % PRETTY_PRINT
diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile
deleted file mode 100644
index b220bc16a0..0000000000
--- a/lib/hipe/icode/Makefile
+++ /dev/null
@@ -1,151 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-ifdef HIPE_ENABLED
-HIPE_MODULES = hipe_icode_heap_test
-else
-HIPE_MODULES =
-endif
-
-DOC_MODULES = hipe_beam_to_icode \
- hipe_icode hipe_icode_bincomp \
- hipe_icode_callgraph hipe_icode_cfg hipe_icode_coordinator \
- hipe_icode_fp \
- hipe_icode_exceptions \
- hipe_icode_inline_bifs hipe_icode_instruction_counter \
- hipe_icode_liveness \
- hipe_icode_pp hipe_icode_primops \
- hipe_icode_range \
- hipe_icode_split_arith \
- hipe_icode_ssa hipe_icode_ssa_const_prop hipe_icode_call_elim \
- hipe_icode_ssa_copy_prop hipe_icode_ssa_struct_reuse \
- hipe_icode_type $(HIPE_MODULES)
-
-MODULES = $(DOC_MODULES) hipe_icode_ebb hipe_icode_mulret
-
-HRL_FILES=hipe_icode.hrl hipe_icode_primops.hrl hipe_icode_type.hrl
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_unused_import +warn_export_vars +warn_missing_spec # +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/icode"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/icode"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-$(EBIN)/hipe_beam_to_icode.beam: hipe_icode_primops.hrl ../main/hipe.hrl ../../compiler/src/beam_disasm.hrl
-$(EBIN)/hipe_icode.beam: ../main/hipe.hrl
-$(EBIN)/hipe_icode_bincomp.beam: ../flow/cfg.hrl
-$(EBIN)/hipe_icode_callgraph.beam: hipe_icode_primops.hrl
-$(EBIN)/hipe_icode_cfg.beam: ../flow/hipe_bb.hrl ../flow/cfg.hrl ../flow/cfg.inc ../main/hipe.hrl
-$(EBIN)/hipe_icode_ebb.beam: ../flow/cfg.hrl ../flow/ebb.inc
-$(EBIN)/hipe_icode_exceptions.beam: ../flow/cfg.hrl
-$(EBIN)/hipe_icode_fp.beam: ../flow/cfg.hrl
-$(EBIN)/hipe_icode_heap_test.beam: ../main/hipe.hrl hipe_icode_primops.hrl ../flow/cfg.hrl ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_icode_inline_bifs.beam: ../flow/cfg.hrl
-$(EBIN)/hipe_icode_instruction_counter.beam: ../main/hipe.hrl ../flow/cfg.hrl
-$(EBIN)/hipe_icode_liveness.beam: ../flow/cfg.hrl ../flow/liveness.inc
-$(EBIN)/hipe_icode_mulret.beam: ../main/hipe.hrl hipe_icode_primops.hrl
-$(EBIN)/hipe_icode_primops.beam: hipe_icode_primops.hrl
-$(EBIN)/hipe_icode_range.beam: ../main/hipe.hrl ../flow/cfg.hrl hipe_icode_primops.hrl
-$(EBIN)/hipe_icode_split_arith.beam: ../main/hipe.hrl hipe_icode.hrl ../flow/cfg.hrl
-$(EBIN)/hipe_icode_ssa.beam: ../main/hipe.hrl ../ssa/hipe_ssa.inc ../ssa/hipe_ssa_liveness.inc
-$(EBIN)/hipe_icode_ssa_const_prop.beam: ../main/hipe.hrl hipe_icode_primops.hrl ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc
-$(EBIN)/hipe_icode_ssa_copy_prop.beam: ../flow/cfg.hrl ../ssa/hipe_ssa_copy_prop.inc
-$(EBIN)/hipe_icode_type.beam: hipe_icode_primops.hrl ../flow/cfg.hrl hipe_icode_type.hrl
-$(EBIN)/hipe_icode_ssa_struct_reuse.beam: ../main/hipe.hrl hipe_icode_primops.hrl ../flow/cfg.hrl
-
-$(TARGET_FILES): hipe_icode.hrl ../misc/hipe_consttab.hrl
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
deleted file mode 100644
index 97d50eb472..0000000000
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ /dev/null
@@ -1,2494 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%=======================================================================
-%% File : hipe_beam_to_icode.erl
-%% Author : Kostis Sagonas
-%% Description : Translates symbolic BEAM code to Icode
-%%=======================================================================
-%% @doc
-%% This file translates symbolic BEAM code to Icode which is HiPE's
-%% intermediate code representation. Either the code of an entire
-%% module, or the code of a specified function can be translated.
-%% @end
-%%=======================================================================
-
--module(hipe_beam_to_icode).
-
--export([module/2]).
-
-%%-----------------------------------------------------------------------
-
-%% Uncomment the following lines to turn on debugging for this module
-%% or comment them to it turn off. Debug-level 6 inserts a print in
-%% each compiled function.
-%%
-%%-ifndef(DEBUG).
-%%-define(DEBUG,6).
-%% Choose one of two tracing methods
-%%-define(DEBUG_BIF_CALL_TRACE,true).
-%%-define(IO_FORMAT_CALL_TRACE,true).
-%%-endif.
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
--include("../../compiler/src/beam_disasm.hrl").
-
--define(no_debug_msg(Str,Xs),ok).
-%%-define(no_debug_msg(Str,Xs),msg(Str,Xs)).
-
--ifdef(DEBUG_BIF_CALL_TRACE).
-
-%% Use BIF hipe_bifs_debug_native_called_2 to trace function calls
-mk_debug_calltrace({_M,_F,A}=MFA, Env, Code) ->
- MFAVar = mk_var(new),
- Ignore = mk_var(new),
- MkMfa = hipe_icode:mk_move(MFAVar,hipe_icode:mk_const(MFA)),
- Args = [mk_var({x,I-1}) || I <- lists:seq(1,A)],
- ArgTup = mk_var(new),
- MkArgTup = hipe_icode:mk_primop([ArgTup], mktuple, Args),
- Call = hipe_icode:mk_primop([Ignore], debug_native_called,
- [MFAVar,ArgTup]),
- {[MkMfa,MkArgTup,Call | Code], Env}.
-
--endif.
-
--ifdef(IO_FORMAT_CALL_TRACE).
-
-%% Use io:format to trace function calls
-mk_debug_calltrace(MFA, Env, Code) ->
- case MFA of
- {io,_,_} ->
- %% We do not want to loop infinitely if we are compiling
- %% the module io.
- {Code,Env};
- {M,F,A} ->
- MFAVar = mk_var(new),
- StringVar = mk_var(new),
- Ignore = mk_var(new),
- MkMfa = hipe_icode:mk_move(MFAVar,hipe_icode:mk_const([MFA])),
- MkString = hipe_icode:mk_move(StringVar,
- hipe_icode:mk_const(
- atom_to_list(M) ++ ":" ++ atom_to_list(F) ++"/"++ integer_to_list(A) ++
- " Native enter fun ~w\n")),
- Call =
- hipe_icode:mk_call([Ignore],io,format,[StringVar,MFAVar],remote),
- {[MkMfa,MkString,Call | Code], Env}
- end.
--endif.
-
-
-%%-----------------------------------------------------------------------
-%% Types
-%%-----------------------------------------------------------------------
-
--type hipe_beam_to_icode_ret() :: [{mfa(),#icode{}}].
-
-%%-----------------------------------------------------------------------
-%% Internal data structures
-%%-----------------------------------------------------------------------
-
--record(beam_const, {value :: simple_const()}). % defined in hipe_icode.hrl
-
--record(closure_info, {mfa :: mfa(), arity :: arity(), fv_arity :: arity()}).
-
--record(environment, {mfa :: mfa(), entry :: non_neg_integer()}).
-
-
-%%-----------------------------------------------------------------------
-%% @doc
-%% Translates the code of a whole module into Icode.
-%% Returns a tuple whose first argument is a list of {{M,F,A}, ICode}
-%% pairs, and its second argument is the list of HiPE compiler options.
-%% @end
-%%-----------------------------------------------------------------------
-
--spec module([#function{}], comp_options()) -> hipe_beam_to_icode_ret().
-
-module(BeamFuns, Options) ->
- BeamCode0 = [beam_disasm:function__code(F) || F <- BeamFuns],
- {ModCode, ClosureInfo} = preprocess_code(BeamCode0),
- pp_beam(ModCode, Options),
- [trans_beam_function_chunk(FunCode, ClosureInfo) || FunCode <- ModCode].
-
-trans_beam_function_chunk(FunBeamCode, ClosureInfo) ->
- {M,F,A} = MFA = find_mfa(FunBeamCode),
- Icode = trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo),
- {MFA,Icode}.
-
-%%-----------------------------------------------------------------------
-%% The main translation function.
-%%-----------------------------------------------------------------------
-
-trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
- ?no_debug_msg("disassembling: {~p,~p,~p} ...", [M,F,A]),
- hipe_gensym:init(icode),
- %% Extract the function arguments
- FunArgs = extract_fun_args(A),
- %% Record the function arguments
- FunLbl = mk_label(new),
- Env1 = env__mk_env(M, F, A, hipe_icode:label_name(FunLbl)),
- Code1 = lists:flatten(trans_fun(FunBeamCode,Env1)),
- Code2 = fix_fallthroughs(fix_catches(Code1)),
- MFA = {M,F,A},
- %% Debug code
- ?IF_DEBUG_LEVEL(5,
- {Code3,_Env3} = mk_debug_calltrace(MFA, Env1, Code2),
- {Code3,_Env3} = {Code2,Env1}),
- %% For stack optimization
- IsClosure = get_closure_info(MFA, ClosureInfo) =/= not_a_closure,
- Leafness = leafness(Code3, IsClosure),
- IsLeaf = is_leaf_code(Leafness),
- Code4 =
- [FunLbl |
- case needs_redtest(Leafness) of
- false -> Code3;
- true -> [mk_redtest()|Code3]
- end],
- Code5 = hipe_icode:mk_icode(MFA, FunArgs, IsClosure, IsLeaf,
- remove_dead_code(Code4),
- hipe_gensym:var_range(icode),
- hipe_gensym:label_range(icode)),
- Icode = %% If this function is the code for a closure ...
- case get_closure_info(MFA, ClosureInfo) of
- not_a_closure -> Code5;
- CI -> %% ... then patch the code to
- %% get the free_vars from the closure
- patch_closure_entry(Code5, CI)
- end,
- ?no_debug_msg("ok~n", []),
- Icode.
-
-mk_redtest() -> hipe_icode:mk_primop([], redtest, []).
-
-leafness(Is, IsClosure) -> % -> true, selfrec, closure, or false
- leafness(Is, IsClosure, true).
-
-leafness([], _IsClosure, Leafness) ->
- Leafness;
-leafness([I|Is], IsClosure, Leafness) ->
- case I of
- #icode_comment{} ->
- %% BEAM self-tailcalls become gotos, but they leave
- %% a trace behind in comments. Check those to ensure
- %% that the computed leafness is correct. Needed to
- %% prevent redtest elimination in those cases.
- NewLeafness =
- case hipe_icode:comment_text(I) of
- 'tail_recursive' -> selfrec; % call_last to selfrec
- 'self_tail_recursive' -> selfrec; % call_only to selfrec
- _ -> Leafness
- end,
- leafness(Is, IsClosure, NewLeafness);
- #icode_call{} ->
- case hipe_icode:call_type(I) of
- 'primop' ->
- case hipe_icode:call_fun(I) of
- call_fun -> false; % Calls closure
- enter_fun -> false; % Calls closure
- #apply_N{} -> false;
- _ -> leafness(Is, IsClosure, Leafness) % Other primop calls are ok
- end;
- T when T =:= 'local' orelse T =:= 'remote' ->
- {M,F,A} = hipe_icode:call_fun(I),
- case erlang:is_builtin(M, F, A) of
- true -> leafness(Is, IsClosure, Leafness);
- false -> false
- end
- end;
- #icode_enter{} ->
- case hipe_icode:enter_type(I) of
- 'primop' ->
- case hipe_icode:enter_fun(I) of
- enter_fun -> false;
- #apply_N{} -> false;
- _ ->
- %% All primops should be ok except those excluded above,
- %% except we don't actually tailcall them...
- io:format("leafness: unexpected enter to primop ~w\n", [I]),
- true
- end;
- T when T =:= 'local' orelse T =:= 'remote' ->
- {M,F,A} = hipe_icode:enter_fun(I),
- case erlang:is_builtin(M, F, A) of
- true -> leafness(Is, IsClosure, Leafness);
- _ when IsClosure -> leafness(Is, IsClosure, closure);
- _ -> false
- end
- end;
- _ -> leafness(Is, IsClosure, Leafness)
- end.
-
-%% XXX: this old stuff is passed around but essentially unused
-is_leaf_code(Leafness) ->
- case Leafness of
- true -> true;
- selfrec -> true;
- closure -> false;
- false -> false
- end.
-
-needs_redtest(Leafness) ->
- case Leafness of
- true -> false;
- %% A "leaf" closure may contain tailcalls to non-closures in addition to
- %% what other leaves may contain. Omitting the redtest is useful to generate
- %% shorter code for closures generated by (fun F/A), and is safe since
- %% control flow cannot return to a "leaf" closure again without a reduction
- %% being consumed. This is true since no function that can call a closure
- %% will ever have its redtest omitted.
- closure -> false;
- selfrec -> true;
- false -> true
- end.
-
-%%-----------------------------------------------------------------------
-%% The main translation switch.
-%%-----------------------------------------------------------------------
-
-%%--- label & func_info combo ---
-trans_fun([{label,_}=F,{func_info,_,_,_}=FI|Instructions], Env) ->
- %% Handle old code without a line instruction.
- trans_fun([F,{line,[]},FI|Instructions], Env);
-trans_fun([{label,B},{label,_},
- {func_info,M,F,A},{label,L}|Instructions], Env) ->
- trans_fun([{label,B},{func_info,M,F,A},{label,L}|Instructions], Env);
-trans_fun([{label,B},
- {line,_},
- {func_info,{atom,_M},{atom,_F},_A},
- {label,L}|Instructions], Env) ->
- %% Emit code to handle function_clause errors. The BEAM test instructions
- %% branch to this label if they fail during function clause selection.
- %% Obviously, we must goto past this error point on normal entry.
- Begin = mk_label(B),
- V = mk_var(new),
- EntryPt = mk_label(L),
- Goto = hipe_icode:mk_goto(hipe_icode:label_name(EntryPt)),
- Mov = hipe_icode:mk_move(V, hipe_icode:mk_const(function_clause)),
- Fail = hipe_icode:mk_fail([V],error),
- [Goto, Begin, Mov, Fail, EntryPt | trans_fun(Instructions, Env)];
-%%--- label ---
-trans_fun([{label,L1},{label,L2}|Instructions], Env) ->
- %% Old BEAM code can have two consecutive labels.
- Lab1 = mk_label(L1),
- Lab2 = mk_label(L2),
- Goto = hipe_icode:mk_goto(map_label(L2)),
- [Lab1, Goto, Lab2 | trans_fun(Instructions, Env)];
-trans_fun([{label,L}|Instructions], Env) ->
- [mk_label(L) | trans_fun(Instructions, Env)];
-%%--- int_code_end --- SHOULD NEVER OCCUR HERE
-%%--- call ---
-trans_fun([{call,_N,{_M,_F,A}=MFA}|Instructions], Env) ->
- Args = extract_fun_args(A),
- Dst = [mk_var({r,0})],
- I = trans_call(MFA, Dst, Args, local),
- [I | trans_fun(Instructions, Env)];
-%%--- call_last ---
-%% Differs from call_only in that it deallocates the environment
-trans_fun([{call_last,_N,{_M,_F,A}=MFA,_}|Instructions], Env) ->
- %% IS IT OK TO IGNORE LAST ARG ??
- ?no_debug_msg(" translating call_last: ~p ...~n", [Env]),
- case env__get_mfa(Env) of
- MFA ->
- %% Does this case really happen, or is it covered by call_only?
- Entry = env__get_entry(Env),
- [hipe_icode:mk_comment('tail_recursive'), % needed by leafness/2
- hipe_icode:mk_goto(Entry) | trans_fun(Instructions,Env)];
- _ ->
- Args = extract_fun_args(A),
- I = trans_enter(MFA, Args, local),
- [I | trans_fun(Instructions, Env)]
- end;
-%%--- call_only ---
-%% Used when the body contains only one call in which case
-%% an environment is not needed/created.
-trans_fun([{call_only,_N,{_M,_F,A}=MFA}|Instructions], Env) ->
- ?no_debug_msg(" translating call_only: ~p ...~n", [Env]),
- case env__get_mfa(Env) of
- MFA ->
- Entry = env__get_entry(Env),
- [hipe_icode:mk_comment('self_tail_recursive'), % needed by leafness/2
- hipe_icode:mk_goto(Entry) | trans_fun(Instructions,Env)];
- _ ->
- Args = extract_fun_args(A),
- I = trans_enter(MFA,Args,local),
- [I | trans_fun(Instructions,Env)]
- end;
-%%--- call_ext ---
-trans_fun([{call_ext,_N,{extfunc,M,F,A}}|Instructions], Env) ->
- Args = extract_fun_args(A),
- Dst = [mk_var({r,0})],
- I = trans_call({M,F,A},Dst,Args,remote),
- [hipe_icode:mk_comment('call_ext'),I | trans_fun(Instructions,Env)];
-%%--- call_ext_last ---
-trans_fun([{call_ext_last,_N,{extfunc,M,F,A},_}|Instructions], Env) ->
- %% IS IT OK TO IGNORE LAST ARG ??
- Args = extract_fun_args(A),
- %% Dst = [mk_var({r,0})],
- I = trans_enter({M,F,A},Args,remote),
- [hipe_icode:mk_comment('call_ext_last'), I | trans_fun(Instructions,Env)];
-%%--- bif0 ---
-trans_fun([{bif,BifName,nofail,[],Reg}|Instructions], Env) ->
- BifInst = trans_bif0(BifName,Reg),
- [BifInst|trans_fun(Instructions,Env)];
-%%--- bif1 ---
-trans_fun([{bif,BifName,{f,Lbl},[_] = Args,Reg}|Instructions], Env) ->
- {BifInsts,Env1} = trans_bif(1,BifName,Lbl,Args,Reg,Env),
- BifInsts ++ trans_fun(Instructions,Env1);
-%%--- bif2 ---
-trans_fun([{bif,BifName,{f,Lbl},[_,_] = Args,Reg}|Instructions], Env) ->
- {BifInsts,Env1} = trans_bif(2,BifName,Lbl,Args,Reg,Env),
- BifInsts ++ trans_fun(Instructions,Env1);
-%%--- bif3 ---
-trans_fun([{bif,BifName,{f,Lbl},[_,_,_] = Args,Reg}|Instructions], Env) ->
- {BifInsts,Env1} = trans_bif(3,BifName,Lbl,Args,Reg,Env),
- BifInsts ++ trans_fun(Instructions,Env1);
-%%--- allocate
-trans_fun([{allocate,StackSlots,_}|Instructions], Env) ->
- trans_allocate(StackSlots) ++ trans_fun(Instructions,Env);
-%%--- allocate_heap
-trans_fun([{allocate_heap,StackSlots,_,_}|Instructions], Env) ->
- trans_allocate(StackSlots) ++ trans_fun(Instructions,Env);
-%%--- allocate_zero
-trans_fun([{allocate_zero,StackSlots,_}|Instructions], Env) ->
- trans_allocate(StackSlots) ++ trans_fun(Instructions,Env);
-%%--- allocate_heap_zero
-trans_fun([{allocate_heap_zero,StackSlots,_,_}|Instructions], Env) ->
- trans_allocate(StackSlots) ++ trans_fun(Instructions,Env);
-%%--- test_heap --- IGNORED ON PURPOSE
-trans_fun([{test_heap,_,_}|Instructions], Env) ->
- trans_fun(Instructions,Env);
-%%--- init --- IGNORED - CORRECT??
-trans_fun([{init,_}|Instructions], Env) ->
- trans_fun(Instructions,Env);
-%%--- deallocate --- IGNORED ON PURPOSE
-trans_fun([{deallocate,_}|Instructions], Env) ->
- trans_fun(Instructions,Env);
-%%--- return ---
-trans_fun([return|Instructions], Env) ->
- [hipe_icode:mk_return([mk_var({r,0})]) | trans_fun(Instructions,Env)];
-%%--- send ---
-trans_fun([send|Instructions], Env) ->
- I = hipe_icode:mk_call([mk_var({r,0})], erlang, send,
- [mk_var({x,0}),mk_var({x,1})], remote),
- [I | trans_fun(Instructions,Env)];
-%%--- remove_message ---
-trans_fun([remove_message|Instructions], Env) ->
- [hipe_icode:mk_primop([],select_msg,[]) | trans_fun(Instructions,Env)];
-%%--- timeout ---
-trans_fun([timeout|Instructions], Env) ->
- [hipe_icode:mk_primop([],clear_timeout,[]) | trans_fun(Instructions,Env)];
-%%--- loop_rec ---
-trans_fun([{loop_rec,{_,Lbl},Reg}|Instructions], Env) ->
- {Movs,[Temp],Env1} = get_constants_in_temps([Reg],Env),
- GotitLbl = mk_label(new),
- ChkGetMsg = hipe_icode:mk_primop([Temp],check_get_msg,[],
- hipe_icode:label_name(GotitLbl),
- map_label(Lbl)),
- Movs ++ [ChkGetMsg, GotitLbl | trans_fun(Instructions,Env1)];
-%%--- loop_rec_end ---
-trans_fun([{loop_rec_end,{_,Lbl}}|Instructions], Env) ->
- Loop = hipe_icode:mk_goto(map_label(Lbl)),
- [hipe_icode:mk_primop([],next_msg,[]), Loop | trans_fun(Instructions,Env)];
-%%--- wait ---
-trans_fun([{wait,{_,Lbl}}|Instructions], Env) ->
- Susp = hipe_icode:mk_primop([],suspend_msg,[]),
- Loop = hipe_icode:mk_goto(map_label(Lbl)),
- [Susp, Loop | trans_fun(Instructions,Env)];
-%%--- wait_timeout ---
-trans_fun([{wait_timeout,{_,Lbl},Reg}|Instructions], Env) ->
- {Movs,[_]=Temps,Env1} = get_constants_in_temps([Reg],Env),
- SetTmout = hipe_icode:mk_primop([],set_timeout,Temps),
- DoneLbl = mk_label(new),
- SuspTmout = hipe_icode:mk_if(suspend_msg_timeout,[],
- map_label(Lbl),hipe_icode:label_name(DoneLbl)),
- Movs ++ [SetTmout, SuspTmout, DoneLbl | trans_fun(Instructions,Env1)];
-%%--- recv_mark/1 & recv_set/1 ---
-trans_fun([{recv_mark,{f,_}}|Instructions], Env) ->
- Mark = hipe_icode:mk_primop([],recv_mark,[]),
- [Mark | trans_fun(Instructions,Env)];
-trans_fun([{recv_set,{f,_}}|Instructions], Env) ->
- Set = hipe_icode:mk_primop([],recv_set,[]),
- [Set | trans_fun(Instructions,Env)];
-%%--------------------------------------------------------------------
-%%--- Translation of arithmetics {bif,ArithOp, ...} ---
-%%--------------------------------------------------------------------
-trans_fun([{arithbif,ArithOp,{f,L},SrcRs,DstR}|Instructions], Env) ->
- {ICode,NewEnv} = trans_arith(ArithOp,SrcRs,DstR,L,Env),
- ICode ++ trans_fun(Instructions,NewEnv);
-%%--------------------------------------------------------------------
-%%--- Translation of arithmetic tests {test,is_ARITHTEST, ...} ---
-%%--------------------------------------------------------------------
-%%--- is_lt ---
-trans_fun([{test,is_lt,{f,Lbl},[Arg1,Arg2]}|Instructions], Env) ->
- {ICode,Env1} = trans_test_guard('<',Lbl,Arg1,Arg2,Env),
- ICode ++ trans_fun(Instructions,Env1);
-%%--- is_ge ---
-trans_fun([{test,is_ge,{f,Lbl},[Arg1,Arg2]}|Instructions], Env) ->
- {ICode,Env1} = trans_test_guard('>=',Lbl,Arg1,Arg2,Env),
- ICode ++ trans_fun(Instructions,Env1);
-%%--- is_eq ---
-trans_fun([{test,is_eq,{f,Lbl},[Arg1,Arg2]}|Instructions], Env) ->
- {ICode,Env1} = trans_is_eq(Lbl,Arg1,Arg2,Env),
- ICode ++ trans_fun(Instructions,Env1);
-%%--- is_ne ---
-trans_fun([{test,is_ne,{f,Lbl},[Arg1,Arg2]}|Instructions], Env) ->
- {ICode,Env1} = trans_is_ne(Lbl,Arg1,Arg2,Env),
- ICode ++ trans_fun(Instructions,Env1);
-%%--- is_eq_exact ---
-trans_fun([{test,is_eq_exact,{f,Lbl},[Arg1,Arg2]}|Instructions], Env) ->
- {ICode,Env1} = trans_is_eq_exact(Lbl,Arg1,Arg2,Env),
- ICode ++ trans_fun(Instructions,Env1);
-%%--- is_ne_exact ---
-trans_fun([{test,is_ne_exact,{f,Lbl},[Arg1,Arg2]}|Instructions], Env) ->
- {ICode,Env1} = trans_is_ne_exact(Lbl,Arg1,Arg2,Env),
- ICode ++ trans_fun(Instructions,Env1);
-%%--------------------------------------------------------------------
-%%--- Translation of type tests {test,is_TYPE, ...} ---
-%%--------------------------------------------------------------------
-%%--- is_integer ---
-trans_fun([{test,is_integer,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(integer,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_float ---
-trans_fun([{test,is_float,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(float,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_number ---
-trans_fun([{test,is_number,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(number,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_atom ---
-trans_fun([{test,is_atom,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(atom,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_pid ---
-trans_fun([{test,is_pid,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(pid,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_ref ---
-trans_fun([{test,is_reference,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(reference,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_port ---
-trans_fun([{test,is_port,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(port,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_nil ---
-trans_fun([{test,is_nil,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(nil,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_binary ---
-trans_fun([{test,is_binary,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(binary,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_list ---
-trans_fun([{test,is_list,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(list,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_nonempty_list ---
-trans_fun([{test,is_nonempty_list,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(cons,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- is_tuple ---
-trans_fun([{test,is_tuple,{f,_Lbl}=FLbl,[Xreg]},
- {test,test_arity,FLbl,[Xreg,_]=Args}|Instructions], Env) ->
- trans_fun([{test,test_arity,FLbl,Args}|Instructions],Env);
-trans_fun([{test,is_tuple,{_,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(tuple,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- test_arity ---
-trans_fun([{test,test_arity,{f,Lbl},[Reg,N]}|Instructions], Env) ->
- True = mk_label(new),
- I = hipe_icode:mk_type([trans_arg(Reg)],{tuple,N},
- hipe_icode:label_name(True),map_label(Lbl)),
- [I,True | trans_fun(Instructions,Env)];
-%%--- test_is_tagged_tuple ---
-trans_fun([{test,is_tagged_tuple,{f,Lbl},[Reg,N,Atom]}|Instructions], Env) ->
- TrueArity = mk_label(new),
- IArity = hipe_icode:mk_type([trans_arg(Reg)],{tuple,N},
- hipe_icode:label_name(TrueArity),map_label(Lbl)),
- Var = hipe_icode:mk_new_var(),
- IGet = hipe_icode:mk_primop([Var],
- #unsafe_element{index=1},
- [trans_arg(Reg)]),
- TrueAtom = mk_label(new),
- IEQ = hipe_icode:mk_type([Var], Atom, hipe_icode:label_name(TrueAtom),
- map_label(Lbl)),
- [IArity,TrueArity,IGet,IEQ,TrueAtom | trans_fun(Instructions,Env)];
-%%--- is_map ---
-trans_fun([{test,is_map,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(map,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--------------------------------------------------------------------
-%%--- select_val ---
-trans_fun([{select_val,Reg,{f,Lbl},{list,Cases}}|Instructions], Env) ->
- {SwVar,CasePairs} = trans_select_stuff(Reg,Cases),
- Len = length(CasePairs),
- I = hipe_icode:mk_switch_val(SwVar,map_label(Lbl),Len,CasePairs),
- ?no_debug_msg("switch_val instr is ~p~n",[I]),
- [I | trans_fun(Instructions,Env)];
-%%--- select_tuple_arity ---
-trans_fun([{select_tuple_arity,Reg,{f,Lbl},{list,Cases}}|Instructions],Env) ->
- {SwVar,CasePairs} = trans_select_stuff(Reg,Cases),
- Len = length(CasePairs),
- I = hipe_icode:mk_switch_tuple_arity(SwVar,map_label(Lbl),Len,CasePairs),
- ?no_debug_msg("switch_tuple_arity instr is ~p~n",[I]),
- [I | trans_fun(Instructions,Env)];
-%%--- jump ---
-trans_fun([{jump,{_,L}}|Instructions], Env) ->
- Label = mk_label(L),
- I = hipe_icode:mk_goto(hipe_icode:label_name(Label)),
- [I | trans_fun(Instructions,Env)];
-%%--- move ---
-trans_fun([{move,Src,Dst}|Instructions], Env) ->
- Dst1 = mk_var(Dst),
- Src1 = trans_arg(Src),
- [hipe_icode:mk_move(Dst1,Src1) | trans_fun(Instructions,Env)];
-%%--- catch --- ITS PROCESSING IS POSTPONED
-trans_fun([{'catch',N,{_,EndLabel}}|Instructions], Env) ->
- NewContLbl = mk_label(new),
- [{'catch',N,EndLabel},NewContLbl | trans_fun(Instructions,Env)];
-%%--- catch_end --- ITS PROCESSING IS POSTPONED
-trans_fun([{catch_end,_N}=I|Instructions], Env) ->
- [I | trans_fun(Instructions,Env)];
-%%--- try --- ITS PROCESSING IS POSTPONED
-trans_fun([{'try',N,{_,EndLabel}}|Instructions], Env) ->
- NewContLbl = mk_label(new),
- [{'try',N,EndLabel},NewContLbl | trans_fun(Instructions,Env)];
-%%--- try_end ---
-trans_fun([{try_end,_N}|Instructions], Env) ->
- [hipe_icode:mk_end_try() | trans_fun(Instructions,Env)];
-%%--- try_case --- ITS PROCESSING IS POSTPONED
-trans_fun([{try_case,_N}=I|Instructions], Env) ->
- [I | trans_fun(Instructions,Env)];
-%%--- try_case_end ---
-trans_fun([{try_case_end,Arg}|Instructions], Env) ->
- BadArg = trans_arg(Arg),
- ErrVar = mk_var(new),
- Vs = [mk_var(new)],
- Atom = hipe_icode:mk_move(ErrVar,hipe_icode:mk_const(try_clause)),
- Tuple = hipe_icode:mk_primop(Vs,mktuple,[ErrVar,BadArg]),
- Fail = hipe_icode:mk_fail(Vs,error),
- [Atom,Tuple,Fail | trans_fun(Instructions,Env)];
-%%--- raise ---
-trans_fun([{raise,{f,0},[Reg1,Reg2],{x,0}}|Instructions], Env) ->
- V1 = trans_arg(Reg1),
- V2 = trans_arg(Reg2),
- Fail = hipe_icode:mk_fail([V1,V2],rethrow),
- [Fail | trans_fun(Instructions,Env)];
-%%--- get_list ---
-trans_fun([{get_list,List,Head,Tail}|Instructions], Env) ->
- TransList = [trans_arg(List)],
- I1 = hipe_icode:mk_primop([mk_var(Head)],unsafe_hd,TransList),
- I2 = hipe_icode:mk_primop([mk_var(Tail)],unsafe_tl,TransList),
- %% Handle the cases where the dest overwrites the src!!
- if
- Head =/= List ->
- [I1, I2 | trans_fun(Instructions,Env)];
- Tail =/= List ->
- [I2, I1 | trans_fun(Instructions,Env)];
- true ->
- %% XXX: We should take care of this case!!!!!
- ?error_msg("hd and tl regs identical in get_list~n",[]),
- erlang:error(not_handled)
- end;
-%%--- get_hd ---
-trans_fun([{get_hd,List,Head}|Instructions], Env) ->
- TransList = [trans_arg(List)],
- I = hipe_icode:mk_primop([mk_var(Head)],unsafe_hd,TransList),
- [I | trans_fun(Instructions,Env)];
-%%--- get_tl ---
-trans_fun([{get_tl,List,Tail}|Instructions], Env) ->
- TransList = [trans_arg(List)],
- I = hipe_icode:mk_primop([mk_var(Tail)],unsafe_tl,TransList),
- [I | trans_fun(Instructions,Env)];
-%%--- get_tuple_element ---
-trans_fun([{get_tuple_element,Xreg,Index,Dst}|Instructions], Env) ->
- I = hipe_icode:mk_primop([mk_var(Dst)],
- #unsafe_element{index=Index+1},
- [trans_arg(Xreg)]),
- [I | trans_fun(Instructions,Env)];
-%%--- set_tuple_element ---
-trans_fun([{set_tuple_element,Elem,Tuple,Index}|Instructions], Env) ->
- Elem1 = trans_arg(Elem),
- I = hipe_icode:mk_primop([mk_var(Tuple)],
- #unsafe_update_element{index=Index+1},
- [mk_var(Tuple),Elem1]),
- [I | trans_fun(Instructions,Env)];
-%%--- put_string ---
-trans_fun([{put_string,_Len,String,Dst}|Instructions], Env) ->
- Mov = hipe_icode:mk_move(mk_var(Dst),trans_const(String)),
- [Mov | trans_fun(Instructions,Env)];
-%%--- put_list ---
-trans_fun([{put_list,Car,Cdr,Dest}|Instructions], Env) ->
- {M1,V1,Env2} = mk_move_and_var(Car,Env),
- {M2,V2,Env3} = mk_move_and_var(Cdr,Env2),
- D = mk_var(Dest),
- M1 ++ M2 ++ [hipe_icode:mk_primop([D],cons,[V1,V2])
- | trans_fun(Instructions,Env3)];
-%%--- put_tuple ---
-trans_fun([{put_tuple,_Size,Reg}|Instructions], Env) ->
- {Moves,Instructions2,Vars,Env2} = trans_puts(Instructions,Env),
- Dest = [mk_var(Reg)],
- Src = lists:reverse(Vars),
- Primop = hipe_icode:mk_primop(Dest,mktuple,Src),
- Moves ++ [Primop | trans_fun(Instructions2,Env2)];
-%%--- put --- SHOULD NOT REALLY EXIST HERE; put INSTRUCTIONS ARE HANDLED ABOVE.
-%%--- put_tuple2 ---
-trans_fun([{put_tuple2,Reg,{list,Elements}}|Instructions], Env) ->
- Dest = [mk_var(Reg)],
- {Moves,Vars,Env2} = trans_elements(Elements, [], [], Env),
- Src = lists:reverse(Vars),
- Primop = hipe_icode:mk_primop(Dest, mktuple, Src),
- Moves ++ [Primop | trans_fun(Instructions, Env2)];
-%%--- badmatch ---
-trans_fun([{badmatch,Arg}|Instructions], Env) ->
- BadVar = trans_arg(Arg),
- ErrVar = mk_var(new),
- Vs = [mk_var(new)],
- Atom = hipe_icode:mk_move(ErrVar,hipe_icode:mk_const(badmatch)),
- Tuple = hipe_icode:mk_primop(Vs,mktuple,[ErrVar,BadVar]),
- Fail = hipe_icode:mk_fail(Vs,error),
- [Atom,Tuple,Fail | trans_fun(Instructions,Env)];
-%%--- if_end ---
-trans_fun([if_end|Instructions], Env) ->
- V = mk_var(new),
- Mov = hipe_icode:mk_move(V,hipe_icode:mk_const(if_clause)),
- Fail = hipe_icode:mk_fail([V],error),
- [Mov,Fail | trans_fun(Instructions, Env)];
-%%--- case_end ---
-trans_fun([{case_end,Arg}|Instructions], Env) ->
- BadArg = trans_arg(Arg),
- ErrVar = mk_var(new),
- Vs = [mk_var(new)],
- Atom = hipe_icode:mk_move(ErrVar,hipe_icode:mk_const(case_clause)),
- Tuple = hipe_icode:mk_primop(Vs,mktuple,[ErrVar,BadArg]),
- Fail = hipe_icode:mk_fail(Vs,error),
- [Atom,Tuple,Fail | trans_fun(Instructions,Env)];
-%%--- enter_fun ---
-trans_fun([{call_fun,N},{deallocate,_},return|Instructions], Env) ->
- Args = extract_fun_args(N+1), %% +1 is for the fun itself
- [hipe_icode:mk_comment('enter_fun'),
- hipe_icode:mk_enter_primop(enter_fun,Args) | trans_fun(Instructions,Env)];
-%%--- call_fun ---
-trans_fun([{call_fun,N}|Instructions], Env) ->
- Args = extract_fun_args(N+1), %% +1 is for the fun itself
- Dst = [mk_var({r,0})],
- [hipe_icode:mk_comment('call_fun'),
- hipe_icode:mk_primop(Dst,call_fun,Args) | trans_fun(Instructions,Env)];
-%%--- make_fun2 ---
-trans_fun([{make_fun2,MFA,Index,Magic,FreeVarNum}|Instructions], Env) ->
- Args = extract_fun_args(FreeVarNum),
- Dst = [mk_var({r,0})],
- Fun = hipe_icode:mk_primop(Dst,
- #mkfun{mfa=MFA,magic_num=Magic,index=Index},
- Args),
- ?no_debug_msg("mkfun translates to: ~p~n",[Fun]),
- [Fun | trans_fun(Instructions,Env)];
-%%--- is_function ---
-trans_fun([{test,is_function,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(function,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--- call_ext_only ---
-trans_fun([{call_ext_only,_N,{extfunc,M,F,A}}|Instructions], Env) ->
- Args = extract_fun_args(A),
- I = trans_enter({M,F,A}, Args, remote),
- [hipe_icode:mk_comment('call_ext_only'), I | trans_fun(Instructions,Env)];
-%%--------------------------------------------------------------------
-%%--- Translation of binary instructions ---
-%%--------------------------------------------------------------------
-%% This code uses a somewhat unorthodox translation:
-%% Since we do not want non-erlang values as arguments to Icode
-%% instructions some compile time constants are coded into the
-%% name of the function (or rather the primop).
-%% TODO: Make sure all cases of argument types are covered.
-%%--------------------------------------------------------------------
-trans_fun([{test,bs_start_match2,{f,Lbl},[X,_Live,Max,Ms]}|Instructions], Env) ->
- Bin = trans_arg(X),
- MsVar = mk_var(Ms),
- trans_op_call({hipe_bs_primop, {bs_start_match, Max}}, Lbl, [Bin],
- [MsVar], Env, Instructions);
-trans_fun([{test,bs_get_float2,{f,Lbl},[Ms,_Live,Size,Unit,{field_flags,Flags0},X]}|
- Instructions], Env) ->
- Dst = mk_var(X),
- MsVar = mk_var(Ms),
- Flags = resolve_native_endianess(Flags0),
- {Name, Args} =
- case Size of
- {integer, NoBits} when is_integer(NoBits), NoBits >= 0 ->
- {{bs_get_float,NoBits*Unit,Flags}, [MsVar]};
- {integer, NoBits} when is_integer(NoBits), NoBits < 0 ->
- ?EXIT({bad_bs_size_constant,Size});
- BitReg ->
- Bits = mk_var(BitReg),
- {{bs_get_float,Unit,Flags}, [MsVar,Bits]}
- end,
- trans_op_call({hipe_bs_primop,Name}, Lbl, Args, [Dst,MsVar], Env, Instructions);
-trans_fun([{test,bs_get_integer2,{f,Lbl},[Ms,_Live,Size,Unit,{field_flags,Flags0},X]}|
- Instructions], Env) ->
- Dst = mk_var(X),
- MsVar = mk_var(Ms),
- Flags = resolve_native_endianess(Flags0),
- {Name, Args} =
- case Size of
- {integer,NoBits} when is_integer(NoBits), NoBits >= 0 ->
- {{bs_get_integer,NoBits*Unit,Flags}, [MsVar]};
- {integer,NoBits} when is_integer(NoBits), NoBits < 0 ->
- ?EXIT({bad_bs_size_constant,Size});
- BitReg ->
- Bits = mk_var(BitReg),
- {{bs_get_integer,Unit,Flags}, [MsVar,Bits]}
- end,
- trans_op_call({hipe_bs_primop,Name}, Lbl, Args, [Dst,MsVar], Env, Instructions);
-trans_fun([{test,bs_get_binary2,{f,Lbl},[Ms,_Live,Size,Unit,{field_flags,Flags},X]}|
- Instructions], Env) ->
- MsVar = mk_var(Ms),
- {Name, Args, Dsts} =
- case Size of
- {atom, all} -> %% put all bits
- if Ms =:= X ->
- {{bs_get_binary_all,Unit,Flags},[MsVar],[mk_var(X)]};
- true ->
- {{bs_get_binary_all_2,Unit,Flags},[MsVar],[mk_var(X),MsVar]}
- end;
- {integer, NoBits} when is_integer(NoBits), NoBits >= 0 ->
- {{bs_get_binary,NoBits*Unit,Flags}, [MsVar], [mk_var(X),MsVar]};%% Create a N*Unit bits subbinary
- {integer, NoBits} when is_integer(NoBits), NoBits < 0 ->
- ?EXIT({bad_bs_size_constant,Size});
- BitReg -> % Use a number of bits only known at runtime.
- Bits = mk_var(BitReg),
- {{bs_get_binary,Unit,Flags}, [MsVar,Bits], [mk_var(X),MsVar]}
- end,
- trans_op_call({hipe_bs_primop,Name}, Lbl, Args, Dsts, Env, Instructions);
-trans_fun([{test,bs_skip_bits2,{f,Lbl},[Ms,Size,NumBits,{field_flags,Flags}]}|
- Instructions], Env) ->
- %% the current match buffer
- MsVar = mk_var(Ms),
- {Name, Args} =
- case Size of
- {atom, all} -> %% Skip all bits
- {{bs_skip_bits_all,NumBits,Flags},[MsVar]};
- {integer, BitSize} when is_integer(BitSize), BitSize >= 0-> %% Skip N bits
- {{bs_skip_bits,BitSize*NumBits}, [MsVar]};
- {integer, BitSize} when is_integer(BitSize), BitSize < 0 ->
- ?EXIT({bad_bs_size_constant,Size});
- X -> % Skip a number of bits only known at runtime.
- Src = mk_var(X),
- {{bs_skip_bits,NumBits},[MsVar,Src]}
- end,
- trans_op_call({hipe_bs_primop,Name}, Lbl, Args, [MsVar], Env, Instructions);
-trans_fun([{test,bs_test_unit,{f,Lbl},[Ms,Unit]}|
- Instructions], Env) ->
- %% the current match buffer
- MsVar = mk_var(Ms),
- trans_op_call({hipe_bs_primop,{bs_test_unit,Unit}}, Lbl,
- [MsVar], [], Env, Instructions);
-trans_fun([{test,bs_match_string,{f,Lbl},[Ms,BitSize,Bin]}|
- Instructions], Env) ->
- %% the current match buffer
- MsVar = mk_var(Ms),
- Primop = {hipe_bs_primop, {bs_match_string, Bin, BitSize}},
- trans_op_call(Primop, Lbl, [MsVar], [MsVar], Env, Instructions);
-trans_fun([{bs_context_to_binary,Var}|Instructions], Env) ->
- %% the current match buffer
- IVars = [trans_arg(Var)],
- [hipe_icode:mk_primop(IVars,{hipe_bs_primop,bs_context_to_binary},IVars)|
- trans_fun(Instructions, Env)];
-trans_fun([{bs_append,{f,Lbl},Size,W,R,U,Binary,{field_flags,F},Dst}|
- Instructions], Env) ->
- %% the current match buffer
- SizeArg = trans_arg(Size),
- BinArg = trans_arg(Binary),
- IcodeDst = mk_var(Dst),
- Offset = mk_var(reg_gcsafe),
- Base = mk_var(reg),
- trans_bin_call({hipe_bs_primop,{bs_append,W,R,U,F}},Lbl,[SizeArg,BinArg],
- [IcodeDst,Base,Offset],
- Base, Offset, Env, Instructions);
-trans_fun([{bs_private_append,{f,Lbl},Size,U,Binary,{field_flags,F},Dst}|
- Instructions], Env) ->
- %% the current match buffer
- SizeArg = trans_arg(Size),
- BinArg = trans_arg(Binary),
- IcodeDst = mk_var(Dst),
- Offset = mk_var(reg_gcsafe),
- Base = mk_var(reg),
- trans_bin_call({hipe_bs_primop,{bs_private_append,U,F}},
- Lbl,[SizeArg,BinArg],
- [IcodeDst,Base,Offset],
- Base, Offset, Env, Instructions);
-trans_fun([bs_init_writable|Instructions], Env) ->
- Vars = [mk_var({x,0})], %{x,0} is implict arg and dst
- [hipe_icode:mk_primop(Vars,{hipe_bs_primop,bs_init_writable},Vars),
- trans_fun(Instructions, Env)];
-trans_fun([{bs_save2,Ms,IndexName}|Instructions], Env) ->
- Index =
- case IndexName of
- {atom, start} -> 0;
- _ -> IndexName+1
- end,
- MsVars = [mk_var(Ms)],
- [hipe_icode:mk_primop(MsVars,{hipe_bs_primop,{bs_save,Index}},MsVars) |
- trans_fun(Instructions, Env)];
-trans_fun([{bs_restore2,Ms,IndexName}|Instructions], Env) ->
- Index =
- case IndexName of
- {atom, start} -> 0;
- _ -> IndexName+1
- end,
- MsVars = [mk_var(Ms)],
- [hipe_icode:mk_primop(MsVars,{hipe_bs_primop,{bs_restore,Index}},MsVars) |
- trans_fun(Instructions, Env)];
-trans_fun([{test,bs_test_tail2,{f,Lbl},[Ms,Numbits]}| Instructions], Env) ->
- MsVar = mk_var(Ms),
- trans_op_call({hipe_bs_primop,{bs_test_tail,Numbits}},
- Lbl, [MsVar], [], Env, Instructions);
-%%--------------------------------------------------------------------
-%% bit syntax instructions added in February 2004 (R10B).
-%%--------------------------------------------------------------------
-trans_fun([{bs_init2,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}|
- Instructions], Env) ->
- Dst = mk_var(X),
- Flags = resolve_native_endianess(Flags0),
- Offset = mk_var(reg_gcsafe),
- Base = mk_var(reg),
- {Name, Args} =
- case Size of
- NoBytes when is_integer(NoBytes) ->
- {{bs_init, Size, Flags}, []};
- BitReg ->
- Bits = mk_var(BitReg),
- {{bs_init, Flags}, [Bits]}
- end,
- trans_bin_call({hipe_bs_primop,Name}, Lbl, Args, [Dst, Base, Offset],
- Base, Offset, Env, Instructions);
-trans_fun([{bs_init_bits,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}|
- Instructions], Env) ->
- Dst = mk_var(X),
- Flags = resolve_native_endianess(Flags0),
- Offset = mk_var(reg_gcsafe),
- Base = mk_var(reg),
- {Name, Args} =
- case Size of
- NoBits when is_integer(NoBits) ->
- {{bs_init_bits, NoBits, Flags}, []};
- BitReg ->
- Bits = mk_var(BitReg),
- {{bs_init_bits, Flags}, [Bits]}
- end,
- trans_bin_call({hipe_bs_primop,Name}, Lbl, Args, [Dst, Base, Offset],
- Base, Offset, Env, Instructions);
-trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) ->
- Dst = mk_var(Res),
- Temp = mk_var(new),
- {FailLblName, FailCode} =
- if Lbl =:= 0 ->
- FailLbl = mk_label(new),
- {hipe_icode:label_name(FailLbl),
- [FailLbl,
- hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error)]};
- true ->
- {map_label(Lbl), []}
- end,
- MultIs =
- case {New,Unit} of
- {{integer, NewInt}, _} ->
- [hipe_icode:mk_move(Temp, hipe_icode:mk_const(NewInt*Unit))];
- {_, 1} ->
- NewVar = mk_var(New),
- [hipe_icode:mk_move(Temp, NewVar)];
- _ ->
- NewVar = mk_var(New),
- Succ = mk_label(new),
- [hipe_icode:mk_primop([Temp], '*',
- [NewVar, hipe_icode:mk_const(Unit)],
- hipe_icode:label_name(Succ), FailLblName),
- Succ]
- end,
- Succ2 = mk_label(new),
- IsPos =
- [hipe_icode:mk_if('>=', [Temp, hipe_icode:mk_const(0)],
- hipe_icode:label_name(Succ2), FailLblName)] ++
- FailCode ++ [Succ2],
- AddRhs =
- case Old of
- {integer,OldInt} -> hipe_icode:mk_const(OldInt);
- _ -> mk_var(Old)
- end,
- Succ3 = mk_label(new),
- AddI = hipe_icode:mk_primop([Dst], '+', [Temp, AddRhs],
- hipe_icode:label_name(Succ3), FailLblName),
- MultIs ++ IsPos ++ [AddI,Succ3|trans_fun(Instructions, Env)];
-%%--------------------------------------------------------------------
-%% Bit syntax instructions added in R12B-5 (Fall 2008)
-%%--------------------------------------------------------------------
-trans_fun([{bs_utf8_size,{f,Lbl},A2,A3}|Instructions], Env) ->
- Bin = trans_arg(A2),
- Dst = mk_var(A3),
- trans_op_call({hipe_bs_primop, bs_utf8_size}, Lbl, [Bin], [Dst], Env, Instructions);
-trans_fun([{test,bs_get_utf8,{f,Lbl},[Ms,_Live,{field_flags,_Flags},X]} |
- Instructions], Env) ->
- trans_bs_get_or_skip_utf8(Lbl, Ms, X, Instructions, Env);
-trans_fun([{test,bs_skip_utf8,{f,Lbl},[Ms,_Live,{field_flags,_Flags}]} |
- Instructions], Env) ->
- trans_bs_get_or_skip_utf8(Lbl, Ms, 'new', Instructions, Env);
-trans_fun([{bs_utf16_size,{f,Lbl},A2,A3}|Instructions], Env) ->
- Bin = trans_arg(A2),
- Dst = mk_var(A3),
- trans_op_call({hipe_bs_primop, bs_utf16_size}, Lbl, [Bin], [Dst], Env, Instructions);
-trans_fun([{test,bs_get_utf16,{f,Lbl},[Ms,_Live,{field_flags,Flags0},X]} |
- Instructions], Env) ->
- trans_bs_get_or_skip_utf16(Lbl, Ms, Flags0, X, Instructions, Env);
-trans_fun([{test,bs_skip_utf16,{f,Lbl},[Ms,_Live,{field_flags,Flags0}]} |
- Instructions], Env) ->
- trans_bs_get_or_skip_utf16(Lbl, Ms, Flags0, 'new', Instructions, Env);
-trans_fun([{test,bs_get_utf32,{f,Lbl},[Ms,_Live,{field_flags,Flags0},X]} | Instructions], Env) ->
- trans_bs_get_or_skip_utf32(Lbl, Ms, Flags0, X, Instructions, Env);
-trans_fun([{test,bs_skip_utf32,{f,Lbl},[Ms,_Live,{field_flags,Flags0}]} | Instructions], Env) ->
- trans_bs_get_or_skip_utf32(Lbl, Ms, Flags0, 'new', Instructions, Env);
-%%--------------------------------------------------------------------
-%%--- Translation of floating point instructions ---
-%%--------------------------------------------------------------------
-%%--- fclearerror ---
-trans_fun([fclearerror|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- [hipe_icode:mk_primop([], fclearerror, []) |
- trans_fun(Instructions,Env)];
- _ ->
- trans_fun(Instructions,Env)
- end;
-%%--- fcheckerror ---
-trans_fun([{fcheckerror,{_,Fail}}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- ContLbl = mk_label(new),
- case Fail of
- 0 ->
- [hipe_icode:mk_primop([], fcheckerror, [],
- hipe_icode:label_name(ContLbl), []),
- ContLbl | trans_fun(Instructions,Env)];
- _ -> %% Can this happen?
- {Guard,Env1} =
- make_guard([], fcheckerror, [],
- hipe_icode:label_name(ContLbl), map_label(Fail), Env),
- [Guard, ContLbl | trans_fun(Instructions,Env1)]
- end;
- _ ->
- trans_fun(Instructions, Env)
- end;
-%%--- fmove ---
-trans_fun([{fmove,Src,Dst}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- Dst1 = mk_var(Dst),
- Src1 = trans_arg(Src),
- case{hipe_icode:is_fvar(Dst1),
- hipe_icode:is_fvar(Src1)} of
- {true, true} -> %% fvar := fvar
- [hipe_icode:mk_move(Dst1,Src1) | trans_fun(Instructions,Env)];
- {false, true} -> %% var := fvar
- [hipe_icode:mk_primop([Dst1], unsafe_tag_float, [Src1]) |
- trans_fun(Instructions,Env)];
- {true, false} -> %% fvar := var or fvar := constant
- [hipe_icode:mk_primop([Dst1], unsafe_untag_float, [Src1]) |
- trans_fun(Instructions,Env)]
- end;
- _ ->
- trans_fun([{move,Src,Dst}|Instructions], Env)
- end;
-%%--- fconv ---
-trans_fun([{fconv,Eterm,FReg}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- Src = trans_arg(Eterm),
- ContLbl = mk_label(new),
- Dst = mk_var(FReg),
- [hipe_icode:mk_primop([Dst], conv_to_float, [Src],
- hipe_icode:label_name(ContLbl), []),
- ContLbl| trans_fun(Instructions, Env)];
- _ ->
- trans_fun([{fmove,Eterm,FReg}|Instructions], Env)
- end;
-%%--- fadd ---
-trans_fun([{arithfbif,fadd,Lab,SrcRs,DstR}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- trans_fun([{arithbif,fp_add,Lab,SrcRs,DstR}|Instructions], Env);
- _ ->
- trans_fun([{arithbif,'+',Lab,SrcRs,DstR}|Instructions], Env)
- end;
-%%--- fsub ---
-trans_fun([{arithfbif,fsub,Lab,SrcRs,DstR}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- trans_fun([{arithbif,fp_sub,Lab,SrcRs,DstR}|Instructions], Env);
- _ ->
- trans_fun([{arithbif,'-',Lab,SrcRs,DstR}|Instructions], Env)
- end;
-%%--- fmult ---
-trans_fun([{arithfbif,fmul,Lab,SrcRs,DstR}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- trans_fun([{arithbif,fp_mul,Lab,SrcRs,DstR}|Instructions], Env);
- _ ->
- trans_fun([{arithbif,'*',Lab,SrcRs,DstR}|Instructions], Env)
- end;
-%%--- fdiv ---
-trans_fun([{arithfbif,fdiv,Lab,SrcRs,DstR}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- trans_fun([{arithbif,fp_div,Lab,SrcRs,DstR}|Instructions], Env);
- _ ->
- trans_fun([{arithbif,'/',Lab,SrcRs,DstR}|Instructions], Env)
- end;
-%%--- fnegate ---
-trans_fun([{arithfbif,fnegate,Lab,[SrcR],DestR}|Instructions], Env) ->
- case get(hipe_inline_fp) of
- true ->
- Src = trans_arg(SrcR),
- Dst = mk_var(DestR),
- [hipe_icode:mk_primop([Dst], fnegate, [Src])|
- trans_fun(Instructions,Env)];
- _ ->
- trans_fun([{arithbif,'-',Lab,[{float,0.0},SrcR],DestR}|Instructions], Env)
- end;
-%%--------------------------------------------------------------------
-%% apply instructions added in April 2004 (R10B).
-%%--------------------------------------------------------------------
-trans_fun([{apply,Arity}|Instructions], Env) ->
- BeamArgs = extract_fun_args(Arity+2), %% +2 is for M and F
- {Args,[M,F]} = lists:split(Arity,BeamArgs),
- Dst = [mk_var({r,0})],
- [hipe_icode:mk_comment('apply'),
- hipe_icode:mk_primop(Dst, #apply_N{arity=Arity}, [M,F|Args])
- | trans_fun(Instructions,Env)];
-trans_fun([{apply_last,Arity,_N}|Instructions], Env) -> % N is StackAdjustment?
- BeamArgs = extract_fun_args(Arity+2), %% +2 is for M and F
- {Args,[M,F]} = lists:split(Arity,BeamArgs),
- [hipe_icode:mk_comment('apply_last'),
- hipe_icode:mk_enter_primop(#apply_N{arity=Arity}, [M,F|Args])
- | trans_fun(Instructions,Env)];
-%%--------------------------------------------------------------------
-%% test for boolean added in April 2004 (R10B).
-%%--------------------------------------------------------------------
-%%--- is_boolean ---
-trans_fun([{test,is_boolean,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(boolean,Lbl,Arg,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--------------------------------------------------------------------
-%% test for function with specific arity added in June 2005 (R11).
-%%--------------------------------------------------------------------
-%%--- is_function2 ---
-trans_fun([{test,is_function2,{f,Lbl},[Arg,Arity]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test2(function2,Lbl,Arg,Arity,Env),
- [Code | trans_fun(Instructions,Env1)];
-%%--------------------------------------------------------------------
-%% garbage collecting BIFs added in January 2006 (R11B).
-%%--------------------------------------------------------------------
-trans_fun([{gc_bif,'-',Fail,_Live,[SrcR],DstR}|Instructions], Env) ->
- %% Unary minus. Change this to binary minus.
- trans_fun([{arithbif,'-',Fail,[{integer,0},SrcR],DstR}|Instructions], Env);
-trans_fun([{gc_bif,'+',Fail,_Live,[SrcR],DstR}|Instructions], Env) ->
- %% Unary plus. Change this to a bif call.
- trans_fun([{bif,'+',Fail,[SrcR],DstR}|Instructions], Env);
-trans_fun([{gc_bif,Name,Fail,_Live,SrcRs,DstR}|Instructions], Env) ->
- case erl_internal:guard_bif(Name, length(SrcRs)) of
- false ->
- %% Arithmetic instruction.
- trans_fun([{arithbif,Name,Fail,SrcRs,DstR}|Instructions], Env);
- true ->
- %% A guard BIF.
- trans_fun([{bif,Name,Fail,SrcRs,DstR}|Instructions], Env)
- end;
-%%--------------------------------------------------------------------
-%% test for bitstream added in July 2007 (R12).
-%%--------------------------------------------------------------------
-%%--- is_bitstr ---
-trans_fun([{test,is_bitstr,{f,Lbl},[Arg]}|Instructions], Env) ->
- {Code,Env1} = trans_type_test(bitstr, Lbl, Arg, Env),
- [Code | trans_fun(Instructions, Env1)];
-%%--------------------------------------------------------------------
-%% stack triming instruction added in October 2007 (R12).
-%%--------------------------------------------------------------------
-trans_fun([{trim,N,NY}|Instructions], Env) ->
- %% trim away N registers leaving NY registers
- Moves = trans_trim(N, NY),
- Moves ++ trans_fun(Instructions, Env);
-%%--------------------------------------------------------------------
-%% line instruction added in Fall 2012 (R15).
-%%--------------------------------------------------------------------
-trans_fun([{line,_}|Instructions], Env) ->
- trans_fun(Instructions,Env);
-%%--------------------------------------------------------------------
-%% Map instructions added in Spring 2014 (17.0).
-%%--------------------------------------------------------------------
-trans_fun([{test,has_map_fields,{f,Lbl},Map,{list,Keys}}|Instructions], Env) ->
- {MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
- %% We assume that hipe_icode:mk_call has no side-effects, and reuse
- %% the help function of get_map_elements below, discarding the value
- %% assignment instruction list.
- {TestInstructions, _GetInstructions, Env2} =
- trans_map_query(MapVar, map_label(Lbl), Env1,
- lists:flatten([[K, {r, 0}] || K <- Keys])),
- [MapMove, TestInstructions | trans_fun(Instructions, Env2)];
-trans_fun([{get_map_elements,{f,Lbl},Map,{list,KVPs}}|Instructions], Env) ->
- KVPs1 = overwrite_map_last(Map, KVPs),
- {MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
- {TestInstructions, GetInstructions, Env2} =
- trans_map_query(MapVar, map_label(Lbl), Env1, KVPs1),
- [MapMove, TestInstructions, GetInstructions | trans_fun(Instructions, Env2)];
-%%--- put_map_assoc ---
-trans_fun([{put_map_assoc,{f,Lbl},Map,Dst,_N,{list,Pairs}}|Instructions], Env) ->
- {MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
- TempMapVar = mk_var(new),
- TempMapMove = hipe_icode:mk_move(TempMapVar, MapVar),
- {PutInstructions, Env2}
- = case Lbl > 0 of
- true ->
- gen_put_map_instrs(exists, assoc, TempMapVar, Dst, Lbl, Pairs, Env1);
- false ->
- gen_put_map_instrs(new, assoc, TempMapVar, Dst, new, Pairs, Env1)
- end,
- [MapMove, TempMapMove, PutInstructions | trans_fun(Instructions, Env2)];
-%%--- put_map_exact ---
-trans_fun([{put_map_exact,{f,Lbl},Map,Dst,_N,{list,Pairs}}|Instructions], Env) ->
- {MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
- TempMapVar = mk_var(new),
- TempMapMove = hipe_icode:mk_move(TempMapVar, MapVar),
- {PutInstructions, Env2}
- = case Lbl > 0 of
- true ->
- gen_put_map_instrs(exists, exact, TempMapVar, Dst, Lbl, Pairs, Env1);
- false ->
- gen_put_map_instrs(new, exact, TempMapVar, Dst, new, Pairs, Env1)
- end,
- [MapMove, TempMapMove, PutInstructions | trans_fun(Instructions, Env2)];
-%%--- build_stacktrace ---
-trans_fun([build_stacktrace|Instructions], Env) ->
- Vars = [mk_var({x,0})], %{x,0} is implict arg and dst
- [hipe_icode:mk_primop(Vars,build_stacktrace,Vars),
- trans_fun(Instructions, Env)];
-%%--- raw_raise ---
-trans_fun([raw_raise|Instructions], Env) ->
- Vars = [mk_var({x,0}),mk_var({x,1}),mk_var({x,2})],
- Dst = [mk_var({x,0})],
- [hipe_icode:mk_primop(Dst,raw_raise,Vars) |
- trans_fun(Instructions, Env)];
-%%--------------------------------------------------------------------
-%% New binary matching added in OTP 22.
-%%--------------------------------------------------------------------
-%%--- bs_get_tail ---
-trans_fun([{bs_get_tail=Name,_,_,_}|_Instructions], _Env) ->
- nyi(Name);
-%%--- bs_start_match3 ---
-trans_fun([{bs_start_match3=Name,_,_,_,_}|_Instructions], _Env) ->
- nyi(Name);
-%%--- bs_get_position ---
-trans_fun([{bs_get_position=Name,_,_,_}|_Instructions], _Env) ->
- nyi(Name);
-%%--- bs_set_position ---
-trans_fun([{bs_set_position=Name,_,_}|_Instructions], _Env) ->
- nyi(Name);
-%%--------------------------------------------------------------------
-%% New instructions added in OTP 23.
-%%--------------------------------------------------------------------
-%%--- swap ---
-trans_fun([{swap,Reg1,Reg2}|Instructions], Env) ->
- Var1 = mk_var(Reg1),
- Var2 = mk_var(Reg2),
- Temp = mk_var(new),
- [hipe_icode:mk_move(Temp, Var1),
- hipe_icode:mk_move(Var1, Var2),
- hipe_icode:mk_move(Var2, Temp) | trans_fun(Instructions, Env)];
-%%--------------------------------------------------------------------
-%%--- ERROR HANDLING ---
-%%--------------------------------------------------------------------
-trans_fun([X|_], _) ->
- ?EXIT({'trans_fun/2',X});
-trans_fun([], _) ->
- [].
-
-nyi(Name) ->
- throw({unimplemented_instruction,Name}).
-
-%%--------------------------------------------------------------------
-%% trans_call and trans_enter generate correct Icode calls/tail-calls,
-%% recognizing explicit fails.
-%%--------------------------------------------------------------------
-
-trans_call(MFA={M,F,_A}, Dst, Args, Type) ->
- handle_fail(MFA, Args, fun () -> hipe_icode:mk_call(Dst,M,F,Args,Type) end).
-
-trans_enter(MFA={M,F,_A}, Args, Type) ->
- handle_fail(MFA, Args, fun () -> hipe_icode:mk_enter(M,F,Args,Type) end).
-
-handle_fail(MFA, Args, F) ->
- case MFA of
- {erlang,exit,1} ->
- hipe_icode:mk_fail(Args,exit);
- {erlang,throw,1} ->
- hipe_icode:mk_fail(Args,throw);
- {erlang,fault,1} ->
- hipe_icode:mk_fail(Args,error);
- {erlang,fault,2} ->
- hipe_icode:mk_fail(Args,error);
- {erlang,error,1} ->
- hipe_icode:mk_fail(Args,error);
- {erlang,error,2} ->
- hipe_icode:mk_fail(Args,error);
- _ ->
- F()
- end.
-
-%%-----------------------------------------------------------------------
-%% trans_bif0(BifName, DestReg)
-%% trans_bif(Arity, BifName, FailLab, Args, DestReg, Environment)
-%%-----------------------------------------------------------------------
-
-trans_bif0(BifName, DestReg) ->
- ?no_debug_msg(" found BIF0: ~p() ...~n", [BifName]),
- BifRes = mk_var(DestReg),
- hipe_icode:mk_call([BifRes],erlang,BifName,[],remote).
-
-trans_bif(Arity, BifName, Lbl, Args, DestReg, Env) ->
- ?no_debug_msg(" found BIF: ~p(~p) ...~n", [BifName,Args]),
- BifRes = mk_var(DestReg),
- {Movs, SrcVars, Env1} = get_constants_in_temps(Args,Env),
- case Lbl of
- 0 -> % Bif is not in a guard
- I = hipe_icode:mk_call([BifRes],erlang,BifName,SrcVars,remote),
- {Movs ++ [I], Env1};
- _ -> % Bif occurs in a guard - fail silently to Lbl
- {GuardI,Env2} =
- make_fallthrough_guard([BifRes],{erlang,BifName,Arity},SrcVars,
- map_label(Lbl),Env1),
- {[Movs,GuardI], Env2}
- end.
-
-trans_op_call(Name, Lbl, Args, Dests, Env, Instructions) ->
- {Code, Env1} = trans_one_op_call(Name, Lbl, Args, Dests, Env),
- [Code|trans_fun(Instructions, Env1)].
-
-trans_one_op_call(Name, Lbl, Args, Dests, Env) ->
- case Lbl of
- 0 -> % Op is not in a guard
- I = hipe_icode:mk_primop(Dests, Name, Args),
- {[I], Env};
- _ -> % op occurs in a guard - fail silently to Lbl
- make_fallthrough_guard(Dests, Name, Args, map_label(Lbl), Env)
- end.
-
-%%-----------------------------------------------------------------------
-%% trans_bin_call
-%%-----------------------------------------------------------------------
-
-trans_bin_call(Name, Lbl, Args, Dests, Base, Offset, Env, Instructions) ->
- {Code, Env1} =
- case Lbl of
- 0 -> % Op is not in a guard
- I = hipe_icode:mk_primop(Dests, Name, Args),
- {[I], Env};
- _ -> % op occurs in a guard - fail silently to Lbl
- make_fallthrough_guard(Dests, Name, Args, map_label(Lbl), Env)
- end,
- [Code|trans_bin(Instructions, Base, Offset, Env1)].
-
-%% Translate instructions for building binaries separately to give
-%% them an appropriate state
-
-trans_bin([{bs_put_float,{f,Lbl},Size,Unit,{field_flags,Flags0},Source}|
- Instructions], Base, Offset, Env) ->
- Flags = resolve_native_endianess(Flags0),
- %% Get source
- {Src,SourceInstrs,ConstInfo} =
- case is_var(Source) of
- true ->
- {mk_var(Source),[], var};
- false ->
- case Source of
- {float, X} when is_float(X) ->
- C = trans_const(Source),
- SrcVar = mk_var(new),
- I = hipe_icode:mk_move(SrcVar, C),
- {SrcVar,[I],pass};
- _ ->
- C = trans_const(Source),
- SrcVar = mk_var(new),
- I = hipe_icode:mk_move(SrcVar, C),
- {SrcVar,[I],fail}
- end
- end,
- %% Get type of put_float
- {Name,Args,Env2} =
- case Size of
- {integer,NoBits} when is_integer(NoBits), NoBits >= 0 ->
- %% Create a N*Unit bits float
- {{bs_put_float, NoBits*Unit, Flags, ConstInfo}, [Src, Base, Offset], Env};
- {integer,NoBits} when is_integer(NoBits), NoBits < 0 ->
- ?EXIT({bad_bs_size_constant,Size});
- BitReg -> % Use a number of bits only known at runtime.
- Bits = mk_var(BitReg),
- {{bs_put_float, Unit, Flags, ConstInfo}, [Src,Bits,Base,Offset], Env}
- end,
- %% Generate code for calling the bs-op.
- SourceInstrs ++
- trans_bin_call({hipe_bs_primop,Name}, Lbl, Args, [Offset], Base, Offset, Env2, Instructions);
-trans_bin([{bs_put_binary,{f,Lbl},Size,Unit,{field_flags,Flags},Source}|
- Instructions], Base, Offset, Env) ->
- %% Get the source of the binary.
- Src = trans_arg(Source),
- %% Get type of put_binary
- {Name, Args, Env2} =
- case Size of
- {atom,all} -> %% put all bits
- {{bs_put_binary_all, Unit, Flags}, [Src,Base,Offset], Env};
- {integer,NoBits} when is_integer(NoBits), NoBits >= 0 ->
- %% Create a N*Unit bits subbinary
- {{bs_put_binary, NoBits*Unit, Flags}, [Src,Base,Offset], Env};
- {integer,NoBits} when is_integer(NoBits), NoBits < 0 ->
- ?EXIT({bad_bs_size_constant,Size});
- BitReg -> % Use a number of bits only known at runtime.
- Bits = mk_var(BitReg),
- {{bs_put_binary, Unit, Flags}, [Src, Bits,Base,Offset], Env}
- end,
- %% Generate code for calling the bs-op.
- trans_bin_call({hipe_bs_primop, Name},
- Lbl, Args, [Offset],
- Base, Offset, Env2, Instructions);
-%%--- bs_put_string ---
-trans_bin([{bs_put_string,SizeInBytes,{string,String}}|Instructions], Base,
- Offset, Env) ->
- [hipe_icode:mk_primop([Offset],
- {hipe_bs_primop,{bs_put_string, String, SizeInBytes}},
- [Base, Offset]) |
- trans_bin(Instructions, Base, Offset, Env)];
-trans_bin([{bs_put_integer,{f,Lbl},Size,Unit,{field_flags,Flags0},Source}|
- Instructions], Base, Offset, Env) ->
- Flags = resolve_native_endianess(Flags0),
- %% Get size-type
-
- %% Get the source of the binary.
- {Src, SrcInstrs, ConstInfo} =
- case is_var(Source) of
- true ->
- {mk_var(Source), [], var};
- false ->
- case Source of
- {integer, X} when is_integer(X) ->
- C = trans_const(Source),
- SrcVar = mk_var(new),
- I = hipe_icode:mk_move(SrcVar, C),
- {SrcVar,[I], pass};
- _ ->
- C = trans_const(Source),
- SrcVar = mk_var(new),
- I = hipe_icode:mk_move(SrcVar, C),
- {SrcVar,[I], fail}
-
- end
- end,
- {Name, Args, Env2} =
- case is_var(Size) of
- true ->
- SVar = mk_var(Size),
- {{bs_put_integer,Unit,Flags,ConstInfo}, [SVar, Base, Offset], Env};
- false ->
- case Size of
- {integer, NoBits} when NoBits >= 0 ->
- {{bs_put_integer,NoBits*Unit,Flags,ConstInfo}, [Base, Offset], Env};
- _ ->
- ?EXIT({bad_bs_size_constant,Size})
- end
- end,
- SrcInstrs ++ trans_bin_call({hipe_bs_primop, Name},
- Lbl, [Src|Args], [Offset], Base, Offset, Env2, Instructions);
-%%----------------------------------------------------------------
-%% binary construction instructions added in Fall 2008 (R12B-5).
-%%----------------------------------------------------------------
-trans_bin([{bs_put_utf8,{f,Lbl},_FF,A3}|Instructions], Base, Offset, Env) ->
- Src = trans_arg(A3),
- Args = [Src, Base, Offset],
- trans_bin_call({hipe_bs_primop, bs_put_utf8}, Lbl, Args, [Offset], Base, Offset, Env, Instructions);
-trans_bin([{bs_put_utf16,{f,Lbl},{field_flags,Flags0},A3}|Instructions], Base, Offset, Env) ->
- Src = trans_arg(A3),
- Args = [Src, Base, Offset],
- Flags = resolve_native_endianess(Flags0),
- Name = {bs_put_utf16, Flags},
- trans_bin_call({hipe_bs_primop, Name}, Lbl, Args, [Offset], Base, Offset, Env, Instructions);
-trans_bin([{bs_put_utf32,F={f,Lbl},FF={field_flags,_Flags0},A3}|Instructions], Base, Offset, Env) ->
- Src = trans_arg(A3),
- trans_bin_call({hipe_bs_primop,bs_validate_unicode}, Lbl, [Src], [], Base, Offset, Env,
- [{bs_put_integer,F,{integer,32},1,FF,A3} | Instructions]);
-%%----------------------------------------------------------------
-%% Base cases for the end of a binary construction sequence.
-%%----------------------------------------------------------------
-trans_bin([{bs_final2,Src,Dst}|Instructions], _Base, Offset, Env) ->
- [hipe_icode:mk_primop([mk_var(Dst)], {hipe_bs_primop, bs_final},
- [trans_arg(Src),Offset])
- |trans_fun(Instructions, Env)];
-trans_bin(Instructions, _Base, _Offset, Env) ->
- trans_fun(Instructions, Env).
-
-%% this translates bs_get_utf8 and bs_skip_utf8 (get with new unused dst)
-trans_bs_get_or_skip_utf8(Lbl, Ms, X, Instructions, Env) ->
- Dst = mk_var(X),
- MsVar = mk_var(Ms),
- trans_op_call({hipe_bs_primop,bs_get_utf8}, Lbl, [MsVar], [Dst,MsVar], Env, Instructions).
-
-%% this translates bs_get_utf16 and bs_skip_utf16 (get with new unused dst)
-trans_bs_get_or_skip_utf16(Lbl, Ms, Flags0, X, Instructions, Env) ->
- Dst = mk_var(X),
- MsVar = mk_var(Ms),
- Flags = resolve_native_endianess(Flags0),
- Name = {bs_get_utf16,Flags},
- trans_op_call({hipe_bs_primop,Name}, Lbl, [MsVar], [Dst,MsVar], Env, Instructions).
-
-%% this translates bs_get_utf32 and bs_skip_utf32 (get with new unused dst)
-trans_bs_get_or_skip_utf32(Lbl, Ms, Flags0, X, Instructions, Env) ->
- Dst = mk_var(X),
- MsVar = mk_var(Ms),
- Flags = resolve_native_endianess(Flags0),
- {I1,Env1} = trans_one_op_call({hipe_bs_primop,{bs_get_integer,32,Flags}},
- Lbl, [MsVar], [Dst,MsVar], Env),
- I1 ++ trans_op_call({hipe_bs_primop,bs_validate_unicode_retract},
- Lbl, [Dst,MsVar], [MsVar], Env1, Instructions).
-
-%%-----------------------------------------------------------------------
-%% trans_arith(Op, SrcVars, Des, Lab, Env) -> {Icode, NewEnv}
-%% A failure label of type {f,0} means in a body.
-%% A failure label of type {f,L} where L>0 means in a guard.
-%% Within a guard a failure should branch to the next guard and
-%% not trigger an exception!!
-%% Handles body arithmetic with Icode primops!
-%% Handles guard arithmetic with Icode guardops!
-%%-----------------------------------------------------------------------
-
-trans_arith(Op, SrcRs, DstR, Lbl, Env) ->
- {Movs,SrcVars,Env1} = get_constants_in_temps(SrcRs,Env),
- DstVar = mk_var(DstR),
- %%io:format("~w:trans_arith()\n ~w := ~w ~w\n",
- %% [?MODULE,DstVar,SrcVars,Op]),
- case Lbl of
- 0 -> % Body arithmetic
- Primop = hipe_icode:mk_primop([DstVar], arith_op_name(Op), SrcVars),
- {Movs++[Primop], Env1};
- _ -> % Guard arithmetic
- {Guard,Env2} =
- make_fallthrough_guard([DstVar], arith_op_name(Op), SrcVars,
- map_label(Lbl), Env1),
- {[Movs,Guard], Env2}
- end.
-
-%% Prevent arbitrary names from leaking into Icode from BEAM.
-arith_op_name('+') -> '+';
-arith_op_name('-') -> '-';
-arith_op_name('*') -> '*';
-arith_op_name('/') -> '/';
-arith_op_name('div') -> 'div';
-arith_op_name('fp_add') -> 'fp_add';
-arith_op_name('fp_sub') -> 'fp_sub';
-arith_op_name('fp_mul') -> 'fp_mul';
-arith_op_name('fp_div') -> 'fp_div';
-arith_op_name('rem') -> 'rem';
-arith_op_name('bsl') -> 'bsl';
-arith_op_name('bsr') -> 'bsr';
-arith_op_name('band') -> 'band';
-arith_op_name('bor') -> 'bor';
-arith_op_name('bxor') -> 'bxor';
-arith_op_name('bnot') -> 'bnot'.
-
-%%-----------------------------------------------------------------------
-%%-----------------------------------------------------------------------
-
-trans_test_guard(TestOp,F,Arg1,Arg2,Env) ->
- {Movs,Vars,Env1} = get_constants_in_temps([Arg1,Arg2],Env),
- True = mk_label(new),
- I = hipe_icode:mk_if(TestOp,Vars,hipe_icode:label_name(True),map_label(F)),
- {[Movs,I,True], Env1}.
-
-%%-----------------------------------------------------------------------
-%%-----------------------------------------------------------------------
-
-make_fallthrough_guard(DstVar,GuardOp,Args,FailLName,Env) ->
- ContL = mk_label(new),
- ContLName = hipe_icode:label_name(ContL),
- {Instrs, NewDsts} = clone_dsts(DstVar),
- {Guard,Env1} = make_guard(NewDsts,GuardOp,Args,ContLName,FailLName,Env),
- {[Guard,ContL]++Instrs,Env1}.
-
-%% Make sure DstVar gets initialised to a dummy value after a fail:
-%make_guard(Dests,{hipe_bs_primop,Primop},Args,ContLName,FailLName,Env) ->
-% {[hipe_icode:mk_guardop(Dests,{hipe_bs_primop,Primop},Args,ContLName,FailLName)],
-% Env};
-make_guard(Dests=[_|_],GuardOp,Args,ContLName,FailLName,Env) ->
- TmpFailL = mk_label(new),
- TmpFailLName = hipe_icode:label_name(TmpFailL),
- GuardOpIns = hipe_icode:mk_guardop(Dests,GuardOp,Args,
- ContLName,TmpFailLName),
- FailCode = [TmpFailL,
- nillify_all(Dests),
- hipe_icode:mk_goto(FailLName)],
- {[GuardOpIns|FailCode], Env};
-%% A guard that does not return anything:
-make_guard([],GuardOp,Args,ContLName,FailLName,Env) ->
- {[hipe_icode:mk_guardop([],GuardOp,Args,ContLName,FailLName)],
- Env}.
-
-nillify_all([Var|Vars]) ->
- [hipe_icode:mk_move(Var,hipe_icode:mk_const([]))|nillify_all(Vars)];
-nillify_all([]) -> [].
-
-clone_dsts(Dests) ->
- clone_dsts(Dests, [],[]).
-
-clone_dsts([Dest|Dests], Instrs, NewDests) ->
- {I,ND} = clone_dst(Dest),
- clone_dsts(Dests, [I|Instrs], [ND|NewDests]);
-clone_dsts([], Instrs, NewDests) ->
- {lists:reverse(Instrs), lists:reverse(NewDests)}.
-
-clone_dst(Dest) ->
- New =
- case hipe_icode:is_reg(Dest) of
- true ->
- case hipe_icode:reg_is_gcsafe(Dest) of
- true -> mk_var(reg_gcsafe);
- false -> mk_var(reg)
- end;
- false ->
- true = hipe_icode:is_var(Dest),
- mk_var(new)
- end,
- {hipe_icode:mk_move(Dest, New), New}.
-
-
-%%-----------------------------------------------------------------------
-%% trans_type_test(Test, Lbl, Arg, Env) -> {Icode, NewEnv}
-%% Handles all unary type tests like is_integer etc.
-%%-----------------------------------------------------------------------
-
-trans_type_test(Test, Lbl, Arg, Env) ->
- True = mk_label(new),
- {Move,Var,Env1} = mk_move_and_var(Arg,Env),
- I = hipe_icode:mk_type([Var], Test,
- hipe_icode:label_name(True), map_label(Lbl)),
- {[Move,I,True],Env1}.
-
-%%
-%% This handles binary type tests. Currently, the only such is the
-%% is_function/2 BIF.
-%%
-trans_type_test2(function2, Lbl, Arg, Arity, Env) ->
- True = mk_label(new),
- {Move1,Var1,Env1} = mk_move_and_var(Arg, Env),
- {Move2,Var2,Env2} = mk_move_and_var(Arity, Env1),
- I = hipe_icode:mk_type([Var1,Var2], function2,
- hipe_icode:label_name(True), map_label(Lbl)),
- {[Move1,Move2,I,True],Env2}.
-
-
-%%
-%% Makes sure that if a get_map_elements instruction will overwrite
-%% the map source, it will be done last.
-%%
-overwrite_map_last(Map, KVPs) ->
- overwrite_map_last2(Map, KVPs, []).
-
-overwrite_map_last2(Map, [Key,Map|KVPs], _Last) ->
- overwrite_map_last2(Map, KVPs, [Key,Map]);
-overwrite_map_last2(Map, [Key,Val|KVPs], Last) ->
- [Key,Val|overwrite_map_last2(Map, KVPs, Last)];
-overwrite_map_last2(_Map, [], Last) ->
- Last.
-
-%%
-%% Handles the get_map_elements instruction and the has_map_fields
-%% test instruction.
-%%
-trans_map_query(_MapVar, _FailLabel, Env, []) ->
- {[], [], Env};
-trans_map_query(MapVar, FailLabel, Env, [Key,Val|KVPs]) ->
- {Move,KeyVar,Env1} = mk_move_and_var(Key,Env),
- PassLabel = mk_label(new),
- BoolVar = hipe_icode:mk_new_var(),
- ValVar = mk_var(Val),
- IsKeyCall = hipe_icode:mk_call([BoolVar], maps, is_key, [KeyVar, MapVar],
- remote),
- TrueTest = hipe_icode:mk_if('=:=', [BoolVar, hipe_icode:mk_const(true)],
- hipe_icode:label_name(PassLabel), FailLabel),
- GetCall = hipe_icode:mk_call([ValVar], maps, get, [KeyVar, MapVar], remote),
- {TestList, GetList, Env2} = trans_map_query(MapVar, FailLabel, Env1, KVPs),
- {[Move, IsKeyCall, TrueTest, PassLabel|TestList], [GetCall|GetList], Env2}.
-
-%%
-%% Generates a fail label if necessary when translating put_map_* instructions.
-%%
-gen_put_map_instrs(exists, Op, TempMapVar, Dst, FailLbl, Pairs, Env) ->
- TrueLabel = mk_label(new),
- IsMapCode = hipe_icode:mk_type([TempMapVar], map,
- hipe_icode:label_name(TrueLabel), map_label(FailLbl)),
- DstMapVar = mk_var(Dst),
- {ReturnLbl, PutInstructions, Env1}
- = case Op of
- assoc ->
- trans_put_map_assoc(TempMapVar, DstMapVar, Pairs, Env, []);
- exact ->
- trans_put_map_exact(TempMapVar, DstMapVar,
- map_label(FailLbl), Pairs, Env, [])
- end,
- {[IsMapCode, TrueLabel, PutInstructions, ReturnLbl], Env1};
-gen_put_map_instrs(new, Op, TempMapVar, Dst, new, Pairs, Env) ->
- FailLbl = mk_label(new),
- DstMapVar = mk_var(Dst),
- {ReturnLbl, PutInstructions, Env1}
- = case Op of
- assoc ->
- trans_put_map_assoc(TempMapVar, DstMapVar, Pairs, Env, []);
- exact ->
- trans_put_map_exact(TempMapVar, DstMapVar,
- none, Pairs, Env, [])
- end,
- Fail = hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error),
- {[PutInstructions, FailLbl, Fail, ReturnLbl], Env1}.
-
-%%-----------------------------------------------------------------------
-%% This function generates the instructions needed to insert several
-%% (Key, Value) pairs into an existing map, each recursive call inserts
-%% one (Key, Value) pair.
-%%-----------------------------------------------------------------------
-trans_put_map_assoc(MapVar, DestMapVar, [], Env, Acc) ->
- MoveToReturnVar = hipe_icode:mk_move(DestMapVar, MapVar),
- ReturnLbl = mk_label(new),
- GotoReturn = hipe_icode:mk_goto(hipe_icode:label_name(ReturnLbl)),
- {ReturnLbl, lists:reverse([GotoReturn, MoveToReturnVar | Acc]), Env};
-trans_put_map_assoc(MapVar, DestMapVar, [Key, Value | Rest], Env, Acc) ->
- {MoveKey, KeyVar, Env1} = mk_move_and_var(Key, Env),
- {MoveVal, ValVar, Env2} = mk_move_and_var(Value, Env1),
- BifCall = hipe_icode:mk_call([MapVar], maps, put,
- [KeyVar, ValVar, MapVar], remote),
- trans_put_map_assoc(MapVar, DestMapVar, Rest, Env2,
- [BifCall, MoveVal, MoveKey | Acc]).
-
-%%-----------------------------------------------------------------------
-%% This function generates the instructions needed to update several
-%% (Key, Value) pairs in an existing map, each recursive call inserts
-%% one (Key, Value) pair.
-%%-----------------------------------------------------------------------
-trans_put_map_exact(MapVar, DestMapVar, _FLbl, [], Env, Acc) ->
- MoveToReturnVar = hipe_icode:mk_move(DestMapVar, MapVar),
- ReturnLbl = mk_label(new),
- GotoReturn = hipe_icode:mk_goto(hipe_icode:label_name(ReturnLbl)),
- {ReturnLbl, lists:reverse([GotoReturn, MoveToReturnVar | Acc]), Env};
-trans_put_map_exact(MapVar, DestMapVar, none, [Key, Value | Rest], Env, Acc) ->
- {MoveKey, KeyVar, Env1} = mk_move_and_var(Key, Env),
- {MoveVal, ValVar, Env2} = mk_move_and_var(Value, Env1),
- BifCallPut = hipe_icode:mk_call([MapVar], maps, update,
- [KeyVar, ValVar, MapVar], remote),
- Acc1 = [BifCallPut, MoveVal, MoveKey | Acc],
- trans_put_map_exact(MapVar, DestMapVar, none, Rest, Env2, Acc1);
-trans_put_map_exact(MapVar, DestMapVar, FLbl, [Key, Value | Rest], Env, Acc) ->
- SuccLbl = mk_label(new),
- {MoveKey, KeyVar, Env1} = mk_move_and_var(Key, Env),
- {MoveVal, ValVar, Env2} = mk_move_and_var(Value, Env1),
- IsKey = hipe_icode:mk_new_var(),
- BifCallIsKey = hipe_icode:mk_call([IsKey], maps, is_key,
- [KeyVar, MapVar], remote),
- IsKeyTest = hipe_icode:mk_if('=:=', [IsKey, hipe_icode:mk_const(true)],
- hipe_icode:label_name(SuccLbl), FLbl),
- BifCallPut = hipe_icode:mk_call([MapVar], maps, put,
- [KeyVar, ValVar, MapVar], remote),
- Acc1 = [BifCallPut, SuccLbl, IsKeyTest, BifCallIsKey, MoveVal, MoveKey | Acc],
- trans_put_map_exact(MapVar, DestMapVar, FLbl, Rest, Env2, Acc1).
-
-%%-----------------------------------------------------------------------
-%% trans_puts(Code, Environment) ->
-%% {Movs, Code, Vars, NewEnv}
-%%-----------------------------------------------------------------------
-
-trans_puts(Code, Env) ->
- trans_puts(Code, [], [], Env).
-
-trans_puts([{put,X}|Code], Vars, Moves, Env) ->
- case type(X) of
- var ->
- Var = mk_var(X),
- trans_puts(Code, [Var|Vars], Moves, Env);
- #beam_const{value=C} ->
- Var = mk_var(new),
- Move = hipe_icode:mk_move(Var, hipe_icode:mk_const(C)),
- trans_puts(Code, [Var|Vars], [Move|Moves], Env)
- end;
-trans_puts(Code, Vars, Moves, Env) -> %% No more put operations
- {Moves, Code, Vars, Env}.
-
-trans_elements([X|Code], Vars, Moves, Env) ->
- case type(X) of
- var ->
- Var = mk_var(X),
- trans_elements(Code, [Var|Vars], Moves, Env);
- #beam_const{value=C} ->
- Var = mk_var(new),
- Move = hipe_icode:mk_move(Var, hipe_icode:mk_const(C)),
- trans_elements(Code, [Var|Vars], [Move|Moves], Env)
- end;
-trans_elements([], Vars, Moves, Env) ->
- {Moves, Vars, Env}.
-
-%%-----------------------------------------------------------------------
-%% The code for this instruction is a bit large because we are treating
-%% different cases differently. We want to use the icode `type'
-%% instruction when it is applicable to take care of match expressions.
-%%-----------------------------------------------------------------------
-
-trans_is_eq_exact(Lbl, Arg1, Arg2, Env) ->
- case {is_var(Arg1),is_var(Arg2)} of
- {true,true} ->
- True = mk_label(new),
- I = hipe_icode:mk_if('=:=',
- [mk_var(Arg1),mk_var(Arg2)],
- hipe_icode:label_name(True), map_label(Lbl)),
- {[I,True], Env};
- {true,false} -> %% right argument is a constant -- use type()!
- trans_is_eq_exact_var_const(Lbl, Arg1, Arg2, Env);
- {false,true} -> %% mirror of the case above; swap args
- trans_is_eq_exact_var_const(Lbl, Arg2, Arg1, Env);
- {false,false} -> %% both arguments are constants !!!
- case Arg1 =:= Arg2 of
- true ->
- {[], Env};
- false ->
- Never = mk_label(new),
- I = hipe_icode:mk_goto(map_label(Lbl)),
- {[I,Never], Env}
- end
- end.
-
-trans_is_eq_exact_var_const(Lbl, Arg1, Arg2, Env) -> % var =:= const
- True = mk_label(new),
- NewArg1 = mk_var(Arg1),
- TrueLabName = hipe_icode:label_name(True),
- FalseLabName = map_label(Lbl),
- I = case Arg2 of
- {float,Float} ->
- hipe_icode:mk_if('=:=',
- [NewArg1, hipe_icode:mk_const(Float)],
- TrueLabName, FalseLabName);
- {literal,Literal} ->
- hipe_icode:mk_if('=:=',
- [NewArg1, hipe_icode:mk_const(Literal)],
- TrueLabName, FalseLabName);
- _ ->
- hipe_icode:mk_type([NewArg1], Arg2, TrueLabName, FalseLabName)
- end,
- {[I,True], Env}.
-
-%%-----------------------------------------------------------------------
-%% ... and this is analogous to the above
-%%-----------------------------------------------------------------------
-
-trans_is_ne_exact(Lbl, Arg1, Arg2, Env) ->
- case {is_var(Arg1),is_var(Arg2)} of
- {true,true} ->
- True = mk_label(new),
- I = hipe_icode:mk_if('=/=',
- [mk_var(Arg1),mk_var(Arg2)],
- hipe_icode:label_name(True), map_label(Lbl)),
- {[I,True], Env};
- {true,false} -> %% right argument is a constant -- use type()!
- trans_is_ne_exact_var_const(Lbl, Arg1, Arg2, Env);
- {false,true} -> %% mirror of the case above; swap args
- trans_is_ne_exact_var_const(Lbl, Arg2, Arg1, Env);
- {false,false} -> %% both arguments are constants !!!
- case Arg1 =/= Arg2 of
- true ->
- {[], Env};
- false ->
- Never = mk_label(new),
- I = hipe_icode:mk_goto(map_label(Lbl)),
- {[I,Never], Env}
- end
- end.
-
-trans_is_ne_exact_var_const(Lbl, Arg1, Arg2, Env) -> % var =/= const
- True = mk_label(new),
- NewArg1 = mk_var(Arg1),
- TrueLabName = hipe_icode:label_name(True),
- FalseLabName = map_label(Lbl),
- I = case Arg2 of
- {float,Float} ->
- hipe_icode:mk_if('=/=',
- [NewArg1, hipe_icode:mk_const(Float)],
- TrueLabName, FalseLabName);
- {literal,Literal} ->
- hipe_icode:mk_if('=/=',
- [NewArg1, hipe_icode:mk_const(Literal)],
- TrueLabName, FalseLabName);
- _ ->
- hipe_icode:mk_type([NewArg1], Arg2, FalseLabName, TrueLabName)
- end,
- {[I,True], Env}.
-
-%%-----------------------------------------------------------------------
-%% Try to do a relatively straightforward optimization: if equality with
-%% an atom is used, then convert this test to use of exact equality test
-%% with the same atom (which in turn will be translated to a `type' test
-%% instruction by the code of trans_is_eq_exact_var_const/4 above).
-%%-----------------------------------------------------------------------
-
-trans_is_eq(Lbl, Arg1, Arg2, Env) ->
- case {is_var(Arg1),is_var(Arg2)} of
- {true,true} -> %% not much can be done in this case
- trans_test_guard('==', Lbl, Arg1, Arg2, Env);
- {true,false} -> %% optimize this case, if possible
- case Arg2 of
- {atom,_SomeAtom} ->
- trans_is_eq_exact_var_const(Lbl, Arg1, Arg2, Env);
- _ ->
- trans_test_guard('==', Lbl, Arg1, Arg2, Env)
- end;
- {false,true} -> %% probably happens rarely; hence the recursive call
- trans_is_eq(Lbl, Arg2, Arg1, Env);
- {false,false} -> %% both arguments are constants !!!
- case Arg1 == Arg2 of
- true ->
- {[], Env};
- false ->
- Never = mk_label(new),
- I = hipe_icode:mk_goto(map_label(Lbl)),
- {[I,Never], Env}
- end
- end.
-
-%%-----------------------------------------------------------------------
-%% ... and this is analogous to the above
-%%-----------------------------------------------------------------------
-
-trans_is_ne(Lbl, Arg1, Arg2, Env) ->
- case {is_var(Arg1),is_var(Arg2)} of
- {true,true} -> %% not much can be done in this case
- trans_test_guard('/=', Lbl, Arg1, Arg2, Env);
- {true,false} -> %% optimize this case, if possible
- case Arg2 of
- {atom,_SomeAtom} ->
- trans_is_ne_exact_var_const(Lbl, Arg1, Arg2, Env);
- _ ->
- trans_test_guard('/=', Lbl, Arg1, Arg2, Env)
- end;
- {false,true} -> %% probably happens rarely; hence the recursive call
- trans_is_ne(Lbl, Arg2, Arg1, Env);
- {false,false} -> %% both arguments are constants !!!
- case Arg1 /= Arg2 of
- true ->
- {[], Env};
- false ->
- Never = mk_label(new),
- I = hipe_icode:mk_goto(map_label(Lbl)),
- {[I,Never], Env}
- end
- end.
-
-
-%%-----------------------------------------------------------------------
-%% Translates an allocate instruction into a sequence of initializations
-%%-----------------------------------------------------------------------
-
-trans_allocate(N) ->
- trans_allocate(N, []).
-
-trans_allocate(0, Acc) ->
- Acc;
-trans_allocate(N, Acc) ->
- Move = hipe_icode:mk_move(mk_var({y,N-1}),
- hipe_icode:mk_const('dummy_value')),
- trans_allocate(N-1, [Move|Acc]).
-
-%%-----------------------------------------------------------------------
-%% Translates a trim instruction into a sequence of moves
-%%-----------------------------------------------------------------------
-
-trans_trim(N, NY) ->
- lists:reverse(trans_trim(N, NY, 0, [])).
-
-trans_trim(_, 0, _, Acc) ->
- Acc;
-trans_trim(N, NY, Y, Acc) ->
- Move = hipe_icode:mk_move(mk_var({y,Y}), mk_var({y,N})),
- trans_trim(N+1, NY-1, Y+1, [Move|Acc]).
-
-%%-----------------------------------------------------------------------
-%%-----------------------------------------------------------------------
-
-mk_move_and_var(Var, Env) ->
- case type(Var) of
- var ->
- V = mk_var(Var),
- {[], V, Env};
- #beam_const{value=C} ->
- V = mk_var(new),
- {[hipe_icode:mk_move(V,hipe_icode:mk_const(C))], V, Env}
- end.
-
-%%-----------------------------------------------------------------------
-%% Find names of closures and number of free vars.
-%%-----------------------------------------------------------------------
-
-closure_info_mfa(#closure_info{mfa=MFA}) -> MFA.
-closure_info_arity(#closure_info{arity=Arity}) -> Arity.
-%% closure_info_fv_arity(#closure_info{fv_arity=Arity}) -> Arity.
-
-find_closure_info(Code) -> mod_find_closure_info(Code, []).
-
-mod_find_closure_info([FunCode|Fs], CI) ->
- mod_find_closure_info(Fs, find_closure_info(FunCode, CI));
-mod_find_closure_info([], CI) ->
- CI.
-
-find_closure_info([{make_fun2,{_M,_F,A}=MFA,_Index,_Magic,FreeVarNum}|BeamCode],
- ClosureInfo) ->
- NewClosure = %% A-FreeVarNum+1 (The real arity + 1 for the closure)
- #closure_info{mfa=MFA, arity=A-FreeVarNum+1, fv_arity=FreeVarNum},
- find_closure_info(BeamCode, [NewClosure|ClosureInfo]);
-find_closure_info([_Inst|BeamCode], ClosureInfo) ->
- find_closure_info(BeamCode, ClosureInfo);
-find_closure_info([], ClosureInfo) ->
- ClosureInfo.
-
-%%-----------------------------------------------------------------------
-%% Is closure
-%%-----------------------------------------------------------------------
-
-get_closure_info(MFA, [CI|Rest]) ->
- case closure_info_mfa(CI) of
- MFA -> CI;
- _ -> get_closure_info(MFA, Rest)
- end;
-get_closure_info(_, []) ->
- not_a_closure.
-
-%%-----------------------------------------------------------------------
-%% Patch closure entry.
-%%-----------------------------------------------------------------------
-
-%% NOTE: this changes the number of parameters in the ICode function,
-%% but does *not* change the arity in the function name. Thus, all
-%% closure-functions have the exact same names in Beam and in native
-%% code, although they have different calling conventions.
-
-patch_closure_entry(Icode, ClosureInfo)->
- Arity = closure_info_arity(ClosureInfo),
- %% ?msg("Arity ~w\n",[Arity]),
- {Args, Closure, FreeVars} =
- split_params(Arity, hipe_icode:icode_params(Icode), []),
- [Start|_] = hipe_icode:icode_code(Icode),
- {_LMin, LMax} = hipe_icode:icode_label_range(Icode),
- hipe_gensym:set_label(icode,LMax+1),
- {_VMin, VMax} = hipe_icode:icode_var_range(Icode),
- hipe_gensym:set_var(icode,VMax+1),
- MoveCode = gen_get_free_vars(FreeVars, Closure,
- hipe_icode:label_name(Start)),
- Icode1 = hipe_icode:icode_code_update(Icode, MoveCode ++
- hipe_icode:icode_code(Icode)),
- Icode2 = hipe_icode:icode_params_update(Icode1, Args),
- %% Arity - 1 since the original arity did not have the closure argument.
- Icode3 = hipe_icode:icode_closure_arity_update(Icode2, Arity-1),
- Icode3.
-
-%%-----------------------------------------------------------------------
-
-gen_get_free_vars(Vars, Closure, StartName) ->
- [hipe_icode:mk_new_label()] ++
- get_free_vars(Vars, Closure, 1, []) ++ [hipe_icode:mk_goto(StartName)].
-
-get_free_vars([V|Vs], Closure, No, MoveCode) ->
- %% TempV = hipe_icode:mk_new_var(),
- get_free_vars(Vs, Closure, No+1,
- [%% hipe_icode:mk_move(TempV,hipe_icode:mk_const(No)),
- hipe_icode:mk_primop([V], #closure_element{n=No}, [Closure])
- |MoveCode]);
-get_free_vars([],_,_,MoveCode) ->
- MoveCode.
-
-%%-----------------------------------------------------------------------
-
-split_params(1, [Closure|_OrgArgs] = Params, Args) ->
- {lists:reverse([Closure|Args]), Closure, Params};
-split_params(1, [], Args) ->
- Closure = hipe_icode:mk_new_var(),
- {lists:reverse([Closure|Args]), Closure, []};
-split_params(N, [ArgN|OrgArgs], Args) ->
- split_params(N-1, OrgArgs, [ArgN|Args]).
-
-%%-----------------------------------------------------------------------
-
-preprocess_code(ModuleCode) ->
- ClosureInfo = find_closure_info(ModuleCode),
- {ModuleCode, ClosureInfo}.
-
-%%-----------------------------------------------------------------------
-
-find_mfa([{label,_}|Code]) ->
- find_mfa(Code);
-find_mfa([{line,_}|Code]) ->
- find_mfa(Code);
-find_mfa([{func_info,{atom,M},{atom,F},A}|_])
- when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 ->
- {M, F, A}.
-
-
-%%-----------------------------------------------------------------------
-%% Takes a list of arguments and returns the constants of them into
-%% fresh temporaries. Return a triple consisting of a list of move
-%% instructions, a list of proper icode arguments and the new environment.
-%%-----------------------------------------------------------------------
-
-get_constants_in_temps(Args, Env) ->
- get_constants_in_temps(Args, [], [], Env).
-
-get_constants_in_temps([Arg|Args], Instrs, Temps, Env) ->
- case get_constant_in_temp(Arg, Env) of
- {none,ArgVar,Env1} ->
- get_constants_in_temps(Args, Instrs, [ArgVar|Temps], Env1);
- {Instr,Temp,Env1} ->
- get_constants_in_temps(Args, [Instr|Instrs], [Temp|Temps], Env1)
- end;
-get_constants_in_temps([], Instrs, Temps, Env) ->
- {lists:reverse(Instrs), lists:reverse(Temps), Env}.
-
-%% If Arg is a constant then put Arg in a fresh temp!
-get_constant_in_temp(Arg, Env) ->
- case is_var(Arg) of
- true -> % Convert into Icode variable format before return
- {none, mk_var(Arg), Env};
- false -> % Create a new temp and move the constant into it
- Temp = mk_var(new),
- Const = trans_const(Arg),
- {hipe_icode:mk_move(Temp, Const), Temp, Env}
- end.
-
-%%-----------------------------------------------------------------------
-%% Makes a list of function arguments.
-%%-----------------------------------------------------------------------
-
-extract_fun_args(A) ->
- lists:reverse(extract_fun_args1(A)).
-
-extract_fun_args1(0) ->
- [];
-extract_fun_args1(1) ->
- [mk_var({r,0})];
-extract_fun_args1(N) ->
- [mk_var({x,N-1}) | extract_fun_args1(N-1)].
-
-%%-----------------------------------------------------------------------
-%% Auxiliary translation for arguments of select_val & select_tuple_arity
-%%-----------------------------------------------------------------------
-
-trans_select_stuff(Reg, CaseList) ->
- SwVar = case is_var(Reg) of
- true ->
- mk_var(Reg);
- false ->
- trans_const(Reg)
- end,
- CasePairs = trans_case_list(CaseList),
- {SwVar,CasePairs}.
-
-trans_case_list([Symbol,{f,Lbl}|L]) ->
- [{trans_const(Symbol),map_label(Lbl)} | trans_case_list(L)];
-trans_case_list([]) ->
- [].
-
-%%-----------------------------------------------------------------------
-%% Makes an Icode argument from a BEAM argument.
-%%-----------------------------------------------------------------------
-
-trans_arg(Arg) ->
- case is_var(Arg) of
- true ->
- mk_var(Arg);
- false ->
- trans_const(Arg)
- end.
-
-%%-----------------------------------------------------------------------
-%% Makes an Icode constant from a BEAM constant.
-%%-----------------------------------------------------------------------
-
-trans_const(Const) ->
- case Const of
- {atom,Atom} when is_atom(Atom) ->
- hipe_icode:mk_const(Atom);
- {integer,N} when is_integer(N) ->
- hipe_icode:mk_const(N);
- {float,Float} when is_float(Float) ->
- hipe_icode:mk_const(Float);
- {string,String} ->
- hipe_icode:mk_const(String);
- {literal,Literal} ->
- hipe_icode:mk_const(Literal);
- nil ->
- hipe_icode:mk_const([]);
- Int when is_integer(Int) ->
- hipe_icode:mk_const(Int)
- end.
-
-%%-----------------------------------------------------------------------
-%% Make an icode variable of proper type
-%% (Variables mod 5) =:= 0 are X regs
-%% (Variables mod 5) =:= 1 are Y regs
-%% (Variables mod 5) =:= 2 are FR regs
-%% (Variables mod 5) =:= 3 are new temporaries
-%% (Variables mod 5) =:= 4 are new register temporaries
-%% Tell hipe_gensym to update its state for each new thing created!!
-%%-----------------------------------------------------------------------
-
-mk_var({r,0}) ->
- hipe_icode:mk_var(0);
-mk_var({x,R}) when is_integer(R) ->
- V = 5*R,
- hipe_gensym:update_vrange(icode,V),
- hipe_icode:mk_var(V);
-mk_var({y,R}) when is_integer(R) ->
- V = (5*R)+1,
- hipe_gensym:update_vrange(icode,V),
- hipe_icode:mk_var(V);
-mk_var({fr,R}) when is_integer(R) ->
- V = (5*R)+2,
- hipe_gensym:update_vrange(icode,V),
- case get(hipe_inline_fp) of
- true ->
- hipe_icode:mk_fvar(V);
- _ ->
- hipe_icode:mk_var(V)
- end;
-mk_var(new) ->
- T = hipe_gensym:new_var(icode),
- V = (5*T)+3,
- hipe_gensym:update_vrange(icode,V),
- hipe_icode:mk_var(V);
-mk_var(reg) ->
- T = hipe_gensym:new_var(icode),
- V = (5*T)+4,
- hipe_gensym:update_vrange(icode,V),
- hipe_icode:mk_reg(V);
-mk_var(reg_gcsafe) ->
- T = hipe_gensym:new_var(icode),
- V = (5*T)+4, % same namespace as 'reg'
- hipe_gensym:update_vrange(icode,V),
- hipe_icode:mk_reg_gcsafe(V).
-
-%%-----------------------------------------------------------------------
-%% Make an icode label of proper type
-%% (Labels mod 2) =:= 0 are actually occuring in the BEAM code
-%% (Labels mod 2) =:= 1 are new labels generated by the translation
-%%-----------------------------------------------------------------------
-
-mk_label(L) when is_integer(L) ->
- LL = 2 * L,
- hipe_gensym:update_lblrange(icode, LL),
- hipe_icode:mk_label(LL);
-mk_label(new) ->
- L = hipe_gensym:new_label(icode),
- LL = (2 * L) + 1,
- hipe_gensym:update_lblrange(icode, LL),
- hipe_icode:mk_label(LL).
-
-%% Maps from the BEAM's labelling scheme to our labelling scheme.
-%% See mk_label to understand how it works.
-
-map_label(L) ->
- L bsl 1. % faster and more type-friendly version of 2 * L
-
-%%-----------------------------------------------------------------------
-%% Returns the type of the given variables.
-%%-----------------------------------------------------------------------
-
-type({x,_}) ->
- var;
-type({y,_}) ->
- var;
-type({fr,_}) ->
- var;
-type({atom,A}) when is_atom(A) ->
- #beam_const{value=A};
-type(nil) ->
- #beam_const{value=[]};
-type({integer,X}) when is_integer(X) ->
- #beam_const{value=X};
-type({float,X}) when is_float(X) ->
- #beam_const{value=X};
-type({literal,X}) ->
- #beam_const{value=X}.
-
-%%-----------------------------------------------------------------------
-%% Returns true iff the argument is a variable.
-%%-----------------------------------------------------------------------
-
-is_var({x,_}) ->
- true;
-is_var({y,_}) ->
- true;
-is_var({fr,_}) ->
- true;
-is_var({atom,A}) when is_atom(A) ->
- false;
-is_var(nil) ->
- false;
-is_var({integer,N}) when is_integer(N) ->
- false;
-is_var({float,F}) when is_float(F) ->
- false;
-is_var({literal,_Literal}) ->
- false.
-
-%%-----------------------------------------------------------------------
-%% Fixes the code for catches by adding some code.
-%%-----------------------------------------------------------------------
-
-fix_catches(Code) ->
- fix_catches(Code, gb_trees:empty()).
-
-%% We need to handle merged catch blocks, that is multiple 'catch' with
-%% only one 'catch_end', or multiple 'try' with one 'try_case'. (Catch
-%% and try can never be merged.) All occurrences of 'catch' or 'try'
-%% with a particular fail-to label are assumed to only occur before the
-%% corresponding 'catch_end'/'try_end' in the Beam code.
-
-fix_catches([{'catch',N,Lbl},ContLbl|Code], HandledCatchLbls) ->
- fix_catch('catch',Lbl,ContLbl,Code,HandledCatchLbls,{catch_end,N});
-fix_catches([{'try',N,Lbl},ContLbl|Code], HandledCatchLbls) ->
- fix_catch('try',Lbl,ContLbl,Code,HandledCatchLbls,{try_case,N});
-fix_catches([Instr|Code], HandledCatchLbls) ->
- [Instr|fix_catches(Code, HandledCatchLbls)];
-fix_catches([], _HandledCatchLbls) ->
- [].
-
-fix_catch(Type, Lbl, ContLbl, Code, HandledCatchLbls, Instr) ->
- TLbl = {Type, Lbl},
- case gb_trees:lookup(TLbl, HandledCatchLbls) of
- {value, Catch} when is_integer(Catch) ->
- nyi(unsafe_catch);
- none ->
- OldCatch = map_label(Lbl),
- OldCatchLbl = hipe_icode:mk_label(OldCatch),
- {CodeToCatch,RestOfCode} = split_code(Code,OldCatchLbl,Instr),
- NewCatchLbl = mk_label(new),
- NewCatch = hipe_icode:label_name(NewCatchLbl),
- %% The rest of the code cannot contain catches with the same label.
- RestOfCode1 = fix_catches(RestOfCode, HandledCatchLbls),
- %% The catched code *can* contain more catches with the same label.
- NewHandledCatchLbls = gb_trees:insert(TLbl, NewCatch, HandledCatchLbls),
- CatchedCode = fix_catches(CodeToCatch, NewHandledCatchLbls),
- %% The variables which will get the tag, value, and trace.
- Vars = [mk_var({r,0}), mk_var({x,1}), mk_var({x,2})],
- Cont = hipe_icode:label_name(ContLbl),
- [hipe_icode:mk_begin_try(NewCatch,Cont), ContLbl]
- ++ CatchedCode
- ++ [mk_label(new), % dummy label before the goto
- hipe_icode:mk_goto(OldCatch), % normal execution path
- NewCatchLbl, % exception handing enters here
- hipe_icode:mk_begin_handler(Vars)]
- ++ catch_handler(Type, Vars, OldCatchLbl)
- ++ RestOfCode1 % back to normal execution
- end.
-
-catch_handler('try', _Vars, OldCatchLbl) ->
- %% A try just falls through to the old fail-to label which marked the
- %% start of the try_case block. All variables are set up as expected.
- [OldCatchLbl];
-catch_handler('catch', [TagVar,ValueVar,TraceVar], OldCatchLbl) ->
- %% This basically implements a catch as a try-expression. We must jump
- %% to the given end label afterwards so we don't pass through both the
- %% begin_handler and the end_try.
- ContLbl = mk_label(new),
- Cont = hipe_icode:label_name(ContLbl),
- ThrowLbl = mk_label(new),
- NoThrowLbl = mk_label(new),
- ExitLbl = mk_label(new),
- ErrorLbl = mk_label(new),
- Dst = mk_var({r,0}),
- [hipe_icode:mk_if('=:=', [TagVar, hipe_icode:mk_const('throw')],
- hipe_icode:label_name(ThrowLbl),
- hipe_icode:label_name(NoThrowLbl)),
- ThrowLbl,
- hipe_icode:mk_move(Dst, ValueVar),
- hipe_icode:mk_goto(Cont),
- NoThrowLbl,
- hipe_icode:mk_if('=:=', [TagVar, hipe_icode:mk_const('exit')],
- hipe_icode:label_name(ExitLbl),
- hipe_icode:label_name(ErrorLbl)),
- ExitLbl,
- hipe_icode:mk_primop([Dst],mktuple,[hipe_icode:mk_const('EXIT'),
- ValueVar]),
- hipe_icode:mk_goto(Cont),
- ErrorLbl,
- %% We use the trace variable to hold the symbolic trace.
- hipe_icode:mk_primop([TraceVar],build_stacktrace,[TraceVar]),
- hipe_icode:mk_primop([ValueVar],mktuple, [ValueVar, TraceVar]),
- hipe_icode:mk_goto(hipe_icode:label_name(ExitLbl)),
- OldCatchLbl, % normal execution paths must go through end_try
- hipe_icode:mk_end_try(),
- hipe_icode:mk_goto(Cont),
- ContLbl].
-
-%% Note that it is the fail-to label that is the important thing, but
-%% for 'catch' we want to make sure that the label is followed by the
-%% 'catch_end' instruction - if it is not, we might have a real problem.
-%% Checking that a 'try' label is followed by 'try_case' is not as
-%% important, but we get that as a bonus.
-
-split_code([First|Code], Label, Instr) ->
- split_code(Code, Label, Instr, First, []).
-
-split_code([Instr|Code], Label, Instr, Prev, As) when Prev =:= Label ->
- split_code_final(Code, As); % drop both label and instruction
-split_code([{icode_end_try}|_]=Code, Label, {try_case,_}, Prev, As)
- when Prev =:= Label ->
- %% The try_case has been replaced with try_end as an optimization.
- %% Keep this instruction, since it might be the only try_end instruction
- %% for this try/catch block.
- split_code_final(Code, As); % drop label
-split_code([Other|_Code], Label, Instr, Prev, _As) when Prev =:= Label ->
- ?EXIT({missing_instr_after_label, Label, Instr, [Other, Prev | _As]});
-split_code([Other|Code], Label, Instr, Prev, As) ->
- split_code(Code, Label, Instr, Other, [Prev|As]);
-split_code([], _Label, _Instr, Prev, As) ->
- split_code_final([], [Prev|As]).
-
-split_code_final(Code, As) ->
- {lists:reverse(As), Code}.
-
-%%-----------------------------------------------------------------------
-%% Fixes fallthroughs
-%%-----------------------------------------------------------------------
-
-fix_fallthroughs([]) ->
- [];
-fix_fallthroughs([I|Is]) ->
- fix_fallthroughs(Is, I, []).
-
-fix_fallthroughs([I1|Is], I0, Acc) ->
- case hipe_icode:is_label(I1) of
- false ->
- fix_fallthroughs(Is, I1, [I0 | Acc]);
- true ->
- case hipe_icode:is_branch(I0) of
- true ->
- fix_fallthroughs(Is, I1, [I0 | Acc]);
- false ->
- %% non-branch before label - insert a goto
- Goto = hipe_icode:mk_goto(hipe_icode:label_name(I1)),
- fix_fallthroughs(Is, I1, [Goto, I0 | Acc])
- end
- end;
-fix_fallthroughs([], I, Acc) ->
- lists:reverse([I | Acc]).
-
-%%-----------------------------------------------------------------------
-%% Removes the code between a fail instruction and the closest following
-%% label.
-%%-----------------------------------------------------------------------
-
--spec remove_dead_code(icode_instrs()) -> icode_instrs().
-remove_dead_code([I|Is]) ->
- case I of
- #icode_fail{} ->
- [I|remove_dead_code(skip_to_label(Is))];
- _ ->
- [I|remove_dead_code(Is)]
- end;
-remove_dead_code([]) ->
- [].
-
-%% returns the instructions from the closest label
--spec skip_to_label(icode_instrs()) -> icode_instrs().
-skip_to_label([I|Is] = Instrs) ->
- case I of
- #icode_label{} -> Instrs;
- _ -> skip_to_label(Is)
- end;
-skip_to_label([]) ->
- [].
-
-%%-----------------------------------------------------------------------
-%% This needs to be extended in case new architectures are added.
-%%-----------------------------------------------------------------------
-
-resolve_native_endianess(Flags) ->
- case {Flags band 16#10, hipe_rtl_arch:endianess()} of
- {16#10, big} ->
- Flags band 5;
- {16#10, little} ->
- (Flags bor 2) band 7;
- _ ->
- Flags band 7
- end.
-
-%%-----------------------------------------------------------------------
-%% Potentially useful for debugging.
-%%-----------------------------------------------------------------------
-
-pp_beam(BeamCode, Options) ->
- case proplists:get_value(pp_beam, Options) of
- true ->
- pp(BeamCode);
- {file,FileName} ->
- {ok,File} = file:open(FileName, [write]),
- pp(File, BeamCode);
- _ -> %% includes "false" case
- ok
- end.
-
-pp(Code) ->
- pp(standard_io, Code).
-
-pp(Stream, []) ->
- case Stream of %% I am not sure whether this is necessary
- standard_io -> ok;
- _ -> ok = file:close(Stream)
- end;
-pp(Stream, [FunCode|FunCodes]) ->
- pp_mfa(Stream, FunCode),
- put_nl(Stream),
- pp(Stream, FunCodes).
-
-pp_mfa(Stream, FunCode) ->
- lists:foreach(fun(Instr) -> print_instr(Stream, Instr) end, FunCode).
-
-print_instr(Stream, {label,Lbl}) ->
- io:format(Stream, " label ~p:\n", [Lbl]);
-print_instr(Stream, Op) ->
- io:format(Stream, " ~p\n", [Op]).
-
-put_nl(Stream) ->
- io:format(Stream, "\n", []).
-
-%%-----------------------------------------------------------------------
-%% Handling of environments -- used to process local tail calls.
-%%-----------------------------------------------------------------------
-
-%% Construct an environment
-env__mk_env(M, F, A, Entry) ->
- #environment{mfa={M,F,A}, entry=Entry}.
-
-%% Get current MFA
-env__get_mfa(#environment{mfa=MFA}) -> MFA.
-
-%% Get entry point of the current function
-env__get_entry(#environment{entry=EP}) -> EP.
-
-%%-----------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
deleted file mode 100644
index bc3403b0c5..0000000000
--- a/lib/hipe/icode/hipe_icode.erl
+++ /dev/null
@@ -1,1847 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% HiPE Intermediate Code
-%% ====================================================================
-%% Filename : hipe_icode.erl
-%% Module : hipe_icode
-%% Purpose : Provide primops for the Icode data structure.
-%% History : 1997-? Erik Johansson (happi@it.uu.se): Created.
-%% 2001-01-30 EJ (happi@it.uu.se):
-%% Apply, primop, guardop removed
-%% 2003-03-15 ES (happi@acm.org):
-%% Started commenting in Edoc.
-%% Moved pretty printer to separate file.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% This module implements "Linear Icode" and Icode instructions.
-%%
-%% <p> Icode is a simple (in that it has few instructions) imperative
-%% language, used as the first Intermediate Code in the HiPE compiler.
-%% Icode is closely related to Erlang, and Icode instructions operate
-%% on Erlang terms. </p>
-%%
-%% <h2><a href="#type-icode">Icode</a></h2>
-%%
-%% <p> Linear Icode for a function consists of:
-%% <ul>
-%% <li> the function's name (`{M,F,A}'), </li>
-%% <li> a list of parameters, </li>
-%% <li> a list of instructions, </li>
-%% <li> data, </li>
-%% <li> information about whether the function is a leaf function, </li>
-%% <li> information about whether the function is a closure, and </li>
-%% <li> the range for labels and variables in the code. </li>
-%% </ul>
-%% </p>
-%%
-%% <h2><a href="#type-icode_instruction">Icode Instructions</a> (and
-%% their components)</h2>
-%%
-%% Control flow:
-%% <dl>
-%% <dt><code><a href="#type-if">'if'</a>
-%% {Cond::<a href="#type-cond">cond()</a>,
-%% Args::[<a href="#type-arg">arg()</a>],
-%% TrueLabel::<a href="#type-label_name">label_name()</a>,
-%% FalseLabel::<a href="#type-label_name">label_name()</a>
-%% } ::
-%% <a href="#type-icode_instruction">icode_instr()</a></code></dt>
-%% <dd>
-%% The if instruction compares the arguments (Args) with
-%% condition (Cond) and jumps to either TrueLabel or
-%% FalseLabel. (At the moment...) There are only binary
-%% conditions so the number of arguments should be two.
-%% <p>
-%% An if instructions ends a basic block and should be followed
-%% by a label (or be the last instruction of the code).
-%% </p></dd>
-%%
-%% <dt><code><a href="#type-switch_val">switch_val</a>
-%% {Term::<a href="#type-arg">var()</a>,
-%% FailLabel::<a href="#type-label_name">label_name()</a>,
-%% Length::integer(),
-%% Cases::[{<a href="#type-symbol">symbol()</a>,<a
-%% href="#type-label_name">label_name()</a>}]
-%% }::
-%% <a href="#type-icode_instruction">icode_instr()</a></code></dt>
-%% <dd>
-%% The switch_val instruction compares the argument Term to the
-%% symbols in the lists Cases, control is transfered to the label
-%% that corresponds to the first symbol that matches. If no
-%% symbol matches control is transfered to FailLabel. (NOTE: The
-%% length argument is not currently in use.)
-%% <p>
-%% The switch_val instruction can be assumed to be implemented as
-%% efficiently as possible given the symbols in the case
-%% list. (Jump-table, bianry-serach, or nested ifs)
-%% </p><p>
-%% A switch_val instructions ends a basic block and should be
-%% followed by a label (or be the last instruction of the code).
-%% </p></dd>
-%%
-%% <dt><code><a href="#type-switch_tuple_arity">switch_tuple_arity</a>
-%% {Term::<a href="#type-arg">var()</a>,
-%% FailLabel::<a href="#type-label_name">label_name()</a>,
-%% Length::integer(),
-%% Cases::[{integer(),<a href="#type-label_name">label_name()</a>}]
-%% }::
-%% <a href="#type-icode_instruction">icode_instr()</a></code></dt>
-%% <dd>
-%% The switch_tuple_arity instruction compares the size of the
-%% tuple in the argument Term to the integers in the lists Cases,
-%% control is transfered to the label that corresponds to the
-%% first integer that matches. If no integer matches control is
-%% transfered to FailLabel. (NOTE: The length argument is not
-%% currently in use.)
-%% <p>
-%% The switch_tuple_arity instruction can be assumed to be
-%% implemented as efficently as possible given the symbols in the
-%% case list. (Jump-table, bianry-serach, or nested ifs)
-%% </p><p>
-%% A switch_tuple_arity instructions ends a basic block and
-%% should be followed by a label (or be the last instruction of
-%% the code).
-%% </p></dd>
-%%
-%% <dt>`type {typ_expr, arg, true_label, false_label}}'</dt>
-%% <dt>`goto {label}'</dt>
-%% <dt>`label {name}'</dt>
-%% </dl>
-%%
-%% Moves:
-%% <dl>
-%% <dt>`move {dst, src}'</dt>
-%% <dt>`phi {dst, arglist}'</dt>
-%% </dl>
-%%
-%% Function application:
-%% <dl>
-%% <dt>`call {[dst], fun, [arg], type, continuation, fail,
-%% in_guard}'</dt>
-%% <dd>
-%% Where `type' is one of {`local', `remote', `primop'}
-%% and `in_guard' is either `true' or `false'.</dd>
-%% <dt>`enter {fun, [arg], type}'</dt>
-%% <dd>
-%% Where `type' is one of {`local', `remote', `primop'}
-%% and `in_guard' is either `true' or `false'.</dd>
-%% <dt>`return {[var]}'</dt>
-%% <dd>
-%% <strong>WARNING:</strong> Multiple return values are yet not
-%% fully implemented and tested.
-%% </dd>
-%% </dl>
-%%
-%% Error handling:
-%% <dl>
-%% <dt>`begin_try {label, successor}'</dt>
-%% <dt>`end_try'</dt>
-%% <dt>`begin_handler {dstlist}'</dt>
-%% <dt>`fail {Args, Class}'</dt>
-%% <dd>Where `Class' is one of
-%% {`exit', `throw', `error', `rethrow'}. For `error/2', `[args]'
-%% is `[Reason,Trace]'. For `rethrow', `Args' is
-%% `[Exception,Reason]' - this only occurs in autogenerated code.
-%% </dd>
-%% </dl>
-%%
-%% Comments:
-%% <dl>
-%% <dt>`comment{Text::string()}'</dt>
-%% </dl>
-%%
-%% <h4>Notes</h4>
-%%
-%% <p> A constant can only show up on the RHS of a `move' instruction
-%% and in `if' and `switch_*'</p>
-%% <p>
-%% Classification of primops should be like this:
-%% <ul>
-%% <li> `erlang:exit/1, erlang:throw/1, erlang:error/1,
-%% erlang:error/2, erlang:fault/1',
-%% and `erlang:fault/2' should use the
-%% {@link fail(). fail-instruction} in Icode.</li>
-%% <li> Calls or tail-recursive calls to BIFs, operators, or internal
-%% functions should be implemented with `call' or `enter'
-%% respectively, with the primop flag set.</li>
-%% <li> All other Erlang functions should be implemented with `call'
-%% or `enter' respectively, without the primop flag set.</li>
-%% </ul>
-%% </p>
-%%
-%% <h4>Primops</h4>
-%%
-%% <pre>
-%% Constructors:
-%% cons - [Car, Cdr]
-%% mktuple - [Element1, Element2, ..., ElementN]
-%% call_fun - [BoundArg1, ..., BoundArgN, Fun]
-%% enter_fun - [BoundArg1, ..., BoundArgN, Fun]
-%% #mkfun{} - [FreeVar1, FreeVar2, ..., FreeVarN]
-%%
-%% Binaries:
-%% bs_init
-%% {bs_put_string, Bytes, Size}
-%% bs_final
-%%
-%% Selectors:
-%% element - [Index, Tuple]
-%% unsafe_hd - [List]
-%% unsafe_tl - [List]
-%% #unsafe_element{} - [Tuple]
-%% #unsafe_update_element{} - [Tuple, Val]
-%% #closure_element{} - [Fun]
-%%
-%% Arithmetic: [Arg1, Arg2]
-%% '+', '-', '*', '/', 'div', 'rem',
-%% 'band', 'bor', 'bxor', 'bnot', 'bsl', 'bsr'
-%%
-%% Receive:
-%% check_get_msg - []
-%% next_msg - []
-%% select_msg - []
-%% set_timeout - [Timeout]
-%% clear_timeout - []
-%% suspend_msg - []
-%%
-%% </pre>
-%%
-%% <h4>Guardops: (primops that can be used in guards and can fail)</h4>
-%% <pre>
-%% Selectors:
-%% unsafe_hd - [List]
-%% unsafe_tl - [List]
-%% #element{} - [Index, Tuple]
-%% #unsafe_element{} - [Tuple]
-%%
-%% Arithmetic: [Arg1, Arg2]
-%% '+', '-', '*', '/', 'div', 'rem',
-%% 'band', 'bor', 'bxor', 'bnot', 'bsl', 'bsr',
-%% fix_add, fix_sub %% Do these exist?
-%%
-%% Concurrency:
-%% {erlang,self,0} - []
-%% </pre>
-%%
-%%
-%% <h4>Relational Operations (Cond in if instruction)</h4>
-%% <pre>
-%% gt, lt, geq, leq,
-%% eqeq, neq, exact_eqeq, exact_neq
-%% </pre>
-%%
-%% <h4>Type tests</h4>
-%% <pre>
-%% list
-%% nil
-%% cons
-%% tuple
-%% {tuple, N}
-%% atom
-%% {atom, Atom}
-%% number
-%% integer
-%% {integer, N}
-%% fixnum
-%% bignum
-%% float
-%% pid
-%% port
-%% {record, Atom, Size}
-%% reference
-%% binary
-%% function
-%% </pre>
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-%%=====================================================================
-
--module(hipe_icode).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
-
-%% @type icode(Fun, Params, IsClosure, IsLeaf, Code, Data, VarRange,LabelRange)
-%% Fun = mfa()
-%% Params = [var()]
-%% IsClosure = boolean()
-%% IsLeaf = boolean()
-%% Code = [icode_instr()]
-%% Data = data()
-%% VarRange = {integer(),integer()}
-%% LabelRange = {integer(),integer()}
-%%
-%% @type icode_instr(I)
-%% I = if() | switch_val() | switch_tuple_arity() | type() | goto()
-%% | label() | move() | phi() | call() | enter() | return()
-%% | begin_try() | end_try() | begin_handler() | fail() | comment()
-%%
-%% @type if(Cond, Args, TrueLabel, FalseLabel)
-%% Cond = cond()
-%% Args = [arg()]
-%% TrueLabel = label_name()
-%% FalseLabel = label_name()
-%%
-%% @type switch_val(Term, FailLabel, Length, Cases)
-%% Term = var()
-%% FailLabel = label_name()
-%% Length = integer()
-%% Cases = [{symbol(),label_name()}]
-%%
-%% @type switch_tuple_arity(Arg, FailLabel, Length, Cases)
-%% Term = var()
-%% FailLabel = label_name()
-%% Length = integer()
-%% Cases = [{symbol(),label_name()}]
-%%
-%% @type type(TypeTest, Arg, True_label, False_label)
-%% TypeTest = type_test()
-%% Args = [arg()]
-%% TrueLabel = label_name()
-%% FalseLabel = label_name()
-%%
-%% @type goto(Label) Label = label_name()
-%%
-%% @type label(Name) Name = label_name()
-%%
-%% @type move(Dst, Src) Dst = var() Src = arg()
-%%
-%% @type phi(Dst, Id, Arglist)
-%% Dst = var() | fvar()
-%% Id = var() | fvar()
-%% Arglist = [{Pred, Src}]
-%% Pred = label_name()
-%% Src = var() | fvar()
-%%
-%% @type call(Dst, Fun, Arg, Type, Continuation, FailLabel, InGuard)
-%% Dst = [var()]
-%% Fun = mfa() | primop() | closure()
-%% Arg = [var()]
-%% Type = call_type()
-%% Continuation = [] | label_name()
-%% FailLabel = [] | label_name()
-%% InGuard = boolean()
-%%
-%% @type enter(Fun, Arg, Type)
-%% Fun = mfa() | primop() | closure()
-%% Arg = [var()]
-%% Type = call_type()
-%%
-%% @type return (Vars) Vars = [var()]
-%%
-%% @type begin_try(FailLabel, Successor)
-%% FailLabel = label_name()
-%% Successor = label_name()
-%%
-%% @type end_try()
-%%
-%% @type begin_handler(Dst)
-%% Dst = [var()]
-%%
-%% @type fail(Class, Args, Label)
-%% Class = exit_class()
-%% Args = [var()]
-%% Label = label_name()
-%%
-%% @type comment(Text) Text = string()
-
-%% @type call_type() = 'local' | 'remote' | 'primop'
-%% @type exit_class() = 'exit' | 'throw' | 'error' | 'rethrow'
-%% @type cond() = gt | lt | geq | leq | eqeq | neq | exact_eqeq | exact_neq
-%% @type type_test() =
-%% list
-%% | nil
-%% | cons
-%% | tuple
-%% | {tuple, integer()}
-%% | atom
-%% | {atom, atom()}
-%% | number
-%% | integer
-%% | {integer, integer()}
-%% | fixnum
-%% | bignum
-%% | float
-%% | pid
-%% | port
-%% | {record, atom(), integer()}
-%% | reference
-%% | binary
-%% | function
-%%
-%% @type mfa(Mod,Fun,Arity) = {atom(),atom(),arity()}
-
-%% @type arg() = var() | const()
-%% @type farg() = fvar() | float()
-%% @type var(Name) Name = integer()
-%% @type fvar(Name) Name = integer()
-%% @type label_name(Name) Name = integer()
-%% @type symbol(S) = atom() | number()
-%% @type const(C) C = immediate()
-%% @type immediate(I) = I
-%% I = term()
-%% @end
-
-
-%% ____________________________________________________________________
-%%
-%% Exports
-%%
--export([mk_icode/7, %% mk_icode(Fun, Params, IsClosure, IsLeaf,
- %% Code, VarRange, LabelRange)
- mk_icode/8, %% mk_icode(Fun, Params, IsClosure, IsLeaf,
- %% Code, Data, VarRange, LabelRange)
- icode_fun/1,
- icode_params/1,
- icode_params_update/2,
- icode_is_closure/1,
- icode_closure_arity/1,
- icode_closure_arity_update/2,
- icode_is_leaf/1,
- icode_code/1,
- icode_code_update/2,
- icode_data/1,
- %% icode_data_update/2,
- icode_var_range/1,
- icode_label_range/1,
- icode_info/1,
- icode_info_update/2]).
-
--export([mk_if/4, %% mk_if(Op, Args, TrueLbl, FalseLbl)
- %% mk_if/5, %% mk_if(Op, Args, TrueLbl, FalseLbl, Prob)
- if_op/1,
- if_op_update/2,
- if_true_label/1,
- if_false_label/1,
- if_args/1,
- if_args_update/2,
- if_pred/1,
- %% is_if/1,
-
- mk_switch_val/4,
- %% mk_switch_val/5,
- switch_val_term/1,
- switch_val_fail_label/1,
- %% switch_val_length/1,
- switch_val_cases/1,
- switch_val_cases_update/2,
- %% is_switch_val/1,
-
- mk_switch_tuple_arity/4,
- %% mk_switch_tuple_arityl/5,
- switch_tuple_arity_term/1,
- switch_tuple_arity_fail_label/1,
- switch_tuple_arity_fail_label_update/2,
- %% switch_tuple_arity_length/1,
- switch_tuple_arity_cases/1,
- switch_tuple_arity_cases_update/2,
- %% is_switch_tuple_arity/1,
-
- mk_type/4, %% mk_type(Args, Type, TrueLbl, FalseLbl)
- mk_type/5, %% mk_type(Args, Type, TrueLbl, FalseLbl, P)
- type_args/1,
- %% type_args_update/2,
- type_test/1,
- type_true_label/1,
- type_false_label/1,
- type_pred/1,
- is_type/1,
-
- mk_guardop/5, %% mk_guardop(Dst, Fun, Args, Continuation, Fail)
- mk_primop/3, %% mk_primop(Dst, Fun, Args)
- mk_primop/5, %% mk_primop(Dst, Fun, Args, Cont, Fail)
- mk_call/5, %% mk_call(Dst, Mod, Fun, Args, Type)
- %% mk_call/7, %% mk_call(Dst, Mod, Fun, Args, Type,
- %% Continuation, Fail)
- mk_call/8, %% mk_call(Dst, Mod, Fun, Args, Type,
- %% Continuation, Fail, Guard)
- call_dstlist/1,
- call_dstlist_update/2,
- %% call_dst_type/1,
- call_args/1,
- call_args_update/2,
- call_fun/1,
- call_fun_update/2,
- call_type/1,
- call_continuation/1,
- call_fail_label/1,
- call_set_fail_label/2,
- call_set_continuation/2,
- is_call/1,
- call_in_guard/1,
-
- mk_goto/1, %% mk_goto(Lbl)
- goto_label/1,
-
- mk_enter/4, %% mk_enter(Mod, Fun, Args, Type)
- mk_enter_primop/2, %% mk_enter_primop(Op, Type)
- enter_fun/1,
- enter_fun_update/2,
- enter_args/1,
- enter_args_update/2,
- enter_type/1,
- is_enter/1,
-
- mk_return/1, %% mk_return(Vars)
- %% mk_fail/1, %% mk_fail(Args) class = exit
- mk_fail/2, %% mk_fail(Args, Class)
- %% mk_fail/3, %% mk_fail(Args, Class, Label)
- mk_move/2, %% mk_move(Dst, Src)
- %% mk_moves/2, %% mk_moves(DstList, SrcList)
- mk_begin_try/2, %% mk_begin_try(Label, Successor)
- mk_begin_handler/1, %% mk_begin_handler(ReasonDst)
- mk_end_try/0, %% mk_end_try()
- %% mk_elements/2, %% mk_elements(Tuple, Vars)
- mk_label/1, %% mk_label(Name)
- mk_new_label/0, %% mk_new_label()
- mk_comment/1, %% mk_comment(Text)
- mk_const/1, %% mk_const(Const)
- mk_var/1, %% mk_var(Id)
- annotate_variable/2, %% annotate_var_or_reg(VarOrReg, Type)
- unannotate_variable/1,%% unannotate_var_or_reg(VarOrReg)
- mk_reg/1, %% mk_reg(Id)
- mk_reg_gcsafe/1, %% mk_reg_gcsafe(Id)
- mk_fvar/1, %% mk_fvar(Id)
- mk_new_var/0, %% mk_new_var()
- mk_new_fvar/0, %% mk_new_fvar()
- mk_new_reg/0, %% mk_new_reg()
- mk_new_reg_gcsafe/0, %% mk_new_reg_gcsafe()
- mk_phi/1, %% mk_phi(Id)
- mk_phi/2 %% mk_phi(Id, ArgList)
- ]).
-
-%%
-%% Identifiers
-%%
-
--export([%% is_fail/1,
- is_return/1,
- is_move/1,
- %% is_begin_try/1,
- %% is_begin_handler/1,
- %% is_end_try/1,
- is_goto/1,
- is_label/1,
- is_comment/1,
- is_const/1,
- is_var/1,
- is_fvar/1,
- is_reg/1,
- is_variable/1,
- is_annotated_variable/1,
- %% is_uncond/1,
- is_phi/1]).
-
-%%
-%% Selectors
-%%
-
--export([phi_dst/1,
- phi_id/1,
- %% phi_args/1,
- phi_arg/2,
- phi_arglist/1,
- phi_enter_pred/3,
- phi_remove_pred/2,
- phi_redirect_pred/3,
- move_dst/1,
- move_src/1,
- move_src_update/2,
- begin_try_label/1,
- begin_try_successor/1,
- begin_handler_dstlist/1,
- label_name/1,
- comment_text/1,
- return_vars/1,
- fail_args/1,
- fail_class/1,
- fail_label/1,
- fail_set_label/2,
- var_name/1,
- variable_annotation/1,
- fvar_name/1,
- reg_name/1,
- reg_is_gcsafe/1,
- const_value/1
- ]).
-
-%%
-%% Misc
-%%
-
--export([args/1,
- uses/1,
- defines/1,
- is_safe/1,
- reduce_unused/1,
- strip_comments/1,
- subst/2,
- subst_uses/2,
- subst_defines/2,
- redirect_jmp/3,
- successors/1,
- fails_to/1,
- is_branch/1
- ]).
-
--export([highest_var/1, highest_label/1]).
-
-%%
-%% Exported types
-%%
-
--export_type([icode/0, params/0]).
-
--type params() :: [icode_var()].
-
-%%---------------------------------------------------------------------
-%%
-%% Icode
-%%
-%%---------------------------------------------------------------------
-
--spec mk_icode(mfa(), params(), boolean(), boolean(), [icode_instr()],
- {non_neg_integer(),non_neg_integer()},
- {icode_lbl(),icode_lbl()}) -> icode().
-mk_icode(Fun, Params, IsClosure, IsLeaf, Code, VarRange, LabelRange) ->
- #icode{'fun'=Fun, params=Params, code=Code,
- is_closure=IsClosure,
- is_leaf=IsLeaf,
- data=hipe_consttab:new(),
- var_range=VarRange,
- label_range=LabelRange}.
-
--spec mk_icode(mfa(), params(), boolean(), boolean(), [icode_instr()],
- hipe_consttab(), {non_neg_integer(),non_neg_integer()},
- {icode_lbl(),icode_lbl()}) -> icode().
-mk_icode(Fun, Params, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) ->
- #icode{'fun'=Fun, params=Params, code=Code,
- data=Data, is_closure=IsClosure, is_leaf=IsLeaf,
- var_range=VarRange, label_range=LabelRange}.
-
--spec icode_fun(icode()) -> mfa().
-icode_fun(#icode{'fun' = MFA}) -> MFA.
-
--spec icode_params(icode()) -> params().
-icode_params(#icode{params = Params}) -> Params.
-
--spec icode_params_update(icode(), params()) -> icode().
-icode_params_update(Icode, Params) ->
- Icode#icode{params = Params}.
-
--spec icode_is_closure(icode()) -> boolean().
-icode_is_closure(#icode{is_closure = Closure}) -> Closure.
-
--spec icode_is_leaf(icode()) -> boolean().
-icode_is_leaf(#icode{is_leaf = Leaf}) -> Leaf.
-
--spec icode_code(icode()) -> icode_instrs().
-icode_code(#icode{code = Code}) -> Code.
-
--spec icode_code_update(icode(), icode_instrs()) -> icode().
-icode_code_update(Icode, NewCode) ->
- Vmax = highest_var(NewCode),
- Lmax = highest_label(NewCode),
- Icode#icode{code = NewCode, var_range = {0,Vmax}, label_range = {0,Lmax}}.
-
--spec icode_data(icode()) -> hipe_consttab().
-icode_data(#icode{data=Data}) -> Data.
-
-%% %% -spec icode_data_update(icode(), hipe_consttab()) -> icode().
-%% icode_data_update(Icode, NewData) -> Icode#icode{data=NewData}.
-
--spec icode_var_range(icode()) -> {non_neg_integer(), non_neg_integer()}.
-icode_var_range(#icode{var_range = VarRange}) -> VarRange.
-
--spec icode_label_range(icode()) -> {non_neg_integer(), non_neg_integer()}.
-icode_label_range(#icode{label_range = LabelRange}) -> LabelRange.
-
--spec icode_info(icode()) -> icode_info().
-icode_info(#icode{info = Info}) -> Info.
-
--spec icode_info_update(icode(), icode_info()) -> icode().
-icode_info_update(Icode, Info) -> Icode#icode{info = Info}.
-
--spec icode_closure_arity(icode()) -> arity().
-icode_closure_arity(#icode{closure_arity = Arity}) -> Arity.
-
--spec icode_closure_arity_update(icode(), arity()) -> icode().
-icode_closure_arity_update(Icode, Arity) -> Icode#icode{closure_arity = Arity}.
-
-
-%%----------------------------------------------------------------------------
-%% Instructions
-%%----------------------------------------------------------------------------
-
-%%----
-%% if
-%%----
-
--spec mk_if(icode_if_op(), [icode_term_arg()],
- icode_lbl(), icode_lbl()) -> #icode_if{}.
-mk_if(Op, Args, TrueLbl, FalseLbl) ->
- #icode_if{op=Op, args=Args, true_label=TrueLbl, false_label=FalseLbl, p=0.5}.
-%% mk_if(Op, Args, TrueLbl, FalseLbl, P) ->
-%% #icode_if{op=Op, args=Args, true_label=TrueLbl, false_label=FalseLbl, p=P}.
-
--spec if_op(#icode_if{}) -> icode_if_op().
-if_op(#icode_if{op=Op}) -> Op.
-
--spec if_op_update(#icode_if{}, icode_if_op()) -> #icode_if{}.
-if_op_update(IF, NewOp) -> IF#icode_if{op=NewOp}.
-
--spec if_args(#icode_if{}) -> [icode_term_arg()].
-if_args(#icode_if{args=Args}) -> Args.
-
--spec if_args_update(#icode_if{}, [icode_term_arg()]) -> #icode_if{}.
-if_args_update(IF, Args) -> IF#icode_if{args=Args}.
-
--spec if_true_label(#icode_if{}) -> icode_lbl().
-if_true_label(#icode_if{true_label=TrueLbl}) -> TrueLbl.
-
--spec if_true_label_update(#icode_if{}, icode_lbl()) -> #icode_if{}.
-if_true_label_update(IF, TrueLbl) -> IF#icode_if{true_label=TrueLbl}.
-
--spec if_false_label(#icode_if{}) -> icode_lbl().
-if_false_label(#icode_if{false_label=FalseLbl}) -> FalseLbl.
-
--spec if_false_label_update(#icode_if{}, icode_lbl()) -> #icode_if{}.
-if_false_label_update(IF, FalseLbl) -> IF#icode_if{false_label=FalseLbl}.
-
--spec if_pred(#icode_if{}) -> float().
-if_pred(#icode_if{p=P}) -> P.
-
-%%------------
-%% switch_val
-%%------------
-
--spec mk_switch_val(icode_var(), icode_lbl(),
- non_neg_integer(), [icode_switch_case()]) ->
- #icode_switch_val{}.
-mk_switch_val(Term = #icode_variable{kind='var'}, FailLbl, Length, Cases) ->
- #icode_switch_val{term=Term, fail_label=FailLbl, length=Length, cases=Cases}.
-
--spec switch_val_term(#icode_switch_val{}) -> icode_var().
-switch_val_term(#icode_switch_val{term=Term}) -> Term.
-
--spec switch_val_fail_label(#icode_switch_val{}) -> icode_lbl().
-switch_val_fail_label(#icode_switch_val{fail_label=FailLbl}) -> FailLbl.
-
--spec switch_val_fail_label_update(#icode_switch_val{}, icode_lbl()) ->
- #icode_switch_val{}.
-switch_val_fail_label_update(SV, FailLbl) ->
- SV#icode_switch_val{fail_label=FailLbl}.
-
-%% switch_val_length(#icode_switch_val{length=Length}) -> Length.
-
--spec switch_val_cases(#icode_switch_val{}) -> [icode_switch_case()].
-switch_val_cases(#icode_switch_val{cases=Cases}) -> Cases.
-
--spec switch_val_cases_update(#icode_switch_val{}, [icode_switch_case()]) ->
- #icode_switch_val{}.
-switch_val_cases_update(SV, NewCases) ->
- SV#icode_switch_val{cases = NewCases}.
-
-%%--------------------
-%% switch_tuple_arity
-%%--------------------
-
--spec mk_switch_tuple_arity(icode_var(), icode_lbl(),
- non_neg_integer(), [icode_switch_case()]) ->
- #icode_switch_tuple_arity{}.
-mk_switch_tuple_arity(Term = #icode_variable{kind='var'}, FailLbl, Length, Cases) ->
- #icode_switch_tuple_arity{term=Term, fail_label=FailLbl,
- length=Length, cases=Cases}.
-
--spec switch_tuple_arity_term(#icode_switch_tuple_arity{}) -> icode_var().
-switch_tuple_arity_term(#icode_switch_tuple_arity{term=Term}) -> Term.
-
--spec switch_tuple_arity_fail_label(#icode_switch_tuple_arity{}) -> icode_lbl().
-switch_tuple_arity_fail_label(#icode_switch_tuple_arity{fail_label=FailLbl}) ->
- FailLbl.
-
--spec switch_tuple_arity_fail_label_update(#icode_switch_tuple_arity{}, icode_lbl()) ->
- #icode_switch_tuple_arity{}.
-switch_tuple_arity_fail_label_update(S, FailLbl) ->
- S#icode_switch_tuple_arity{fail_label=FailLbl}.
-
-%% switch_tuple_arity_length(#icode_switch_tuple_arity{length=Length}) -> Length.
-
--spec switch_tuple_arity_cases(#icode_switch_tuple_arity{}) -> [icode_switch_case()].
-switch_tuple_arity_cases(#icode_switch_tuple_arity{cases=Cases}) -> Cases.
-
--spec switch_tuple_arity_cases_update(#icode_switch_tuple_arity{},
- [icode_switch_case()]) ->
- #icode_switch_tuple_arity{}.
-switch_tuple_arity_cases_update(Cond, NewCases) ->
- Cond#icode_switch_tuple_arity{cases = NewCases}.
-
-%%------
-%% type
-%%------
-
--spec mk_type([icode_term_arg()], icode_type_test(), icode_lbl(), icode_lbl()) ->
- #icode_type{}.
-mk_type(Args, Test, TrueLbl, FalseLbl) ->
- mk_type(Args, Test, TrueLbl, FalseLbl, 0.5).
-
--spec mk_type([icode_term_arg()], icode_type_test(),
- icode_lbl(), icode_lbl(), float()) -> #icode_type{}.
-mk_type(Args, Test, TrueLbl, FalseLbl, P) ->
- #icode_type{test=Test, args=Args,
- true_label=TrueLbl, false_label=FalseLbl, p=P}.
-
--spec type_test(#icode_type{}) -> icode_type_test().
-type_test(#icode_type{test=Test}) -> Test.
-
--spec type_args(#icode_type{}) -> [icode_term_arg()].
-type_args(#icode_type{args=Args}) -> Args.
-
-%% type_args_update(T, Args) -> T#icode_type{args=Args}.
-
--spec type_true_label(#icode_type{}) -> icode_lbl().
-type_true_label(#icode_type{true_label=TrueLbl}) -> TrueLbl.
-
--spec type_false_label(#icode_type{}) -> icode_lbl().
-type_false_label(#icode_type{false_label=FalseLbl}) -> FalseLbl.
-
--spec type_pred(#icode_type{}) -> float().
-type_pred(#icode_type{p=P}) -> P.
-
--spec is_type(icode_instr()) -> boolean().
-is_type(#icode_type{}) -> true;
-is_type(_) -> false.
-
-%%------
-%% goto
-%%------
-
--spec mk_goto(icode_lbl()) -> #icode_goto{}.
-mk_goto(Lbl) -> #icode_goto{label=Lbl}.
-
--spec goto_label(#icode_goto{}) -> icode_lbl().
-goto_label(#icode_goto{label=Lbl}) -> Lbl.
-
--spec is_goto(icode_instr()) -> boolean().
-is_goto(#icode_goto{}) -> true;
-is_goto(_) -> false.
-
-%%--------
-%% return
-%%--------
-
--spec mk_return([icode_var()]) -> #icode_return{}.
-mk_return(Vars) -> #icode_return{vars=Vars}.
-
--spec return_vars(#icode_return{}) -> [icode_var()].
-return_vars(#icode_return{vars=Vars}) -> Vars.
-
--spec is_return(icode_instr()) -> boolean().
-is_return(#icode_return{}) -> true;
-is_return(_) -> false.
-
-%%------
-%% fail
-%%------
-
-%% mk_fail(Args) when is_list(Args) -> mk_fail(Args, error).
-
--spec mk_fail([icode_term_arg()], icode_exit_class()) -> #icode_fail{}.
-mk_fail(Args, Class) when is_list(Args) ->
- case Class of
- error -> ok;
- exit -> ok;
- rethrow -> ok;
- throw -> ok
- end,
- #icode_fail{class=Class, args=Args}.
-
-%% mk_fail(Args, Class, Label) when is_list(Args) ->
-%% #icode_fail{class=Class, args=Args, fail_label=Label}.
-
--spec fail_class(#icode_fail{}) -> icode_exit_class().
-fail_class(#icode_fail{class=Class}) -> Class.
-
--spec fail_args(#icode_fail{}) -> [icode_term_arg()].
-fail_args(#icode_fail{args=Args}) -> Args.
-
--spec fail_label(#icode_fail{}) -> [] | icode_lbl().
-fail_label(#icode_fail{fail_label=Label}) -> Label.
-
--spec fail_set_label(#icode_fail{}, [] | icode_lbl()) -> #icode_fail{}.
-fail_set_label(I=#icode_fail{}, Label) ->
- I#icode_fail{fail_label = Label}.
-
-%%------
-%% move
-%%------
-
--spec mk_move(#icode_variable{}, #icode_variable{} | #icode_const{}) ->
- #icode_move{}.
-mk_move(Dst, Src) ->
- case Src of
- #icode_variable{} -> ok;
- #icode_const{} -> ok
- end,
- #icode_move{dst=Dst, src=Src}.
-
--spec move_dst(#icode_move{}) -> #icode_variable{}.
-move_dst(#icode_move{dst=Dst}) -> Dst.
-
--spec move_src(#icode_move{}) -> #icode_variable{} | #icode_const{}.
-move_src(#icode_move{src=Src}) -> Src.
-
--spec move_src_update(#icode_move{}, #icode_variable{} | #icode_const{}) ->
- #icode_move{}.
-move_src_update(M, NewSrc) -> M#icode_move{src=NewSrc}.
-
--spec is_move(icode_instr()) -> boolean().
-is_move(#icode_move{}) -> true;
-is_move(_) -> false.
-
-%%-----
-%% phi
-%%-----
-
-%% The id field is not entirely redundant. It is used in mappings
-%% in the SSA pass since the dst field can change.
--spec mk_phi(#icode_variable{}) -> #icode_phi{}.
-mk_phi(Var) -> #icode_phi{dst=Var, id=Var, arglist=[]}.
-
--spec mk_phi(#icode_variable{}, [{icode_lbl(), #icode_variable{}}]) ->
- #icode_phi{}.
-mk_phi(Var, ArgList) -> #icode_phi{dst=Var, id=Var, arglist=ArgList}.
-
--spec phi_dst(#icode_phi{}) -> #icode_variable{}.
-phi_dst(#icode_phi{dst=Dst}) -> Dst.
-
--spec phi_id(#icode_phi{}) -> #icode_variable{}.
-phi_id(#icode_phi{id=Id}) -> Id.
-
--spec phi_arglist(#icode_phi{}) -> [{icode_lbl(), #icode_variable{}}].
-phi_arglist(#icode_phi{arglist=ArgList}) -> ArgList.
-
--spec phi_args(#icode_phi{}) -> [#icode_variable{}].
-phi_args(P) -> [Var || {_, Var} <- phi_arglist(P)].
-
--spec phi_arg(#icode_phi{}, icode_lbl()) -> #icode_variable{}.
-phi_arg(P, Pred) ->
- case lists:keyfind(Pred, 1, phi_arglist(P)) of
- {_, Var} -> Var;
- false -> exit({'No such predecessor to phi', {Pred, P}})
- end.
-
--spec is_phi(icode_instr()) -> boolean().
-is_phi(#icode_phi{}) -> true;
-is_phi(_) -> false.
-
--spec phi_enter_pred(#icode_phi{}, icode_lbl(), #icode_variable{}) ->
- #icode_phi{}.
-phi_enter_pred(Phi, Pred, Var) ->
- NewArg = {Pred, Var},
- Phi#icode_phi{arglist=[NewArg|lists:keydelete(Pred, 1, phi_arglist(Phi))]}.
-
--spec phi_remove_pred(#icode_phi{}, icode_lbl()) -> #icode_move{} | #icode_phi{}.
-phi_remove_pred(Phi, Pred) ->
- NewArgList = lists:keydelete(Pred, 1, phi_arglist(Phi)),
- case NewArgList of
- [Arg] -> %% the Phi should be turned into an appropriate move instruction
- {_Label, Var = #icode_variable{}} = Arg,
- mk_move(phi_dst(Phi), Var);
- [_|_] ->
- Phi#icode_phi{arglist=NewArgList}
- end.
-
-phi_argvar_subst(P, Subst) ->
- NewArgList = [{Pred, subst1(Subst, Var)} || {Pred,Var} <- phi_arglist(P)],
- P#icode_phi{arglist=NewArgList}.
-
--spec phi_redirect_pred(#icode_phi{}, icode_lbl(), icode_lbl()) -> #icode_phi{}.
-phi_redirect_pred(P, OldPred, NewPred) ->
- Subst = [{OldPred, NewPred}],
- NewArgList = [{subst1(Subst, Pred), Var} || {Pred,Var} <- phi_arglist(P)],
- P#icode_phi{arglist=NewArgList}.
-
-%%
-%% primop and guardop
-%%
-%% Whether a function is a "primop" - i.e., an internal thing - or not,
-%% is really only shown by its name. An {M,F,A} always represents a
-%% function in some Erlang module (although it might be a BIF, and
-%% could possibly be inline expanded). It is convenient to let the
-%% constructor functions check the name and set the type automatically,
-%% especially for guardops - some guardops are primitives and some are
-%% MFA:s, and this way we won't have to rewrite all calls to mk_guardop
-%% to flag whether they are primops or not.
-
--spec mk_primop([#icode_variable{}], icode_funcall(),
- [icode_argument()]) -> #icode_call{}.
-mk_primop(DstList, Fun, ArgList) ->
- mk_primop(DstList, Fun, ArgList, [], []).
-
--spec mk_primop([#icode_variable{}], icode_funcall(),
- [icode_argument()], [] | icode_lbl(), [] | icode_lbl()) ->
- #icode_call{}.
-mk_primop(DstList, Fun, ArgList, Continuation, Fail) ->
- Type = op_type(Fun),
- make_call(DstList, Fun, ArgList, Type, Continuation, Fail, false).
-
-%% Note that a 'guardop' is just a call that occurred in a guard. In
-%% this case, we should always have continuation labels True and False.
-
--spec mk_guardop([#icode_variable{}], icode_funcall(),
- [icode_argument()], icode_lbl(), icode_lbl()) -> #icode_call{}.
-mk_guardop(DstList, Fun, ArgList, True, False) ->
- Type = op_type(Fun),
- make_call(DstList, Fun, ArgList, Type, True, False, true).
-
-op_type(Fun) ->
- case is_mfa(Fun) of
- true -> remote;
- false -> primop
- end.
-
-is_mfa({M,F,A}) when is_atom(M), is_atom(F),
- is_integer(A), 0 =< A, A =< 255 -> true;
-is_mfa(_) -> false.
-
-%%------
-%% call
-%%------
-
--spec mk_call([#icode_variable{}], atom(), atom(),
- [icode_argument()], 'local' | 'remote') -> #icode_call{}.
-mk_call(DstList, M, F, ArgList, Type) ->
- mk_call(DstList, M, F, ArgList, Type, [], [], false).
-
-%% mk_call(DstList, M, F, ArgList, Type, Continuation, Fail) ->
-%% mk_call(DstList, M, F, ArgList, Type, Continuation, Fail, false).
-
--spec mk_call([#icode_variable{}], atom(), atom(), [icode_argument()],
- 'local' | 'remote', [] | icode_lbl(), [] | icode_lbl(), boolean()) ->
- #icode_call{}.
-mk_call(DstList, M, F, ArgList, Type, Continuation, Fail, InGuard)
- when is_atom(M), is_atom(F) ->
- case Type of
- local -> ok;
- remote -> ok
- end,
- Fun = {M,F,length(ArgList)},
- make_call(DstList, Fun, ArgList, Type, Continuation, Fail, InGuard).
-
-%% The common constructor for all calls (for internal use only)
-%%
-%% Note: If the "guard" flag is `true', it means that if the call fails,
-%% we can simply jump to the Fail label (if it exists) without
-%% generating any additional exception information - it isn't needed.
--spec make_call([#icode_variable{}], icode_funcall(), [icode_argument()],
- icode_call_type(), [] | icode_lbl(), [] | icode_lbl(), boolean()) ->
- #icode_call{}.
-make_call(DstList, Fun, ArgList, Type, Continuation, Fail, InGuard) ->
- #icode_call{dstlist=DstList, 'fun'=Fun, args=ArgList, type=Type,
- continuation=Continuation, fail_label=Fail, in_guard=InGuard}.
-
--spec call_dstlist(#icode_call{}) -> [#icode_variable{}].
-call_dstlist(#icode_call{dstlist=DstList}) -> DstList.
-
--spec call_dstlist_update(#icode_call{}, [#icode_variable{}]) -> #icode_call{}.
-call_dstlist_update(C, Dest) -> C#icode_call{dstlist=Dest}.
-
--spec call_type(#icode_call{}) -> icode_call_type().
-call_type(#icode_call{type=Type}) -> Type.
-
-%% -spec call_dst_type(#icode_call{}) -> erl_type().
-%% call_dst_type(#icode_call{dst_type=DstType}) -> DstType.
-
--spec call_args(#icode_call{}) -> [icode_argument()].
-call_args(#icode_call{args=Args}) -> Args.
-
--spec call_args_update(#icode_call{}, [icode_argument()]) -> #icode_call{}.
-call_args_update(C, Args) -> C#icode_call{args=Args}.
-
--spec call_fun(#icode_call{}) -> icode_funcall().
-call_fun(#icode_call{'fun'=Fun}) -> Fun.
-
-%% Note that updating the name field requires recomputing the call type,
-%% in case it changes from a remote/local call to a primop call.
--spec call_fun_update(#icode_call{}, icode_funcall()) -> #icode_call{}.
-call_fun_update(C, Fun) ->
- Type = case is_mfa(Fun) of
- true -> call_type(C);
- false -> primop
- end,
- C#icode_call{'fun'=Fun, type=Type}.
-
--spec call_continuation(#icode_call{}) -> [] | icode_lbl().
-call_continuation(#icode_call{continuation=Continuation}) -> Continuation.
-
--spec call_fail_label(#icode_call{}) -> [] | icode_lbl().
-call_fail_label(#icode_call{fail_label=Fail}) -> Fail.
-
--spec call_set_continuation(#icode_call{}, [] | icode_lbl()) -> #icode_call{}.
-call_set_continuation(I, Continuation) ->
- I#icode_call{continuation = Continuation}.
-
--spec call_set_fail_label(#icode_call{}, [] | icode_lbl()) -> #icode_call{}.
-call_set_fail_label(I=#icode_call{}, Fail) ->
- case Fail of
- [] ->
- I#icode_call{fail_label=Fail, in_guard=false};
- _ ->
- I#icode_call{fail_label=Fail}
- end.
-
--spec is_call(icode_instr()) -> boolean().
-is_call(#icode_call{}) -> true;
-is_call(_) -> false.
-
--spec call_in_guard(#icode_call{}) -> boolean().
-call_in_guard(#icode_call{in_guard=InGuard}) -> InGuard.
-
-%%-------
-%% enter
-%%-------
-
--spec mk_enter(atom(), atom(), [icode_term_arg()], 'local' | 'remote') ->
- #icode_enter{}.
-mk_enter(M, F, Args, Type) when is_atom(M), is_atom(F) ->
- case Type of
- local -> ok;
- remote -> ok
- end,
- #icode_enter{'fun'={M,F,length(Args)}, args=Args, type=Type}.
-
--spec enter_fun(#icode_enter{}) -> icode_funcall().
-enter_fun(#icode_enter{'fun'=Fun}) -> Fun.
-
--spec enter_fun_update(#icode_enter{}, icode_funcall()) ->
- #icode_enter{}.
-enter_fun_update(E, Fun) ->
- Type = case is_mfa(Fun) of
- true -> enter_type(E);
- false -> primop
- end,
- E#icode_enter{'fun'=Fun, type=Type}.
-
--spec enter_args(#icode_enter{}) -> [icode_term_arg()].
-enter_args(#icode_enter{args=Args}) -> Args.
-
--spec enter_args_update(#icode_enter{}, [icode_term_arg()]) -> #icode_enter{}.
-enter_args_update(E, Args) -> E#icode_enter{args=Args}.
-
--spec enter_type(#icode_enter{}) -> icode_call_type().
-enter_type(#icode_enter{type=Type}) -> Type.
-
--spec is_enter(icode_instr()) -> boolean().
-is_enter(#icode_enter{}) -> true;
-is_enter(_) -> false.
-
--spec mk_enter_primop(icode_primop(), [icode_term_arg()]) ->
- #icode_enter{type::'primop'}.
-mk_enter_primop(Op, Args) ->
- #icode_enter{'fun'=Op, args=Args, type=primop}.
-
-%%-----------
-%% begin_try
-%%-----------
-
-%% The reason that begin_try is a branch instruction is just so that it
-%% keeps the fail-to block linked into the CFG, until the exception
-%% handling instructions are eliminated.
-
--spec mk_begin_try(icode_lbl(), icode_lbl()) -> #icode_begin_try{}.
-mk_begin_try(Label, Successor) ->
- #icode_begin_try{label=Label, successor=Successor}.
-
--spec begin_try_label(#icode_begin_try{}) -> icode_lbl().
-begin_try_label(#icode_begin_try{label=Label}) -> Label.
-
--spec begin_try_successor(#icode_begin_try{}) -> icode_lbl().
-begin_try_successor(#icode_begin_try{successor=Successor}) -> Successor.
-
-%%---------
-%% end_try
-%%---------
-
--spec mk_end_try() -> #icode_end_try{}.
-mk_end_try() -> #icode_end_try{}.
-
-%%---------------
-%% begin_handler
-%%---------------
-
--spec mk_begin_handler([icode_var()]) -> #icode_begin_handler{}.
-mk_begin_handler(Dstlist) ->
- #icode_begin_handler{dstlist=Dstlist}.
-
--spec begin_handler_dstlist(#icode_begin_handler{}) -> [icode_var()].
-begin_handler_dstlist(#icode_begin_handler{dstlist=Dstlist}) -> Dstlist.
-
-%% -spec is_begin_handler(icode_instr()) -> boolean().
-%% is_begin_handler(#icode_begin_handler{}) -> true;
-%% is_begin_handler(_) -> false.
-
-%%-------
-%% label
-%%-------
-
--spec mk_label(icode_lbl()) -> #icode_label{}.
-mk_label(Name) when is_integer(Name), Name >= 0 -> #icode_label{name=Name}.
-
--spec label_name(#icode_label{}) -> icode_lbl().
-label_name(#icode_label{name=Name}) -> Name.
-
--spec is_label(icode_instr()) -> boolean().
-is_label(#icode_label{}) -> true;
-is_label(_) -> false.
-
-%%---------
-%% comment
-%%---------
-
--spec mk_comment(icode_comment_text()) -> #icode_comment{}.
-%% @doc If `Txt' is a list of characters (possibly deep), it will be
-%% printed as a string; otherwise, `Txt' will be printed as a term.
-mk_comment(Txt) -> #icode_comment{text=Txt}.
-
--spec comment_text(#icode_comment{}) -> icode_comment_text().
-comment_text(#icode_comment{text=Txt}) -> Txt.
-
--spec is_comment(icode_instr()) -> boolean().
-is_comment(#icode_comment{}) -> true;
-is_comment(_) -> false.
-
-
-%%---------------------------------------------------------------------
-%% Arguments (variables and constants)
-%%---------------------------------------------------------------------
-
-%%-------
-%% const
-%%-------
-
--spec mk_const(simple_const() | structured_const() | binary()) -> #icode_const{}.
-mk_const(C) -> #icode_const{value=#flat{value=C}}.
-
--spec const_value(#icode_const{}) -> simple_const() | structured_const() | binary().
-const_value(#icode_const{value=#flat{value=X}}) -> X.
-
--spec is_const(icode_argument()) -> boolean().
-is_const(#icode_const{}) -> true;
-is_const(_) -> false.
-
-%%-----
-%% var
-%%-----
-
--spec mk_var(non_neg_integer()) -> #icode_variable{kind::'var'}.
-mk_var(V) -> #icode_variable{name=V, kind=var}.
-
--spec var_name(#icode_variable{kind::'var'}) -> non_neg_integer().
-var_name(#icode_variable{name=Name, kind=var}) -> Name.
-
--spec is_var(icode_argument()) -> boolean().
-is_var(#icode_variable{kind=var}) -> true;
-is_var(_) -> false.
-
--spec mk_reg(non_neg_integer()) -> #icode_variable{kind::'reg'}.
-mk_reg(V) -> #icode_variable{name=V, kind=reg}.
-
--spec mk_reg_gcsafe(non_neg_integer()) -> #icode_variable{kind::'reg_gcsafe'}.
-mk_reg_gcsafe(V) -> #icode_variable{name=V, kind=reg_gcsafe}.
-
--spec reg_name(#icode_variable{kind::'reg'|'reg_gcsafe'})
- -> non_neg_integer().
-reg_name(#icode_variable{name=Name, kind=reg}) -> Name;
-reg_name(#icode_variable{name=Name, kind=reg_gcsafe}) -> Name.
-
--spec reg_is_gcsafe(#icode_variable{kind::'reg'}) -> 'false';
- (#icode_variable{kind::'reg_gcsafe'}) -> 'true'.
-reg_is_gcsafe(#icode_variable{kind=reg}) -> false;
-reg_is_gcsafe(#icode_variable{kind=reg_gcsafe}) -> true.
-
--spec is_reg(icode_argument()) -> boolean().
-is_reg(#icode_variable{kind=reg}) -> true;
-is_reg(#icode_variable{kind=reg_gcsafe}) -> true;
-is_reg(_) -> false.
-
--spec mk_fvar(non_neg_integer()) -> #icode_variable{kind::'fvar'}.
-mk_fvar(V) -> #icode_variable{name=V, kind=fvar}.
-
--spec fvar_name(#icode_variable{kind::'fvar'}) -> non_neg_integer().
-fvar_name(#icode_variable{name=Name, kind=fvar}) -> Name.
-
--spec is_fvar(icode_argument()) -> boolean().
-is_fvar(#icode_variable{kind=fvar}) -> true;
-is_fvar(_) -> false.
-
--spec is_variable(icode_argument()) -> boolean().
-is_variable(#icode_variable{}) -> true;
-is_variable(_) -> false.
-
--spec annotate_variable(#icode_variable{}, variable_annotation()) ->
- #icode_variable{}.
-annotate_variable(X, Anno) ->
- X#icode_variable{annotation = Anno}.
-
--spec is_annotated_variable(icode_argument()) -> boolean().
-is_annotated_variable(#icode_variable{annotation=[]}) ->
- false;
-is_annotated_variable(#icode_variable{}) ->
- true;
-is_annotated_variable(_) ->
- false.
-
--spec unannotate_variable(#icode_variable{}) -> #icode_variable{}.
-unannotate_variable(X) ->
- X#icode_variable{annotation=[]}.
-
--spec variable_annotation(#icode_variable{}) -> variable_annotation().
-variable_annotation(#icode_variable{annotation=Anno}) ->
- Anno.
-
-%%
-%% Floating point Icode instructions.
-%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Liveness info
-%%
-
--spec uses(icode_instr()) -> [#icode_variable{}].
-uses(Instr) ->
- remove_constants(args(Instr)).
-
--spec args(icode_instr()) -> [icode_argument()].
-args(I) ->
- case I of
- #icode_if{} -> if_args(I);
- #icode_switch_val{} -> [switch_val_term(I)];
- #icode_switch_tuple_arity{} -> [switch_tuple_arity_term(I)];
- #icode_type{} -> type_args(I);
- #icode_move{} -> [move_src(I)];
- #icode_fail{} -> fail_args(I);
- #icode_call{} -> call_args(I);
- #icode_enter{} -> enter_args(I);
- #icode_return{} -> return_vars(I);
- #icode_phi{} -> phi_args(I);
- #icode_goto{} -> [];
- #icode_begin_try{} -> [];
- #icode_begin_handler{} -> [];
- #icode_end_try{} -> [];
- #icode_comment{} -> [];
- #icode_label{} -> []
- end.
-
--spec defines(icode_instr()) -> [#icode_variable{}].
-defines(I) ->
- case I of
- #icode_move{} -> remove_constants([move_dst(I)]);
- #icode_call{} -> remove_constants(call_dstlist(I));
- #icode_begin_handler{} -> remove_constants(begin_handler_dstlist(I));
- #icode_phi{} -> remove_constants([phi_dst(I)]);
- #icode_if{} -> [];
- #icode_switch_val{} -> [];
- #icode_switch_tuple_arity{} -> [];
- #icode_type{} -> [];
- #icode_goto{} -> [];
- #icode_fail{} -> [];
- #icode_enter{} -> [];
- #icode_return{} -> [];
- #icode_begin_try{} -> [];
- #icode_end_try{} -> [];
- #icode_comment{} -> [];
- #icode_label{} -> []
- end.
-
--spec remove_constants([icode_argument()]) -> [#icode_variable{}].
-remove_constants(L) ->
- [V || V <- L, (not is_const(V))].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Utilities
-%%
-
-%%
-%% Substitution: replace occurrences of X by Y if {X,Y} is in the
-%% Subst_list.
-
--spec subst([{_,_}], I) -> I when I :: icode_instr().
-
-subst(Subst, I) ->
- subst_defines(Subst, subst_uses(Subst, I)).
-
--spec subst_uses([{_,_}], I) -> I when I :: icode_instr().
-
-subst_uses(Subst, I) ->
- case I of
- #icode_if{} -> I#icode_if{args = subst_list(Subst, if_args(I))};
- #icode_switch_val{} ->
- I#icode_switch_val{term = subst1(Subst, switch_val_term(I))};
- #icode_switch_tuple_arity{} ->
- I#icode_switch_tuple_arity{term = subst1(Subst, switch_tuple_arity_term(I))};
- #icode_type{} -> I#icode_type{args = subst_list(Subst, type_args(I))};
- #icode_move{} -> I#icode_move{src = subst1(Subst, move_src(I))};
- #icode_fail{} -> I#icode_fail{args = subst_list(Subst, fail_args(I))};
- #icode_call{} -> I#icode_call{args = subst_list(Subst, call_args(I))};
- #icode_enter{} -> I#icode_enter{args = subst_list(Subst, enter_args(I))};
- #icode_return{} -> I#icode_return{vars = subst_list(Subst, return_vars(I))};
- #icode_phi{} -> phi_argvar_subst(I, Subst);
- #icode_goto{} -> I;
- #icode_begin_try{} -> I;
- #icode_begin_handler{} -> I;
- #icode_end_try{} -> I;
- #icode_comment{} -> I;
- #icode_label{} -> I
- end.
-
--spec subst_defines([{_,_}], I) -> I when I :: icode_instr().
-
-subst_defines(Subst, I) ->
- case I of
- #icode_move{} -> I#icode_move{dst = subst1(Subst, move_dst(I))};
- #icode_call{} ->
- I#icode_call{dstlist = subst_list(Subst, call_dstlist(I))};
- #icode_begin_handler{} ->
- I#icode_begin_handler{dstlist = subst_list(Subst,
- begin_handler_dstlist(I))};
- #icode_phi{} -> I#icode_phi{dst = subst1(Subst, phi_dst(I))};
- #icode_if{} -> I;
- #icode_switch_val{} -> I;
- #icode_switch_tuple_arity{} -> I;
- #icode_type{} -> I;
- #icode_goto{} -> I;
- #icode_fail{} -> I;
- #icode_enter{} -> I;
- #icode_return{} -> I;
- #icode_begin_try{} -> I;
- #icode_end_try{} -> I;
- #icode_comment{} -> I;
- #icode_label{} -> I
- end.
-
-subst_list(S, Is) ->
- [subst1(S, I) || I <- Is].
-
-subst1([], I) -> I;
-subst1([{I,Y}|_], I) -> Y;
-subst1([_|Pairs], I) -> subst1(Pairs, I).
-
-%%
-%% @doc Returns the successors of an Icode instruction.
-%% In CFG form only branch instructions have successors,
-%% but in linear form other instructions like e.g. moves
-%% might be the last instruction of some basic block.
-%%
-
--spec successors(icode_instr()) -> [icode_lbl()].
-
-successors(I) ->
- case I of
- #icode_if{} ->
- [if_true_label(I), if_false_label(I)];
- #icode_goto{} ->
- [goto_label(I)];
- #icode_switch_val{} ->
- CaseLabels = [L || {_,L} <- switch_val_cases(I)],
- [switch_val_fail_label(I) | CaseLabels];
- #icode_switch_tuple_arity{} ->
- CaseLabels = [L || {_,L} <- switch_tuple_arity_cases(I)],
- [switch_tuple_arity_fail_label(I) | CaseLabels];
- #icode_type{} ->
- [type_true_label(I), type_false_label(I)];
- #icode_call{} ->
- case call_continuation(I) of [] -> []; L when is_integer(L) -> [L] end
- ++
- case call_fail_label(I) of [] -> []; L when is_integer(L) -> [L] end;
- #icode_begin_try{} ->
- [begin_try_successor(I), begin_try_label(I)];
- #icode_fail{} ->
- case fail_label(I) of [] -> []; L when is_integer(L) -> [L] end;
- #icode_enter{} -> [];
- #icode_return{} -> [];
- #icode_comment{} -> [];
- %% the following are included here for handling linear code
- #icode_move{} -> [];
- #icode_begin_handler{} -> []
- end.
-
-%%
-%% @doc Returns the fail labels of an Icode instruction.
-%%
-
--spec fails_to(icode_instr()) -> [icode_lbl()].
-
-fails_to(I) ->
- case I of
- #icode_switch_val{} -> [switch_val_fail_label(I)];
- #icode_switch_tuple_arity{} -> [switch_tuple_arity_fail_label(I)];
- #icode_call{} ->
- case call_fail_label(I) of [] -> []; L when is_integer(L) -> [L] end;
- #icode_begin_try{} -> [begin_try_label(I)]; % just for safety
- #icode_fail{} ->
- case fail_label(I) of [] -> []; L when is_integer(L) -> [L] end;
- #icode_if{} -> []; % XXX: Correct?
- #icode_enter{} -> []; % XXX: Correct?
- #icode_goto{} -> [];
- #icode_type{} -> []; % XXX: Correct?
- #icode_return{} -> []
- end.
-
-%%
-%% @doc Redirects jumps from label Old to label New.
-%% If the instruction does not jump to Old, it remains unchanged.
-%% The New label can be the special [] label used for calls with
-%% fall-throughs.
-%%
-
--spec redirect_jmp(icode_instr(), icode_lbl(), [] | icode_lbl()) -> icode_instr().
-
-redirect_jmp(Jmp, ToOld, ToOld) ->
- Jmp; % no need to do anything
-redirect_jmp(Jmp, ToOld, ToNew) ->
- NewI =
- case Jmp of
- #icode_if{} ->
- NewJmp = case if_true_label(Jmp) of
- ToOld -> if_true_label_update(Jmp, ToNew);
- _ -> Jmp
- end,
- case if_false_label(NewJmp) of
- ToOld -> if_false_label_update(NewJmp, ToNew);
- _ -> NewJmp
- end;
- #icode_goto{} ->
- case goto_label(Jmp) of
- ToOld -> Jmp#icode_goto{label=ToNew};
- _ -> Jmp
- end;
- #icode_switch_val{} ->
- NewJmp = case switch_val_fail_label(Jmp) of
- ToOld -> switch_val_fail_label_update(Jmp, ToNew);
- _ -> Jmp
- end,
- Cases = [case Pair of
- {Val,ToOld} -> {Val,ToNew};
- Unchanged -> Unchanged
- end || Pair <- switch_val_cases(NewJmp)],
- NewJmp#icode_switch_val{cases = Cases};
- #icode_switch_tuple_arity{} ->
- NewJmp = case switch_tuple_arity_fail_label(Jmp) of
- ToOld ->
- Jmp#icode_switch_tuple_arity{fail_label=ToNew};
- _ -> Jmp
- end,
- Cases = [case Pair of
- {Val,ToOld} -> {Val,ToNew};
- Unchanged -> Unchanged
- end || Pair <- switch_tuple_arity_cases(NewJmp)],
- NewJmp#icode_switch_tuple_arity{cases = Cases};
- #icode_type{} ->
- NewJmp = case type_true_label(Jmp) of
- ToOld -> Jmp#icode_type{true_label=ToNew};
- _ -> Jmp
- end,
- case type_false_label(NewJmp) of
- ToOld -> NewJmp#icode_type{false_label=ToNew};
- _ -> NewJmp
- end;
- #icode_call{} ->
- NewCont = case call_continuation(Jmp) of
- ToOld -> ToNew;
- OldCont -> OldCont
- end,
- NewFail = case call_fail_label(Jmp) of
- ToOld -> ToNew;
- OldFail -> OldFail
- end,
- Jmp#icode_call{continuation = NewCont,
- fail_label = NewFail};
- #icode_begin_try{} ->
- NewLabl = case begin_try_label(Jmp) of
- ToOld -> ToNew;
- OldLab -> OldLab
- end,
- NewSucc = case begin_try_successor(Jmp) of
- ToOld -> ToNew;
- OldSucc -> OldSucc
- end,
- Jmp#icode_begin_try{label=NewLabl, successor=NewSucc};
- #icode_fail{} ->
- case fail_label(Jmp) of
- ToOld -> Jmp#icode_fail{fail_label=ToNew};
- _ -> Jmp
- end
- end,
- %% Turn a branch into a goto if it has only one successor and it is
- %% safe to do so.
- case ordsets:from_list(successors(NewI)) of
- [Label] ->
- Goto = mk_goto(Label),
- case NewI of
- #icode_if{} -> Goto;
- #icode_switch_tuple_arity{} -> Goto;
- #icode_switch_val{} -> Goto;
- #icode_type{} -> Goto;
- _ -> NewI
- end;
- _ -> NewI
- end.
-
-%%
-%% Is this an unconditional jump (causes a basic block not to have a
-%% fallthrough successor).
-%%
-
-%% is_uncond(I) ->
-%% case I of
-%% #icode_goto{} -> true;
-%% #icode_fail{} -> true;
-%% #icode_enter{} -> true;
-%% #icode_return{} -> true;
-%% #icode_call{} ->
-%% case call_fail_label(I) of
-%% [] ->
-%% case call_continuation(I) of
-%% [] -> false;
-%% _ -> true
-%% end;
-%% _ -> true
-%% end;
-%% _ -> false
-%% end.
-
-%% @spec is_branch(icode_instr()) -> boolean()
-%%
-%% @doc Succeeds if the Icode instruction is a branch. I.e. a
-%% (possibly conditional) discontinuation of linear control flow.
-%% @end
-
--spec is_branch(icode_instr()) -> boolean().
-is_branch(Instr) ->
- case Instr of
- #icode_if{} -> true;
- #icode_switch_val{} -> true;
- #icode_switch_tuple_arity{} -> true;
- #icode_type{} -> true;
- #icode_goto{} -> true;
- #icode_fail{} -> true;
- #icode_call{} ->
- case call_fail_label(Instr) of
- [] -> call_continuation(Instr) =/= [];
- _ -> true
- end;
- #icode_enter{} -> true;
- #icode_return{} -> true;
- #icode_begin_try{} -> true;
- %% false cases below
- #icode_move{} -> false;
- #icode_begin_handler{} -> false;
- #icode_end_try{} -> false;
- #icode_comment{} -> false;
- #icode_label{} -> false;
- #icode_phi{} -> false
- end.
-
-%%
-%% @doc Makes a new variable.
-%%
-
--spec mk_new_var() -> icode_var().
-mk_new_var() ->
- mk_var(hipe_gensym:get_next_var(icode)).
-
-%%
-%% @doc Makes a new fp variable.
-%%
-
--spec mk_new_fvar() -> icode_fvar().
-mk_new_fvar() ->
- mk_fvar(hipe_gensym:get_next_var(icode)).
-
-%%
-%% @doc Makes a new register.
-%%
-
--spec mk_new_reg() -> icode_reg().
-mk_new_reg() ->
- mk_reg(hipe_gensym:get_next_var(icode)).
-
-%%
-%% @doc Makes a new gcsafe register; that is, a register that is allowed to be
-%% live over calls and other operations that might cause GCs and thus move heap
-%% data around.
-%%
-
--spec mk_new_reg_gcsafe() -> icode_reg().
-mk_new_reg_gcsafe() ->
- mk_reg_gcsafe(hipe_gensym:get_next_var(icode)).
-
-%%
-%% @doc Makes a new label.
-%%
-
--spec mk_new_label() -> #icode_label{}.
-mk_new_label() ->
- mk_label(hipe_gensym:get_next_label(icode)).
-
-%% %%
-%% %% @doc Makes a bunch of move operations.
-%% %%
-%%
-%% -spec mk_moves([_], [_]) -> [#icode_move{}].
-%% mk_moves([], []) ->
-%% [];
-%% mk_moves([X|Xs], [Y|Ys]) ->
-%% [mk_move(X, Y) | mk_moves(Xs, Ys)].
-
-%%
-%% Makes a series of element operations.
-%%
-
-%% mk_elements(_, []) ->
-%% [];
-%% mk_elements(Tuple, [X|Xs]) ->
-%% [mk_primop([X], #unsafe_element{index=length(Xs)+1}, [Tuple]) |
-%% mk_elements(Tuple, Xs)].
-
-%%
-%% @doc Removes comments from Icode.
-%%
-
--spec strip_comments(icode()) -> icode().
-strip_comments(ICode) ->
- icode_code_update(ICode, no_comments(icode_code(ICode))).
-
-%% The following spec is underspecified: the resulting list does not
-%% contain any #comment{} instructions
--spec no_comments(icode_instrs()) -> icode_instrs().
-no_comments([]) ->
- [];
-no_comments([I|Xs]) ->
- case is_comment(I) of
- true -> no_comments(Xs);
- false -> [I|no_comments(Xs)]
- end.
-
-%%-----------------------------------------------------------------------
-
-%% @doc True if an Icode instruction is safe (can be removed if the
-%% result is not used). Note that pure control flow instructions
-%% cannot be regarded as safe, as they are not defining anything.
-
--spec is_safe(icode_instr()) -> boolean().
-
-is_safe(Instr) ->
- case Instr of
- %% Instructions that are safe, or might be safe to remove.
- #icode_move{} -> true;
- #icode_phi{} -> true;
- #icode_begin_handler{} -> true;
- #icode_call{} ->
- case call_fun(Instr) of
- {M,F,A} ->
- erl_bifs:is_safe(M,F,A);
- Op ->
- hipe_icode_primops:is_safe(Op)
- end;
- %% Control flow instructions.
- #icode_if{} -> false;
- #icode_switch_val{} -> false;
- #icode_switch_tuple_arity{} -> false;
- #icode_type{} -> false;
- #icode_goto{} -> false;
- #icode_label{} -> false;
- %% Returning instructions without defines.
- #icode_return{} -> false;
- #icode_fail{} -> false;
- #icode_enter{} -> false;
- %% Internal auxiliary instructions that should not be removed
- %% unless you really know what you are doing.
- #icode_comment{} -> false;
- #icode_begin_try{} -> false;
- #icode_end_try{} -> false
- end.
-
-%% @doc Produces a simplified instruction sequence that is equivalent to [Instr]
-%% under the assumption that all results of Instr are unused, or 'false' if
-%% there is no such sequence (other than [Instr] itself).
-
--spec reduce_unused(icode_instr()) -> false | [icode_instr()].
-
-reduce_unused(Instr) ->
- case is_safe(Instr) of
- true -> [];
- false -> false
- end.
-
-%%-----------------------------------------------------------------------
-
--spec highest_var(icode_instrs()) -> non_neg_integer().
-highest_var(Instrs) ->
- highest_var(Instrs, 0).
-
--spec highest_var(icode_instrs(), non_neg_integer()) -> non_neg_integer().
-highest_var([I|Is], Max) ->
- Defs = defines(I),
- Uses = uses(I),
- highest_var(Is, new_max(Defs++Uses, Max));
-highest_var([], Max) ->
- Max.
-
--spec new_max([#icode_variable{}], non_neg_integer()) -> non_neg_integer().
-new_max([V|Vs], Max) ->
- VName =
- case is_var(V) of
- true ->
- var_name(V);
- false ->
- case is_fvar(V) of
- true ->
- fvar_name(V);
- _ ->
- reg_name(V)
- end
- end,
- new_max(Vs, erlang:max(VName, Max));
-new_max([], Max) when is_integer(Max) ->
- Max.
-
-%%-----------------------------------------------------------------------
-
--spec highest_label(icode_instrs()) -> icode_lbl().
-highest_label(Instrs) ->
- highest_label(Instrs, 0).
-
--spec highest_label(icode_instrs(), icode_lbl()) -> icode_lbl().
-highest_label([I|Is], Max) ->
- case is_label(I) of
- true ->
- L = label_name(I),
- NewMax = erlang:max(L, Max),
- highest_label(Is, NewMax);
- false ->
- highest_label(Is, Max)
- end;
-highest_label([], Max) when is_integer(Max) ->
- Max.
-
-%%-----------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode.hrl b/lib/hipe/icode/hipe_icode.hrl
deleted file mode 100644
index 7ed80a9ed4..0000000000
--- a/lib/hipe/icode/hipe_icode.hrl
+++ /dev/null
@@ -1,177 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%=====================================================================
-%%
-%% Contains type and record definitions for all Icode data structures.
-%%
-%%=====================================================================
-
-%%---------------------------------------------------------------------
-%% Include files needed for the compilation of this header file
-%%---------------------------------------------------------------------
-
--include("../misc/hipe_consttab.hrl").
-
-%%---------------------------------------------------------------------
-%% Icode argument types
-%%---------------------------------------------------------------------
-
--type simple_const() :: atom() | [] | integer() | float().
--type structured_const() :: list() | tuple().
-
--type icode_lbl() :: non_neg_integer().
-
-%%---------------------------------------------------------------------
-%% Icode records
-%%---------------------------------------------------------------------
-
--record(flat, {value :: simple_const() | structured_const() | binary()}).
-
--record(icode_const, {value :: #flat{}}).
-
--type variable_annotation() :: {atom(), any(), fun((any()) -> string())}.
-
--record(icode_variable, {name :: non_neg_integer(),
- kind :: 'var' | 'reg' | 'reg_gcsafe' | 'fvar',
- annotation = [] :: [] | variable_annotation()}).
-
-%%---------------------------------------------------------------------
-%% Type declarations for Icode instructions
-%%---------------------------------------------------------------------
-
--type icode_if_op() :: '>' | '<' | '>=' | '=<' | '=:=' | '=/=' | '==' | '/='
- | 'fixnum_eq' | 'fixnum_neq' | 'fixnum_lt'
- | 'fixnum_le' | 'fixnum_ge' | 'fixnum_gt'
- | 'op_exact_eqeq_2' | 'suspend_msg_timeout'.
-
--type icode_type_test() :: 'atom' | 'bignum' | 'binary' | 'bitstr' | 'boolean'
- | 'cons' | 'fixnum' | 'float' | 'function'
- | 'function2' | 'integer' | 'list' | 'map' | 'nil'
- | 'number' | 'pid' | 'port' | 'reference' | 'tuple'
- | {'atom', atom()} | {'integer', integer()}
- | {'record', atom(), non_neg_integer()}
- | {'tuple', non_neg_integer()}.
-
--type icode_primop() :: atom() | tuple(). % XXX: temporarily, I hope
--type icode_funcall() :: mfa() | icode_primop().
-
--type icode_var() :: #icode_variable{kind::'var'}.
--type icode_reg() :: #icode_variable{kind::'reg'|'reg_gcsafe'}.
--type icode_fvar() :: #icode_variable{kind::'fvar'}.
--type icode_argument() :: #icode_const{} | #icode_variable{}.
--type icode_term_arg() :: icode_var() | #icode_const{}.
-
--type icode_switch_case() :: {#icode_const{}, icode_lbl()}.
-
--type icode_call_type() :: 'local' | 'primop' | 'remote'.
--type icode_exit_class() :: 'error' | 'exit' | 'rethrow' | 'throw'.
-
--type icode_comment_text() :: atom() | string().
-
--type icode_info() :: [{'arg_types', [erl_types:erl_type()]}].
-
-%%---------------------------------------------------------------------
-%% Icode instructions
-%%---------------------------------------------------------------------
-
--record(icode_label, {name :: icode_lbl()}).
-
--record(icode_if, {op :: icode_if_op(),
- args :: [icode_term_arg()],
- true_label :: icode_lbl(),
- false_label :: icode_lbl(),
- p :: float()}).
-
--record(icode_switch_val, {term :: icode_var(),
- fail_label :: icode_lbl(),
- length :: non_neg_integer(),
- cases :: [icode_switch_case()]}).
-
--record(icode_switch_tuple_arity, {term :: icode_var(),
- fail_label :: icode_lbl(),
- length :: non_neg_integer(),
- cases :: [icode_switch_case()]}).
-
--record(icode_type, {test :: icode_type_test(),
- args :: [icode_term_arg()],
- true_label :: icode_lbl(),
- false_label :: icode_lbl(),
- p :: float()}).
-
--record(icode_goto, {label :: icode_lbl()}).
-
--record(icode_move, {dst :: #icode_variable{},
- src :: #icode_variable{} | #icode_const{}}).
-
--record(icode_phi, {dst :: #icode_variable{},
- id :: #icode_variable{},
- arglist :: [{icode_lbl(), #icode_variable{}}]}).
-
--record(icode_call, {dstlist :: [#icode_variable{}],
- 'fun' :: icode_funcall(),
- args :: [icode_argument()],
- type :: icode_call_type(),
- continuation :: [] | icode_lbl(),
- fail_label = [] :: [] | icode_lbl(),
- in_guard = false :: boolean()}).
-
--record(icode_enter, {'fun' :: icode_funcall(),
- args :: [icode_term_arg()],
- type :: icode_call_type()}).
-
--record(icode_return, {vars :: [icode_var()]}).
-
--record(icode_begin_try, {label :: icode_lbl(), successor :: icode_lbl()}).
-
--record(icode_end_try, {}).
-
--record(icode_begin_handler, {dstlist :: [icode_var()]}).
-
-%% TODO: Remove [] from fail_label
--record(icode_fail, {class :: icode_exit_class(),
- args :: [icode_term_arg()],
- fail_label = [] :: [] | icode_lbl()}).
-
--record(icode_comment, {text :: icode_comment_text()}).
-
-%%---------------------------------------------------------------------
-%% Icode instructions
-%%---------------------------------------------------------------------
-
--type icode_instr() :: #icode_begin_handler{} | #icode_begin_try{}
- | #icode_call{} | #icode_comment{} | #icode_end_try{}
- | #icode_enter{} | #icode_fail{}
- | #icode_goto{} | #icode_if{} | #icode_label{}
- | #icode_move{} | #icode_phi{} | #icode_return{}
- | #icode_switch_tuple_arity{} | #icode_switch_val{}
- | #icode_type{}.
--type icode_instrs() :: [icode_instr()].
-
-%%---------------------------------------------------------------------
-%% The Icode data structure
-%%---------------------------------------------------------------------
-
--record(icode, {'fun' :: mfa(),
- params :: hipe_icode:params(),
- %% TODO: merge is_closure and closure_arity into one field
- is_closure :: boolean(),
- closure_arity = none :: 'none' | arity(),
- is_leaf :: boolean(),
- code = [] :: icode_instrs(),
- data :: hipe_consttab(),
- var_range :: {non_neg_integer(), non_neg_integer()},
- label_range :: {icode_lbl(), icode_lbl()},
- info = [] :: icode_info()}).
--type icode() :: #icode{}.
-
-%%---------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode_bincomp.erl b/lib/hipe/icode/hipe_icode_bincomp.erl
deleted file mode 100644
index f88637e526..0000000000
--- a/lib/hipe/icode/hipe_icode_bincomp.erl
+++ /dev/null
@@ -1,189 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_icode_bincomp.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Description :
-%%%
-%%% Created : 12 Sep 2005 by Per Gustafsson <pergu@it.uu.se>
-%%%-------------------------------------------------------------------
-
--module(hipe_icode_bincomp).
-
--export([cfg/1]).
-
-%%--------------------------------------------------------------------
-
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
-%%--------------------------------------------------------------------
-
--spec cfg(cfg()) -> cfg().
-
-cfg(Cfg1) ->
- StartLbl = hipe_icode_cfg:start_label(Cfg1),
- find_bs_get_integer([StartLbl], Cfg1, set_from_list([StartLbl])).
-
-find_bs_get_integer([Lbl|Rest], Cfg, Visited) ->
- BB = hipe_icode_cfg:bb(Cfg, Lbl),
- Last = hipe_bb:last(BB),
- NewCfg =
- case ok(Last, Cfg) of
- {ok,{Type, FakeFail, RealFail, SuccLbl, MsIn, MsOut}} ->
- {Cont, Info, OldLbl, LastMsOut} =
- collect_info(SuccLbl, Cfg, [Type], Lbl, RealFail, MsOut),
- update_code(Lbl, OldLbl, Cfg, Info, Cont, FakeFail, MsIn, LastMsOut);
- not_ok ->
- Cfg
- end,
- Succs = hipe_icode_cfg:succ(NewCfg, Lbl),
- NewSuccs = not_visited(Succs, Visited),
- NewLbls = NewSuccs ++ Rest,
- NewVisited = set_union(set_from_list(NewSuccs), Visited),
- find_bs_get_integer(NewLbls, NewCfg, NewVisited);
-find_bs_get_integer([], Cfg, _) ->
- Cfg.
-
-ok(I, Cfg) ->
- case hipe_icode:is_call(I) of
- true ->
- case hipe_icode:call_fun(I) of
- {hipe_bs_primop, {bs_get_integer, Size, Flags}} when (Flags band 6) =:= 0 ->
- case {hipe_icode:call_dstlist(I), hipe_icode:call_args(I)} of
- {[Dst, MsOut] = DstList, [MsIn]} ->
- Cont = hipe_icode:call_continuation(I),
- FirstFail = hipe_icode:call_fail_label(I),
- FirstFailBB = hipe_icode_cfg:bb(Cfg, FirstFail),
- case check_for_restore_block(FirstFailBB, DstList) of
- {restore_block, RealFail} ->
- {ok, {{Dst, Size}, FirstFail, RealFail, Cont, MsIn, MsOut}};
- not_restore_block ->
- not_ok
- end;
- _ ->
- not_ok
- end;
- _ ->
- not_ok
- end;
- false ->
- not_ok
- end.
-
-check_for_restore_block(FirstFailBB, DefVars) ->
- Moves = hipe_bb:butlast(FirstFailBB),
- case [Instr || Instr <- Moves, is_badinstr(Instr, DefVars)] of
- [] ->
- Last = hipe_bb:last(FirstFailBB),
- case hipe_icode:is_goto(Last) of
- true ->
- {restore_block, hipe_icode:goto_label(Last)};
- false ->
- not_restore_block
- end;
- [_|_] ->
- not_restore_block
- end.
-
-is_badinstr(Instr, DefVars) ->
- not(hipe_icode:is_move(Instr) andalso
- lists:member(hipe_icode:move_dst(Instr), DefVars)).
-
-collect_info(Lbl, Cfg, Acc, OldLbl, FailLbl, MsOut) ->
- case do_collect_info(Lbl, Cfg, Acc, FailLbl, MsOut) of
- done ->
- {Lbl, Acc, OldLbl, MsOut};
- {cont, NewAcc, NewLbl, NewMsOut} ->
- collect_info(NewLbl, Cfg, NewAcc, Lbl, FailLbl, NewMsOut)
- end.
-
-do_collect_info(Lbl, Cfg, Acc, FailLbl, MsOut) ->
- BB = hipe_icode_cfg:bb(Cfg,Lbl),
- case hipe_bb:code(BB) of
- [I] ->
- case hipe_icode_cfg:pred(Cfg,Lbl) of
- [_] ->
- case ok(I, Cfg) of
- {ok, {Type,_FakeFail,FailLbl,SuccLbl,MsOut,NewMsOut}} ->
- NewAcc = [Type|Acc],
- MaxSize = hipe_rtl_arch:word_size() * 8 - 5,
- case calc_size(NewAcc) of
- Size when Size =< MaxSize ->
- {cont,NewAcc,SuccLbl,NewMsOut};
- _ ->
- done
- end;
- _ ->
- done
- end;
- _ ->
- done
- end;
- _ ->
- done
- end.
-
-calc_size([{_,Size}|Rest]) when is_integer(Size) ->
- Size + calc_size(Rest);
-calc_size([]) -> 0.
-
-update_code(_Lbl, _, Cfg, [_Info], _Cont, _LastFail, _MsIn, _MsOut) ->
- Cfg;
-update_code(Lbl, OldLbl, Cfg, Info, Cont, LastFail, MsIn, MsOut) ->
- BB = hipe_icode_cfg:bb(Cfg, Lbl),
- ButLast = hipe_bb:butlast(BB),
- NewVar = hipe_icode:mk_new_var(),
- Size = calc_size(Info),
- NewLast =
- hipe_icode:mk_primop([NewVar,MsOut],
- {hipe_bs_primop, {bs_get_integer,Size,0}},
- [MsIn],
- OldLbl,
- LastFail),
- NewBB = hipe_bb:mk_bb(ButLast++[NewLast]),
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Lbl, NewBB),
- fix_rest(Info, NewVar, OldLbl, Cont, NewCfg).
-
-fix_rest(Info, Var, Lbl, Cont, Cfg) ->
- ButLast = make_butlast(Info, Var),
- Last = hipe_icode:mk_goto(Cont),
- NewBB = hipe_bb:mk_bb(ButLast++[Last]),
- hipe_icode_cfg:bb_add(Cfg, Lbl, NewBB).
-
-make_butlast([{Res,_Size}], Var) ->
- [hipe_icode:mk_move(Res, Var)];
-make_butlast([{Res, Size}|Rest], Var) ->
- NewVar = hipe_icode:mk_new_var(),
- [hipe_icode:mk_primop([Res], 'band',
- [Var, hipe_icode:mk_const((1 bsl Size)-1)]),
- hipe_icode:mk_primop([NewVar], 'bsr', [Var, hipe_icode:mk_const(Size)])
- |make_butlast(Rest, NewVar)].
-
-%%--------------------------------------------------------------------
-%% Sets
-
-set_from_list([]) -> #{};
-set_from_list(L) ->
- maps:from_list([{E, []} || E <- L]).
-
-not_visited([], _) -> [];
-not_visited([E|T], M) ->
- case M of
- #{E := _} -> not_visited(T, M);
- _ -> [E|not_visited(T, M)]
- end.
-
-set_union(A, B) -> maps:merge(A, B).
diff --git a/lib/hipe/icode/hipe_icode_call_elim.erl b/lib/hipe/icode/hipe_icode_call_elim.erl
deleted file mode 100644
index 367ce7cfe5..0000000000
--- a/lib/hipe/icode/hipe_icode_call_elim.erl
+++ /dev/null
@@ -1,72 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%----------------------------------------------------------------------
-%% File : hipe_icode_call_elim.erl
-%% Authors : Daniel S. McCain <dsmccain@acm.org>,
-%% Magnus LÃ¥ng <margnus1@telia.com>
-%% Created : 14 Apr 2014 by Magnus LÃ¥ng <margnus1@telia.com>
-%% Purpose : Eliminate calls to BIFs that are side-effect free only when
-%% executed on some argument types.
-%%----------------------------------------------------------------------
--module(hipe_icode_call_elim).
--export([cfg/1]).
-
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
--spec cfg(cfg()) -> cfg().
-
-cfg(IcodeSSA) ->
- lists:foldl(fun (Lbl, CFG1) ->
- BB1 = hipe_icode_cfg:bb(CFG1, Lbl),
- Code1 = hipe_bb:code(BB1),
- Code2 = lists:map(fun elim_insn/1, Code1),
- BB2 = hipe_bb:code_update(BB1, Code2),
- hipe_icode_cfg:bb_add(CFG1, Lbl, BB2)
- end, IcodeSSA, hipe_icode_cfg:labels(IcodeSSA)).
-
--spec elim_insn(icode_instr()) -> icode_instr().
-elim_insn(Insn=#icode_call{'fun'={_,_,_}=MFA, args=Args, type=remote,
- dstlist=[Dst=#icode_variable{
- annotation={type_anno, RetType, _}}],
- continuation=[], fail_label=[]}) ->
- Opaques = 'universe',
- case erl_types:t_is_singleton(RetType, Opaques) of
- true ->
- ArgTypes = [case Arg of
- #icode_variable{annotation={type_anno, Type, _}} -> Type;
- #icode_const{} ->
- erl_types:t_from_term(hipe_icode:const_value(Arg))
- end || Arg <- Args],
- case can_be_eliminated(MFA, ArgTypes) of
- true ->
- Const = hipe_icode:mk_const(
- erl_types:t_singleton_to_term(RetType, Opaques)),
- #icode_move{dst=Dst, src=Const};
- false -> Insn
- end;
- false -> Insn
- end;
-elim_insn(Insn) -> Insn.
-
-
-%% A function can be eliminated for some argument types if it has no side
-%% effects when run on arguments of those types.
-
--spec can_be_eliminated(mfa(), [erl_types:erl_type()]) -> boolean().
-
-can_be_eliminated({maps, is_key, 2}, [_K, M]) ->
- erl_types:t_is_map(M);
-can_be_eliminated(_, _) ->
- false.
diff --git a/lib/hipe/icode/hipe_icode_callgraph.erl b/lib/hipe/icode/hipe_icode_callgraph.erl
deleted file mode 100644
index 365c65315e..0000000000
--- a/lib/hipe/icode/hipe_icode_callgraph.erl
+++ /dev/null
@@ -1,210 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-----------------------------------------------------------------------
-%% File : hipe_icode_callgraph.erl
-%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%% Purpose : Creates a call graph to find out in what order functions
-%% in a module have to be compiled to gain best information
-%% in hipe_icode_type.erl.
-%%
-%% Created : 7 Jun 2004 by Tobias Lindahl <tobiasl@it.uu.se>
-%%-----------------------------------------------------------------------
--module(hipe_icode_callgraph).
-
--export([construct/1,
- get_called_modules/1,
- to_list/1,
- construct_callgraph/1]).
-
--define(NO_UNUSED, true).
-
--ifndef(NO_UNUSED).
--export([is_empty/1, take_first/1, pp/1]).
--endif.
-
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
-
-%%------------------------------------------------------------------------
-
--type mfa_icode() :: {mfa(), #icode{}}.
-
--record(icode_callgraph, {codedict :: dict:dict(), ordered_sccs :: [[mfa()]]}).
-
-%%------------------------------------------------------------------------
-%% Exported functions
-%%------------------------------------------------------------------------
-
--spec construct([mfa_icode()]) -> #icode_callgraph{}.
-
-construct(List) ->
- Calls = get_local_calls(List),
- %% io:format("Calls: ~p\n", [lists:keysort(1, Calls)]),
- Edges = get_edges(Calls),
- %% io:format("Edges: ~p\n", [Edges]),
- DiGraph = hipe_digraph:from_list(Edges),
- Nodes = ordsets:from_list([MFA || {MFA, _} <- List]),
- DiGraph1 = hipe_digraph:add_node_list(Nodes, DiGraph),
- SCCs = hipe_digraph:reverse_preorder_sccs(DiGraph1),
- #icode_callgraph{codedict = dict:from_list(List), ordered_sccs = SCCs}.
-
--spec construct_callgraph([mfa_icode()]) -> hipe_digraph:hdg().
-
-construct_callgraph(List) ->
- Calls = get_local_calls2(List),
- Edges = get_edges(Calls),
- hipe_digraph:from_list(Edges).
-
--spec to_list(#icode_callgraph{}) -> [mfa_icode()].
-
-to_list(#icode_callgraph{codedict = Dict, ordered_sccs = SCCs}) ->
- FlatList = lists:flatten(SCCs),
- [{MFA, dict:fetch(MFA, Dict)} || MFA <- FlatList].
-
-%%------------------------------------------------------------------------
-
--ifndef(NO_UNUSED).
-
--spec is_empty(#icode_callgraph{}) -> boolean().
-
-is_empty(#icode_callgraph{ordered_sccs = SCCs}) ->
- SCCs =:= [].
-
--spec take_first(#icode_callgraph{}) -> {[mfa_icode()], #icode_callgraph{}}.
-
-take_first(#icode_callgraph{codedict = Dict, ordered_sccs = [H|T]} = CG) ->
- SCCCode = [{Mod, dict:fetch(Mod, Dict)} || Mod <- H],
- {SCCCode, CG#icode_callgraph{ordered_sccs = T}}.
-
--spec pp(#icode_callgraph{}) -> 'ok'.
-
-pp(#icode_callgraph{ordered_sccs = SCCs}) ->
- io:format("Callgraph ~p\n", [SCCs]).
--endif.
-
-%%------------------------------------------------------------------------
-%% Get the modules called from this module
-
--spec get_called_modules([mfa_icode()]) -> ordsets:ordset(atom()).
-
-get_called_modules(List) ->
- get_remote_calls(List, []).
-
-get_remote_calls([{_MFA, Icode}|Left], Acc) ->
- CallSet = get_remote_calls_1(hipe_icode:icode_code(Icode), Acc),
- get_remote_calls(Left, ordsets:union(Acc, CallSet));
-get_remote_calls([], Acc) ->
- Acc.
-
-get_remote_calls_1([I|Left], Set) ->
- NewSet =
- case I of
- #icode_call{} ->
- case hipe_icode:call_type(I) of
- remote ->
- {M, _F, _A} = hipe_icode:call_fun(I),
- ordsets:add_element(M, Set);
- _ ->
- Set
- end;
- #icode_enter{} ->
- case hipe_icode:enter_type(I) of
- remote ->
- {M, _F, _A} = hipe_icode:enter_fun(I),
- ordsets:add_element(M, Set);
- _ ->
- Set
- end;
- _ ->
- Set
- end,
- get_remote_calls_1(Left, NewSet);
-get_remote_calls_1([], Set) ->
- Set.
-
-%%------------------------------------------------------------------------
-%% Find functions called (or entered) by each function.
-
-get_local_calls(List) ->
- RemoveFun = fun ordsets:del_element/2,
- get_local_calls(List, RemoveFun, []).
-
-get_local_calls2(List) ->
- RemoveFun = fun(_,Set) -> Set end,
- get_local_calls(List, RemoveFun, []).
-
-get_local_calls([{{_M, _F, _A} = MFA, Icode}|Left], RemoveFun, Acc) ->
- CallSet = get_local_calls_1(hipe_icode:icode_code(Icode)),
- %% Exclude recursive calls.
- CallSet1 = RemoveFun(MFA, CallSet),
- get_local_calls(Left, RemoveFun, [{MFA, CallSet1}|Acc]);
-get_local_calls([], _RemoveFun, Acc) ->
- Acc.
-
-get_local_calls_1(Icode) ->
- get_local_calls_1(Icode, []).
-
-get_local_calls_1([I|Left], Set) ->
- NewSet =
- case I of
- #icode_call{} ->
- case hipe_icode:call_type(I) of
- local ->
- Fun = hipe_icode:call_fun(I),
- ordsets:add_element(Fun, Set);
- primop ->
- case hipe_icode:call_fun(I) of
- #mkfun{mfa = Fun} ->
- ordsets:add_element(Fun, Set);
- _ ->
- Set
- end;
- remote ->
- Set
- end;
- #icode_enter{} ->
- case hipe_icode:enter_type(I) of
- local ->
- Fun = hipe_icode:enter_fun(I),
- ordsets:add_element(Fun, Set);
- primop ->
- case hipe_icode:enter_fun(I) of
- #mkfun{mfa = Fun} ->
- ordsets:add_element(Fun, Set);
- _ ->
- Set
- end;
- remote ->
- Set
- end;
- _ ->
- Set
- end,
- get_local_calls_1(Left, NewSet);
-get_local_calls_1([], Set) ->
- Set.
-
-%%------------------------------------------------------------------------
-%% Find the edges in the callgraph.
-
-get_edges(Calls) ->
- get_edges(Calls, []).
-
-get_edges([{MFA, Set}|Left], Edges) ->
- EdgeList = [{MFA, X} || X <- Set],
- EdgeSet = ordsets:from_list(EdgeList),
- get_edges(Left, ordsets:union(EdgeSet, Edges));
-get_edges([], Edges) ->
- Edges.
diff --git a/lib/hipe/icode/hipe_icode_cfg.erl b/lib/hipe/icode/hipe_icode_cfg.erl
deleted file mode 100644
index c5f5592cc9..0000000000
--- a/lib/hipe/icode/hipe_icode_cfg.erl
+++ /dev/null
@@ -1,199 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_icode_cfg).
-
--export([bb/2, bb_add/3,
- cfg_to_linear/1,
- is_closure/1,
- closure_arity/1,
- linear_to_cfg/1,
- labels/1, start_label/1,
- pp/1, pp/2,
- params/1, params_update/2,
- pred/2,
- redirect/4,
- remove_trivial_bbs/1, remove_unreachable_code/1,
- succ/2,
- visit/2, is_visited/2, none_visited/0
- ]).
--export([postorder/1, reverse_postorder/1]).
-
--define(ICODE_CFG, true). % needed by cfg.inc
-%%-define(DO_ASSERT, true).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("../flow/hipe_bb.hrl").
--include("../flow/cfg.hrl").
--include("../flow/cfg.inc").
-
-%%----------------------------------------------------------------------
-%% Prototypes for exported functions which are Icode specific
-%%----------------------------------------------------------------------
-
--spec labels(cfg()) -> [icode_lbl()].
--spec postorder(cfg()) -> [icode_lbl()].
--spec reverse_postorder(cfg()) -> [icode_lbl()].
-
--spec params(cfg()) -> hipe_icode:params().
--spec params_update(cfg(), hipe_icode:params()) -> cfg().
-
--spec is_visited(icode_lbl(), gb_sets:set()) -> boolean().
--spec visit(icode_lbl(), gb_sets:set()) -> gb_sets:set().
-
--spec bb(cfg(), icode_lbl()) -> 'not_found' | bb().
--spec bb_add(cfg(), icode_lbl(), bb()) -> cfg().
--spec pred(cfg(), icode_lbl()) -> [icode_lbl()].
--spec succ(cfg(), icode_lbl()) -> [icode_lbl()].
--spec redirect(cfg(), icode_lbl(), icode_lbl(), icode_lbl()) -> cfg().
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to Icode
-%%
-
--spec linear_to_cfg(#icode{}) -> cfg().
-
-linear_to_cfg(LinearIcode) ->
- %% hipe_icode_pp:pp(Icode),
- Code = hipe_icode:icode_code(LinearIcode),
- IsClosure = hipe_icode:icode_is_closure(LinearIcode),
- StartLabel = hipe_icode:label_name(hd(Code)),
- CFG0 = mk_empty_cfg(hipe_icode:icode_fun(LinearIcode),
- StartLabel,
- hipe_icode:icode_data(LinearIcode),
- IsClosure,
- hipe_icode:icode_is_leaf(LinearIcode),
- hipe_icode:icode_params(LinearIcode)),
- CFG1 = info_update(CFG0, hipe_icode:icode_info(LinearIcode)),
- CFG2 = case IsClosure of
- true ->
- closure_arity_update(CFG1,
- hipe_icode:icode_closure_arity(LinearIcode));
- false ->
- CFG1
- end,
- ?opt_start_timer("Get BBs icode"),
- FullCFG = take_bbs(Code, CFG2),
- ?opt_stop_timer("Get BBs icode"),
- FullCFG.
-
-%% remove_blocks(CFG, []) ->
-%% CFG;
-%% remove_blocks(CFG, [Lbl|Lbls]) ->
-%% remove_blocks(bb_remove(CFG, Lbl), Lbls).
-
--spec is_label(icode_instr()) -> boolean().
-is_label(Instr) ->
- hipe_icode:is_label(Instr).
-
-label_name(Instr) ->
- hipe_icode:label_name(Instr).
-
-mk_label(Name) ->
- hipe_icode:mk_label(Name).
-
-mk_goto(Name) ->
- hipe_icode:mk_goto(Name).
-
-branch_successors(Instr) ->
- hipe_icode:successors(Instr).
-
-fails_to(Instr) ->
- hipe_icode:fails_to(Instr).
-
-%% True if instr has no effect.
--spec is_comment(icode_instr()) -> boolean().
-is_comment(Instr) ->
- hipe_icode:is_comment(Instr).
-
-%% True if instr is just a jump (no side-effects).
--spec is_goto(icode_instr()) -> boolean().
-is_goto(Instr) ->
- hipe_icode:is_goto(Instr).
-
--spec is_branch(icode_instr()) -> boolean().
-is_branch(Instr) ->
- hipe_icode:is_branch(Instr).
-
--spec is_pure_branch(icode_instr()) -> boolean().
-is_pure_branch(Instr) ->
- case Instr of
- #icode_if{} -> true;
- #icode_goto{} -> true;
- #icode_switch_val{} -> true;
- #icode_switch_tuple_arity{} -> true;
- #icode_type{} -> true;
- %% false cases below -- XXX: are they correct?
- #icode_label{} -> false;
- #icode_move{} -> false;
- #icode_phi{} -> false;
- #icode_call{} -> false;
- #icode_enter{} -> false;
- #icode_return{} -> false;
- #icode_begin_try{} -> false;
- #icode_end_try{} -> false;
- #icode_begin_handler{} -> false;
- #icode_fail{} -> false;
- #icode_comment{} -> false
- end.
-
--spec is_phi(icode_instr()) -> boolean().
-is_phi(I) ->
- hipe_icode:is_phi(I).
-
-phi_remove_pred(I, Pred) ->
- hipe_icode:phi_remove_pred(I, Pred).
-
-%% phi_redirect_pred(I, OldPred, NewPred) ->
-%% hipe_icode:phi_redirect_pred(I, OldPred, NewPred).
-
-redirect_jmp(Jmp, ToOld, ToNew) ->
- hipe_icode:redirect_jmp(Jmp, ToOld, ToNew).
-
-redirect_ops(_, CFG, _) -> %% We do not refer to labels in Icode ops.
- CFG.
-
-%%----------------------------------------------------------------------------
-
--spec pp(cfg()) -> 'ok'.
-
-pp(CFG) ->
- hipe_icode_pp:pp(cfg_to_linear(CFG)).
-
--spec pp(io:device(), cfg()) -> 'ok'.
-
-pp(Dev, CFG) ->
- hipe_icode_pp:pp(Dev, cfg_to_linear(CFG)).
-
-%%----------------------------------------------------------------------------
-
--spec cfg_to_linear(cfg()) -> #icode{}.
-cfg_to_linear(CFG) ->
- Code = linearize_cfg(CFG),
- IsClosure = is_closure(CFG),
- Icode = hipe_icode:mk_icode(function(CFG),
- params(CFG),
- IsClosure,
- is_leaf(CFG),
- Code,
- data(CFG),
- hipe_gensym:var_range(icode),
- hipe_gensym:label_range(icode)),
- Icode1 = hipe_icode:icode_info_update(Icode, info(CFG)),
- case IsClosure of
- true -> hipe_icode:icode_closure_arity_update(Icode1, closure_arity(CFG));
- false -> Icode1
- end.
diff --git a/lib/hipe/icode/hipe_icode_coordinator.erl b/lib/hipe/icode/hipe_icode_coordinator.erl
deleted file mode 100644
index 4ef210eca4..0000000000
--- a/lib/hipe/icode/hipe_icode_coordinator.erl
+++ /dev/null
@@ -1,289 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%--------------------------------------------------------------------
-%% File : hipe_icode_coordinator.erl
-%% Author : Per Gustafsson <pergu@it.uu.se>
-%% Description : This module coordinates an Icode pass.
-%% Created : 20 Feb 2007 by Per Gustafsson <pergu@it.uu.se>
-%%---------------------------------------------------------------------
-
--module(hipe_icode_coordinator).
-
--export([coordinate/4]).
-
--include("hipe_icode.hrl").
-
-%%---------------------------------------------------------------------
-
--define(MAX_CONCURRENT, erlang:system_info(schedulers)).
-
-%%---------------------------------------------------------------------
-
--spec coordinate(hipe_digraph:hdg(), [mfa()], [mfa()], module()) ->
- no_return().
-
-coordinate(CG, Escaping, NonEscaping, Mod) ->
- ServerPid = initialize_server(Escaping, Mod),
- All = ordsets:from_list(Escaping ++ NonEscaping),
- Restart = fun (MFALs, PM) -> restart_funs(MFALs, PM, All, ServerPid) end,
- LastAction = fun (PM) -> last_action(PM, ServerPid, Mod, All) end,
- MFALists = {Escaping, All},
- coordinate(MFALists, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
-
--type mfalists() :: {[mfa()], [mfa()]}.
-
--spec coordinate(mfalists(), hipe_digraph:hdg(), gb_trees:tree(),
- fun((mfalists(), gb_trees:tree()) -> mfalists()),
- fun((gb_trees:tree()) -> 'ok'), pid()) -> no_return().
-
-coordinate(MFALists, CG, PM, Restart, LastAction, ServerPid) ->
- case MFALists of
- {[], []} ->
- LastAction(PM),
- ServerPid ! stop,
- receive
- {stop, Ans2Pid} ->
- Ans2Pid ! {done, self()},
- exit(normal)
- end;
- _ -> ok
- end,
- receive
- {stop, AnsPid} ->
- ServerPid ! stop,
- AnsPid ! {done, self()},
- exit(normal);
- Message ->
- {NewPM, NewMFALists} =
- case Message of
- {restart_call, MFA} ->
- {PM, handle_restart_call(MFA, MFALists)};
- {ready, {MFA, Pid}} ->
- handle_ready(MFA, Pid, MFALists, PM);
- {restart_done, MFA} ->
- {PM, handle_restart_done(MFA, MFALists, CG)};
- {no_change_done, MFA} ->
- {PM, handle_no_change_done(MFA, MFALists)}
- end,
- coordinate(Restart(NewMFALists, NewPM), CG, NewPM, Restart,
- LastAction, ServerPid)
- end.
-
-handle_restart_call(MFA, {Queue, Busy} = QB) ->
- case lists:member(MFA, Queue) of
- true ->
- QB;
- false ->
- {[MFA|Queue], Busy}
- end.
-
-handle_ready(MFA, Pid, {Queue, Busy}, PM) ->
- {gb_trees:insert(MFA, Pid, PM), {Queue, Busy -- [MFA]}}.
-
-handle_restart_done(MFA, {Queue, Busy}, CG) ->
- Restarts = hipe_digraph:get_parents(MFA, CG),
- {ordsets:from_list(Restarts ++ Queue), Busy -- [MFA]}.
-
-handle_no_change_done(MFA, {Queue, Busy}) ->
- {Queue, Busy -- [MFA]}.
-
-last_action(PM, ServerPid, Mod, All) ->
- last_action(PM, ServerPid, Mod, All, []).
-
-last_action(_, _, _, [], []) -> ok;
-last_action(PM, ServerPid, Mod, [], [MFA|Busy]) ->
- receive
- {done_rewrite, MFA} ->
- last_action(PM, ServerPid, Mod, [], Busy)
- end;
-last_action(PM, ServerPid, Mod, All0, Busy) ->
- receive
- {done_rewrite, MFA} ->
- last_action(PM, ServerPid, Mod, All0, Busy -- [MFA])
- after 0 ->
- case ?MAX_CONCURRENT - length(Busy) of
- X when is_integer(X), X > 0 ->
- [MFA|All1] = All0,
- gb_trees:get(MFA, PM) ! {done, final_funs(ServerPid, Mod)},
- last_action(PM, ServerPid, Mod, All1, [MFA|Busy]);
- X when is_integer(X) ->
- Busy1 = receive {done_rewrite, MFA} -> Busy -- [MFA] end,
- last_action(PM, ServerPid, Mod, All0, Busy1)
- end
- end.
-
-restart_funs({Queue, Busy} = QB, PM, All, ServerPid) ->
- case ?MAX_CONCURRENT - length(Busy) of
- X when is_integer(X), X > 0 ->
- Possible = [Pos || Pos <- Queue, (not lists:member(Pos, Busy))],
- Restarts = lists:sublist(Possible, X),
- lists:foreach(fun (MFA) ->
- restart_fun(MFA, PM, All, ServerPid)
- end, Restarts),
- {Queue -- Restarts, Busy ++ Restarts};
- X when is_integer(X) ->
- QB
- end.
-
-initialize_server(Escaping, Mod) ->
- Pid = spawn_link(fun () -> info_server(Mod) end),
- lists:foreach(fun (MFA) -> Pid ! {set_escaping, MFA} end, Escaping),
- Pid.
-
-safe_get_args(MFA, Cfg, Pid, Mod) ->
- Mod:replace_nones(get_args(MFA, Cfg, Pid)).
-
-get_args(MFA, Cfg, Pid) ->
- Ref = make_ref(),
- Pid ! {get_call, MFA, Cfg, self(), Ref},
- receive
- {Ref, Types} ->
- Types
- end.
-
-safe_get_res(MFA, Pid, Mod) ->
- Mod:replace_nones(get_res(MFA, Pid)).
-
-get_res(MFA, Pid) ->
- Ref = make_ref(),
- Pid ! {get_return, MFA, self(), Ref},
- receive
- {Ref, Types} ->
- Types
- end.
-
-update_return_type(MFA, NewType, Pid) ->
- Ref = make_ref(),
- Pid ! {update_return, MFA, NewType, self(), Ref},
- receive
- {Ref, Ans} ->
- Ans
- end.
-
-update_call_type(MFA, NewTypes, Pid) ->
- Ref = make_ref(),
- Pid ! {update_call, MFA, NewTypes, self(), Ref},
- receive
- {Ref, Ans} ->
- Ans
- end.
-
-restart_fun(MFA, PM, All, ServerPid) ->
- gb_trees:get(MFA, PM) ! {analyse, analysis_funs(All, ServerPid)},
- ok.
-
-analysis_funs(All, Pid) ->
- Self = self(),
- ArgsFun = fun (MFA, Cfg) -> get_args(MFA, Cfg, Pid) end,
- GetResFun = fun (MFA, Args) ->
- case lists:member(MFA, All) of
- true ->
- case update_call_type(MFA, Args, Pid) of
- do_restart ->
- Self ! {restart_call, MFA},
- ok;
- no_change ->
- ok
- end;
- false ->
- ok
- end,
- [Ans] = get_res(MFA, Pid),
- Ans
- end,
- FinalFun = fun (MFA, RetTypes) ->
- case update_return_type(MFA, RetTypes, Pid) of
- do_restart ->
- Self ! {restart_done, MFA},
- ok;
- no_change ->
- Self ! {no_change_done, MFA},
- ok
- end
- end,
- {ArgsFun, GetResFun, FinalFun}.
-
-final_funs(Pid,Mod) ->
- ArgsFun = fun (MFA, Cfg) -> safe_get_args(MFA, Cfg, Pid, Mod) end,
- GetResFun = fun (MFA, _) ->
- [Ans] = safe_get_res(MFA, Pid, Mod),
- Ans
- end,
- FinalFun = fun (_, _) -> ok end,
- {ArgsFun, GetResFun, FinalFun}.
-
-info_server(Mod) ->
- info_server_loop(gb_trees:empty(), gb_trees:empty(), Mod).
-
-info_server_loop(CallInfo, ReturnInfo, Mod) ->
- receive
- {update_return, MFA, NewInfo, Pid, Ref} ->
- NewReturnInfo = handle_update(MFA, ReturnInfo, NewInfo, Pid, Ref, Mod),
- info_server_loop(CallInfo, NewReturnInfo, Mod);
- {update_call, MFA, NewInfo, Pid, Ref} ->
- NewCallInfo = handle_update(MFA, CallInfo, NewInfo, Pid, Ref, Mod),
- info_server_loop(NewCallInfo, ReturnInfo, Mod);
- {get_return, MFA, Pid, Ref} ->
- Ans =
- case gb_trees:lookup(MFA, ReturnInfo) of
- none ->
- Mod:return_none();
- {value, TypesComp} ->
- Mod:return__info((TypesComp))
- end,
- Pid ! {Ref, Ans},
- info_server_loop(CallInfo, ReturnInfo, Mod);
- {get_call, MFA, Cfg, Pid, Ref} ->
- Ans =
- case gb_trees:lookup(MFA, CallInfo) of
- none ->
- Mod:return_none_args(Cfg, MFA);
- {value, escaping} ->
- Mod:return_any_args(Cfg, MFA);
- {value, TypesComp} ->
- Mod:return__info(TypesComp)
- end,
- Pid ! {Ref, Ans},
- info_server_loop(CallInfo, ReturnInfo, Mod);
- {set_escaping, MFA} ->
- NewCallInfo = gb_trees:enter(MFA, escaping, CallInfo),
- info_server_loop(NewCallInfo, ReturnInfo, Mod);
- stop ->
- ok
- end.
-
-handle_update(MFA, Tree, NewInfo, Pid, Ref, Mod) ->
- ResType =
- case gb_trees:lookup(MFA, Tree) of
- none ->
- %% io:format("First Type: ~w ~w~n", [NewType, MFA]),
- Pid ! {Ref, do_restart},
- Mod:new__info(NewInfo);
- {value, escaping} ->
- Pid ! {Ref, no_change},
- escaping;
- {value, OldInfo} ->
- %% io:format("New Type: ~w ~w~n", [NewType, MFA]),
- %% io:format("Old Type: ~w ~w~n", [OldType, MFA]),
- case Mod:update__info(NewInfo, OldInfo) of
- {true, Type} ->
- Pid ! {Ref, no_change},
- Type;
- {false, Type} ->
- Pid ! {Ref, do_restart},
- Type
- end
- end,
- gb_trees:enter(MFA, ResType, Tree).
diff --git a/lib/hipe/icode/hipe_icode_ebb.erl b/lib/hipe/icode/hipe_icode_ebb.erl
deleted file mode 100644
index 2cc4321fb8..0000000000
--- a/lib/hipe/icode/hipe_icode_ebb.erl
+++ /dev/null
@@ -1,24 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Icode version of extended basic blocks.
-%%
-
--module(hipe_icode_ebb).
-
--define(CFG, hipe_icode_cfg).
-
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
--include("../flow/ebb.inc").
diff --git a/lib/hipe/icode/hipe_icode_exceptions.erl b/lib/hipe/icode/hipe_icode_exceptions.erl
deleted file mode 100644
index 0039eb5091..0000000000
--- a/lib/hipe/icode/hipe_icode_exceptions.erl
+++ /dev/null
@@ -1,472 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ====================================================================
-%% Filename : hipe_icode_exceptions.erl
-%% Module : hipe_icode_exceptions
-%% Purpose : Rewrite calls in intermediate code to use Continuation
-%% and Fail-To labels.
-%%
-%% Catch-instructions work as follows:
-%% - A begin_try(FailLabel) starts a catch-region which
-%% is ended by a corresponding end_try(FailLabel).
-%% - The handler begins with a begin_handler(FailLabel).
-%%
-%% However, the begin/end instructions do not always appear
-%% as parentheses around the section that they protect (in
-%% linear Beam/Icode). Also, different begin_catch
-%% instructions can reach the same basic blocks (which may
-%% raise exceptions), due to code compation optimizations
-%% in the Beam compiler, even though they have different
-%% handlers. Because of this, a data flow analysis is
-%% necessary to find out which catches may reach which
-%% basic blocks. After that, we clone basic blocks as
-%% needed to ensure that each block belongs to at most one
-%% unique begin_catch. The Beam does not have this problem,
-%% since it will find the correct catch-handler frame
-%% pushed on the stack. (Note that since there can be no
-%% tail-calls within a catch region, our dataflow analysis
-%% for finding all catch-stacks is sure to terminate.)
-%%
-%% Finally, we can remove all special catch instructions
-%% and rewrite calls within catch regions to use explicit
-%% fail-to labels, which is the main point of all this.
-%% Fail labels that were set before this pass are kept.
-%% (Note that calls that have only a continuation label do
-%% not always end their basic blocks. Adding a fail label
-%% to such a call can thus force us to split the block.)
-%%
-%% Notes : As of November 2003, primops that do not fail in the
-%% normal sense are allowed to have a fail-label even
-%% before this pass. (Used for the mbox-empty + get_msg
-%% primitive in receives.)
-%%
-%% Native floating point operations cannot fail in the
-%% normal sense. Instead they throw a hardware exception
-%% which will be caught by a special fp check error
-%% instruction. These primops do not need a fail label even
-%% in a catch. This pass checks for this with
-%% hipe_icode_primops:fails/1. If a call cannot fail, no
-%% fail label is added.
-%%
-%% Explicit fails (exit, error and throw) inside
-%% a catch have to be handled. They have to build their
-%% exit value and jump directly to the catch handler. An
-%% alternative solution would be to have a new type of
-%% fail instruction that takes a fail-to label...
-%% ====================================================================
-
--module(hipe_icode_exceptions).
-
--export([fix_catches/1]).
-
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
-%%----------------------------------------------------------------------------
-
--spec fix_catches(cfg()) -> cfg().
-
-fix_catches(CFG) ->
- {Map, State} = build_mapping(find_catches(init_state(CFG))),
- hipe_icode_cfg:remove_unreachable_code(get_cfg(rewrite(State, Map))).
-
-%% This finds the set of possible catch-stacks for each basic block
-
-find_catches(State) ->
- find_catches(get_start_labels(State),
- clear_visited(clear_changed(State))).
-
-find_catches([L|Ls], State0) ->
- case is_visited(L, State0) of
- true ->
- find_catches(Ls, State0);
- false ->
- State1 = set_visited(L, State0),
- Code = get_bb_code(L, State1),
- Cs = get_new_catches_in(L, State1),
- State2 = set_catches_in(L, Cs, State1), % memorize
- Cs1 = catches_out(Code, Cs),
- Ls1 = get_succ(L, State2) ++ Ls,
- Cs0 = get_catches_out(L, State2),
- if Cs1 =:= Cs0 ->
- find_catches(Ls1, State2);
- true ->
- State3 = set_catches_out(L, Cs1, State2),
- find_catches(Ls1, set_changed(State3))
- end
- end;
-find_catches([], State) ->
- case is_changed(State) of
- true ->
- find_catches(State);
- false ->
- State
- end.
-
-catches_out([I|Is], Cs) ->
- catches_out(Is, catches_out_instr(I, Cs));
-catches_out([], Cs) ->
- Cs.
-
-catches_out_instr(I, Cs) ->
- case I of
- #icode_begin_try{} ->
- Id = hipe_icode:begin_try_label(I),
- push_catch(Id, Cs);
- #icode_end_try{} ->
- pop_catch(Cs);
- #icode_begin_handler{} ->
- pop_catch(Cs);
- _ ->
- Cs
- end.
-
-
-%% This builds the mapping used for cloning
-
-build_mapping(State) ->
- build_mapping(get_start_labels(State), clear_visited(State),
- new_mapping()).
-
-build_mapping([L|Ls], State0, Map) ->
- case is_visited(L, State0) of
- true ->
- build_mapping(Ls, State0, Map);
- false ->
- State1 = set_visited(L, State0),
- Cs = list_of_catches(get_catches_in(L, State1)), % get memorized
- {Map1, State2} = map_bb(L, Cs, State1, Map),
- Ls1 = get_succ(L, State2) ++ Ls,
- build_mapping(Ls1, State2, Map1)
- end;
-build_mapping([], State, Map) ->
- {Map, State}.
-
-map_bb(_L, [_C], State, Map) ->
- {Map, State};
-map_bb(L, [C | Cs], State, Map) ->
- %% This block will be cloned - we need to create N-1 new labels.
- %% The identity mapping will be used for the first element.
- Map1 = new_catch_labels(Cs, L, Map),
- State1 = set_catches_in(L, single_catch(C), State), % update catches in
- Code = get_bb_code(L, State1),
- State2 = clone(Cs, L, Code, State1, Map1),
- {Map1, State2}.
-
-clone([C | Cs], L, Code, State, Map) ->
- Ren = get_renaming(C, Map),
- L1 = Ren(L),
- State1 = set_bb_code(L1, Code, State),
- State2 = set_catches_in(L1, single_catch(C), State1), % set catches in
- clone(Cs, L, Code, State2, Map);
-clone([], _L, _Code, State, _Map) ->
- State.
-
-new_catch_labels([C | Cs], L, Map) ->
- L1 = hipe_icode:label_name(hipe_icode:mk_new_label()),
- Map1 = set_mapping(C, L, L1, Map),
- new_catch_labels(Cs, L, Map1);
-new_catch_labels([], _L, Map) ->
- Map.
-
-
-%% This does all the actual rewriting and cloning.
-
-rewrite(State, Map) ->
- rewrite(get_start_labels(State), clear_visited(State), Map).
-
-rewrite([L|Ls], State0, Map) ->
- case is_visited(L, State0) of
- true ->
- rewrite(Ls, State0, Map);
- false ->
- State1 = set_visited(L, State0),
- Code = get_bb_code(L, State1),
- Cs = list_of_catches(get_catches_in(L, State1)), % get memorized
- State2 = rewrite_bb(L, Cs, Code, State1, Map),
- Ls1 = get_succ(L, State2) ++ Ls,
- rewrite(Ls1, State2, Map)
- end;
-rewrite([], State, _Map) ->
- State.
-
-rewrite_bb(L, [C], Code, State, Map) ->
- {Code1, State1} = rewrite_code(Code, C, State, Map),
- set_bb_code(L, Code1, State1).
-
-rewrite_code(Is, C, State, Map) ->
- rewrite_code(Is, C, State, Map, []).
-
-rewrite_code([I|Is], C, State, Map, As) ->
- [C1] = list_of_catches(catches_out_instr(I, single_catch(C))),
- case I of
- #icode_begin_try{} ->
- {I1, Is1, State1} = update_begin_try(I, Is, C, State, Map),
- I2 = redirect_instr(I1, C, Map),
- rewrite_code(Is1, C1, State1, Map, [I2 | As]);
- #icode_end_try{} ->
- rewrite_code(Is, C1, State, Map, As);
- #icode_call{} ->
- {I1, Is1, State1} = update_call(I, Is, C, State, Map),
- I2 = redirect_instr(I1, C, Map),
- rewrite_code(Is1, C1, State1, Map, [I2 | As]);
- #icode_fail{} ->
- {I1, Is1, State1} = update_fail(I, Is, C, State, Map),
- I2 = redirect_instr(I1, C, Map),
- rewrite_code(Is1, C1, State1, Map, [I2 | As]);
- _ ->
- I1 = redirect_instr(I, C, Map),
- rewrite_code(Is, C1, State, Map, [I1 | As])
- end;
-rewrite_code([], _C, State, _Map, As) ->
- {lists:reverse(As), State}.
-
-redirect_instr(I, C, Map) ->
- redirect_instr_1(I, hipe_icode:successors(I), get_renaming(C, Map)).
-
-redirect_instr_1(I, [L0 | Ls], Ren) ->
- I1 = hipe_icode:redirect_jmp(I, L0, Ren(L0)),
- redirect_instr_1(I1, Ls, Ren);
-redirect_instr_1(I, [], _Ren) ->
- I.
-
-update_begin_try(I, Is, _C, State0, _Map) ->
- L = hipe_icode:begin_try_successor(I),
- I1 = hipe_icode:mk_goto(L),
- {I1, Is, State0}.
-
-update_call(I, Is, C, State0, Map) ->
- case top_of_stack(C) of
- [] ->
- %% No active catch. Assume cont./fail labels are correct as is.
- {I, Is, State0};
- L ->
- %% Only update the fail label if the call *can* fail.
- case hipe_icode_primops:fails(hipe_icode:call_fun(I)) of
- true ->
- %% We only update the fail label if it is not already set.
- case hipe_icode:call_fail_label(I) of
- [] ->
- I1 = hipe_icode:call_set_fail_label(I, L),
- %% Now the call will end the block, so we must put the rest of
- %% the code (if nonempty) in a new block!
- if Is =:= [] ->
- {I1, Is, State0};
- true ->
- L1 = hipe_icode:label_name(hipe_icode:mk_new_label()),
- I2 = hipe_icode:call_set_continuation(I1, L1),
- State1 = set_bb_code(L1, Is, State0),
- State2 = set_catches_in(L1, single_catch(C), State1),
- State3 = rewrite_bb(L1, [C], Is, State2, Map),
- {I2, [], State3}
- end;
- _ when Is =:= [] ->
- %% Something is very wrong if Is is not empty here. A call
- %% with a fail label should have ended its basic block.
- {I, Is, State0}
- end;
- false ->
- %% Make sure that the fail label is not set.
- I1 = hipe_icode:call_set_fail_label(I, []),
- {I1, Is, State0}
- end
- end.
-
-update_fail(I, Is, C, State, _Map) ->
- case hipe_icode:fail_label(I) of
- [] ->
- {hipe_icode:fail_set_label(I, top_of_stack(C)), Is, State};
- _ ->
- {I, Is, State}
- end.
-
-
-%%---------------------------------------------------------------------
-%% Abstraction for sets of catch stacks.
-
-%% This is the bottom element
-no_catches() -> [].
-
-%% A singleton set
-single_catch(C) -> [C].
-
-%% A single, empty stack
-empty_stack() -> [].
-
-%% Getting the label to fail to
-top_of_stack([C|_]) -> C;
-top_of_stack([]) -> []. % nil is used in Icode for "no label"
-
-join_catches(Cs1, Cs2) ->
- ordsets:union(Cs1, Cs2).
-
-list_of_catches(Cs) -> Cs.
-
-%% Note that prepending an element to all elements in the list will
-%% preserve the ordering of the list, and will never make two existing
-%% elements become identical, so the list is still an ordset.
-
-push_catch(L, []) ->
- [[L]];
-push_catch(L, Cs) ->
- push_catch_1(L, Cs).
-
-push_catch_1(L, [C|Cs]) ->
- [[L|C] | push_catch_1(L, Cs)];
-push_catch_1(_L, []) ->
- [].
-
-%% However, after discarding the head of all elements, the list
-%% is no longer an ordset, and must be processed.
-
-pop_catch(Cs) ->
- ordsets:from_list(pop_catch_1(Cs)).
-
-pop_catch_1([[_|C] | Cs]) ->
- [C | pop_catch_1(Cs)];
-pop_catch_1([[] | Cs]) ->
- %% The elements in the list represent different possible incoming
- %% stacks of catch handlers to this BB. Before the fixpoint has
- %% been found these elements are underapproximations of the true
- %% stacks, therefore it's possible for these elements to be too
- %% short for the number of pops implied by the code in the BB.
- %% We must not fail in that case, so we set pop([]) = [].
- %% This fixes find_catches_crash.erl and compiler_tests in the
- %% HiPE test suite.
- [[] | pop_catch_1(Cs)];
-pop_catch_1([]) ->
- [].
-
-
-%%---------------------------------------------------------------------
-%% Mapping from catch-stacks to renamings on labels.
-
-new_mapping() ->
- gb_trees:empty().
-
-set_mapping(C, L0, L1, Map) ->
- Dict = case gb_trees:lookup(C, Map) of
- {value, Dict0} ->
- gb_trees:enter(L0, L1, Dict0);
- none ->
- gb_trees:insert(L0, L1, gb_trees:empty())
- end,
- gb_trees:enter(C, Dict, Map).
-
-%% Return a label renaming function for a particular catch-stack
-
-get_renaming(C, Map) ->
- case gb_trees:lookup(C, Map) of
- {value, Dict} ->
- fun (L0) ->
- case gb_trees:lookup(L0, Dict) of
- {value, L1} -> L1;
- none -> L0
- end
- end;
- none ->
- fun (L0) -> L0 end
- end.
-
-
-%%---------------------------------------------------------------------
-%% State abstraction
-
--record(state, {cfg :: cfg(),
- changed = false :: boolean(),
- succ :: cfg(),
- pred :: cfg(),
- start_labels :: [icode_lbl(),...],
- visited = hipe_icode_cfg:none_visited() :: gb_sets:set(),
- out = gb_trees:empty() :: gb_trees:tree(),
- in = gb_trees:empty() :: gb_trees:tree()
- }).
-
-init_state(CFG) ->
- SLs = [hipe_icode_cfg:start_label(CFG)],
- #state{cfg = CFG, succ = CFG, pred = CFG, start_labels = SLs}.
-
-get_cfg(State) ->
- State#state.cfg.
-
-get_start_labels(State) ->
- State#state.start_labels.
-
-get_pred(L, State) ->
- hipe_icode_cfg:pred(State#state.pred, L).
-
-get_succ(L, State) ->
- hipe_icode_cfg:succ(State#state.succ, L).
-
-set_changed(State) ->
- State#state{changed = true}.
-
-is_changed(State) ->
- State#state.changed.
-
-clear_changed(State) ->
- State#state{changed = false}.
-
-set_catches_out(L, Cs, State) ->
- State#state{out = gb_trees:enter(L, Cs, State#state.out)}.
-
-get_catches_out(L, State) ->
- case gb_trees:lookup(L, State#state.out) of
- {value, Cs} -> Cs;
- none -> no_catches()
- end.
-
-set_catches_in(L, Cs, State) ->
- State#state{in = gb_trees:enter(L, Cs, State#state.in)}.
-
-get_catches_in(L, State) ->
- case gb_trees:lookup(L, State#state.in) of
- {value, Cs} -> Cs;
- none -> no_catches()
- end.
-
-set_visited(L, State) ->
- State#state{visited = hipe_icode_cfg:visit(L, State#state.visited)}.
-
-is_visited(L, State) ->
- hipe_icode_cfg:is_visited(L, State#state.visited).
-
-clear_visited(State) ->
- State#state{visited = hipe_icode_cfg:none_visited()}.
-
-get_bb_code(L, State) ->
- hipe_bb:code(hipe_icode_cfg:bb(State#state.cfg, L)).
-
-set_bb_code(L, Code, State) ->
- CFG = State#state.cfg,
- CFG1 = hipe_icode_cfg:bb_add(CFG, L, hipe_bb:mk_bb(Code)),
- SLs = [hipe_icode_cfg:start_label(CFG1)],
- State#state{cfg = CFG1, succ = CFG1, pred = CFG1, start_labels = SLs}.
-
-get_new_catches_in(L, State) ->
- Ps = get_pred(L, State),
- Cs = case lists:member(L, get_start_labels(State)) of
- true -> single_catch(empty_stack());
- false -> no_catches()
- end,
- get_new_catches_in(Ps, Cs, State).
-
-get_new_catches_in([P | Ps], Cs, State) ->
- Cs1 = join_catches(Cs, get_catches_out(P, State)),
- get_new_catches_in(Ps, Cs1, State);
-get_new_catches_in([], Cs, _) ->
- Cs.
-
-%%---------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl
deleted file mode 100644
index 4933ee96b4..0000000000
--- a/lib/hipe/icode/hipe_icode_fp.erl
+++ /dev/null
@@ -1,1190 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%--------------------------------------------------------------------
-%% File : hipe_icode_fp.erl
-%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%% Description : One pass analysis to find floating point values.
-%% Mapping to FP variables and creation of FP EBBs.
-%%
-%% Created : 23 Apr 2003 by Tobias Lindahl <tobiasl@it.uu.se>
-%%--------------------------------------------------------------------
-
--module(hipe_icode_fp).
-
--export([cfg/1]).
-
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
--type mapped_fvar() :: icode_fvar() | {assigned, icode_fvar()} .
--type incoming_fvars() :: [{icode_lbl(), mapped_fvar()}].
--type initial_var_map() :: #{icode_var() => incoming_fvars()}.
--type bb_phi_list() :: [{icode_fvar(), [{icode_lbl(), icode_fvar()}]}].
--type var_map_phi() :: #{phi => bb_phi_list(),
- icode_var() => mapped_fvar()}.
--type var_map() :: #{icode_var() => mapped_fvar()}.
-
--type edge() :: {icode_lbl(), icode_lbl()}.
--type edge_map() :: #{edge() => var_map()}.
-
--type worklist(Item) :: {[Item], [Item], gb_sets:set(Item)}.
--type worklist() :: worklist(icode_lbl()).
-
--type fail_lbl() :: [] | icode_lbl().
--type in_block() :: {true, fail_lbl()} | false.
--type fp_ebb_map() :: #{{inblock_in | inblock_out, icode_lbl()} | edge()
- => in_block()}.
-
--record(state, {edge_map = #{} :: edge_map(),
- fp_ebb_map = #{} :: fp_ebb_map(),
- cfg :: cfg()}).
--type state() :: #state{}.
-
--type icode_phi() :: #icode_phi{}.
--type icode_variable() :: #icode_variable{}.
--type icode_const() :: #icode_const{}.
-
-%%--------------------------------------------------------------------
-
--spec cfg(cfg()) -> cfg().
-
-cfg(Cfg) ->
- %%hipe_icode_cfg:pp(Cfg),
- NewCfg = annotate_fclearerror(Cfg),
- State = new_state(NewCfg),
- NewState = place_fp_blocks(State),
- %% hipe_icode_cfg:pp(state__cfg(NewState)),
- NewState2 = finalize(NewState),
- NewCfg1 = state__cfg(NewState2),
- %% hipe_icode_cfg:pp(NewCfg1),
- NewCfg2 = unannotate_fclearerror(NewCfg1),
- NewCfg2.
-
-%%--------------------------------------------------------------------
-%% Annotate fclearerror with information of the fail label of the
-%% corresponding fcheckerror.
-%%--------------------------------------------------------------------
-
--spec annotate_fclearerror(cfg()) -> cfg().
-
-annotate_fclearerror(Cfg) ->
- Labels = hipe_icode_cfg:reverse_postorder(Cfg),
- annotate_fclearerror(Labels, Cfg).
-
--spec annotate_fclearerror([icode_lbl()], cfg()) -> cfg().
-
-annotate_fclearerror([Label|Left], Cfg) ->
- BB = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- NewCode = annotate_fclearerror1(Code, Label, Cfg, []),
- NewBB = hipe_bb:code_update(BB, NewCode),
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB),
- annotate_fclearerror(Left, NewCfg);
-annotate_fclearerror([], Cfg) ->
- Cfg.
-
--spec annotate_fclearerror1(icode_instrs(), icode_lbl(), cfg(), icode_instrs())
- -> icode_instrs().
-
-annotate_fclearerror1([I|Left], Label, Cfg, Acc) ->
- case I of
- #icode_call{} ->
- case hipe_icode:call_fun(I) of
- fclearerror ->
- Fail = lookahead_for_fcheckerror(Left, Label, Cfg),
- NewI = hipe_icode:call_fun_update(I, {fclearerror, Fail}),
- annotate_fclearerror1(Left, Label, Cfg, [NewI|Acc]);
- _ ->
- annotate_fclearerror1(Left, Label, Cfg, [I|Acc])
- end;
- _ ->
- annotate_fclearerror1(Left, Label, Cfg, [I|Acc])
- end;
-annotate_fclearerror1([], _Label, _Cfg, Acc) ->
- lists:reverse(Acc).
-
--spec lookahead_for_fcheckerror(icode_instrs(), icode_lbl(), cfg()) ->
- fail_lbl().
-
-lookahead_for_fcheckerror([I|Left], Label, Cfg) ->
- case I of
- #icode_call{} ->
- case hipe_icode:call_fun(I) of
- fcheckerror ->
- hipe_icode:call_fail_label(I);
- _ ->
- lookahead_for_fcheckerror(Left, Label, Cfg)
- end;
- _ ->
- lookahead_for_fcheckerror(Left, Label, Cfg)
- end;
-lookahead_for_fcheckerror([], Label, Cfg) ->
- case hipe_icode_cfg:succ(Cfg, Label) of
- [] -> exit("Unterminated fp ebb");
- SuccList ->
- Succ = hd(SuccList),
- Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Label)),
- lookahead_for_fcheckerror(Code, Succ, Cfg)
- end.
-
--spec unannotate_fclearerror(cfg()) -> cfg().
-
-unannotate_fclearerror(Cfg) ->
- Labels = hipe_icode_cfg:reverse_postorder(Cfg),
- unannotate_fclearerror(Labels, Cfg).
-
--spec unannotate_fclearerror([icode_lbl()], cfg()) -> cfg().
-
-unannotate_fclearerror([Label|Left], Cfg) ->
- BB = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- NewCode = unannotate_fclearerror1(Code, []),
- NewBB = hipe_bb:code_update(BB, NewCode),
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB),
- unannotate_fclearerror(Left, NewCfg);
-unannotate_fclearerror([], Cfg) ->
- Cfg.
-
--spec unannotate_fclearerror1(icode_instrs(), icode_instrs()) ->
- icode_instrs().
-
-unannotate_fclearerror1([I|Left], Acc) ->
- case I of
- #icode_call{} ->
- case hipe_icode:call_fun(I) of
- {fclearerror, _Fail} ->
- NewI = hipe_icode:call_fun_update(I, fclearerror),
- unannotate_fclearerror1(Left, [NewI|Acc]);
- _ ->
- unannotate_fclearerror1(Left, [I|Acc])
- end;
- _ ->
- unannotate_fclearerror1(Left, [I|Acc])
- end;
-unannotate_fclearerror1([], Acc) ->
- lists:reverse(Acc).
-
-%%--------------------------------------------------------------------
-%% Make float EBBs
-%%--------------------------------------------------------------------
-
--spec place_fp_blocks(state()) -> state().
-
-place_fp_blocks(State) ->
- WorkList = new_worklist(State),
- transform_block(WorkList, State).
-
--spec transform_block(worklist(), state()) -> state().
-
-transform_block(WorkList, State) ->
- case get_work(WorkList) of
- none ->
- State;
- {Label, NewWorkList} ->
- %%io:format("Handling ~w \n", [Label]),
- BB = state__bb(State, Label),
- Code1 = hipe_bb:butlast(BB),
- Last = hipe_bb:last(BB),
- NofPreds = length(state__pred(State, Label)),
- Map = state__map(State, Label),
- FilteredMap = filter_map(Map, NofPreds),
- {Prelude, NewFilteredMap} = do_prelude(FilteredMap),
-
- %% Take care to have a map without any new bindings from the
- %% last instruction if it can fail.
- {FailMap, NewCode1} = transform_instrs(Code1, Map, NewFilteredMap, []),
- {NewMap, NewCode2} = transform_instrs([Last], Map, FailMap, []),
- SuccSet0 = ordsets:from_list(hipe_icode:successors(Last)),
- FailSet = ordsets:from_list(hipe_icode:fails_to(Last)),
- SuccSet = ordsets:subtract(SuccSet0, FailSet),
- NewCode = NewCode1 ++ NewCode2,
- NewBB = hipe_bb:code_update(BB, Prelude++NewCode),
- NewState = state__bb_add(State, Label, NewBB),
- case update_maps(NewState, Label, SuccSet, NewMap, FailSet, FailMap) of
- fixpoint ->
- transform_block(NewWorkList, NewState);
- {NewState1, AddBlocks} ->
- NewWorkList1 = add_work(NewWorkList, AddBlocks),
- transform_block(NewWorkList1, NewState1)
- end
- end.
-
--spec update_maps(state(), icode_lbl(), ordsets:ordset(icode_lbl()),
- var_map(), ordsets:ordset(icode_lbl()), var_map())
- -> fixpoint | {state(), [icode_lbl()]}.
-
-update_maps(State, Label, SuccSet, SuccMap, FailSet, FailMap) ->
- {NewState, Add1} = update_maps(State, Label, SuccSet, SuccMap, []),
- case update_maps(NewState, Label, FailSet, FailMap, Add1) of
- {_NewState1, []} -> fixpoint;
- {_NewState1, _Add} = Ret -> Ret
- end.
-
--spec update_maps(state(), icode_lbl(), ordsets:ordset(icode_lbl()),
- var_map(), [icode_lbl()])
- -> {state(), [icode_lbl()]}.
-
-update_maps(State, From, [To|Left], Map, Acc) ->
- case state__map_update(State, From, To, Map) of
- fixpoint ->
- update_maps(State, From, Left, Map, Acc);
- NewState ->
- update_maps(NewState, From, Left, Map, [To|Acc])
- end;
-update_maps(State, _From, [], _Map, Acc) ->
- {State, Acc}.
-
--spec transform_instrs(icode_instrs(), edge_map(), var_map(), icode_instrs())
- -> {var_map(), icode_instrs()}.
-
-transform_instrs([I|Left], PhiMap, Map, Acc) ->
- Defines = hipe_icode:defines(I),
- NewMap = maps:without(Defines, Map),
- NewPhiMap = maps:without(Defines, PhiMap),
- case I of
- #icode_phi{} ->
- Uses = hipe_icode:uses(I),
- case [X || X <- Uses, lookup(X, PhiMap) =/= none] of
- [] ->
- %% No ordinary variables from the argument have been untagged.
- transform_instrs(Left, NewPhiMap, NewMap, [I|Acc]);
- Uses ->
- %% All arguments are untagged. Let's untag the destination.
- Dst = hipe_icode:phi_dst(I),
- NewDst = hipe_icode:mk_new_fvar(),
- NewMap1 = NewMap#{Dst => NewDst},
- NewI = subst_phi_uncond(I, NewDst, PhiMap),
- transform_instrs(Left, NewPhiMap, NewMap1, [NewI|Acc]);
- _ ->
- %% Some arguments are untagged. Keep the destination.
- Dst = hipe_icode:phi_dst(I),
- NewI = subst_phi(I, Dst, PhiMap),
- transform_instrs(Left, NewPhiMap, NewMap, [NewI|Acc])
- end;
- #icode_call{} ->
- case hipe_icode:call_fun(I) of
- X when X =:= unsafe_untag_float orelse X =:= conv_to_float ->
- [Dst] = hipe_icode:defines(I),
- case hipe_icode:uses(I) of
- [] -> %% Constant
- transform_instrs(Left, NewPhiMap, NewMap, [I|Acc]);
- [Src] ->
- case lookup(Src, Map) of
- none ->
- NewMap1 = NewMap#{Src => {assigned, Dst}},
- transform_instrs(Left, NewPhiMap, NewMap1, [I|Acc]);
- Dst ->
- %% This is the instruction that untagged the variable.
- %% Use old maps.
- transform_instrs(Left, NewPhiMap, Map, [I|Acc]);
- FVar ->
- %% The variable was already untagged.
- %% This instruction can be changed to a move.
- NewI = hipe_icode:mk_move(Dst, FVar),
- case hipe_icode:call_continuation(I) of
- [] ->
- transform_instrs(Left,NewPhiMap,NewMap,[NewI|Acc]);
- ContLbl ->
- Goto = hipe_icode:mk_goto(ContLbl),
- transform_instrs(Left, NewPhiMap, NewMap,
- [Goto, NewI|Acc])
- end
- end
- end;
- unsafe_tag_float ->
- [Dst] = hipe_icode:defines(I),
- [Src] = hipe_icode:uses(I),
- NewMap1 = NewMap#{Dst => {assigned, Src}},
- transform_instrs(Left, NewPhiMap, NewMap1,[I|Acc]);
- _ ->
- {NewMap1, NewAcc} = check_for_fop_candidates(I, NewMap, Acc),
- transform_instrs(Left, NewPhiMap, NewMap1, NewAcc)
- end;
- _ ->
- NewIns = handle_untagged_arguments(I, NewMap),
- transform_instrs(Left, NewPhiMap, NewMap, NewIns ++ Acc)
- end;
-transform_instrs([], _PhiMap, Map, Acc) ->
- {Map, lists:reverse(Acc)}.
-
--spec check_for_fop_candidates(icode_instr(), var_map(), icode_instrs())
- -> {var_map(), icode_instrs()}.
-
-check_for_fop_candidates(I, Map, Acc) ->
- case is_fop_cand(I) of
- false ->
- NewIs = handle_untagged_arguments(I, Map),
- {Map, NewIs ++ Acc};
- true ->
- Fail = hipe_icode:call_fail_label(I),
- Cont = hipe_icode:call_continuation(I),
- Op = fun_to_fop(hipe_icode:call_fun(I)),
- case Fail of
- [] ->
- Args = hipe_icode:args(I),
- ConstArgs = [X || X <- Args, hipe_icode:is_const(X)],
- try lists:foreach(fun(X) -> float(hipe_icode:const_value(X)) end,
- ConstArgs) of
- ok ->
- %%io:format("Changing ~w to ~w\n", [hipe_icode:call_fun(I), Op]),
- Uses = hipe_icode:uses(I),
- Defines = hipe_icode:defines(I),
- Convs = [X||X <- remove_duplicates(Uses), lookup(X,Map) =:= none],
- NewMap0 = add_new_bindings_assigned(Convs, Map),
- NewMap = add_new_bindings_unassigned(Defines, NewMap0),
- ConvIns = get_conv_instrs(Convs, NewMap),
- NewI = hipe_icode:mk_primop(lookup_list(Defines, NewMap), Op,
- lookup_list_keep_consts(Args,NewMap),
- Cont, Fail),
- NewI2 = conv_consts(ConstArgs, NewI),
- {NewMap, [NewI2|ConvIns]++Acc}
- catch
- error:badarg ->
- %% This instruction will fail at runtime. The warning
- %% should already have happened in hipe_icode_type.
- NewIs = handle_untagged_arguments(I, Map),
- {Map, NewIs ++ Acc}
- end;
- _ -> %% Bailing out! Can't handle instructions in catches (yet).
- NewIs = handle_untagged_arguments(I, Map),
- {Map, NewIs ++ Acc}
- end
- end.
-
-
--spec handle_untagged_arguments(icode_instr(), var_map()) -> icode_instrs().
-
-%% If this is an instruction that needs to operate on tagged values,
-%% which currently are untagged, we must tag the values and perhaps
-%% end the fp ebb.
-
-handle_untagged_arguments(I, Map) ->
- case [X || X <- hipe_icode:uses(I), must_be_tagged(X, Map)] of
- [] ->
- [I];
- Tag ->
- TagIntrs =
- [hipe_icode:mk_primop([Dst], unsafe_tag_float,
- [maps:get(Dst, Map)]) || Dst <- Tag],
- [I|TagIntrs]
- end.
-
--spec do_prelude(var_map_phi()) -> {[icode_phi()], var_map()}.
-
-%% Add phi nodes for untagged fp values.
-
-do_prelude(Map = #{phi := List}) ->
- %%io:format("Adding phi: ~w\n", [List]),
- Fun = fun ({FVar, Bindings}, Acc) ->
- [hipe_icode:mk_phi(FVar, Bindings)|Acc]
- end,
- {lists:foldl(Fun, [], List), maps:remove(phi, Map)};
-do_prelude(Map) -> {[], Map}.
-
--spec split_code([I]) -> {[I], I} when
- I :: icode_instr().
-
-split_code(Code) ->
- split_code(Code, []).
-
-split_code([I], Acc) ->
- {lists:reverse(Acc), I};
-split_code([I|Left], Acc) ->
- split_code(Left, [I|Acc]).
-
-
--spec finalize(state()) -> state().
-
-%% When all code is mapped to fp instructions we must make sure that
-%% the fp ebb information going into each block is the same as the
-%% information coming out of each predecessor. Otherwise, we must add
-%% a block in between.
-
-finalize(State) ->
- Worklist = new_worklist(State),
- NewState = place_error_handling(Worklist, State),
- Edges = needs_fcheckerror(NewState),
- finalize(Edges, NewState).
-
--spec finalize([edge()], state()) -> state().
-
-finalize([{From, To}|Left], State) ->
- NewState = add_fp_ebb_fixup(From, To, State),
- finalize(Left, NewState);
-finalize([], State) ->
- State.
-
--spec needs_fcheckerror(state()) -> [{none | icode_lbl(), icode_lbl()}].
-
-needs_fcheckerror(State) ->
- Cfg = state__cfg(State),
- Labels = hipe_icode_cfg:labels(Cfg),
- needs_fcheckerror(Labels, State, []).
-
--spec needs_fcheckerror([icode_lbl()], state(),
- [{none | icode_lbl(), icode_lbl()}])
- -> [{none | icode_lbl(), icode_lbl()}].
-
-needs_fcheckerror([Label|Left], State, Acc) ->
- case state__get_in_block_in(State, Label) of
- {true, _} ->
- needs_fcheckerror(Left, State, Acc);
- false ->
- Pred = state__pred(State, Label),
- case [X || X <- Pred, state__get_in_block_out(State, X) =/= false] of
- [] ->
- needs_fcheckerror(Left, State, Acc);
- NeedsFcheck ->
- case length(Pred) =:= length(NeedsFcheck) of
- true ->
- %% All edges need fcheckerror. Add this to the
- %% beginning of the block instead.
- needs_fcheckerror(Left, State, [{none, Label}|Acc]);
- false ->
- Edges = [{X, Label} || X <- NeedsFcheck],
- needs_fcheckerror(Left, State, Edges ++ Acc)
- end
- end
- end;
-needs_fcheckerror([], _State, Acc) ->
- Acc.
-
--spec add_fp_ebb_fixup(none | icode_lbl(), icode_lbl(), state()) -> state().
-
-add_fp_ebb_fixup('none', To, State) ->
- %% Add the fcheckerror to the start of the block.
- BB = state__bb(State, To),
- Code = hipe_bb:code(BB),
- Phis = lists:takewhile(fun(X) -> hipe_icode:is_phi(X) end, Code),
- TailCode = lists:dropwhile(fun(X) -> hipe_icode:is_phi(X) end, Code),
- FC = hipe_icode:mk_primop([], fcheckerror, []),
- NewCode = Phis ++ [FC|TailCode],
- state__bb_add(State, To, hipe_bb:code_update(BB, NewCode));
-add_fp_ebb_fixup(From, To, State) ->
- FCCode = [hipe_icode:mk_primop([], fcheckerror, [], To, [])],
- FCBB = hipe_bb:mk_bb(FCCode),
- FCLabel = hipe_icode:label_name(hipe_icode:mk_new_label()),
- NewState = state__bb_add(State, FCLabel, FCBB),
- NewState1 = state__redirect(NewState, From, To, FCLabel),
- ToBB = state__bb(NewState, To),
- ToCode = hipe_bb:code(ToBB),
- NewToCode = redirect_phis(ToCode, From, FCLabel),
- NewToBB = hipe_bb:code_update(ToBB, NewToCode),
- state__bb_add(NewState1, To, NewToBB).
-
--spec redirect_phis(icode_instrs(), icode_lbl(), icode_lbl())
- -> icode_instrs().
-
-redirect_phis(Code, OldFrom, NewFrom) ->
- redirect_phis(Code, OldFrom, NewFrom, []).
-
--spec redirect_phis(icode_instrs(), icode_lbl(), icode_lbl(), icode_instrs())
- -> icode_instrs().
-
-redirect_phis([I|Is] = Code, OldFrom, NewFrom, Acc) ->
- case I of
- #icode_phi{} ->
- NewI = hipe_icode:phi_redirect_pred(I, OldFrom, NewFrom),
- redirect_phis(Is, OldFrom, NewFrom, [NewI|Acc]);
- _ ->
- lists:reverse(Acc, Code)
- end;
-redirect_phis([], _OldFrom, _NewFrom, Acc) ->
- lists:reverse(Acc).
-
--spec subst_phi(icode_phi(), icode_variable(), edge_map())
- -> icode_phi().
-
-subst_phi(I, Dst, Map) ->
- ArgList = subst_phi_uses0(hipe_icode:phi_arglist(I), Map, []),
- hipe_icode:mk_phi(Dst, ArgList).
-
--spec subst_phi_uses0([{icode_lbl(), icode_variable()}], edge_map(),
- [{icode_lbl(), icode_variable()}])
- -> [{icode_lbl(), icode_variable()}].
-
-subst_phi_uses0([{Pred, Var}|Left], Map, Acc) ->
- case Map of
- #{Var := List} ->
- case lists:keyfind(Pred, 1, List) of
- {Pred, {assigned, _NewVar}} ->
- %% The variable is untagged, but it has been assigned. Keep it!
- subst_phi_uses0(Left, Map, [{Pred, Var} | Acc]);
- {Pred, _NewVar} = PredNV ->
- %% The variable is untagged and it has never been assigned as tagged.
- subst_phi_uses0(Left, Map, [PredNV | Acc]);
- false ->
- %% The variable is not untagged.
- subst_phi_uses0(Left, Map, [{Pred, Var} | Acc])
- end;
- #{} ->
- %% The variable is not untagged.
- subst_phi_uses0(Left, Map, [{Pred, Var} | Acc])
- end;
-subst_phi_uses0([], _Map, Acc) ->
- Acc.
-
--spec subst_phi_uncond(icode_phi(), icode_variable(), edge_map())
- -> icode_phi().
-
-subst_phi_uncond(I, Dst, Map) ->
- ArgList = subst_phi_uses_uncond0(hipe_icode:phi_arglist(I), Map, []),
- hipe_icode:mk_phi(Dst, ArgList).
-
--spec subst_phi_uses_uncond0([{icode_lbl(), icode_variable()}], edge_map(),
- [{icode_lbl(), icode_variable()}])
- -> [{icode_lbl(), icode_variable()}].
-
-subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) ->
- case Map of
- #{Var := List} ->
- case lists:keyfind(Pred, 1, List) of
- {Pred, {assigned, NewVar}} ->
- %% The variable is untagged!
- subst_phi_uses_uncond0(Left, Map, [{Pred, NewVar} | Acc]);
- {Pred, _NewVar} = PredNV ->
- %% The variable is untagged!
- subst_phi_uses_uncond0(Left, Map, [PredNV | Acc]);
- false ->
- %% The variable is not untagged.
- subst_phi_uses_uncond0(Left, Map, [{Pred, Var} | Acc])
- end;
- #{} ->
- %% The variable is not untagged.
- subst_phi_uses_uncond0(Left, Map, [{Pred, Var} | Acc])
- end;
-subst_phi_uses_uncond0([], _Map, Acc) ->
- Acc.
-
--spec place_error_handling(worklist(), state()) -> state().
-
-place_error_handling(WorkList, State) ->
- case get_work(WorkList) of
- none ->
- State;
- {Label, NewWorkList} ->
- BB = state__bb(State, Label),
- Code = hipe_bb:code(BB),
- case state__join_in_block(State, Label) of
- fixpoint ->
- place_error_handling(NewWorkList, State);
- {NewState, NewInBlock} ->
- {NewCode1, InBlockOut} = place_error(Code, NewInBlock, []),
- Succ = state__succ(NewState, Label),
- NewCode2 = handle_unchecked_end(Succ, NewCode1, InBlockOut),
- NewBB = hipe_bb:code_update(BB, NewCode2),
- NewState1 = state__bb_add(NewState, Label, NewBB),
- NewState2 = state__in_block_out_update(NewState1, Label, InBlockOut),
- NewWorkList1 = add_work(NewWorkList, Succ),
- place_error_handling(NewWorkList1, NewState2)
- end
- end.
-
--spec place_error(icode_instrs(), in_block(), icode_instrs())
- -> {icode_instrs(), in_block()}.
-
-place_error([I|Left], InBlock, Acc) ->
- case I of
- #icode_call{} ->
- case hipe_icode:call_fun(I) of
- X when X =:= fp_add; X =:= fp_sub;
- X =:= fp_mul; X =:= fp_div; X =:= fnegate ->
- case InBlock of
- false ->
- Clear = hipe_icode:mk_primop([], {fclearerror, []}, []),
- place_error(Left, {true, []}, [I, Clear|Acc]);
- {true, _} ->
- place_error(Left, InBlock, [I|Acc])
- end;
- unsafe_tag_float ->
- case InBlock of
- {true, Fail} ->
- Check = hipe_icode:mk_primop([], fcheckerror, [], [], Fail),
- place_error(Left, false, [I, Check|Acc]);
- false ->
- place_error(Left, InBlock, [I|Acc])
- end;
- {fclearerror, Fail} ->
- case InBlock of
- {true, Fail} ->
- %% We can remove this fclearerror!
- case hipe_icode:call_continuation(I) of
- [] ->
- place_error(Left, InBlock, Acc);
- Cont ->
- place_error(Left, InBlock, [hipe_icode:mk_goto(Cont)|Acc])
- end;
- {true, _OtherFail} ->
- %% TODO: This can be handled but it requires breaking up
- %% the BB in two. Currently this should not happen.
- exit("Starting fp ebb with different fail label");
- false ->
- place_error(Left, {true, Fail}, [I|Acc])
- end;
- fcheckerror ->
- case {true, hipe_icode:call_fail_label(I)} of
- InBlock ->
- %% No problem
- place_error(Left, false, [I|Acc]);
- NewInblock ->
- exit({"Fcheckerror has the wrong fail label",
- InBlock, NewInblock})
- end;
- X when X =:= conv_to_float; X =:= unsafe_untag_float ->
- place_error(Left, InBlock, [I|Acc]);
- _Other ->
- case hipe_icode_primops:fails(hipe_icode:call_fun(I)) of
- false ->
- place_error(Left, InBlock, [I|Acc]);
- true ->
- case InBlock of
- {true, Fail} ->
- Check = hipe_icode:mk_primop([], fcheckerror, [], [], Fail),
- place_error(Left, false, [I, Check|Acc]);
- false ->
- place_error(Left, InBlock, [I|Acc])
- end
- end
- end;
- #icode_fail{} ->
- place_error_1(I, Left, InBlock, Acc);
- #icode_return{} ->
- place_error_1(I, Left, InBlock, Acc);
- #icode_enter{} ->
- place_error_1(I, Left, InBlock, Acc);
- Other ->
- case instr_allowed_in_fp_ebb(Other) of
- true ->
- place_error(Left, InBlock, [I|Acc]);
- false ->
- case InBlock of
- {true, []} ->
- Check = hipe_icode:mk_primop([], fcheckerror, []),
- place_error(Left, false, [I, Check|Acc]);
- {true, _} ->
- exit({"Illegal instruction in caught fp ebb", I});
- false ->
- place_error(Left, InBlock, [I|Acc])
- end
- end
- end;
-place_error([], InBlock, Acc) ->
- {lists:reverse(Acc), InBlock}.
-
-place_error_1(I, Left, InBlock, Acc) ->
- case InBlock of
- {true, []} ->
- Check = hipe_icode:mk_primop([], fcheckerror, []),
- place_error(Left, false, [I, Check|Acc]);
- {true, _} ->
- exit({"End of control flow in caught fp ebb", I});
- false ->
- place_error(Left, InBlock, [I|Acc])
- end.
-
-%% If the block has no successors and we still are in a fp ebb we must
-%% end it to make sure we don't have any unchecked fp exceptions.
-
-handle_unchecked_end(Succ, Code, InBlock) ->
- case Succ of
- [] ->
- case InBlock of
- {true, []} ->
- {TopCode, Last} = split_code(Code),
- NewI = hipe_icode:mk_primop([], fcheckerror, []),
- TopCode ++ [NewI, Last];
- false ->
- Code
- end;
- _ ->
- Code
- end.
-
-instr_allowed_in_fp_ebb(Instr) ->
- case Instr of
- #icode_comment{} -> true;
- #icode_goto{} -> true;
- #icode_if{} -> true;
- #icode_move{} -> true;
- #icode_phi{} -> true;
- #icode_begin_handler{} -> true;
- #icode_switch_tuple_arity{} -> true;
- #icode_switch_val{} -> true;
- #icode_type{} -> true;
- _ -> false
- end.
-
-%%=============================================================
-%% Help functions
-%%=============================================================
-
-%% ------------------------------------------------------------
-%% Handling the variable map
-
--spec lookup_list([icode_var() | icode_const()], var_map())
- -> [none | icode_fvar()].
-
-lookup_list(List, Info) ->
- lookup_list(List, fun lookup/2, Info, []).
-
-lookup_list([H|T], Fun, Info, Acc) ->
- lookup_list(T, Fun, Info, [Fun(H, Info)|Acc]);
-lookup_list([], _, _, Acc) ->
- lists:reverse(Acc).
-
--spec lookup(icode_var() | icode_const(), var_map()) -> none | icode_fvar().
-
-lookup(Key, Tree) ->
- case hipe_icode:is_const(Key) of
- %% This can be true if the same constant has been
- %% untagged more than once
- true -> none;
- false ->
- case Tree of
- #{Key := {assigned, Val}} -> Val;
- #{Key := Val} -> Val;
- #{} -> none
- end
- end.
-
--spec lookup_list_keep_consts([icode_var() | icode_const()], var_map())
- -> [none | icode_fvar() | icode_const()].
-
-lookup_list_keep_consts(List, Info) ->
- lookup_list(List, fun lookup_keep_consts/2, Info, []).
-
--spec lookup_keep_consts(icode_var() | icode_const(), var_map())
- -> none | icode_fvar() | icode_const().
-
-lookup_keep_consts(Key, Tree) ->
- case hipe_icode:is_const(Key) of
- true -> Key;
- false ->
- case Tree of
- #{Key := {assigned, Val}} -> Val;
- #{Key := Val} -> Val;
- #{} -> none
- end
- end.
-
--spec get_type(icode_argument()) -> erl_types:erl_type().
-
-get_type(Var) ->
- case hipe_icode:is_const(Var) of
- true -> erl_types:t_from_term(hipe_icode:const_value(Var));
- false ->
- case hipe_icode:is_annotated_variable(Var) of
- true ->
- {type_anno, Type, _} = hipe_icode:variable_annotation(Var),
- Type
-%%% false -> erl_types:t_any()
- end
- end.
-
-%% ------------------------------------------------------------
-%% Handling the map from variables to fp-variables
-
--spec join_maps([edge()], edge_map()) -> initial_var_map().
-
-join_maps(Edges, EdgeMap) ->
- join_maps(Edges, EdgeMap, #{}).
-
-join_maps([Edge = {Pred, _}|Left], EdgeMap, Map) ->
- case EdgeMap of
- #{Edge := OldMap} ->
- NewMap = join_maps0(maps:to_list(OldMap), Pred, Map),
- join_maps(Left, EdgeMap, NewMap);
- #{} ->
- %% All predecessors have not been handled. Use empty map.
- #{}
- end;
-join_maps([], _, Map) ->
- Map.
-
--spec join_maps0(list(), icode_lbl(), initial_var_map()) -> initial_var_map().
-
-join_maps0([{Var=#icode_variable{kind=var}, FVar}|Tail], Pred, Map) ->
- case Map of
- #{Var := List} ->
- case lists:keyfind(Pred, 1, List) of
- false ->
- join_maps0(Tail, Pred, Map#{Var := [{Pred, FVar}|List]});
- {Pred, FVar} ->
- %% No problem.
- join_maps0(Tail, Pred, Map);
- _ ->
- exit('New binding to same variable')
- end;
- #{} ->
- join_maps0(Tail, Pred, Map#{Var => [{Pred, FVar}]})
- end;
-join_maps0([], _, Map) ->
- Map.
-
--spec filter_map(initial_var_map(), pos_integer()) -> var_map_phi().
-
-filter_map(Map, NofPreds) ->
- filter_map(maps:to_list(Map), NofPreds, Map).
-
--spec filter_map([{icode_var(), incoming_fvars()}], pos_integer(),
- var_map_phi()) -> var_map_phi().
-
-filter_map([{Var, Bindings}|Left], NofPreds, Map) ->
- case length(Bindings) =:= NofPreds of
- true ->
- BindingsAllAssigned = lists:all(fun({_, {assigned, _}}) -> true;
- ({_, _}) -> false
- end, Bindings),
- case all_args_equal(Bindings) of
- true ->
- NewBinding =
- case hd(Bindings) of
- {Pred, {assigned, FVar0}} when is_integer(Pred) ->
- case BindingsAllAssigned of
- true -> {assigned, FVar0};
- false -> FVar0
- end;
- {Pred, FVar0} when is_integer(Pred) -> FVar0
- end,
- filter_map(Left, NofPreds, Map#{Var := NewBinding});
- false ->
- PhiDst = hipe_icode:mk_new_fvar(),
- PhiArgs = strip_of_assigned(Bindings),
- NewMap =
- case Map of
- #{phi := Val} ->
- Map#{phi := [{PhiDst, PhiArgs}|Val]};
- #{} ->
- Map#{phi => [{PhiDst, PhiArgs}]}
- end,
- NewBinding =
- case BindingsAllAssigned of
- true -> {assigned, PhiDst};
- false -> PhiDst
- end,
- filter_map(Left, NofPreds, NewMap#{Var := NewBinding})
- end;
- false ->
- filter_map(Left, NofPreds, maps:remove(Var, Map))
- end;
-filter_map([], _NofPreds, Map) ->
- Map.
-
--spec all_args_equal(incoming_fvars()) -> boolean().
-
-%% all_args_equal returns true if the mapping for a variable is the
-%% same from all predecessors, i.e., we do not need a phi-node.
-
-%% During the fixpoint loop, a mapping might become assigned, without that
-%% information having propagated into all predecessors. We take care to answer
-%% true even if FVar is only assigned in some predecessors.
-
-all_args_equal([{_, {assigned, FVar}}|Left]) ->
- all_args_equal(Left, FVar);
-all_args_equal([{_, FVar}|Left]) ->
- all_args_equal(Left, FVar).
-
-all_args_equal([{_, {assigned, FVar1}}|Left], FVar1) ->
- all_args_equal(Left, FVar1);
-all_args_equal([{_, FVar1}|Left], FVar1) ->
- all_args_equal(Left, FVar1);
-all_args_equal([], _) ->
- true;
-all_args_equal(_, _) ->
- false.
-
-
--spec add_new_bindings_unassigned([icode_var()], var_map()) -> var_map().
-
-%% We differentiate between values that have been assigned as
-%% tagged variables and those that got a 'virtual' binding.
-
-add_new_bindings_unassigned([Var|Left], Map) ->
- FVar = hipe_icode:mk_new_fvar(),
- add_new_bindings_unassigned(Left, Map#{Var => FVar});
-add_new_bindings_unassigned([], Map) ->
- Map.
-
--spec add_new_bindings_assigned([icode_var()], var_map()) -> var_map().
-
-add_new_bindings_assigned([Var|Left], Map) ->
- case lookup(Var, Map) of
- none ->
- FVar = hipe_icode:mk_new_fvar(),
- NewMap = Map#{Var => {assigned, FVar}},
- add_new_bindings_assigned(Left, NewMap);
- _ ->
- add_new_bindings_assigned(Left, Map)
- end;
-add_new_bindings_assigned([], Map) ->
- Map.
-
--spec strip_of_assigned(incoming_fvars()) -> [{icode_lbl(), icode_fvar()}].
-
-strip_of_assigned(List) ->
- strip_of_assigned(List, []).
-
-strip_of_assigned([{Pred, {assigned, Val}}|Left], Acc) ->
- strip_of_assigned(Left, [{Pred, Val}|Acc]);
-strip_of_assigned([Tuple|Left], Acc) ->
- strip_of_assigned(Left, [Tuple|Acc]);
-strip_of_assigned([], Acc) ->
- Acc.
-
-%% ------------------------------------------------------------
-%% Help functions for the transformation from ordinary instruction to
-%% fp-instruction
-
--spec is_fop_cand(icode_instr()) -> boolean().
-
-is_fop_cand(I) ->
- case hipe_icode:call_fun(I) of
- '/' -> true;
- Fun ->
- case fun_to_fop(Fun) of
- false -> false;
- _ -> any_is_float(hipe_icode:args(I))
- end
- end.
-
--spec any_is_float([icode_argument()]) -> boolean().
-
-any_is_float(Vars) ->
- lists:any(fun (V) -> erl_types:t_is_float(get_type(V)) end, Vars).
-
-remove_duplicates(List) ->
- remove_duplicates(List, []).
-
-remove_duplicates([X|Left], Acc) ->
- case lists:member(X, Acc) of
- true ->
- remove_duplicates(Left, Acc);
- false ->
- remove_duplicates(Left, [X|Acc])
- end;
-remove_duplicates([], Acc) ->
- Acc.
-
-fun_to_fop(Fun) ->
- case Fun of
- '+' -> fp_add;
- '-' -> fp_sub;
- '*' -> fp_mul;
- '/' -> fp_div;
- _ -> false
- end.
-
-
--spec must_be_tagged(icode_var(), var_map()) -> boolean().
-
-%% If there is a tagged version of this variable available we don't
-%% have to tag the untagged version.
-
-must_be_tagged(Var, Map) ->
- case Map of
- #{Var := {assigned, _}} -> false;
- #{Var := Val} -> hipe_icode:is_fvar(Val);
- #{} -> false
- end.
-
-
--spec get_conv_instrs([icode_argument()], var_map()) -> icode_instrs().
-
-%% Converting to floating point variables
-
-get_conv_instrs(Vars, Map) ->
- get_conv_instrs(Vars, Map, []).
-
--spec get_conv_instrs([icode_argument()], var_map(), icode_instrs())
- -> icode_instrs().
-
-get_conv_instrs([Var|Left], Map, Acc) ->
- #{Var := {_, Dst}} = Map,
- NewI =
- case erl_types:t_is_float(get_type(Var)) of
- true ->
- [hipe_icode:mk_primop([Dst], unsafe_untag_float, [Var])];
- false ->
- [hipe_icode:mk_primop([Dst], conv_to_float, [Var])]
- end,
- get_conv_instrs(Left, Map, NewI++Acc);
-get_conv_instrs([], _, Acc) ->
- Acc.
-
-
--spec conv_consts([icode_const()], icode_instr()) -> icode_instr().
-
-conv_consts(ConstArgs, I) ->
- conv_consts(ConstArgs, I, []).
-
-conv_consts([Const|Left], I, Subst) ->
- NewConst = hipe_icode:mk_const(float(hipe_icode:const_value(Const))),
- conv_consts(Left, I, [{Const, NewConst}|Subst]);
-conv_consts([], I, Subst) ->
- hipe_icode:subst_uses(Subst, I).
-
-
-%% _________________________________________________________________
-%%
-%% Handling the state
-%%
-
-new_state(Cfg) ->
- #state{cfg = Cfg}.
-
-state__cfg(#state{cfg = Cfg}) ->
- Cfg.
-
-state__succ(#state{cfg = Cfg}, Label) ->
- hipe_icode_cfg:succ(Cfg, Label).
-
-state__pred(#state{cfg = Cfg}, Label) ->
- hipe_icode_cfg:pred(Cfg, Label).
-
-state__redirect(S = #state{cfg = Cfg}, From, ToOld, ToNew) ->
- NewCfg = hipe_icode_cfg:redirect(Cfg, From, ToOld, ToNew),
- S#state{cfg=NewCfg}.
-
-state__bb(#state{cfg = Cfg}, Label) ->
- hipe_icode_cfg:bb(Cfg, Label).
-
-state__bb_add(S = #state{cfg = Cfg}, Label, BB) ->
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, BB),
- S#state{cfg = NewCfg}.
-
--spec state__map(state(), icode_lbl()) -> initial_var_map().
-
-state__map(S = #state{edge_map = EM}, To) ->
- join_maps([{From, To} || From <- state__pred(S, To)], EM).
-
--spec state__map_update(state(), icode_lbl(), icode_lbl(), var_map()) ->
- fixpoint | state().
-
-state__map_update(S = #state{edge_map = EM}, From, To, Map) ->
- FromTo = {From, To},
- MapChanged =
- case EM of
- #{FromTo := Map1} -> not match(Map1, Map);
- #{} -> true
- end,
- case MapChanged of
- true ->
- NewEM = EM#{FromTo => Map},
- S#state{edge_map = NewEM};
- false ->
- fixpoint
- end.
-
--spec state__join_in_block(state(), icode_lbl())
- -> fixpoint | {state(), in_block()}.
-
-state__join_in_block(S = #state{fp_ebb_map = Map}, Label) ->
- Pred = state__pred(S, Label),
- Edges = [{X, Label} || X <- Pred],
- NewInBlock = join_in_block([maps:find(X, Map) || X <- Edges]),
- InBlockLabel = {inblock_in, Label},
- case Map of
- #{InBlockLabel := NewInBlock} ->
- fixpoint;
- _ ->
- NewMap = Map#{InBlockLabel => NewInBlock},
- {S#state{fp_ebb_map = NewMap}, NewInBlock}
- end.
-
--spec state__in_block_out_update(state(), icode_lbl(), in_block())
- -> state().
-
-state__in_block_out_update(S = #state{fp_ebb_map = Map}, Label, NewInBlock) ->
- Succ = state__succ(S, Label),
- Edges = [{Label, X} || X <- Succ],
- NewMap = update_edges(Edges, NewInBlock, Map),
- NewMap1 = NewMap#{{inblock_out, Label} => NewInBlock},
- S#state{fp_ebb_map = NewMap1}.
-
--spec update_edges([edge()], in_block(), fp_ebb_map()) -> fp_ebb_map().
-
-update_edges([Edge|Left], NewInBlock, Map) ->
- NewMap = Map#{Edge => NewInBlock},
- update_edges(Left, NewInBlock, NewMap);
-update_edges([], _NewInBlock, NewMap) ->
- NewMap.
-
--spec join_in_block([error | {ok, in_block()}]) -> in_block().
-
-join_in_block([]) ->
- false;
-join_in_block([error|_]) ->
- false;
-join_in_block([{ok, InBlock}|Left]) ->
- join_in_block(Left, InBlock).
-
--spec join_in_block([error | {ok, in_block()}], Current)
- -> false | Current when
- Current :: in_block().
-
-join_in_block([error|_], _Current) ->
- false;
-join_in_block([{ok, InBlock}|Left], Current) ->
- if Current =:= InBlock -> join_in_block(Left, Current);
- Current =:= false -> false;
- InBlock =:= false -> false;
- true -> exit("Basic block is in two different fp ebb:s")
- end;
-join_in_block([], Current) ->
- Current.
-
-
--spec state__get_in_block_in(state(), icode_lbl()) -> in_block().
-
-state__get_in_block_in(#state{fp_ebb_map = Map}, Label) ->
- maps:get({inblock_in, Label}, Map).
-
-state__get_in_block_out(#state{fp_ebb_map = Map}, Label) ->
- maps:get({inblock_out, Label}, Map).
-
-
--spec new_worklist(state()) -> worklist().
-
-new_worklist(#state{cfg = Cfg}) ->
- Start = hipe_icode_cfg:start_label(Cfg),
- {[Start], [], gb_sets:insert(Start, gb_sets:empty())}.
-
--spec get_work(worklist()) -> none | {icode_lbl(), worklist()}.
-
-get_work({[Label|Left], List, Set}) ->
- {Label, {Left, List, gb_sets:delete(Label, Set)}};
-get_work({[], [], _Set}) ->
- none;
-get_work({[], List, Set}) ->
- get_work({lists:reverse(List), [], Set}).
-
--spec add_work(worklist(), [icode_lbl()]) -> worklist().
-
-add_work({List1, List2, Set} = Work, [Label|Left]) ->
- case gb_sets:is_member(Label, Set) of
- true ->
- add_work(Work, Left);
- false ->
- %% io:format("Added work: ~w\n", [Label]),
- NewSet = gb_sets:insert(Label, Set),
- add_work({List1, [Label|List2], NewSet}, Left)
- end;
-add_work(WorkList, []) ->
- WorkList.
-
--spec match(var_map(), var_map()) -> boolean().
-
-match(Tree1, Tree2) when is_map(Tree1), is_map(Tree2) ->
- Tree1 =:= Tree2.
diff --git a/lib/hipe/icode/hipe_icode_heap_test.erl b/lib/hipe/icode/hipe_icode_heap_test.erl
deleted file mode 100644
index 1a4f28e1af..0000000000
--- a/lib/hipe/icode/hipe_icode_heap_test.erl
+++ /dev/null
@@ -1,192 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2000 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Filename : hipe_icode_heap_test.erl
-%% Module : hipe_icode_heap_test
-%% Purpose :
-%% Notes :
-%% History : * 2000-11-07 Erik Johansson (happi@it.uu.se):
-%% Created.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_icode_heap_test).
-
--export([cfg/1]).
-
--define(DO_ASSERT,true).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
--include("../flow/cfg.hrl").
--include("../rtl/hipe_literals.hrl").
-
-%-------------------------------------------------------------------------
-
--spec cfg(#cfg{}) -> #cfg{}.
-
-cfg(CFG) ->
- Icode = hipe_icode_cfg:cfg_to_linear(CFG),
- Code = hipe_icode:icode_code(Icode),
- ActualVmax = hipe_icode:highest_var(Code),
- ActualLmax = hipe_icode:highest_label(Code),
- hipe_gensym:set_label(icode, ActualLmax+1),
- hipe_gensym:set_var(icode, ActualVmax+1),
- EBBs = hipe_icode_ebb:cfg(CFG),
- {EBBcode,_Visited} = ebbs(EBBs, [], CFG),
- NewCode = add_gc_tests(EBBcode),
- NewIcode = hipe_icode:icode_code_update(Icode, NewCode),
- NewCFG = hipe_icode_cfg:linear_to_cfg(NewIcode),
- %% hipe_icode_cfg:pp(NewCFG),
- NewCFG.
-
-ebbs([EBB|EBBs], Visited, CFG) ->
- case hipe_icode_ebb:type(EBB) of
- node ->
- L = hipe_icode_ebb:node_label(EBB),
- case visited(L, Visited) of
- true ->
- ebbs(EBBs, Visited, CFG);
- false ->
- EBBCode = hipe_bb:code(hipe_icode_cfg:bb(CFG, L)),
- case hipe_icode_ebb:node_successors(EBB) of
- [Succ|Succs] ->
- {[SuccCode|More], Visited1} =
- ebbs([Succ], [L|Visited], CFG),
- {[OtherCode|MoreOther], Visited2} =
- ebbs(Succs ++ EBBs, Visited1, CFG),
- {[[hipe_icode:mk_label(L)|EBBCode] ++ SuccCode|
- More] ++ [OtherCode|MoreOther],
- Visited2};
- [] ->
- {OtherCode, Visited1} = ebbs(EBBs, [L|Visited], CFG),
- {[[hipe_icode:mk_label(L)|EBBCode] | OtherCode], Visited1}
- end
- end;
- leaf ->
- ebbs(EBBs, Visited, CFG)
- end;
-ebbs([], Visited,_) ->
- {[[]], Visited}.
-
-visited(L, Visited) ->
- lists:member(L, Visited).
-
-add_gc_tests([[]|EBBCodes]) -> add_gc_tests(EBBCodes);
-add_gc_tests([EBBCode|EBBCodes]) ->
- case need(EBBCode, 0, []) of
- {Need, RestCode, [Lbl|Code]} ->
- if Need > 0 ->
- [Lbl] ++ gc_test(Need) ++ Code ++ add_gc_tests([RestCode|EBBCodes]);
- true ->
- [Lbl|Code] ++ add_gc_tests([RestCode|EBBCodes])
- end;
- {0, RestCode, []} ->
- add_gc_tests([RestCode|EBBCodes])
- end;
-add_gc_tests([]) -> [].
-
-need([I|Is] , Need, Code) ->
- case split(I) of
- true ->
- case I of
- #icode_call{} ->
- case hipe_icode:call_continuation(I) of
- [] -> %% Was fallthrough.
- NewLab = hipe_icode:mk_new_label(),
- LabName = hipe_icode:label_name(NewLab),
- NewCall = hipe_icode:call_set_continuation(I,LabName),
- {Need + need(I), [NewLab|Is], lists:reverse([NewCall|Code])};
- _ ->
- {Need + need(I), Is, lists:reverse([I|Code])}
- end;
- _ ->
- {Need + need(I), Is, lists:reverse([I|Code])}
- end;
- false ->
- need(Is, Need + need(I), [I|Code])
- end;
-need([], Need, Code) ->
- {Need, [], lists:reverse(Code)}.
-
-need(I) ->
- case I of
- #icode_call{} ->
- primop_need(hipe_icode:call_fun(I), hipe_icode:call_args(I));
- #icode_enter{} ->
- primop_need(hipe_icode:enter_fun(I), hipe_icode:enter_args(I));
- _ ->
- 0
- end.
-
-primop_need(Op, As) ->
- case Op of
- cons ->
- 2;
- mktuple ->
- length(As) + 1;
- #mkfun{} ->
- NumFree = length(As),
- ?ERL_FUN_SIZE + NumFree;
- unsafe_tag_float ->
- 3;
- _ ->
- 0
- end.
-
-gc_test(Need) ->
- L = hipe_icode:mk_new_label(),
- [hipe_icode:mk_primop([], #gc_test{need=Need}, [],
- hipe_icode:label_name(L),
- hipe_icode:label_name(L)),
- L].
-
-split(I) ->
- case I of
- #icode_call{} -> not known_heap_need(hipe_icode:call_fun(I));
- #icode_enter{} -> not known_heap_need(hipe_icode:enter_fun(I));
- _ -> false
- end.
-
-known_heap_need(Name) ->
- case Name of
- %% Primops
- cons -> true;
- fcheckerror -> true;
- fclearerror -> true;
- fnegate -> true;
- fp_add -> true;
- fp_div -> true;
- fp_mul -> true;
- fp_sub -> true;
- mktuple -> true;
- unsafe_hd -> true;
- unsafe_tag_float -> true;
- unsafe_tl -> true;
- unsafe_untag_float -> true;
- #element{} -> true;
- #unsafe_element{} -> true;
- #unsafe_update_element{} -> true;
-
- %% MFAs
- {erlang, element, 2} -> true;
- {erlang, length, 1} -> true;
- {erlang, self, 0} -> true;
- {erlang, size, 1} -> true;
-
- _ -> false
- end.
diff --git a/lib/hipe/icode/hipe_icode_inline_bifs.erl b/lib/hipe/icode/hipe_icode_inline_bifs.erl
deleted file mode 100644
index 16a95991e7..0000000000
--- a/lib/hipe/icode/hipe_icode_inline_bifs.erl
+++ /dev/null
@@ -1,238 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%--------------------------------------------------------------------
-%% File : hipe_icode_inline_bifs.erl
-%% Author : Per Gustafsson <pergu@it.uu.se>
-%% Purpose : Inlines BIFs which can be expressed easily in ICode.
-%% This allows for optimizations in later ICode passes
-%% and makes the code faster.
-%%
-%% Created : 14 May 2007 by Per Gustafsson <pergu@it.uu.se>
-%%--------------------------------------------------------------------
-
-%% Currently inlined BIFs:
-%% and, or, xor, not, <, >, >=, =<, ==, /=, =/=, =:=
-%% is_atom, is_binary, is_bitstring, is_boolean, is_float,
-%% is_function, is_integer, is_list, is_map, is_number,
-%% is_pid, is_port, is_reference, is_tuple
-
--module(hipe_icode_inline_bifs).
-
--export([cfg/1]).
-
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
-%%--------------------------------------------------------------------
-
--spec cfg(#cfg{}) -> #cfg{}.
-
-cfg(Cfg) ->
- Linear = hipe_icode_cfg:cfg_to_linear(Cfg),
- #icode{code = StraightCode} = Linear,
- FinalCode = lists:flatten([inline_bif(I) || I <- StraightCode]),
- Cfg1 = hipe_icode_cfg:linear_to_cfg(Linear#icode{code = FinalCode}),
- hipe_icode_cfg:remove_unreachable_code(Cfg1).
-
-inline_bif(I = #icode_call{}) ->
- try_conditional(I);
-inline_bif(I) ->
- I.
-
-try_conditional(I = #icode_call{dstlist = [Dst], 'fun' = {erlang, Name, 2},
- args = [Arg1, Arg2],
- continuation = Cont}) ->
- case is_conditional(Name) of
- true ->
- inline_conditional(Dst, Name, Arg1, Arg2, Cont);
- false ->
- try_bool(I)
- end;
-try_conditional(I) ->
- try_bool(I).
-
-is_conditional(Name) ->
- case Name of
- '=:=' -> true;
- '=/=' -> true;
- '==' -> true;
- '/=' -> true;
- '>' -> true;
- '<' -> true;
- '>=' -> true;
- '=<' -> true;
- _ -> false
- end.
-
-try_bool(I = #icode_call{dstlist = [Dst], 'fun' = Name,
- args = [Arg1, Arg2],
- continuation = Cont, fail_label = Fail}) ->
- case is_binary_bool(Name) of
- {true, Results, ResLbls} ->
- inline_binary_bool(Dst, Results, ResLbls, Arg1, Arg2, Cont, Fail, I);
- false ->
- try_type_tests(I)
- end;
-try_bool(I = #icode_call{dstlist = [Dst], 'fun' = {erlang, 'not', 1},
- args = [Arg1],
- continuation = Cont,
- fail_label = Fail}) ->
- inline_unary_bool(Dst, {false, true}, Arg1, Cont, Fail, I);
-try_bool(I) -> try_type_tests(I).
-
-is_binary_bool({erlang, Name, 2}) ->
- ResTLbl = hipe_icode:mk_new_label(),
- ResFLbl = hipe_icode:mk_new_label(),
- ResTL = hipe_icode:label_name(ResTLbl),
- ResFL = hipe_icode:label_name(ResFLbl),
- case Name of
- 'and' -> {true, {ResTL, ResFL, ResFL}, {ResTLbl, ResFLbl}};
- 'or' -> {true, {ResTL, ResTL, ResFL}, {ResTLbl, ResFLbl}};
- 'xor' -> {true, {ResFL, ResTL, ResFL}, {ResTLbl, ResFLbl}};
- _ -> false
- end;
-is_binary_bool(_) -> false.
-
-try_type_tests(I = #icode_call{dstlist=[Dst], 'fun' = {erlang, Name, 1},
- args = Args, continuation = Cont}) ->
- case is_type_test(Name) of
- {true, Type} ->
- inline_type_test(Dst, Type, Args, Cont);
- false ->
- I
- end;
-try_type_tests(I) -> I.
-
-is_type_test(Name) ->
- case Name of
- is_atom -> {true, atom};
- is_binary -> {true, binary};
- is_bitstring -> {true, bitstr};
- is_boolean -> {true, boolean};
- is_float -> {true, float};
- is_function -> {true, function};
- is_integer -> {true, integer};
- is_list -> {true, list};
- is_map -> {true, map};
- is_number -> {true, number};
- is_pid -> {true, pid};
- is_port -> {true, port};
- is_reference -> {true, reference};
- is_tuple -> {true, tuple};
- _ -> false
- end.
-
-inline_type_test(BifRes, Type, Src, Cont) ->
- {NewCont, NewEnd} = get_cont_lbl(Cont),
- TLbl = hipe_icode:mk_new_label(),
- FLbl = hipe_icode:mk_new_label(),
- TL = hipe_icode:label_name(TLbl),
- FL = hipe_icode:label_name(FLbl),
- [hipe_icode:mk_type(Src, Type, TL, FL),
- TLbl,
- hipe_icode:mk_move(BifRes, hipe_icode:mk_const(true)),
- hipe_icode:mk_goto(NewCont),
- FLbl,
- hipe_icode:mk_move(BifRes, hipe_icode:mk_const(false)),
- hipe_icode:mk_goto(NewCont)|
- NewEnd].
-
-inline_conditional(BifRes, Op, Src1, Src2, Cont) ->
- {NewCont, NewEnd} = get_cont_lbl(Cont),
- TLbl = hipe_icode:mk_new_label(),
- FLbl = hipe_icode:mk_new_label(),
- TL = hipe_icode:label_name(TLbl),
- FL = hipe_icode:label_name(FLbl),
- [hipe_icode:mk_if(Op, [Src1, Src2], TL, FL),
- TLbl,
- hipe_icode:mk_move(BifRes, hipe_icode:mk_const(true)),
- hipe_icode:mk_goto(NewCont),
- FLbl,
- hipe_icode:mk_move(BifRes, hipe_icode:mk_const(false)),
- hipe_icode:mk_goto(NewCont)|
- NewEnd].
-
-%%
-%% The TTL TFL FFL labelnames points to either ResTLbl or ResFLbl
-%% Depending on what boolean expression we are inlining
-%%
-
-inline_binary_bool(Dst, {TTL, TFL, FFL}, {ResTLbl, ResFLbl},
- Arg1, Arg2, Cont, Fail, I) ->
- {NewCont, NewEnd} = get_cont_lbl(Cont),
- {NewFail, FailCode} = get_fail_lbl(Fail, I),
- EndCode = FailCode++NewEnd,
- TLbl = hipe_icode:mk_new_label(),
- FLbl = hipe_icode:mk_new_label(),
- NotTLbl = hipe_icode:mk_new_label(),
- NotTTLbl = hipe_icode:mk_new_label(),
- NotTFLbl = hipe_icode:mk_new_label(),
- TL = hipe_icode:label_name(TLbl),
- FL = hipe_icode:label_name(FLbl),
- NotTL = hipe_icode:label_name(NotTLbl),
- NotTTL = hipe_icode:label_name(NotTTLbl),
- NotTFL = hipe_icode:label_name(NotTFLbl),
- [hipe_icode:mk_type([Arg1], {atom, true}, TL, NotTL, 0.5),
- NotTLbl,
- hipe_icode:mk_type([Arg1], {atom, false}, FL, NewFail, 0.99),
- TLbl,
- hipe_icode:mk_type([Arg2], {atom, true}, TTL, NotTTL, 0.5),
- NotTTLbl,
- hipe_icode:mk_type([Arg2], {atom, false}, TFL, NewFail, 0.99),
- FLbl,
- hipe_icode:mk_type([Arg2], {atom, true}, TFL, NotTFL, 0.5),
- NotTFLbl,
- hipe_icode:mk_type([Arg2], {atom, false}, FFL, NewFail, 0.99),
- ResTLbl,
- hipe_icode:mk_move(Dst, hipe_icode:mk_const(true)),
- hipe_icode:mk_goto(NewCont),
- ResFLbl,
- hipe_icode:mk_move(Dst, hipe_icode:mk_const(false)),
- hipe_icode:mk_goto(NewCont)|
- EndCode].
-
-inline_unary_bool(Dst, {T,F}, Arg1, Cont, Fail, I) ->
- TLbl = hipe_icode:mk_new_label(),
- NotTLbl = hipe_icode:mk_new_label(),
- FLbl = hipe_icode:mk_new_label(),
- TL = hipe_icode:label_name(TLbl),
- NotTL = hipe_icode:label_name(NotTLbl),
- FL = hipe_icode:label_name(FLbl),
- {NewCont, NewEnd} = get_cont_lbl(Cont),
- {NewFail, FailCode} = get_fail_lbl(Fail, I),
- EndCode = FailCode ++ NewEnd,
- Arg1L = [Arg1],
- [hipe_icode:mk_type(Arg1L, {atom, true}, TL, NotTL, 0.5),
- NotTLbl,
- hipe_icode:mk_type(Arg1L, {atom, false}, FL, NewFail, 0.99),
- TLbl,
- hipe_icode:mk_move(Dst, hipe_icode:mk_const(T)),
- hipe_icode:mk_goto(NewCont),
- FLbl,
- hipe_icode:mk_move(Dst, hipe_icode:mk_const(F)),
- hipe_icode:mk_goto(NewCont)|
- EndCode].
-
-get_cont_lbl([]) ->
- NL = hipe_icode:mk_new_label(),
- {hipe_icode:label_name(NL), [NL]};
-get_cont_lbl(Cont) ->
- {Cont, []}.
-
-get_fail_lbl([], I) ->
- NL = hipe_icode:mk_new_label(),
- {hipe_icode:label_name(NL), [NL, I]};
-get_fail_lbl(Fail, _) ->
- {Fail, []}.
diff --git a/lib/hipe/icode/hipe_icode_instruction_counter.erl b/lib/hipe/icode/hipe_icode_instruction_counter.erl
deleted file mode 100644
index 97a19753a1..0000000000
--- a/lib/hipe/icode/hipe_icode_instruction_counter.erl
+++ /dev/null
@@ -1,131 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-------------------------------------------------------------------
-%% File : icode_instruction_counter.erl
-%% Author : Andreas Hasselberg <anha0825@student.uu.se>
-%% Purpose : This module counts the number of different instructions
-%% in a function. It is useful when you want to know if
-%% your Icode analysis or specialization is good, bad or
-%% simply unlucky :)
-%%
-%% Created : 2 Oct 2006 by Andreas Hasselberg <anha0825@student.uu.se>
-%%-------------------------------------------------------------------
-
--module(hipe_icode_instruction_counter).
-
--export([cfg/3, compare/3]).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
-%%-------------------------------------------------------------------
-%% A general CFG instruction walktrough
-%%-------------------------------------------------------------------
-
--spec cfg(#cfg{}, mfa(), comp_options()) -> [_].
-
-cfg(Cfg, _IcodeFun, _Options) ->
- Labels = hipe_icode_cfg:labels(Cfg),
- %% Your Info init function goes here
- InitInfo = counter__init_info(),
- Info = lists:foldl(fun (Label, InfoAcc) ->
- BB = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- walktrough_bb(Code, InfoAcc)
- end, InitInfo, Labels),
- %% counter__output_info(IcodeFun, Info),
- Info.
-
-walktrough_bb(BB, Info) ->
- lists:foldl(fun (Insn, InfoAcc) ->
- %% Your analysis function here
- counter__analys_insn(Insn, InfoAcc)
- end, Info, BB).
-
-%%-------------------------------------------------------------------
-%% The counter specific functions
-%%-------------------------------------------------------------------
-
--spec compare(gb_trees:tree(), gb_trees:tree(), gb_trees:tree()) ->
- gb_trees:tree().
-
-compare(Name, Old, New) ->
- NewList = gb_trees:to_list(New),
- OldList = gb_trees:to_list(Old),
- TempTree = compare_one_way(NewList, Old, added, gb_trees:empty()),
- DiffTree = compare_one_way(OldList, New, removed, TempTree),
- DiffList = gb_trees:to_list(DiffTree),
- if DiffList =:= [] ->
- ok;
- true ->
- io:format("~p: ~p ~n", [Name, DiffList])
- end,
- DiffTree.
-
-compare_one_way(List, Tree, Key, Fold_tree) ->
- lists:foldl(fun({Insn, ListCount}, DiffAcc) when is_integer(ListCount) ->
- DiffCount =
- case gb_trees:lookup(Insn, Tree) of
- {value, TreeCount} when is_integer(TreeCount) ->
- ListCount - TreeCount;
- none ->
- ListCount
- end,
- if DiffCount > 0 ->
- gb_trees:insert({Key, Insn}, DiffCount, DiffAcc);
- true ->
- DiffAcc
- end
- end,
- Fold_tree,
- List).
-
-counter__init_info() ->
- gb_trees:empty().
-
-counter__analys_insn(Insn, Info) ->
- Key = counter__insn_get_key(Insn),
- counter__increase_key(Key, Info).
-
-counter__insn_get_key(If = #icode_if{}) -> {'if', hipe_icode:if_op(If)};
-counter__insn_get_key(Call = #icode_call{}) -> {call, hipe_icode:call_fun(Call)};
-counter__insn_get_key(#icode_enter{}) -> enter;
-counter__insn_get_key(#icode_return{}) -> return;
-counter__insn_get_key(#icode_type{}) -> type;
-counter__insn_get_key(#icode_switch_val{}) -> switch_val;
-counter__insn_get_key(#icode_switch_tuple_arity{}) -> switch_tuple_arity;
-counter__insn_get_key(#icode_goto{}) -> goto;
-counter__insn_get_key(#icode_move{}) -> move;
-counter__insn_get_key(#icode_phi{}) -> phi;
-counter__insn_get_key(#icode_begin_try{}) -> begin_try;
-counter__insn_get_key(#icode_end_try{}) -> end_try;
-counter__insn_get_key(#icode_begin_handler{}) -> begin_handler;
-counter__insn_get_key(#icode_fail{}) -> fail;
-counter__insn_get_key(#icode_comment{}) -> comment.
-
-counter__increase_key(Key, Info) ->
- NewCounter =
- case gb_trees:lookup(Key, Info) of
- {value, Counter} when is_integer(Counter) ->
- Counter + 1;
- none ->
- 1
- end,
- gb_trees:enter(Key, NewCounter, Info).
-
-%%counter__output_info(IcodeFun, Info) ->
-%% InfoList = gb_trees:to_list(Info),
-%% io:format("~p instructions : ~p ~n", [IcodeFun, InfoList]).
diff --git a/lib/hipe/icode/hipe_icode_liveness.erl b/lib/hipe/icode/hipe_icode_liveness.erl
deleted file mode 100644
index e61529a1bb..0000000000
--- a/lib/hipe/icode/hipe_icode_liveness.erl
+++ /dev/null
@@ -1,97 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% ICODE LIVENESS ANALYSIS
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_icode_liveness).
-
--define(PRETTY_PRINT, true).
-
--include("hipe_icode.hrl").
--include("../flow/liveness.inc").
-
-%%--------------------------------------------------------------------
-%% Interface to CFG and icode.
-%%--------------------------------------------------------------------
-
-cfg_bb(CFG, L) ->
- hipe_icode_cfg:bb(CFG, L).
-
-cfg_postorder(CFG) ->
- hipe_icode_cfg:postorder(CFG).
-
-cfg_succ(CFG, L) ->
- hipe_icode_cfg:succ(CFG, L).
-
-uses(Instr) ->
- hipe_icode:uses(Instr).
-
-defines(Instr) ->
- hipe_icode:defines(Instr).
-
-%%
-%% This is the list of registers that are live at exit from a function
-%%
-cfg_labels(CFG) ->
- hipe_icode_cfg:labels(CFG).
-
-liveout_no_succ() ->
- ordsets:new().
-
-pp_liveness_info(LiveList) ->
- print_live_list(LiveList).
-
-print_live_list([]) ->
- io:format(" none~n", []);
-print_live_list([Last]) ->
- io:format(" ", []),
- print_var(Last),
- io:format("~n", []);
-print_live_list([Var|Rest]) ->
- io:format(" ", []),
- print_var(Var),
- io:format(",", []),
- print_live_list(Rest).
-
-pp_block(Label, CFG) ->
- BB = hipe_icode_cfg:bb(CFG, Label),
- Code = hipe_bb:code(BB),
- hipe_icode_pp:pp_block(Code).
-
-print_var(#icode_variable{name=V, kind=Kind, annotation=T}) ->
- case Kind of
- var -> io:format("v~p", [V]);
- reg -> io:format("r~p", [V]);
- reg_gcsafe -> io:format("rs~p", [V]);
- fvar -> io:format("fv~p", [V])
- end,
- case T of
- [] -> ok;
- {_,X,F} -> io:format(" (~s)", F(X))
- end.
-
-%%
-%% The following are used only if annotation of the code is requested.
-%%
--ifdef(DEBUG_LIVENESS).
-cfg_bb_add(CFG, L, NewBB) ->
- hipe_icode_cfg:bb_add(CFG, L, NewBB).
-
-mk_comment(Text) ->
- hipe_icode:mk_comment(Text).
--endif.
diff --git a/lib/hipe/icode/hipe_icode_mulret.erl b/lib/hipe/icode/hipe_icode_mulret.erl
deleted file mode 100644
index 227cfadfda..0000000000
--- a/lib/hipe/icode/hipe_icode_mulret.erl
+++ /dev/null
@@ -1,1318 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_icode_mulret.erl
-%% Author : Christoffer Vikström <chvi3471@it.uu.se>
-%% Purpose :
-%% Created : 23 Jun 2004 by Christoffer Vikström <chvi3471@it.uu.se>
-%%----------------------------------------------------------------------
-
--module(hipe_icode_mulret).
--export([mult_ret/4]).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
-
-%%>----------------------------------------------------------------------<
-%% Procedure : mult_ret/4
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-
--spec mult_ret([_], atom(), comp_options(), _) -> [_].
-
-mult_ret(List, Mod, Opts, Exports) ->
- case length(List) > 1 of
- true ->
- Table = analyse(List, Mod, Exports),
- %% printTable(Mod, Exports, Table),
- optimize(List, Mod, Opts, Table);
- false ->
- List
- end.
-
-%%>-----------------------< Analysis Steps >-----------------------------<
-
-%%>----------------------------------------------------------------------<
-%% Procedure : analyse/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-analyse(List, _Mod, Exports) ->
- MaxRets = hipe_rtl_arch:nr_of_return_regs(),
- Table = mkTable(List),
- %% printTable(Mod, Exports, Table),
- Table2 = filterTable(Table, MaxRets, Exports),
- %% printTable(Mod, Exports, Table2),
- Table2.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : mkTable/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-mkTable(List) ->
- mkTable(List, {[], []}).
-
-mkTable([{MFA, Icode} | List], Table) ->
- %% New Icode
- {_LMin,LMax} = hipe_icode:icode_label_range(Icode),
- hipe_gensym:set_label(icode, LMax+1),
- {_VMin,VMax} = hipe_icode:icode_var_range(Icode),
- hipe_gensym:set_var(icode, VMax+1),
- case isFunDef(MFA) of
- true ->
- mkTable(List, Table);
- false ->
- CallList = mkCallList(MFA, Icode),
- Optimizable = isOptimizable(Icode),
- NewTable = addToTable(MFA, Optimizable, CallList, Table),
- mkTable(List, NewTable)
- end;
-mkTable([_|List], Table) -> mkTable(List, Table);
-mkTable([], Table) -> Table.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : isFunDef/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-isFunDef({_, F, _}) ->
- hd(atom_to_list(F)) =:= 45. %% 45 is the character '-'
-
-%%>----------------------------------------------------------------------<
-%% Procedure : mkCallList/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-mkCallList(MFA, Icode) ->
- Code = hipe_icode:icode_code(Icode),
- mkCallList(Code, MFA, []).
-
-mkCallList([#icode_call{'fun'=F, dstlist=Vars, type=local}|Code], MFA, Res) ->
- {Size, DstList} = lookForDef(Code, Vars),
- mkCallList(Code, MFA, [{callPair,MFA,{F,{matchSize,Size,DstList}}}|Res]);
-mkCallList([_|Code], MFA, Res) -> mkCallList(Code, MFA, Res);
-mkCallList([], _, Res) -> Res.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : lookForDef/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-lookForDef([#icode_type{test={tuple,Size}, true_label=L}|Code], Vars) ->
- Code2 = skipToLabel(Code, L),
- DstLst = lookForUnElems(Code2, Vars),
- case DstLst of
- [] -> {1, Vars};
- _ ->
- DstLst2 = fixDstLst(DstLst, Size),
- {Size, DstLst2}
- end;
-lookForDef([#icode_move{src=Var, dst=NewVar}|Code], [Var]) ->
- lookForDef(Code, [NewVar]);
-lookForDef([#icode_label{}|_], Vars) ->
- {1, Vars};
-lookForDef([I|Code], [Var] = Vars) ->
- Defs = hipe_icode:defines(I),
- case lists:member(Var, Defs) of
- true ->
- {1, Vars};
- false ->
- lookForDef(Code, Vars)
- end;
-lookForDef([], Vars) -> {1, Vars}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : skipToLabel/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-skipToLabel(Code, L) ->
- case skipToLabel2(Code, L) of
- noLabel ->
- Code;
- NewCode ->
- NewCode
- end.
-
-skipToLabel2([#icode_label{name = L}|Code],L) -> Code;
-skipToLabel2([_|Code], L) -> skipToLabel2(Code, L);
-skipToLabel2([], _) -> noLabel.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : lookForUnElems/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-lookForUnElems(Code, Var) ->
- lookForUnElems(Code, Var, []).
-
-lookForUnElems([#icode_call{'fun'=#unsafe_element{index=Nr}, args=Var,
- dstlist=[Ret]}|Code], Var, Res) ->
- lookForUnElems(Code, Var, [{Nr, Ret}|Res]);
-lookForUnElems([#icode_move{dst=Var}|_], [Var], Res) ->
- lists:flatten(Res);
-lookForUnElems([#icode_call{dstlist=VarList}|_], VarList, Res) ->
- lists:flatten(Res);
-lookForUnElems([_|Code], Var, Res) ->
- lookForUnElems(Code, Var, Res);
-lookForUnElems([], _, Res) -> lists:flatten(Res).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : fixDstLst/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-fixDstLst(DstLst, Size) when is_integer(Size) ->
- fixDstLst(DstLst, Size, 1, []).
-
-fixDstLst(DstLst, Size, Cnt, Res) when Cnt =< Size ->
- case isInLst(Cnt, DstLst) of
- {true, Var} ->
- fixDstLst(DstLst, Size, Cnt+1, [Var|Res]);
- false ->
- Var = hipe_icode:mk_var(hipe_gensym:new_var(icode)),
- fixDstLst(DstLst, Size, Cnt+1, [Var|Res])
- end;
-fixDstLst(_, Size, Cnt, Res) when Cnt > Size -> lists:reverse(Res).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : isInLst/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-isInLst(Nr, [{Nr,Var}|_]) -> {true, Var};
-isInLst(Cnt, [_|DstLst]) -> isInLst(Cnt, DstLst);
-isInLst(_, []) -> false.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : isOptimizable/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-isOptimizable(Icode) ->
- %% Icode2 = hipe_icode:fixup_fallthroughs(Icode),
- Icode2 = hipe_icode:strip_comments(Icode),
- Cfg = hipe_icode_cfg:linear_to_cfg(Icode2),
- %% hipe_icode_cfg:pp(Cfg),
- case findReturnBlocks(Cfg) of
- noReturn ->
- {false, -1};
- BlockList ->
- processReturnBlocks(BlockList, Cfg)
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : findReturnBlocks/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-findReturnBlocks(IcodeCfg) ->
- Labels = hipe_icode_cfg:labels(IcodeCfg),
- case searchBlocks(Labels, IcodeCfg) of
- [] ->
- noReturn;
- BlockList->
- BlockList
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : searchBlocks/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-searchBlocks(Labels, IcodeCfg) ->
- searchBlocks(Labels, IcodeCfg, []).
-
-searchBlocks([Label|Labels], IcodeCfg, Res) ->
- Block = hipe_icode_cfg:bb(IcodeCfg, Label),
- Code = hipe_bb:code(Block),
- case searchBlockCode(Code) of
- {hasReturn, RetVar} ->
- searchBlocks(Labels, IcodeCfg, [{Label, RetVar}|Res]);
- noReturn ->
- searchBlocks(Labels, IcodeCfg, Res)
- end;
-searchBlocks([], _, Res) -> Res.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : searchBlockCode/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-searchBlockCode([#icode_return{vars=Vars}|_]) ->
- {hasReturn, Vars};
-searchBlockCode([_|Icode]) ->
- searchBlockCode(Icode);
-searchBlockCode([]) -> noReturn.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : processReturnBlock/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-processReturnBlocks(Blocks, Cfg) ->
- processReturnBlocks(Blocks, Cfg, {true, -1}, []).
-
-processReturnBlocks([{Label, Var}|BlockList], Cfg, {Opts, Size}, TypeLst) ->
- {Opt, Type, Size2} = traverseCode(Label, Var, Cfg),
- case (Size =:= -1) orelse (Size =:= Size2) of
- true ->
- processReturnBlocks(BlockList, Cfg,
- {Opt andalso Opts, Size2}, [Type|TypeLst]);
- false ->
- {false, -1}
- end;
-processReturnBlocks([], _, Res, TypeLst) ->
- case lists:member(icode_var, TypeLst) of
- true ->
- {_, Size} = Res,
- case Size > 1 of
- true ->
- Res;
- false ->
- {false, -1}
- end;
- false ->
- {false, -1}
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : traverseCode/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-traverseCode(Label, Var, Cfg) ->
- traverseCode(Label, Var, Cfg, []).
-
-traverseCode(Label, Var, Cfg, LabLst) ->
- Preds = hipe_icode_cfg:pred(Cfg, Label),
- Block = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(Block),
- case findDefine(lists:reverse(Code), Var) of
- {found, Type, NumRets} ->
- {true, Type, NumRets};
- {notFound, SrcVar} ->
- case Preds of
- [] ->
- {false, none, -1};
- [Pred] ->
- case lists:member(Label, LabLst) of
- false ->
- traverseCode(Pred, SrcVar, Cfg, [Label|LabLst]);
- true ->
- {false, none, -1}
- end;
- _ ->
- {false, none, -1}
- end
- end.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : findDefine/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-findDefine([#icode_call{dstlist=Vars,'fun'=mktuple,args=Vs}|_], Vars) ->
- case length(Vs) of
- 1 ->
- [{Type, _}] = Vs,
- {found, Type, 1};
- Len ->
- case lists:any(fun hipe_icode:is_var/1, Vs) of
- true ->
- {found, icode_var, Len};
- false ->
- {found, icode_const, Len}
- end
- end;
-findDefine([#icode_move{dst=Var, src=Src}|Code], [Var]) ->
- case hipe_icode:is_var(Src) of
- true ->
- findDefine(Code, [Src]);
- false ->
- case Src of
- #icode_const{value={flat, Value}} ->
- case is_tuple(Value) of
- true ->
- {found, icode_const, tuple_size(Value)};
- false ->
- {found, icode_const, 1}
- end;
- _ ->
- findDefine(Code, [Var])
- end
- end;
-findDefine([_|Code], Var) ->
- findDefine(Code, Var);
-findDefine([], Var) ->
- {notFound, Var}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : addToTable/4
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-addToTable(MFA, Optimizable, CallList, {FunLst, CallLst}) ->
- NewFunLst = [{MFA, Optimizable}|FunLst],
- {NewFunLst, CallList ++ CallLst}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : filterTable/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-filterTable({FunLst, CallLst}, MaxRets, Exports) ->
- filterTable(FunLst, CallLst, MaxRets, Exports, {[],[]}).
-
-filterTable([Fun|FunLst], CallLst, MaxRets, Exports, {Funs, Calls} = FCs) ->
- {MFA, {ReturnOpt, Rets}} = Fun,
- {CallOpt, CallsToKeep} = checkCalls(CallLst, MFA, Rets),
- CallsToKeep2 = removeDuplicateCalls(CallsToKeep),
- NotExported = checkExported(MFA, Exports),
- case CallOpt andalso ReturnOpt andalso (Rets =< MaxRets) andalso
- NotExported andalso (not containRecursiveCalls(CallsToKeep2, MFA)) of
- true ->
- filterTable(FunLst, CallLst, MaxRets, Exports,
- {[Fun|Funs], CallsToKeep2 ++ Calls});
- false ->
- filterTable(FunLst, CallLst, MaxRets, Exports, FCs)
- end;
-filterTable([], _, _, _, Res) -> Res.
-
-removeDuplicateCalls(Calls) ->
- removeDuplicateCalls(Calls, []).
-
-removeDuplicateCalls([Call|CallsToKeep], Res) ->
- case lists:member(Call, CallsToKeep) of
- true ->
- removeDuplicateCalls(CallsToKeep, Res);
- false ->
- removeDuplicateCalls(CallsToKeep, [Call|Res])
- end;
-removeDuplicateCalls([], Res) -> lists:reverse(Res).
-
-containRecursiveCalls([Call|Calls], Fun) ->
- {callPair, Caller, {Callee, _}} = Call,
- case (Callee =:= Fun) andalso (Caller =:= Fun) of
- true ->
- true;
- false->
- containRecursiveCalls(Calls, Fun)
- end;
-containRecursiveCalls([], _) -> false.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : checkCalls/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-checkCalls(CallLst, MFA, Rets) ->
- checkCalls(CallLst, MFA, Rets, [], []).
-
-checkCalls([C = {callPair, _, {MFA, {matchSize, Rets, _}}}|CallLst],
- MFA, Rets, Res, Opt) ->
- checkCalls(CallLst, MFA, Rets, [C|Res], [true|Opt]);
-checkCalls([{callPair, _, {MFA, {matchSize, _, _}}}|CallLst],
- MFA, Rets, Res, Opt) ->
- checkCalls(CallLst, MFA, Rets, Res, [false|Opt]);
-checkCalls([_|CallLst], MFA, Rets, Res, Opt) ->
- checkCalls(CallLst, MFA, Rets, Res, Opt);
-checkCalls([], _, _, Res, Opt) -> {combineOpts(Opt), Res}.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : combineOpts/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-combineOpts([]) -> false;
-combineOpts([Opt]) -> Opt;
-combineOpts([Opt|Opts]) -> Opt andalso combineOpts(Opts).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : checkCalls/2
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-checkExported({_,F,A}, [{F,A}|_]) -> false;
-checkExported(MFA, [_|Exports]) -> checkExported(MFA, Exports);
-checkExported(_, []) -> true.
-
-%%>----------------------< Optimization Steps >--------------------------<
-
-%%>----------------------------------------------------------------------<
-%% Procedure : optimize/4
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-optimize(List, _Mod, Opts, Table) ->
- {FunLst, CallLst} = Table,
- List2 = optimizeFuns(FunLst, Opts, List),
- optimizeCalls(CallLst, Opts, List2).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : optimizeFuns/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-optimizeFuns([{Fun, _}|FunList], Opts, List) ->
- NewList = findFun(List, Fun),
- optimizeFuns(FunList, Opts, NewList);
-optimizeFuns([],_,List) -> List.
-
-findFun(List, Fun) -> findFun(List, Fun, []).
-findFun([{Fun, Icode}|List], Fun, Res) ->
- NewIcode = optimizeFun(Icode),
- findFun(List, Fun, [{Fun, NewIcode}|Res]);
-findFun([I|List], Fun, Res) -> findFun(List, Fun, [I|Res]);
-findFun([], _, Res) -> lists:reverse(Res).
-
-
-optimizeFun(Icode) ->
- {_LMin,LMax} = hipe_icode:icode_label_range(Icode),
- hipe_gensym:set_label(icode, LMax+1),
- {_VMin,VMax} = hipe_icode:icode_var_range(Icode),
- hipe_gensym:set_var(icode, VMax+1),
- %% Icode2 = hipe_icode:fixup_fallthroughs(Icode),
- Icode2 = hipe_icode:strip_comments(Icode),
- Cfg = hipe_icode_cfg:linear_to_cfg(Icode2),
- case findReturnBlocks(Cfg) of
- noReturn ->
- false;
- BlockList ->
- NewCfg = optimizeReturnBlocks(BlockList, Cfg),
- hipe_icode_cfg:cfg_to_linear(NewCfg)
- end.
-
-optimizeReturnBlocks([Block|BlockList], Cfg) ->
- {NewCfg, Vars} = optimizeReturnBlock(Block, Cfg),
- NewCfg2 = case Vars of
- [_] ->
- Cfg;
- _ ->
- {Label, _} = Block,
- updateReturnBlock(Label, Vars, NewCfg)
- end,
- optimizeReturnBlocks(BlockList, NewCfg2);
-optimizeReturnBlocks([], Cfg) -> Cfg.
-
-optimizeReturnBlock(Block, Cfg) ->
- optimizeReturnBlock(Block, Cfg, []).
-
-optimizeReturnBlock({Label,Var}, Cfg, UpdateMap) ->
- Preds = hipe_icode_cfg:pred(Cfg, Label),
- Block = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(Block),
- case optimizeDefine(Code, Var) of
- {found, NewBlockCode, Vars} ->
- NewBlock = hipe_bb:code_update(Block, NewBlockCode),
- NewCfg = resolveUpdateMap(UpdateMap, Cfg),
- {hipe_icode_cfg:bb_add(NewCfg, Label, NewBlock), Vars};
- {none, NewBlockCode, NewVar} ->
- case Preds of
- [Pred] ->
- NewBlock = hipe_bb:code_update(Block, NewBlockCode),
- optimizeReturnBlock({Pred,NewVar}, Cfg,
- [{Label, NewBlock}|UpdateMap]);
- [_|_] ->
- {Cfg, Var}
- end;
- {none, noOpt} ->
- {Cfg, Var}
- end.
-
-optimizeDefine(Code, Dst) ->
- optimizeDefine(lists:reverse(Code), Dst, [], []).
-
-optimizeDefine([I|Code], Dsts, DstLst, Res) ->
- [Ds] = Dsts,
- case isCallPrimop(I, mktuple) andalso DstLst =:= [] of
- true ->
- case hipe_icode:call_dstlist(I) =:= Dsts of
- true ->
- case length(hipe_icode:call_args(I)) > 1 of
- true ->
- optimizeDefine(Code, Dsts, hipe_icode:call_args(I), Res);
- false ->
- {none, noOpt}
- end;
- false ->
- optimizeDefine(Code, Dsts, DstLst, [I|Res])
- end;
- false ->
- case hipe_icode:is_move(I) andalso DstLst =:= [] of
- true ->
- case hipe_icode:move_dst(I) =:= Ds of
- true ->
- Src = hipe_icode:move_src(I),
- case hipe_icode:is_var(Src) of
- true ->
- NewDst = hipe_icode:move_src(I),
- optimizeDefine(Code, [NewDst], DstLst, Res);
- false ->
- case Src of
- #icode_const{value={flat, T}} when is_tuple(T) ->
- NewLst = tuple_to_list(T),
- optimizeDefine(Code, Dsts, NewLst, Res);
- _ ->
- {none, noOpt}
- end
- end;
- false ->
- optimizeDefine(Code, Dsts, DstLst, [I|Res])
- end;
- false ->
- case lists:member(Ds, hipe_icode:defines(I)) andalso DstLst =:= [] of
- true ->
- {none, noOpt};
- false ->
- optimizeDefine(Code, Dsts, DstLst, [I|Res])
- end
- end
- end;
-optimizeDefine([], Dsts, DstLst, Res) ->
- case DstLst of
- [] ->
- {none, Res, Dsts};
- _ ->
- {found, Res, DstLst}
- end.
-
-resolveUpdateMap([{Label, Block}|UpdateMap], Cfg) ->
- resolveUpdateMap(UpdateMap, hipe_icode_cfg:bb_add(Cfg, Label, Block));
-resolveUpdateMap([], Cfg) -> Cfg.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : updateReturnBlock/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-updateReturnBlock(Label, Vars, IcodeCfg) ->
- Block = hipe_icode_cfg:bb(IcodeCfg, Label),
- Code = hipe_bb:code(Block),
- NewCode = updateReturnCode(Code, Vars),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- hipe_icode_cfg:bb_add(IcodeCfg, Label, NewBlock).
-
-updateReturnCode(Code, DstLst) ->
- updateReturnCode(Code, DstLst, []).
-
-updateReturnCode([I| Code], DstLst, Res) ->
- case hipe_icode:is_return(I) of
- true ->
- updateReturnCode(Code, DstLst, [hipe_icode:mk_return(DstLst)|Res]);
- false ->
- updateReturnCode(Code, DstLst, [I|Res])
- end;
-updateReturnCode([], _, Res) -> lists:reverse(Res).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : optimizeCalls/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-optimizeCalls([Call|CallLst], _Opts, List) ->
- {callPair, Caller, {Callee, {matchSize, _, DstLst}}} = Call,
- NewList = optimizeCall(List, Caller, Callee, DstLst),
- optimizeCalls(CallLst, _Opts, NewList);
-optimizeCalls([], _Opts, List) -> List.
-
-%%>----------------------------------------------------------------------<
-%% Procedure : optimizeCall/4
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-optimizeCall(List, Caller, Callee, DstLst) ->
- optimizeCall(List, Caller, Callee, DstLst, []).
-
-optimizeCall([{MFA, Icode}|List], MFA, Callee, DstLst, Res) ->
- {_LMin,LMax} = hipe_icode:icode_label_range(Icode),
- hipe_gensym:set_label(icode, LMax+1),
- {_VMin,VMax} = hipe_icode:icode_var_range(Icode),
- hipe_gensym:set_var(icode, VMax+1),
- %% Icode2 = hipe_icode:fixup_fallthroughs(Icode),
- Icode2 = hipe_icode:strip_comments(Icode),
- Cfg = hipe_icode_cfg:linear_to_cfg(Icode2),
- NewIcode = findAndUpdateCalls(Cfg, Callee, DstLst),
- optimizeCall(List, MFA, Callee, DstLst, [{MFA, NewIcode}|Res]);
-optimizeCall([I|List], Caller, Callee, DstLst, Res) ->
- optimizeCall(List, Caller, Callee, DstLst, [I|Res]);
-optimizeCall([], _, _, _, Res) -> lists:reverse(Res).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : findAndUpdateCall/3
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-findAndUpdateCalls(Cfg, Callee, DstLst) ->
- Labels = hipe_icode_cfg:labels(Cfg),
- Cfg2 = findAndUpdateCalls(Cfg, Labels, Callee, DstLst, []),
- hipe_icode_cfg:cfg_to_linear(Cfg2).
-findAndUpdateCalls(Cfg, [L|Labels], Callee, DstLst, Visited) ->
- %% Block = hipe_icode_cfg:bb(Cfg, L),
- %% Code = hipe_bb:code(Block),
- case containCorrectCall(Cfg, L, Callee, DstLst) of
- true ->
- Block = hipe_icode_cfg:bb(Cfg,L),
- Code = hipe_bb:code(Block),
- {NewCode, OldVar} = updateCode(Code, Callee, DstLst),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- Cfg2 = hipe_icode_cfg:bb_add(Cfg, L, NewBlock),
- Cfg3 = cleanUpAffectedCode(Cfg2, OldVar, Callee, L, Visited),
- findAndUpdateCalls(Cfg3, Labels, Callee, DstLst, [L|Visited]);
- false ->
- findAndUpdateCalls(Cfg, Labels, Callee, DstLst, [L|Visited])
- end;
-findAndUpdateCalls(Cfg,[], _, _, _) -> Cfg.
-
-containCorrectCall(Cfg, Label, Callee, DstLst) ->
- Block = hipe_icode_cfg:bb(Cfg,Label),
- Code = hipe_bb:code(Block),
- case containCallee(Code, Callee) of
- {true, OldVar} ->
- Succs = hipe_icode_cfg:succ(Cfg, Label),
- checkForUnElems(Succs, OldVar, DstLst, Cfg);
- false ->
- false
- end.
-
-checkForUnElems([], _, _, _) -> false;
-checkForUnElems([Succ|Succs], OldVar, DstLst, Cfg) ->
- Block = hipe_icode_cfg:bb(Cfg,Succ),
- Code = hipe_bb:code(Block),
- case checkForUnElems2(Code, OldVar, DstLst, []) of
- true ->
- true;
- false ->
- checkForUnElems(Succs, OldVar, DstLst, Cfg)
- end.
-
-checkForUnElems2([I|Code], OldVar, DstLst, DstRes) ->
- case isCallPrimop(I, unsafe_element) of
- true ->
- case (hipe_icode:call_args(I) =:= OldVar) of
- true ->
- [Dst] = hipe_icode:call_dstlist(I),
- case lists:member(Dst, DstLst) of
- true ->
- checkForUnElems2(Code, OldVar, DstLst, [Dst|DstRes]);
- false ->
- checkForUnElems2(Code, OldVar, DstLst, DstRes)
- end;
- false ->
- checkForUnElems2(Code, OldVar, DstLst, DstRes)
- end;
- false ->
- checkForUnElems2(Code, OldVar, DstLst, DstRes)
- end;
-checkForUnElems2([], _, DstLst, DstRes) -> DstLst =:= lists:reverse(DstRes).
-
-
-containCallee([I|Code], Callee) ->
- case isCallLocal(I, Callee) of
- true ->
- {true, hipe_icode:call_dstlist(I)};
- false ->
- containCallee(Code, Callee)
- end;
-containCallee([], _) -> false.
-
-
-updateCode(Code, Callee, DstLst) ->
- updateCode(Code, Callee, DstLst, [], []).
-
-updateCode([I|Code], Callee, DstLst, Res, OldVars) ->
- case isCallLocal(I, Callee) of
- true ->
- Vars = hipe_icode:call_dstlist(I),
- I2 = hipe_icode:call_dstlist_update(I, DstLst),
- updateCode(Code, Callee, DstLst, [I2|Res], Vars);
- false ->
- updateCode(Code, Callee, DstLst, [I|Res], OldVars)
- end;
-updateCode([], _, _, Res, OldVars) -> {lists:reverse(Res), OldVars}.
-
-
-cleanUpAffectedCode(Cfg, OldVar, Callee, Label, Visited) ->
- Block = hipe_icode_cfg:bb(Cfg,Label),
- Code = hipe_bb:code(Block),
- {CodeBefore, CodeAfter, DstLst} = divideAtCall(Code, Callee),
- {NewCodeAfter, ContLab, FailLab} = findType(CodeAfter, OldVar),
- ContBlock = hipe_icode_cfg:bb(Cfg, ContLab),
- Succs = hipe_icode_cfg:succ(Cfg, ContLab),
- ContCode = hipe_bb:code(ContBlock),
- {NewContCode, NewFailLab} = removeUnElems(ContCode, OldVar, DstLst),
- NewBlock = hipe_bb:code_update(Block,
- CodeBefore ++ NewCodeAfter ++ NewContCode),
- Cfg2 = hipe_icode_cfg:bb_add(Cfg, Label, NewBlock),
- Cfg3 = resolveSuccBlocks(Succs, OldVar, DstLst, [Label|Visited],
- NewFailLab, Cfg2),
- insertMiddleFailBlock(Cfg3, NewFailLab, FailLab, OldVar, DstLst).
-
-divideAtCall(Code, Caller) ->
- divideAtCall(Code, Caller, []).
-
-divideAtCall([I|Code], Caller, Tail) ->
- case isCallLocal(I, Caller) of
- true ->
- {lists:reverse([I|Tail]), Code, hipe_icode:call_dstlist(I)};
- false ->
- divideAtCall(Code, Caller, [I|Tail])
- end;
-divideAtCall([], _, Tail) -> {Tail, []}.
-
-findType(CodeAfter, OldVar) ->
- findType(CodeAfter, OldVar, [], {none, none}).
-
-findType([I|Code], OldVar, Rest, Succs) ->
- case hipe_icode:is_type(I) of
- true ->
- case hipe_icode:type_args(I) =:= OldVar of
- true ->
- TrueLab = hipe_icode:type_true_label(I),
- FalseLab = hipe_icode:type_false_label(I),
- findType(Code, OldVar, Rest, {TrueLab, FalseLab});
- false ->
- findType(Code, OldVar, [I|Rest], Succs)
- end;
- false ->
- case hipe_icode:is_move(I) of
- true ->
- case [hipe_icode:move_src(I)] =:= OldVar of
- true ->
- findType(Code, hipe_icode:move_dst(I), [I|Rest], Succs);
- false ->
- findType(Code, OldVar, [I|Rest], Succs)
- end;
- false ->
- findType(Code, OldVar, [I|Rest], Succs)
- end
- end;
-findType([],_,Rest, {TrueLab, FalseLab}) ->
- {lists:reverse(Rest), TrueLab, FalseLab}.
-
-%% Nesting hell... check for redundancies.
-%% ---------------------------------------
-removeUnElems(Code, OldVars, DstLst) ->
- removeUnElems(Code, OldVars, DstLst, [], false, none).
-
-removeUnElems([I|Code], [OldVar] = OldVars, DstLst, Res, Def, Lab) ->
- case isCallPrimop(I, unsafe_element) of
- true ->
- case (hipe_icode:call_args(I) =:= OldVars) of
- true ->
- removeUnElems(Code, OldVars, DstLst, Res, Def, Lab);
- false ->
- case lists:member(OldVar, hipe_icode:call_args(I)) of
- true ->
- %% XXX: the following test seems redundant,
- %% hence commented out -- KOSTIS
- %% case Def of
- %% true ->
- removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab);
- %% false ->
- %% removeUnElems(Code, OldVars, DstLst,
- %% [I|Res], Def, Lab)
- %% end;
- false ->
- io:format("Borde aldrig kunna hamna här!", []),
- removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
- end
- end;
- false ->
- case hipe_icode:is_move(I) of
- true ->
- case hipe_icode:move_src(I) =:= OldVar of
- true ->
- NewVar = hipe_icode:move_dst(I),
- removeUnElems(Code, [NewVar], DstLst, [I|Res], Def, Lab);
- false ->
- removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
- end;
- false ->
- case hipe_icode:is_type(I) andalso not Def of
- true ->
- NewFalseLab = case Lab =:= none of
- true ->
- hipe_gensym:get_next_label(icode);
- false ->
- Lab
- end,
- _I2 = updateTypeFalseLabel(I, NewFalseLab),
- removeUnElems(Code, OldVars, DstLst, [I|Res], Def, NewFalseLab);
- false ->
- case lists:member(OldVar, hipe_icode:uses(I)) andalso Def of
- true ->
- removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab);
- false ->
- case lists:member(OldVar, hipe_icode:defines(I)) of
- true ->
- removeUnElems(Code, OldVars, DstLst, [I|Res], true, Lab);
- false ->
- removeUnElems(Code, OldVars, DstLst, [I|Res], Def, Lab)
- end
- end
- end
- end
- end;
-removeUnElems([], _, _, Res,_, Lab) -> {lists:reverse(Res), Lab}.
-
-
-updateTypeFalseLabel(Instr, NewFalseLabel) ->
- TrueLabel = hipe_icode:type_true_label(Instr),
- Args = hipe_icode:type_args(Instr),
- Type = hipe_icode:type_test(Instr),
- hipe_icode:mk_type(Args, Type, TrueLabel, NewFalseLabel).
-
-
-resolveSuccBlocks(Succs, OldVar, DstLst, Visited, FailLab, Cfg) ->
- NewSuccs = [X || X <- Succs, not lists:member(X, Visited)],
- resolveSuccBlocks2(NewSuccs, OldVar, DstLst, Visited, FailLab, Cfg).
-
-resolveSuccBlocks2([Succ|Succs], OldVar, DstLst, Vis, FailLab, Cfg) ->
- Block = hipe_icode_cfg:bb(Cfg,Succ),
- Code = hipe_bb:code(Block),
- {NewCode, ReDefined} = checkUsesDefs(Code, OldVar, DstLst, FailLab),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- Cfg2 = hipe_icode_cfg:bb_add(Cfg, Succ, NewBlock),
- case ReDefined of
- true ->
- resolveSuccBlocks2(Succs, OldVar, DstLst, [Succ|Vis], FailLab, Cfg2);
- false ->
- NewSuccs = hipe_icode_cfg:succ(Cfg, Succ),
- NewSuccs2 = [X || X <- NewSuccs, not lists:member(X, Vis++Succs)],
- resolveSuccBlocks2(NewSuccs2++Succs, OldVar, DstLst,
- [Succ|Vis], FailLab, Cfg2)
- end;
-resolveSuccBlocks2([], _, _, _, _, Cfg) -> Cfg.
-
-
-checkUsesDefs(Code, OldVar, DstLst, FailLab) ->
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [], false).
-
-checkUsesDefs([I|Code], OldVar, DstLst, FailLab, Res, Defined) ->
- [OVar] = OldVar,
- case hipe_icode:is_move(I) of
- true ->
- case hipe_icode:move_src(I) =:= OVar of
- true ->
- NewVar = hipe_icode:move_dst(I),
- checkUsesDefs(Code, NewVar, DstLst, FailLab, [I|Res], true);
- false ->
- case lists:member(OVar, hipe_icode:defines(I)) of
- true ->
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], true);
- false ->
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], Defined)
- end
- end;
- false ->
- case hipe_icode:is_type(I) andalso not Defined of
- true ->
- case FailLab =/= none of
- true ->
- _I2 = updateTypeFalseLabel(I, FailLab),
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], Defined);
- false ->
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], Defined)
- end;
- false ->
- case (lists:member(OVar, hipe_icode:uses(I))) andalso
- (not Defined) andalso (FailLab =/= none) of
- true ->
- Tpl = hipe_icode:mk_primop(OldVar, mktuple, DstLst),
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I,Tpl|Res], true);
- false ->
- case lists:member(OVar, hipe_icode:defines(I)) of
- true ->
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res], true);
- false ->
- checkUsesDefs(Code, OldVar, DstLst, FailLab, [I|Res],Defined)
- end
- end
- end
- end;
-checkUsesDefs([], _, _, _, Res, Defined) -> {lists:reverse(Res), Defined}.
-
-
-insertMiddleFailBlock(Cfg, NewFailLabel, OldFailLabel, OldVar, DstLst) ->
- case NewFailLabel =:= none of
- true ->
- Cfg;
- false ->
- NewCode = [hipe_icode:mk_primop(OldVar, mktuple, DstLst),
- hipe_icode:mk_goto(OldFailLabel)],
- NewBlock = hipe_bb:mk_bb(NewCode),
- hipe_icode_cfg:bb_add(Cfg, NewFailLabel, NewBlock)
- end.
-
-
-isCallLocal(Instr, Fun) ->
- hipe_icode:is_call(Instr) andalso (hipe_icode:call_type(Instr) =:= local)
- andalso (hipe_icode:call_fun(Instr) =:= Fun).
-
-isCallPrimop(Instr, Fun) ->
- case hipe_icode:is_call(Instr) of
- true ->
- case is_tuple(hipe_icode:call_fun(Instr)) of
- true ->
- ((hipe_icode:call_type(Instr) =:= primop) andalso
- (element(1,hipe_icode:call_fun(Instr)) =:= Fun));
- false ->
- ((hipe_icode:call_type(Instr) =:= primop) andalso
- (hipe_icode:call_fun(Instr) =:= Fun))
- end;
- false ->
- false
- end.
-
-
-%% >-------------------------< Debug code >------------------------------<
-
--ifdef(DEBUG_MULRET).
-
-%%>----------------------------------------------------------------------<
-%% Procedure : printTable/1
-%% Purpose :
-%% Arguments :
-%% Return :
-%% Notes :
-%%>----------------------------------------------------------------------<
-printTable(Mod, Exports, {FunLst, CallLst}) ->
- {Y,Mo,D} = date(),
- {H,Mi,S} = time(),
- io:format("Module: ~w - (~w/~w-~w, ~w:~w:~w)~n=======~n",
- [Mod,D,Mo,Y,H,Mi,S]),
- io:format("Exports: ~w~n", [Exports]),
- io:format("FunList: ~n"),
- printFunList(FunLst),
- io:format("CallList: ~n"),
- printCallList(CallLst).
-
-printFunList([Fun|FunLst]) ->
- io:format(" ~w~n", [Fun]),
- printFunList(FunLst);
-printFunList([]) -> io:format("~n").
-
-printCallList([Call|CallLst]) ->
- io:format(" ~w~n", [Call]),
- printCallList(CallLst);
-printCallList([]) -> io:format("~n").
-
--endif.
-
-%% >----------------------------< Old code >--------------------------------<
-
-%% %%>----------------------------------------------------------------------<
-%% % Procedure : findCallCode/3
-%% % Purpose :
-%% % Arguments :
-%% % Return :
-%% % Notes :
-%% %%>----------------------------------------------------------------------<
-%% findCallCode(List, Callee, DstLst) -> findCallCode(List, Callee, DstLst, []).
-%% findCallCode([I=#icode_call{'fun'=Callee, dstlist=Var, type=local}, I2, I3|List],
-%% Callee, DstLst, Res) ->
-%% NewList = removeUnElems(List, Var),
-%% %% _Uses = checkForUses(NewList, Var, DstLst),
-%% Size = length(DstLst),
-%% case I2 of
-%% #icode_type{test={tuple, Size}, args=Var, true_label=Label} ->
-%% case I3 of
-%% #icode_label{name=Label} ->
-%% findCallCode(NewList, Callee, DstLst,
-%% [I#icode_call{dstlist=DstLst}|Res]);
-%% _ ->
-%% findCallCode(NewList, Callee, DstLst,
-%% [#goto{label=Label},
-%% I#icode_call{dstlist=DstLst}|Res])
-%% end;
-%% _ ->
-%% findCallCode(NewList, Callee, DstLst,
-%% [I2,I#icode_call{dstlist=DstLst}|Res])
-%% end;
-%% findCallCode([I|List], Callee, DstLst, Res) ->
-%% findCallCode(List, Callee, DstLst, [I|Res]);
-%% findCallCode([], _, _, Res) -> lists:reverse(Res).
-
-
-%% %%>----------------------------------------------------------------------<
-%% % Procedure : checkForUses
-%% % Purpose :
-%% % Arguments :
-%% % Return :
-%% % Notes :
-%% %%>----------------------------------------------------------------------<
-%% checkForUses(List, Var, Dsts) -> checkForUses(List, Var, Dsts, [], List).
-%% checkForUses([I|List], Var, Dsts, Rest, Code) ->
-%% Defs = hipe_icode:defines(I),
-%% Uses = hipe_icode:uses(I),
-%% case lists:member(Var, Uses) of
-%% true ->
-%% true;
-%% false ->
-%% case lists:member(Var, Defs) of
-%% true ->
-%% false;
-%% false ->
-%% case hipe_icode:is_branch(I) of
-%% true ->
-%% Succs = hipe_icode:successors(I),
-%% checkSuccsForUses(Succs, Var, Dsts, Rest, Code);
-%% false ->
-%% checkForUses(List, Var, Dsts, [I|Rest], Code)
-%% end
-%% end
-%% end;
-%% checkForUses([], _, _, _, _) -> false.
-
-%% checkSuccsForUses(Succs, Var, Dsts, Rest, Code) ->
-%% checkSuccsForUses(Succs, Var, Dsts, Rest, Code, false).
-%% checkSuccsForUses([S|Succs], Var, Dsts, Rest, Code, Res) ->
-%% List = gotoLabel(S, Code),
-%% Used = checkForUses(List, Var, Dsts, Rest, Code),
-%% checkSuccsForUses(Succs, Var, Code, Dsts, Used andalso Res);
-%% checkSuccsForUses([], _, _, _, _, Res) -> Res.
-
-%% gotoLabel(L, [L|List]) -> List;
-%% gotoLabel(L, [_|List]) -> gotoLabel(L, List);
-%% gotoLabel(_, []) -> [].
-
-
-%% %%>----------------------------------------------------------------------<
-%% % Procedure : removeUnElems/2
-%% % Purpose :
-%% % Arguments :
-%% % Return :
-%% % Notes : Fixa så att funktionen använder defines(I) istället och
-%% % selektorer istället för att matcha på #call{}. Lätt gjort.
-%% %%>----------------------------------------------------------------------<
-%% removeUnElems(List, Var) -> removeUnElems(List, Var, []).
-%% removeUnElems([#icode_call{'fun'={unsafe_element,_}, args=Var}|List], Var, Res) ->
-%% removeUnElems(List, Var, Res);
-%% removeUnElems([I=#icode_move{dst=Var}|List], [Var], Res) ->
-%% lists:reverse(Res, [I|List]);
-%% removeUnElems([I=#icode_call{dstlist=Var}|List], Var, Res) ->
-%% lists:reverse(Res, [I|List]);
-%% removeUnElems([I|List], Var, Res) ->
-%% removeUnElems(List, Var, [I|Res]);
-%% removeUnElems([], _, Res) -> lists:reverse(Res).
-
-%% removeUnElems(List, Var) -> removeUnElems(List, Var, []).
-%% removeUnElems([I|List], Var, Res) ->
-%% Defs = hipe_icode:defines(I),
-%% case hipe_icode:is_call(I) of
-%% true ->
-%% Fn = hipe_icode:call_fun(I),
-%% case (hipe_icode:call_args(I) =:= Var) andalso is_tuple(Fn) of
-%% true ->
-%% case element(1,Fn) =:= unsafe_element of
-%% true ->
-%% removeUnElems(List, Var, Res);
-%% false ->
-%% case lists:member(Var, Defs) of
-%% true ->
-%% lists:reverse(Res, [I|List]);
-%% false ->
-%% removeUnElems(List, Var, [I|Res])
-%% end
-%% end;
-%% false ->
-%% case lists:member(Var, Defs) of
-%% true ->
-%% lists:reverse(Res, [I|List]);
-%% false ->
-%% removeUnElems(List, Var, [I|Res])
-%% end
-%% end;
-%% false ->
-%% case lists:member(Var, Defs) of
-%% true ->
-%% lists:reverse(Res, [I|List]);
-%% false ->
-%% removeUnElems(List, Var, [I|Res])
-%% end
-%% end;
-%% removeUnElems([], _, Res) -> lists:reverse(Res).
-
-
-%% Old findDefine that also could update it.
-%% -----------------------------------------
-%% findDefine(Code, Var) -> findDefine(Code, Var, [], []).
-%% findDefine([#icode_call{dstlist=Var,'fun'=mktuple,args=Vs}|Code],Var,NewCode,_)->
-%% findDefine(Code, Var, NewCode, Vs);
-%% findDefine([I=#icode_move{dst=Var, src=Src}|Code], [Var], NewCode, _) ->
-%% case Src of
-%% #icode_var{} ->
-%% findDefine(Code, [Src], [I|NewCode], [Src]);
-%% #icode_const{value={flat, Tuple}} ->
-%% findDefine(Code, [Var], [I|NewCode], []) %% Check this case! [Var]
-%% end;
-%% findDefine([I|Code], Var, NewCode, Vars) ->
-%% findDefine(Code, Var, [I|NewCode], Vars);
-%% findDefine([], _, NewCode, Vars) ->
-%% case Vars of
-%% [] ->
-%% notFound;
-%% [_] ->
-%% {notFound, Vars};
-%% _ ->
-%% {found, lists:reverse(NewCode), Vars}
-%% end.
-
-%% modifyCode(Code, Var) ->
-%% [#icode_return{vars=Var}|Code2] = lists:reverse(Code),
-%% case (length(Var) =< hipe_rtl_arch:nr_of_return_regs()) of
-%% true ->
-%% {Arity, Code3} = modifyCode(Code2, Var, []),
-%% {Arity, Code3};
-%% false ->
-%% {1, Code}
-%% end.
-
-%% modifyCode([I|Code], Var, Res) ->
-%% case scanInstr(I, Var) of
-%% {move, Arity, VarLst} ->
-%% Code2 = [#icode_return{vars=VarLst}, I |lists:reverse(Res, Code)],
-%% {Arity, lists:reverse(Code2)};
-%% {mktuple, Arity, VarLst} ->
-%% Code2 = [#icode_return{vars=VarLst}|lists:reverse(Res, Code)],
-%% {Arity, lists:reverse(Code2)};
-%% other ->
-%% modifyCode(Code, Var, [I|Res])
-%% end;
-%% modifyCode([], Var, Res) ->
-%% {1, lists:reverse(Res, [#icode_return{vars=Var}]}.
-
-%% scanInstr(#icode_call{dstlist=Var, 'fun'=mktuple, args=Lst}, Var) ->
-%% {mktuple, length(Lst), Lst};
-%% scanInstr(_, _) -> other.
-
-%% printCode(Cfg) ->
-%% Labels = hipe_icode_cfg:labels(Cfg),
-%% {_,_,{_,F,_,_,_,_,_,_},_} = Cfg,
-%% io:format("~nFunction: ~w~n", [F]),
-%% Print = fun(Label) ->
-%% Block = hipe_icode_cfg:bb(Cfg, Label),
-%% Code = hipe_bb:code(Block),
-%% io:format("Label: ~w~n", [Label]),
-%% lists:foreach(fun(I) -> io:format("~w~n", [I]) end, Code),
-%% io:format("~n")
-%% end,
-%% lists:foreach(Print, Labels).
-
-%% printList(File, [{MFA, #icode{code=Code, params=Parms}}|List]) ->
-%% io:format(File, "MFA: ~w - Params: ~w~n", [MFA, Parms]),
-%% printList2(File, Code),
-%% printList(File, List);
-%% printList(_, []) -> ok.
-
-%% printList2(File, []) -> io:format(File, "~n~n", []);
-%% printList2(File, IList) when is_list(IList) ->
-%% [I|List] = IList,
-%% io:format(File, "~w~n", [I]),
-%% printList2(File, List);
-%% printList2(File, SomethingElse) ->
-%% io:format(File, "Got: ~w~n", [SomethingElse]).
-
-%% optimizeDefine([#icode_call{dstlist=Var,'fun'=mktuple,args=Vs}|Code],
-%% Var, _, Res) ->
-%% case Vs of
-%% [_] ->
-%% {none, noOpt};
-%% _ ->
-%% optimizeDefine(Code, Var, Vs, Res)
-%% end;
-%% optimizeDefine([I=#icode_move{dst=Var, src=Src}|Code], [Var], Rets, Res) ->
-%% case hipe_icode:is_var(Src) of
-%% true ->
-%% optimizeDefine(Code, [Src], Rets, Res);
-%% false ->
-%% case Src of
-%% #icode_const{value={flat, Tuple}} when is_tuple(Tuple) ->
-%% optimizeDefine(Code, [Var], tuple_to_list(Tuple), [I|Res]);
-%% #icode_const{value={flat, _}} ->
-%% {none, noOpt};
-%% _ ->
-%% optimizeDefine(Code, [Var], Rets, [I|Res])
-%% end
-%% end;
-%% optimizeDefine([I|Code], Var, Rets, Res) ->
-%% optimizeDefine(Code, Var, Rets, [I|Res]);
-%% optimizeDefine([], Var, Rets, Res) ->
-%% case Rets of
-%% [] ->
-%% {none, Res, Var};
-%% _ ->
-%% {found, Res, Rets}
-%% end.
diff --git a/lib/hipe/icode/hipe_icode_pp.erl b/lib/hipe/icode/hipe_icode_pp.erl
deleted file mode 100644
index 33d1e62884..0000000000
--- a/lib/hipe/icode/hipe_icode_pp.erl
+++ /dev/null
@@ -1,297 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2003 by Erik Stenman.
-%% ====================================================================
-%% Filename : hipe_icode_pp.erl
-%% Module : hipe_icode_pp
-%% Purpose : Pretty-printer for Icode.
-%% Notes :
-%% History : * 2003-04-16 (stenman@epfl.ch): Created.
-%% ====================================================================
-%%
-%% @doc
-%% Icode Pretty-Printer.
-%% @end
-%%
-%% ====================================================================
-
--module(hipe_icode_pp).
-
--export([pp/1, pp/2, pp_block/1]).
-
--ifdef(DEBUG_ICODE).
--export([pp_instrs/2]).
--endif.
-
--include("hipe_icode.hrl").
-
-%%---------------------------------------------------------------------
-
--spec pp(#icode{}) -> 'ok'.
-%% @doc Prettyprints linear Icode on stdout.
-%% <p> Badly formed or unknown instructions are printed surrounded
-%% by three stars "***".</p>
-pp(Icode) ->
- pp(standard_io, Icode).
-
--spec pp(io:device(), #icode{}) -> 'ok'.
-%% @doc Prettyprints linear Icode on IoDevice.
-%% <p> Badly formed or unknown instructions are printed surrounded by
-%% three stars "***".</p>
-pp(Dev, Icode) ->
- {Mod, Fun, Arity} = hipe_icode:icode_fun(Icode),
- Args = hipe_icode:icode_params(Icode),
- io:format(Dev, "~w:~w/~w(", [Mod, Fun, Arity]),
- pp_args(Dev, Args),
- io:format(Dev, ") ->~n", []),
- io:format(Dev, "%% Info:~p\n",
- [[case hipe_icode:icode_is_closure(Icode) of
- true -> 'Closure';
- false -> 'Not a closure'
- end,
- case hipe_icode:icode_is_leaf(Icode) of
- true -> 'Leaf function';
- false -> 'Not a leaf function'
- end |
- hipe_icode:icode_info(Icode)]]),
- pp_instrs(Dev, hipe_icode:icode_code(Icode)),
- io:format(Dev, "%% Data:\n", []),
- hipe_data_pp:pp(Dev, hipe_icode:icode_data(Icode), icode, "").
-
--spec pp_block(icode_instrs()) -> 'ok'.
-pp_block(Code) ->
- pp_instrs(standard_io, Code).
-
--spec pp_instrs(io:device(), icode_instrs()) -> 'ok'.
-%% @doc Prettyprints a list of Icode instructions.
-pp_instrs(Dev, Is) ->
- lists:foreach(fun (I) -> pp_instr(Dev, I) end, Is).
-
-%%---------------------------------------------------------------------
-
-pp_instr(Dev, I) ->
- case I of
- #icode_label{} ->
- io:format(Dev, "~p:~n", [hipe_icode:label_name(I)]);
- #icode_comment{} ->
- Txt = hipe_icode:comment_text(I),
- Str = case io_lib:deep_char_list(Txt) of
- true -> Txt;
- false -> io_lib:format("~p", [Txt])
- end,
- io:format(Dev, " % ~s~n", [Str]);
- #icode_phi{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, hipe_icode:phi_dst(I)),
- io:format(Dev, " := phi(", []),
- pp_phi_args(Dev, hipe_icode:phi_arglist(I)),
- io:format(Dev, ")~n", []);
- #icode_move{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, hipe_icode:move_dst(I)),
- io:format(Dev, " := ", []),
- pp_arg(Dev, hipe_icode:move_src(I)),
- io:format(Dev, "~n", []);
- #icode_call{} ->
- io:format(Dev, " ", []),
- case hipe_icode:call_dstlist(I) of
- [] -> %% result is unused -- e.g. taken out by dead code elimination
- io:format(Dev, "_ := ", []);
- DstList ->
- pp_args(Dev, DstList),
- io:format(Dev, " := ", [])
- end,
- pp_fun(Dev, hipe_icode:call_fun(I),
- hipe_icode:call_args(I),
- hipe_icode:call_type(I),
- hipe_icode:call_in_guard(I)),
- case hipe_icode:call_continuation(I) of
- [] ->
- ok;
- CC ->
- io:format(Dev, " -> ~w", [CC])
- end,
- case hipe_icode:call_fail_label(I) of
- [] -> io:format(Dev, "~n", []);
- Fail -> io:format(Dev, ", #fail ~w~n", [Fail])
- end;
- #icode_enter{} ->
- io:format(Dev, " ", []),
- pp_fun(Dev, hipe_icode:enter_fun(I),
- hipe_icode:enter_args(I),
- hipe_icode:enter_type(I)),
- io:format(Dev, "~n", []);
- #icode_return{} ->
- io:format(Dev, " return(", []),
- pp_args(Dev, hipe_icode:return_vars(I)),
- io:format(Dev, ")~n", []);
- #icode_begin_try{} ->
- io:format(Dev, " begin_try -> ~w cont ~w~n",
- [hipe_icode:begin_try_label(I),
- hipe_icode:begin_try_successor(I)]);
- #icode_begin_handler{} ->
- io:format(Dev, " ", []),
- pp_args(Dev, hipe_icode:begin_handler_dstlist(I)),
- io:format(Dev, " := begin_handler()~n",[]);
- #icode_end_try{} ->
- io:format(Dev, " end_try~n", []);
- #icode_fail{} ->
- Type = hipe_icode:fail_class(I),
- io:format(Dev, " fail(~w, [", [Type]),
- pp_args(Dev, hipe_icode:fail_args(I)),
- case hipe_icode:fail_label(I) of
- [] -> io:put_chars(Dev, "])\n");
- Fail -> io:format(Dev, "]) -> ~w\n", [Fail])
- end;
- #icode_if{} ->
- io:format(Dev, " if ~w(", [hipe_icode:if_op(I)]),
- pp_args(Dev, hipe_icode:if_args(I)),
- io:format(Dev, ") then ~p (~.2f) else ~p~n",
- [hipe_icode:if_true_label(I), hipe_icode:if_pred(I),
- hipe_icode:if_false_label(I)]);
- #icode_switch_val{} ->
- io:format(Dev, " switch_val ",[]),
- pp_arg(Dev, hipe_icode:switch_val_term(I)),
- pp_switch_cases(Dev, hipe_icode:switch_val_cases(I)),
- io:format(Dev, " fail -> ~w\n",
- [hipe_icode:switch_val_fail_label(I)]);
- #icode_switch_tuple_arity{} ->
- io:format(Dev, " switch_tuple_arity ",[]),
- pp_arg(Dev, hipe_icode:switch_tuple_arity_term(I)),
- pp_switch_cases(Dev,hipe_icode:switch_tuple_arity_cases(I)),
- io:format(Dev, " fail -> ~w\n",
- [hipe_icode:switch_tuple_arity_fail_label(I)]);
- #icode_type{} ->
- io:format(Dev, " if is_", []),
- pp_type(Dev, hipe_icode:type_test(I)),
- io:format(Dev, "(", []),
- pp_args(Dev, hipe_icode:type_args(I)),
- io:format(Dev, ") then ~p (~.2f) else ~p~n",
- [hipe_icode:type_true_label(I), hipe_icode:type_pred(I),
- hipe_icode:type_false_label(I)]);
- #icode_goto{} ->
- io:format(Dev, " goto ~p~n", [hipe_icode:goto_label(I)])
- end.
-
-pp_fun(Dev, Fun, Args, Type) ->
- pp_fun(Dev, Fun, Args, Type, false).
-
-pp_fun(Dev, Fun, Args, Type, Guard) ->
- case Type of
- primop ->
- hipe_icode_primops:pp(Dev, Fun);
- local ->
- {_,F,A} = Fun,
- io:format(Dev, "~w/~w", [F, A]);
- remote ->
- {M,F,A} = Fun,
- io:format(Dev, "~w:~w/~w", [M, F, A])
- end,
- io:format(Dev, "(", []),
- pp_args(Dev, Args),
- case Guard of
- true ->
- case Type of
- primop ->
- io:format(Dev, ") (primop,guard)", []);
- _ ->
- io:format(Dev, ") (guard)", [])
- end;
- false ->
- case Type of
- primop ->
- io:format(Dev, ") (primop)", []);
- _ ->
- io:format(Dev, ")", [])
- end
- end.
-
-pp_arg(Dev, Arg) ->
- case hipe_icode:is_variable(Arg) of
- true ->
- case hipe_icode:is_var(Arg) of
- true ->
- N = hipe_icode:var_name(Arg),
- io:format(Dev, "v~p", [N]);
- false ->
- case hipe_icode:is_reg(Arg) of
- true ->
- N = hipe_icode:reg_name(Arg),
- case hipe_icode:reg_is_gcsafe(Arg) of
- true -> io:format(Dev, "rs~p", [N]);
- false -> io:format(Dev, "r~p", [N])
- end;
- false ->
- N = hipe_icode:fvar_name(Arg),
- io:format(Dev, "fv~p", [N])
- end
- end,
- case hipe_icode:is_annotated_variable(Arg) of
- true ->
- {_,Val,Fun} = hipe_icode:variable_annotation(Arg),
- io:format(Dev, " (~s)", [Fun(Val)]);
- false ->
- ok
- end;
- false ->
- Const = hipe_icode:const_value(Arg),
- io:format(Dev, "~p", [Const]) % ~p because it also prints ""
- end.
-
-pp_args(_Dev, []) -> ok;
-pp_args(Dev, [A]) ->
- pp_arg(Dev, A);
-pp_args(Dev, [A|Args]) ->
- pp_arg(Dev, A),
- io:format(Dev, ", ", []),
- pp_args(Dev, Args).
-
-pp_phi_args(_Dev, []) -> ok;
-pp_phi_args(Dev, [{Pred,A}]) ->
- io:format(Dev, "{~w, ", [Pred]),
- pp_arg(Dev, A),
- io:format(Dev, "}", []);
-pp_phi_args(Dev, [{Pred,A}|Args]) ->
- io:format(Dev, "{~w, ", [Pred]),
- pp_arg(Dev, A),
- io:format(Dev, "}, ", []),
- pp_phi_args(Dev, Args).
-
-pp_type(Dev, T) ->
- io:format(Dev, "~w", [T]).
-
-pp_switch_cases(Dev, Cases) ->
- io:format(Dev, " of\n",[]),
- pp_switch_cases(Dev, Cases,1),
- io:format(Dev, "",[]).
-
-pp_switch_cases(Dev, [{Val,L}], _Pos) ->
- io:format(Dev, " ",[]),
- pp_arg(Dev, Val),
- io:format(Dev, " -> ~w\n", [L]);
-pp_switch_cases(Dev, [{Val, L}|Ls], Pos) ->
- io:format(Dev, " ",[]),
- pp_arg(Dev, Val),
- io:format(Dev, " -> ~w;\n", [L]),
- NewPos = Pos,
- %% case Pos of
- %% 5 -> io:format(Dev, "\n ",[]),
- %% 0;
- %% N -> N + 1
- %% end,
- pp_switch_cases(Dev, Ls, NewPos);
-pp_switch_cases(_Dev, [], _) -> ok.
-
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
deleted file mode 100644
index 2941cf15fc..0000000000
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ /dev/null
@@ -1,999 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Filename : hipe_icode_primops.erl
-%% Module : hipe_icode_primops
-%% Purpose :
-%% Notes :
-%% History : * 2001-06-13 Erik Johansson (happi@it.uu.se):
-%% Created.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_icode_primops).
-
--export([is_safe/1, fails/1, pp/2, type/1, type/2, arg_types/1]).
-
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
-
-%%---------------------------------------------------------------------
-
-%% Note that 'unsafe_...' operations are generally "safe", i.e., it is
-%% typically unsafe to use them unless you have extra information about
-%% the call (e.g., if the types are known). However, if they have been
-%% correctly introduced in the code, most of them are also OK to remove
-%% if the result is not used.
-
--spec is_safe(icode_primop()) -> boolean().
-
-is_safe('+') -> false;
-is_safe('/') -> false;
-is_safe('*') -> false;
-is_safe('-') -> false;
-is_safe('bsr') -> false;
-is_safe('bsl') -> false;
-is_safe('band') -> false;
-is_safe('bor') -> false;
-is_safe('bxor') -> false;
-is_safe('bnot') -> false;
-is_safe('div') -> false;
-is_safe('rem') -> false;
-is_safe(call_fun) -> false;
-is_safe(check_get_msg) -> false;
-is_safe(clear_timeout) -> false;
-is_safe(cons) -> true;
-%% is_safe(conv_to_float) -> false;
-is_safe(extra_unsafe_add) -> true;
-is_safe(extra_unsafe_sub) -> true;
-is_safe(fcheckerror) -> false;
-is_safe(fclearerror) -> false;
-is_safe(fp_add) -> false;
-is_safe(fp_div) -> false;
-is_safe(fp_mul) -> false;
-is_safe(fp_sub) -> false;
-is_safe(mktuple) -> true;
-is_safe(next_msg) -> false;
-is_safe(recv_mark) -> false;
-is_safe(recv_set) -> false;
-is_safe(redtest) -> false;
-is_safe(select_msg) -> false;
-is_safe(self) -> true;
-is_safe(set_timeout) -> false;
-is_safe(suspend_msg) -> false;
-is_safe(unsafe_add) -> true;
-is_safe(unsafe_band) -> true;
-is_safe(unsafe_bnot) -> true;
-is_safe(unsafe_bor) -> true;
-is_safe(unsafe_bsl) -> true;
-is_safe(unsafe_bsr) -> true;
-is_safe(unsafe_bxor) -> true;
-is_safe(unsafe_hd) -> true;
-is_safe(unsafe_sub) -> true;
-is_safe(unsafe_tag_float) -> true;
-is_safe(unsafe_tl) -> true;
-is_safe(unsafe_untag_float) -> true;
-is_safe(#apply_N{}) -> false;
-is_safe(#closure_element{}) -> true;
-is_safe(#element{}) -> false;
-%% is_safe(#gc_test{}) -> ???
-is_safe({hipe_bs_primop, {bs_start_match, _}}) -> false;
-is_safe({hipe_bs_primop, {{bs_start_match, bitstr}, _}}) -> true;
-is_safe({hipe_bs_primop, {{bs_start_match, ok_matchstate}, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_get_binary, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_get_binary_all, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_get_binary_all_2, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_get_integer, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_get_float, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_skip_bits, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_skip_bits_all, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_test_tail, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_restore, _}}) -> true;
-is_safe({hipe_bs_primop, {bs_save, _}}) -> true;
-is_safe({hipe_bs_primop, {bs_add, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_add, _, _}}) -> false;
-is_safe({hipe_bs_primop, bs_bits_to_bytes}) -> false;
-is_safe({hipe_bs_primop, bs_bits_to_bytes2}) -> false;
-is_safe({hipe_bs_primop, {bs_init, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_init, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_init_bits, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_init_bits, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_put_binary, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_put_float, _, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_put_string, _, _}}) -> false;
-is_safe({hipe_bs_primop, bs_put_utf8}) -> false;
-is_safe({hipe_bs_primop, bs_utf8_size}) -> true;
-is_safe({hipe_bs_primop, bs_get_utf8}) -> false;
-is_safe({hipe_bs_primop, bs_utf16_size}) -> true;
-is_safe({hipe_bs_primop, {bs_put_utf16, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_get_utf16, _}}) -> false;
-is_safe({hipe_bs_primop, bs_validate_unicode}) -> false;
-is_safe({hipe_bs_primop, bs_validate_unicode_retract}) -> false;
-is_safe({hipe_bs_primop, {unsafe_bs_put_integer, _, _, _}}) -> false;
-is_safe({hipe_bs_primop, bs_final}) -> true;
-is_safe({hipe_bs_primop, bs_context_to_binary}) -> true;
-is_safe({hipe_bs_primop, {bs_test_unit, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_match_string, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_append, _, _, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_private_append, _, _}}) -> false;
-is_safe({hipe_bs_primop, bs_init_writable}) -> true;
-is_safe(build_stacktrace) -> true;
-is_safe(raw_raise) -> false;
-is_safe(#mkfun{}) -> true;
-is_safe(#unsafe_element{}) -> true;
-is_safe(#unsafe_update_element{}) -> true;
-is_safe(debug_native_called) -> false.
-
-
--spec fails(icode_funcall()) -> boolean().
-
-fails('+') -> true;
-fails('-') -> true;
-fails('*') -> true;
-fails('/') -> true;
-fails('bnot') -> true;
-fails('band') -> true;
-fails('bor') -> true;
-fails('bsl') -> true;
-fails('bsr') -> true;
-fails('bxor') -> true;
-fails('div') -> true;
-fails('rem') -> true;
-fails(call_fun) -> true;
-fails(check_get_msg) -> true;
-fails(clear_timeout) -> false;
-fails(cons) -> false;
-fails(conv_to_float) -> true;
-fails(extra_unsafe_add) -> false;
-fails(extra_unsafe_sub) -> false;
-fails(fcheckerror) -> true;
-fails(fclearerror) -> false;
-fails(fp_add) -> false;
-fails(fp_div) -> false;
-fails(fp_mul) -> false;
-fails(fp_sub) -> false;
-fails(mktuple) -> false;
-fails(next_msg) -> false;
-fails(recv_mark) -> false;
-fails(recv_set) -> false;
-fails(redtest) -> false;
-fails(select_msg) -> false;
-fails(self) -> false;
-fails(set_timeout) -> true;
-fails(suspend_msg) -> false;
-fails(unsafe_untag_float) -> false;
-fails(unsafe_tag_float) -> false;
-fails(unsafe_add) -> false;
-fails(unsafe_band) -> false;
-fails(unsafe_bnot) -> false;
-fails(unsafe_bor) -> false;
-fails(unsafe_bsl) -> false;
-fails(unsafe_bsr) -> false;
-fails(unsafe_bxor) -> false;
-fails(unsafe_hd) -> false;
-fails(unsafe_sub) -> false;
-%% fails(unsafe_tag_float) -> false;
-fails(unsafe_tl) -> false;
-%% fails(unsafe_untag_float) -> false;
-fails(#apply_N{}) -> true;
-fails(#closure_element{}) -> false;
-fails(#element{}) -> true;
-%% fails(#gc_test{}) -> ???
-fails({hipe_bs_primop, {bs_start_match, _}}) -> true;
-fails({hipe_bs_primop, {{bs_start_match, bitstr}, _}}) -> true;
-fails({hipe_bs_primop, {{bs_start_match, ok_matchstate}, _}}) -> true;
-fails({hipe_bs_primop, {bs_get_binary, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_get_binary_all, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_get_binary_all_2, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_get_integer, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_get_float, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_skip_bits, _}}) -> true;
-fails({hipe_bs_primop, {bs_skip_bits_all, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_test_tail, _}}) -> true;
-fails({hipe_bs_primop, {bs_restore, _}}) -> false;
-fails({hipe_bs_primop, {bs_save, _}}) -> false;
-fails({hipe_bs_primop, bs_context_to_binary}) -> false;
-fails({hipe_bs_primop, {bs_test_unit, _}}) -> true;
-fails({hipe_bs_primop, {bs_match_string, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_add, _}}) -> true;
-fails({hipe_bs_primop, {bs_add, _, _}}) -> true;
-fails({hipe_bs_primop, bs_bits_to_bytes}) -> true;
-fails({hipe_bs_primop, bs_bits_to_bytes2}) -> true;
-fails({hipe_bs_primop, {bs_init, _}}) -> true;
-fails({hipe_bs_primop, {bs_init, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_init_bits, _}}) -> true;
-fails({hipe_bs_primop, {bs_init_bits, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_put_binary, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_put_float, _, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_put_string, _, _}}) -> true;
-fails({hipe_bs_primop, bs_put_utf8}) -> true;
-fails({hipe_bs_primop, bs_utf8_size}) -> false;
-fails({hipe_bs_primop, bs_get_utf8}) -> true;
-fails({hipe_bs_primop, bs_utf16_size}) -> false;
-fails({hipe_bs_primop, {bs_put_utf16, _}}) -> true;
-fails({hipe_bs_primop, {bs_get_utf16, _}}) -> true;
-fails({hipe_bs_primop, bs_validate_unicode}) -> true;
-fails({hipe_bs_primop, bs_validate_unicode_retract}) -> true;
-fails({hipe_bs_primop, {unsafe_bs_put_integer, _, _, _}}) -> true;
-fails({hipe_bs_primop, bs_final}) -> false;
-fails({hipe_bs_primop, {bs_append, _, _, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_private_append, _, _}}) -> true;
-fails({hipe_bs_primop, bs_init_writable}) -> true;
-fails(build_stacktrace) -> false;
-fails(raw_raise) -> true;
-fails(#mkfun{}) -> false;
-fails(#unsafe_element{}) -> false;
-fails(#unsafe_update_element{}) -> false;
-fails(debug_native_called) -> false;
-%% Apparently, we are calling fails/1 for all MFAs which are compiled.
-%% This is weird and we should restructure the compiler to avoid
-%% calling fails/1 for things that are not primops.
-fails({M, F, A}) when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 ->
- %% Yes, we should move this.
- not erl_bifs:is_safe(M, F, A).
-
-%%=====================================================================
-%% Pretty printing
-%%=====================================================================
-
--spec pp(io:device(), icode_primop()) -> 'ok'.
-
-pp(Dev, Op) ->
- case Op of
- #apply_N{arity = N} ->
- io:format(Dev, "apply_N<~w>/", [N]);
- #closure_element{n = N} ->
- io:format(Dev, "closure_element<~w>", [N]);
- #element{} ->
- io:format(Dev, "element", []);
- #gc_test{need = N} ->
- io:format(Dev, "gc_test<~w>", [N]);
- {hipe_bs_primop, BsOp} ->
- case BsOp of
- {bs_put_binary_all, Unit, Flags} ->
- io:format(Dev, "bs_put_binary_all<~w, ~w>", [Unit,Flags]);
- {bs_put_binary, Size} ->
- io:format(Dev, "bs_put_binary<~w>", [Size]);
- {bs_put_binary, Flags, Size} ->
- io:format(Dev, "bs_put_binary<~w, ~w>", [Flags, Size]);
- {bs_put_float, Flags, Size, _ConstInfo} ->
- io:format(Dev, "bs_put_float<~w, ~w>", [Flags, Size]);
- {bs_put_string, String, SizeInBytes} ->
- io:format(Dev, "bs_put_string<~w, ~w>", [String, SizeInBytes]);
- {bs_put_integer, Bits, Flags, _ConstInfo} ->
- io:format(Dev, "bs_put_integer<~w, ~w>", [Bits, Flags]);
- {unsafe_bs_put_integer, Bits, Flags, _ConstInfo} ->
- io:format(Dev, "unsafe_bs_put_integer<~w, ~w>", [Bits, Flags]);
- {bs_skip_bits_all, Unit, Flags} ->
- io:format(Dev, "bs_skip_bits_all<~w,~w>", [Unit, Flags]);
- {bs_skip_bits, Unit} ->
- io:format(Dev, "bs_skip_bits<~w>", [Unit]);
- {bs_start_match, Max} ->
- io:format(Dev, "bs_start_match<~w>", [Max]);
- {{bs_start_match, Type}, Max} ->
- io:format(Dev, "bs_start_match<~w,~w>", [Type,Max]);
- {bs_match_string, String, SizeInBits} ->
- io:format(Dev, "bs_match_string<~w, ~w>", [String, SizeInBits]);
- {bs_get_integer, Size, Flags} ->
- io:format(Dev, "bs_get_integer<~w, ~w>", [Size, Flags]);
- {bs_get_float, Size, Flags} ->
- io:format(Dev, "bs_get_float<~w, ~w>", [Size, Flags]);
- {bs_get_binary, Size, Flags} ->
- io:format(Dev, "bs_get_binary<~w, ~w>", [Size, Flags]);
- {bs_get_binary_all, Unit, Flags} ->
- io:format(Dev, "bs_get_binary_all<~w,~w>", [Unit, Flags]);
- {bs_get_binary_all_2, Unit, Flags} ->
- io:format(Dev, "bs_get_binary_all<~w,~w>", [Unit, Flags]);
- {bs_test_tail, NumBits} ->
- io:format(Dev, "bs_test_tail<~w>", [NumBits]);
- {bs_test_unit, Unit} ->
- io:format(Dev, "bs_test_unit<~w>", [Unit]);
- bs_context_to_binary ->
- io:format(Dev, "bs_context_to_binary", []);
- {bs_restore, Index} ->
- io:format(Dev, "bs_restore<~w>", [Index]);
- {bs_save, Index} ->
- io:format(Dev, "bs_save<~w>", [Index]);
- {bs_init, Size, Flags} ->
- io:format(Dev, "bs_init<~w, ~w>", [Size, Flags]);
- {bs_init,Flags} ->
- io:format(Dev, "bs_init<~w>", [Flags]);
- {bs_init_bits, Size, Flags} ->
- io:format(Dev, "bs_init_bits<~w, ~w>", [Size, Flags]);
- {bs_init_bits, Flags} ->
- io:format(Dev, "bs_init_bits<~w>", [Flags]);
- {bs_add, Unit} ->
- io:format(Dev, "bs_add<~w>", [Unit]);
- {bs_add, Const, Unit} ->
- io:format(Dev, "bs_add<~w, ~w>", [Const, Unit]);
- {bs_append, X, Y, Z, W} ->
- io:format(Dev, "bs_append<~w, ~w, ~w, ~w>", [X, Y, Z, W]);
- {bs_private_append, U, Flags} ->
- io:format(Dev, "bs_private_append<~w, ~w>", [U, Flags]);
- bs_bits_to_bytes ->
- io:format(Dev, "bs_bits_to_bytes", []);
- bs_bits_to_bytes2 ->
- io:format(Dev, "bs_bits_to_bytes2", []);
- bs_utf8_size ->
- io:format(Dev, "bs_utf8_size", []);
- bs_put_utf8 ->
- io:format(Dev, "bs_put_utf8", []);
- bs_get_utf8 ->
- io:format(Dev, "bs_get_utf8", []);
- bs_utf16_size ->
- io:format(Dev, "bs_utf16_size", []);
- {bs_put_utf16, Flags} ->
- io:format(Dev, "bs_put_utf16<~w>", [Flags]);
- {bs_get_utf16, Flags} ->
- io:format(Dev, "bs_get_utf16<~w>", [Flags]);
- bs_validate_unicode ->
- io:format(Dev, "bs_validate_unicode", []);
- bs_validate_unicode_retract ->
- io:format(Dev, "bs_validate_unicode_retract", []);
- bs_final ->
- io:format(Dev, "bs_final", []);
- bs_final2 ->
- io:format(Dev, "bs_final2", []);
- bs_init_writable ->
- io:format(Dev, "bs_init_writable", [])
- end;
- #mkfun{mfa = {Mod, Fun, Arity}, magic_num = Unique, index = I} ->
- io:format(Dev, "mkfun<~w,~w,~w,~w,~w>", [Mod, Fun, Arity, Unique, I]);
- #unsafe_element{index = N} ->
- io:format(Dev, "unsafe_element<~w>", [N]);
- #unsafe_update_element{index = N} ->
- io:format(Dev, "unsafe_update_element<~w>", [N]);
- Fun when is_atom(Fun) ->
- io:format(Dev, "~w", [Fun])
- end.
-
-%%=====================================================================
-%% Type handling
-%%=====================================================================
-
--spec type(icode_funcall(), [erl_types:erl_type()]) -> erl_types:erl_type().
-
-type(Primop, Args) ->
- case Primop of
-%%% -----------------------------------------------------
-%%% Arithops
- '+' ->
- erl_bif_types:type(erlang, '+', 2, Args);
- '-' ->
- erl_bif_types:type(erlang, '-', 2, Args);
- '*' ->
- erl_bif_types:type(erlang, '*', 2, Args);
- '/' ->
- erl_bif_types:type(erlang, '/', 2, Args);
- 'band' ->
- erl_bif_types:type(erlang, 'band', 2, Args);
- 'bnot' ->
- erl_bif_types:type(erlang, 'bnot', 1, Args);
- 'bor' ->
- erl_bif_types:type(erlang, 'bor', 2, Args);
- 'bxor' ->
- erl_bif_types:type(erlang, 'bxor', 2, Args);
- 'bsl' ->
- erl_bif_types:type(erlang, 'bsl', 2, Args);
- 'bsr' ->
- erl_bif_types:type(erlang, 'bsr', 2, Args);
- 'div' ->
- erl_bif_types:type(erlang, 'div', 2, Args);
- 'rem' ->
- erl_bif_types:type(erlang, 'rem', 2, Args);
- extra_unsafe_add ->
- erl_bif_types:type(erlang, '+', 2, Args);
- unsafe_add ->
- erl_bif_types:type(erlang, '+', 2, Args);
- unsafe_bnot ->
- erl_bif_types:type(erlang, 'bnot', 1, Args);
- unsafe_bor ->
- erl_bif_types:type(erlang, 'bor', 2, Args);
- unsafe_band ->
- erl_bif_types:type(erlang, 'band', 2, Args);
- unsafe_bxor ->
- erl_bif_types:type(erlang, 'bxor', 2, Args);
- unsafe_sub ->
- erl_bif_types:type(erlang, '-', 2, Args);
-%%% -----------------------------------------------------
-%%% Lists
- cons ->
- [HeadType, TailType] = Args,
- erl_types:t_cons(HeadType, TailType);
- unsafe_hd ->
- [Type] = Args,
- case erl_types:t_is_cons(Type) of
- true -> erl_types:t_cons_hd(Type);
- false -> erl_types:t_none()
- end;
- unsafe_tl ->
- [Type] = Args,
- case erl_types:t_is_cons(Type) of
- true -> erl_types:t_cons_tl(Type);
- false -> erl_types:t_none()
- end;
-%%% -----------------------------------------------------
-%%% Tuples
- mktuple ->
- erl_types:t_tuple(Args);
- #element{} ->
- erl_bif_types:type(erlang, element, 2, Args);
- #unsafe_element{index = N} ->
- Index = erl_types:t_from_term(N),
- erl_bif_types:type(erlang, element, 2, [Index | Args]);
- #unsafe_update_element{index = N} ->
- %% Same, same
- erl_bif_types:type(erlang, setelement, 3, [erl_types:t_integer(N)|Args]);
-%%% -----------------------------------------------------
-%%% Floats
- fclearerror ->
- erl_types:t_any();
- fcheckerror ->
- erl_types:t_any();
- unsafe_tag_float ->
- erl_types:t_float();
- %% These might look surprising, but the return is an untagged
- %% float and we have no type for untagged values.
- conv_to_float ->
- erl_types:t_any();
- unsafe_untag_float ->
- erl_types:t_any();
- fp_add ->
- erl_types:t_any();
- fp_sub ->
- erl_types:t_any();
- fp_mul ->
- erl_types:t_any();
- fp_div ->
- erl_types:t_any();
- fnegate ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%%
- {hipe_bs_primop, {bs_start_match, Max}} ->
- [Type] = Args,
- Init =
- erl_types:t_sup(
- erl_types:t_matchstate_present(Type),
- erl_types:t_inf(erl_types:t_bitstr(1, 0), Type)),
- case erl_types:t_is_none(Init) of
- true ->
- erl_types:t_none();
- false ->
- erl_types:t_matchstate(Init, Max)
- end;
- {hipe_bs_primop, {{bs_start_match, _}, Max}} ->
- [Type] = Args,
- Init =
- erl_types:t_sup(
- erl_types:t_matchstate_present(Type),
- erl_types:t_inf(erl_types:t_bitstr(1, 0), Type)),
- case erl_types:t_is_none(Init) of
- true ->
- erl_types:t_none();
- false ->
- erl_types:t_matchstate(Init, Max)
- end;
- {hipe_bs_primop, {bs_get_integer, Size, Flags}} ->
- Signed = Flags band 4,
- [MatchState|RestArgs] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- case RestArgs of
- [] ->
- NewBinType = match_bin(erl_types:t_bitstr(0, Size), BinType),
- NewMatchState =
- erl_types:t_matchstate_update_present(NewBinType, MatchState),
- Range =
- case Signed of
- 0 ->
- UpperBound = inf_add(safe_bsl_1(Size), -1),
- erl_types:t_from_range(0, UpperBound);
- 4 ->
- Bound = safe_bsl_1(Size - 1),
- erl_types:t_from_range(inf_inv(Bound), inf_add(Bound, -1))
- end,
- erl_types:t_product([Range, NewMatchState]);
- [_Arg] ->
- NewBinType = match_bin(erl_types:t_bitstr(Size, 0), BinType),
- NewMatchState =
- erl_types:t_matchstate_update_present(NewBinType, MatchState),
- erl_types:t_product([erl_types:t_integer(), NewMatchState])
- end;
- {hipe_bs_primop, {bs_get_float, Size, _Flags}} ->
- [MatchState|RestArgs] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- NewBinType =
- case RestArgs of
- [] ->
- match_bin(erl_types:t_bitstr(0,Size),BinType);
- [_Arg] ->
- erl_types:t_sup(match_bin(erl_types:t_bitstr(0, 32), BinType),
- match_bin(erl_types:t_bitstr(0, 64), BinType))
- end,
- NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState),
- erl_types:t_product([erl_types:t_float(), NewMatchState]);
- {hipe_bs_primop, {bs_get_binary, Size, _Flags}} ->
- [MatchState|RestArgs] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- case RestArgs of
- [] ->
- NewBinType = match_bin(erl_types:t_bitstr(0, Size), BinType),
- NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState),
- erl_types:t_product([erl_types:t_bitstr(0,Size), NewMatchState]);
- [ArgType] ->
- Posint = erl_types:t_inf(erl_types:t_non_neg_integer(), ArgType),
- case erl_types:t_is_none(Posint) of
- true ->
- erl_types:t_product([erl_types:t_none(),
- erl_types:t_matchstate_update_present(
- erl_types:t_none(),
- MatchState)]);
- false ->
- OutBinType =
- erl_types:t_bitstr(Size,erl_types:number_min(Posint)*Size),
- NewBinType = match_bin(OutBinType,BinType),
- NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState),
- erl_types:t_product([OutBinType, NewMatchState])
- end
- end;
- {hipe_bs_primop, {bs_get_binary_all, Unit, _Flags}} ->
- [MatchState] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- erl_types:t_inf(BinType, erl_types:t_bitstr(Unit, 0));
- {hipe_bs_primop, {bs_get_binary_all_2, Unit, _Flags}} ->
- [MatchState] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- erl_types:t_product(
- [erl_types:t_inf(BinType,erl_types:t_bitstr(Unit, 0)),
- erl_types:t_matchstate_update_present(
- erl_types:t_bitstr(0, 0), MatchState)]);
- {hipe_bs_primop, {bs_skip_bits_all, _Unit, _Flags}} ->
- [MatchState] = Args,
- erl_types:t_matchstate_update_present(erl_types:t_bitstr(0,0),MatchState);
- {hipe_bs_primop, {bs_skip_bits, Size}} ->
- [MatchState|RestArgs] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- NewBinType =
- case RestArgs of
- [] ->
- match_bin(erl_types:t_bitstr(0, Size), BinType);
- [_Arg] ->
- match_bin(erl_types:t_bitstr(Size, 0), BinType)
- end,
- erl_types:t_matchstate_update_present(NewBinType, MatchState);
- {hipe_bs_primop, {bs_save, Slot}} ->
- [MatchState] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- erl_types:t_matchstate_update_slot(BinType, MatchState, Slot);
- {hipe_bs_primop, {bs_restore, Slot}} ->
- [MatchState] = Args,
- BinType = erl_types:t_matchstate_slot(MatchState, Slot),
- erl_types:t_matchstate_update_present(BinType, MatchState);
- {hipe_bs_primop, bs_context_to_binary} ->
- [Type] = Args,
- erl_types:t_sup(
- erl_types:t_subtract(Type, erl_types:t_matchstate()),
- erl_types:t_matchstate_slot(
- erl_types:t_inf(Type, erl_types:t_matchstate()), 0));
- {hipe_bs_primop, {bs_match_string,_,Bits}} ->
- [MatchState] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- NewBinType = match_bin(erl_types:t_bitstr(0, Bits), BinType),
- erl_types:t_matchstate_update_present(NewBinType, MatchState);
- {hipe_bs_primop, {bs_test_unit,Unit}} ->
- [MatchState] = Args,
- BinType = erl_types:t_matchstate_present(MatchState),
- NewBinType = erl_types:t_inf(erl_types:t_bitstr(Unit, 0), BinType),
- erl_types:t_matchstate_update_present(NewBinType, MatchState);
- {hipe_bs_primop, {bs_add, _, _}} ->
- erl_types:t_integer();
- {hipe_bs_primop, {bs_add, _}} ->
- erl_types:t_integer();
- {hipe_bs_primop, bs_bits_to_bytes} ->
- erl_types:t_integer();
- {hipe_bs_primop, bs_bits_to_bytes2} ->
- erl_types:t_integer();
- {hipe_bs_primop, {Name, Size, _Flags, _ConstInfo}}
- when Name =:= bs_put_integer;
- Name =:= bs_put_float ->
- case Args of
- [_SrcType, _Base, Type] ->
- erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(0, Size));
- [_SrcType,_BitsType, _Base, Type] ->
- erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(Size, 0))
- end;
- {hipe_bs_primop, {bs_put_binary, Size, _Flags}} ->
- case Args of
- [_SrcType, _Base, Type] ->
- erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(0, Size));
- [_SrcType, _BitsType, _Base, Type] ->
- erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(Size, 0))
- end;
- {hipe_bs_primop, {bs_put_binary_all, Unit, _Flags}} ->
- [SrcType0, _Base, Type] = Args,
- SrcType = erl_types:t_inf(erl_types:t_bitstr(Unit, 0), SrcType0),
- erl_types:t_bitstr_concat(SrcType,Type);
- {hipe_bs_primop, {bs_put_string, _, Size}} ->
- [_Base, Type] = Args,
- erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(0, 8*Size));
- {hipe_bs_primop, bs_utf8_size} ->
- [_Arg] = Args,
- erl_types:t_from_range(1, 4);
- {hipe_bs_primop, bs_utf16_size} ->
- [_Arg] = Args,
- erl_types:t_from_range(2, 4); % XXX: really 2 | 4
- {hipe_bs_primop, bs_final} ->
- [_Base, Type] = Args,
- Type;
- {hipe_bs_primop, {bs_init, Size, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(0, Size*8),
- erl_types:t_any(),
- erl_types:t_bitstr(0, 0)]);
- {hipe_bs_primop, {bs_init, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_binary(),
- erl_types:t_any(),
- erl_types:t_bitstr(0, 0)]);
- {hipe_bs_primop, {bs_init_bits, Size, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(0, Size),
- erl_types:t_any(),
- erl_types:t_bitstr(0, 0)]);
- {hipe_bs_primop, {bs_init_bits, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(),
- erl_types:t_any(),
- erl_types:t_bitstr(0, 0)]);
- {hipe_bs_primop, {bs_private_append, _U, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(),
- erl_types:t_any(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, {bs_append, _W, _R, _U, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(),
- erl_types:t_any(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, bs_init_writable} ->
- erl_types:t_bitstr(0, 0);
- {hipe_bs_primop, _BsOp} ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%% Funs
- #mkfun{mfa = {_M, _F, A}} ->
- %% Note that the arity includes the bound variables in args
- erl_types:t_fun(A - length(Args), erl_types:t_any());
- #apply_N{} ->
- erl_types:t_any();
- Op when Op =:= call_fun orelse Op =:= enter_fun ->
- [Fun0|TailArgs0] = lists:reverse(Args),
- TailArgs = lists:reverse(TailArgs0),
- Fun = erl_types:t_inf(erl_types:t_fun(), Fun0),
- case erl_types:t_is_fun(Fun) of
- true ->
- case erl_types:t_fun_args(Fun) of
- unknown ->
- erl_types:t_any();
- FunArgs ->
- case check_fun_args(FunArgs, TailArgs) of
- ok ->
- erl_types:t_fun_range(Fun);
- error ->
- erl_types:t_none()
- end
- end;
- false ->
- erl_types:t_none()
- end;
-%%% -----------------------------------------------------
-%%% Communication
- check_get_msg ->
- erl_types:t_any();
- clear_timeout ->
- erl_types:t_any();
- next_msg ->
- erl_types:t_any();
- recv_mark ->
- erl_types:t_any();
- recv_set ->
- erl_types:t_any();
- select_msg ->
- erl_types:t_any();
- set_timeout ->
- erl_types:t_any();
- suspend_msg ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%% Other
- #closure_element{} ->
- erl_types:t_any();
- redtest ->
- erl_types:t_any();
- debug_native_called ->
- erl_types:t_any();
- build_stacktrace ->
- erl_types:t_list();
- raw_raise ->
- erl_types:t_atom();
- {M, F, A} ->
- erl_bif_types:type(M, F, A, Args)
- end.
-
-
--spec type(icode_funcall()) -> erl_types:erl_type().
-
-type(Primop) ->
- case Primop of
-%%% -----------------------------------------------------
-%%% Arithops
- 'bnot' ->
- erl_bif_types:type(erlang, 'bnot', 1);
- '+' ->
- erl_bif_types:type(erlang, '+', 2);
- '-' ->
- erl_bif_types:type(erlang, '-', 2);
- '*' ->
- erl_bif_types:type(erlang, '*', 2);
- '/' ->
- erl_bif_types:type(erlang, '/', 2);
- 'div' ->
- erl_bif_types:type(erlang, 'div', 2);
- 'rem' ->
- erl_bif_types:type(erlang, 'rem', 2);
- 'band' ->
- erl_bif_types:type(erlang, 'band', 2);
- 'bor' ->
- erl_bif_types:type(erlang, 'bor', 2);
- 'bxor' ->
- erl_bif_types:type(erlang, 'bxor', 2);
- 'bsr' ->
- erl_bif_types:type(erlang, 'bsr', 2);
- 'bsl' ->
- erl_bif_types:type(erlang, 'bsl', 2);
- unsafe_add ->
- erl_bif_types:type(erlang, '+', 2);
- extra_unsafe_add ->
- erl_bif_types:type(erlang, '+', 2);
- unsafe_sub ->
- erl_bif_types:type(erlang, '-', 2);
- unsafe_bor ->
- erl_bif_types:type(erlang, 'bor', 2);
- unsafe_band ->
- erl_bif_types:type(erlang, 'band', 2);
- unsafe_bxor ->
- erl_bif_types:type(erlang, 'bxor', 2);
-%%% -----------------------------------------------------
-%%% Lists
- cons ->
- erl_types:t_cons();
- unsafe_hd ->
- erl_bif_types:type(erlang, hd, 1);
- unsafe_tl ->
- erl_bif_types:type(erlang, tl, 1);
-%%% -----------------------------------------------------
-%%% Tuples
- mktuple ->
- erl_types:t_tuple();
- #element{} ->
- erl_bif_types:type(erlang, element, 2);
- #unsafe_element{} ->
- erl_bif_types:type(erlang, element, 2);
- #unsafe_update_element{} ->
- erl_bif_types:type(erlang, setelement, 3);
-%%% -----------------------------------------------------
-%%% Floats
- fclearerror ->
- erl_types:t_any();
- fcheckerror ->
- erl_types:t_any();
- unsafe_tag_float ->
- erl_types:t_float();
- %% These might look surprising, but the return is an untagged
- %% float and we have no type for untagged values.
- conv_to_float ->
- erl_types:t_any();
- unsafe_untag_float ->
- erl_types:t_any();
- fp_add ->
- erl_types:t_any();
- fp_sub ->
- erl_types:t_any();
- fp_mul ->
- erl_types:t_any();
- fp_div ->
- erl_types:t_any();
- fnegate ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%% Binaries
- {hipe_bs_primop, bs_get_utf8} ->
- erl_types:t_product([erl_types:t_integer(), erl_types:t_matchstate()]);
- {hipe_bs_primop, {bs_get_utf16, _Flags}} ->
- erl_types:t_product([erl_types:t_integer(), erl_types:t_matchstate()]);
- {hipe_bs_primop, {bs_get_integer, _Size, _Flags}} ->
- erl_types:t_product([erl_types:t_integer(), erl_types:t_matchstate()]);
- {hipe_bs_primop, {bs_get_float, _, _}} ->
- erl_types:t_product([erl_types:t_float(), erl_types:t_matchstate()]);
- {hipe_bs_primop, {bs_get_binary, _, _}} ->
- erl_types:t_product([erl_types:t_bitstr(), erl_types:t_matchstate()]);
- {hipe_bs_primop, {bs_get_binary_all, _, _}} ->
- erl_types:t_bitstr();
- {hipe_bs_primop, {bs_get_binary_all_2, _, _}} ->
- erl_types:t_product([erl_types:t_bitstr(), erl_types:t_matchstate()]);
- {hipe_bs_primop, bs_final} ->
- erl_types:t_bitstr();
- {hipe_bs_primop, {bs_init, _, _}} ->
- erl_types:t_product([erl_types:t_binary(), erl_types:t_bitstr(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, {bs_init, _}} ->
- erl_types:t_product([erl_types:t_binary(), erl_types:t_bitstr(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, {bs_init_bits, Size, _}} ->
- erl_types:t_product([erl_types:t_bitstr(0, Size), erl_types:t_bitstr(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, {bs_init_bits, _}} ->
- erl_types:t_product([erl_types:t_bitstr(), erl_types:t_bitstr(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, {bs_add, _, _}} ->
- erl_types:t_integer();
- {hipe_bs_primop, {bs_add, _}} ->
- erl_types:t_integer();
- {hipe_bs_primop, bs_bits_to_bytes} ->
- erl_types:t_integer();
- {hipe_bs_primop, bs_bits_to_bytes2} ->
- erl_types:t_integer();
- {hipe_bs_primop, {bs_private_append, _U, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(),
- erl_types:t_any(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, {bs_append, _W, _R, _U, _Flags}} ->
- erl_types:t_product(
- [erl_types:t_bitstr(),
- erl_types:t_any(),
- erl_types:t_bitstr()]);
- {hipe_bs_primop, bs_init_writable} ->
- erl_types:t_bitstr();
- {hipe_bs_primop, _BsOp} ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%% Funs
- #mkfun{} ->
- %% Note that the arity includes the bound variables in args
- erl_types:t_fun();
- #apply_N{} ->
- erl_types:t_any();
- call_fun ->
- erl_types:t_any();
- enter_fun ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%% Communication
- check_get_msg ->
- erl_types:t_any();
- clear_timeout ->
- erl_types:t_any();
- next_msg ->
- erl_types:t_any();
- recv_mark ->
- erl_types:t_any();
- recv_set ->
- erl_types:t_any();
- select_msg ->
- erl_types:t_any();
- set_timeout ->
- erl_types:t_any();
- suspend_msg ->
- erl_types:t_any();
-%%% -----------------------------------------------------
-%%% Other
- build_stacktrace ->
- erl_types:t_any();
- raw_raise ->
- erl_types:t_any();
- #closure_element{} ->
- erl_types:t_any();
- redtest ->
- erl_types:t_any();
- debug_native_called ->
- erl_types:t_any();
- {M, F, A} ->
- erl_bif_types:type(M, F, A)
- end.
-
-
-%% =====================================================================
-%% @doc
-%% function arg_types returns a list of the demanded argument types for
-%% a bif to succeed.
-
--spec arg_types(icode_funcall()) -> [erl_types:erl_type()] | 'unknown'.
-
-arg_types(Primop) ->
- case Primop of
- {M, F, A} ->
- erl_bif_types:arg_types(M, F, A);
- #element{} ->
- [erl_types:t_pos_fixnum(), erl_types:t_tuple()];
- '+' ->
- erl_bif_types:arg_types(erlang, '+', 2);
- '-' ->
- erl_bif_types:arg_types(erlang, '-', 2);
- '*' ->
- erl_bif_types:arg_types(erlang, '*', 2);
- '/' ->
- erl_bif_types:arg_types(erlang, '/', 2);
- 'band' ->
- erl_bif_types:arg_types(erlang, 'band', 2);
- 'bnot' ->
- erl_bif_types:arg_types(erlang, 'bnot', 1);
- 'bor' ->
- erl_bif_types:arg_types(erlang, 'bor', 2);
- 'bxor' ->
- erl_bif_types:arg_types(erlang, 'bxor', 2);
- 'bsl' ->
- erl_bif_types:arg_types(erlang, 'bsl', 2);
- 'bsr' ->
- erl_bif_types:arg_types(erlang, 'bsr', 2);
- 'div' ->
- erl_bif_types:arg_types(erlang, 'div', 2);
- 'rem' ->
- erl_bif_types:arg_types(erlang, 'rem', 2);
- _ ->
- unknown % safe approximation for all primops.
- end.
-
-%%=====================================================================
-%% Auxiliary functions
-%%=====================================================================
-
-check_fun_args([T1|Left1], [T2|Left2]) ->
- Inf = erl_types:t_inf(T1, T2),
- case erl_types:t_inf(Inf, T2) of
- Inf ->
- check_fun_args(Left1, Left2);
- _ ->
- error
- end;
-check_fun_args([], []) ->
- ok;
-check_fun_args(_, _) ->
- error.
-
-match_bin(Pattern, Match) ->
- erl_types:t_bitstr_match(Pattern, Match).
-
--spec safe_bsl_1(non_neg_integer()) -> non_neg_integer() | 'pos_inf'.
-
-safe_bsl_1(Shift) when Shift =< 128 -> 1 bsl Shift;
-safe_bsl_1(_Shift) -> pos_inf.
-
-%%
-%% The following two functions are stripped-down versions of more
-%% general functions that exist in hipe_icode_range.erl
-%%
-
-inf_inv(pos_inf) -> neg_inf;
-inf_inv(Number) when is_integer(Number) -> -Number.
-
-inf_add(pos_inf, _Number) -> pos_inf;
-inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
- Number1 + Number2.
diff --git a/lib/hipe/icode/hipe_icode_primops.hrl b/lib/hipe/icode/hipe_icode_primops.hrl
deleted file mode 100644
index 6c6fbd3dad..0000000000
--- a/lib/hipe/icode/hipe_icode_primops.hrl
+++ /dev/null
@@ -1,33 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%=======================================================================
-%% File : hipe_icode_primops.hrl
-%% Author : Kostis Sagonas
-%% Description : Contains definitions for HiPE's primitive operations.
-%%=======================================================================
-
--record(apply_N, {arity :: arity()}).
-
--record(closure_element, {n :: arity()}).
-
--record(element, {typeinfo :: list()}). %% XXX: refine?
-
--record(gc_test, {need :: non_neg_integer()}).
-
--record(mkfun, {mfa :: mfa(), magic_num :: integer(), index :: integer()}).
-
--record(unsafe_element, {index :: non_neg_integer()}).
-
--record(unsafe_update_element, {index :: non_neg_integer()}).
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
deleted file mode 100644
index 098a7a8d8c..0000000000
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ /dev/null
@@ -1,1974 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_icode_range.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Description :
-%%%
-%%% Created : 12 Mar 2007 by Per Gustafsson <pergu@it.uu.se>
-%%%-------------------------------------------------------------------
--module(hipe_icode_range).
-
--export([cfg/4]).
-
-%%=====================================================================
-%% Icode Coordinator Behaviour Callbacks
-%%=====================================================================
-
--export([replace_nones/1,
- update__info/2, new__info/1, return__info/1,
- return_none/0, return_none_args/2, return_any_args/2]).
-
-%%=====================================================================
-
--import(erl_types, [t_any/0,
- t_from_range_unsafe/2,
- t_inf/2, t_integer/0,
- t_to_string/1, t_to_tlist/1,
- t_limit/2, t_none/0,
- number_min/1, number_max/1]).
-
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
--include("../main/hipe.hrl").
--include("../flow/cfg.hrl").
--include("../flow/hipe_bb.hrl").
--include("hipe_icode_type.hrl").
-
--type range_tuple() :: {'neg_inf' | integer(), 'pos_inf' | integer()}.
--type range_rep() :: range_tuple() | 'empty'.
--type fun_name() :: atom() | tuple().
--type inf_integer() :: 'neg_inf' | 'pos_inf' | integer().
-
--record(range, {range :: range_rep(),
- other :: boolean()}).
--type range() :: #range{}.
-
--record(ann, {range :: range(),
- type :: erl_types:erl_type(),
- count :: integer()}).
--type ann() :: #ann{}.
-
--type range_anno() :: {'range_anno', ann(), fun((ann()) -> string())}.
--type args_fun() :: fun((mfa(), cfg()) -> [range()]).
--type call_fun() :: fun((mfa(), [range()]) -> range()).
--type final_fun() :: fun((mfa(), [range()]) -> 'ok').
--type data() :: {mfa(), args_fun(), call_fun(), final_fun()}.
--type label() :: non_neg_integer().
--type info() :: map().
--type work_list() :: {[label()], [label()], set(label())}.
--type variable() :: #icode_variable{}.
--type annotated_variable() :: #icode_variable{}.
--type argument() :: #icode_const{} | variable().
--type three_range_fun() :: fun((range(),range(),range()) -> range()).
--type instr_split_info() :: {icode_instr(), [{label(),info()}]}.
--type last_instr_return() :: {instr_split_info(), range()}.
-
--record(state, {info_map = #{} :: info(),
- cfg :: cfg(),
- liveness :: hipe_icode_ssa:liveness(),
- ret_type :: range(),
- lookup_fun :: call_fun(),
- result_action :: final_fun()}).
--type state() :: #state{}.
-
--define(WIDEN, 1).
-
--define(TAG_IMMED1_SIZE, 4).
-
--define(BITS, 64).
-
-%%---------------------------------------------------------------------
-
--spec cfg(cfg(), mfa(), comp_options(), #comp_servers{}) -> cfg().
-
-cfg(Cfg, MFA, Options, Servers) ->
- case proplists:get_bool(concurrent_comp, Options) of
- true ->
- concurrent_cfg(Cfg, MFA, Servers#comp_servers.range);
- false ->
- ordinary_cfg(Cfg, MFA)
- end.
-
--spec concurrent_cfg(cfg(), mfa(), pid()) -> cfg().
-
-concurrent_cfg(Cfg, MFA, CompServer) ->
- CompServer ! {ready, {MFA, self()}},
- {ArgsFun, CallFun, FinalFun} = do_analysis(Cfg, MFA),
- Ans = do_rewrite(Cfg, MFA, ArgsFun, CallFun, FinalFun),
- CompServer ! {done_rewrite, MFA},
- Ans.
-
--spec do_analysis(cfg(), mfa()) -> {args_fun(), call_fun(), final_fun()}.
-
-do_analysis(Cfg, MFA) ->
- receive
- {analyse, {ArgsFun, CallFun, FinalFun}} ->
- analyse(Cfg, {MFA, ArgsFun, CallFun, FinalFun}),
- do_analysis(Cfg, MFA);
- {done, {_NewArgsFun, _NewCallFun, _NewFinalFun} = T} ->
- T
- end.
-
--spec do_rewrite(cfg(), mfa(), args_fun(), call_fun(), final_fun()) -> cfg().
-
-do_rewrite(Cfg, MFA, ArgsFun, CallFun, FinalFun) ->
- common_rewrite(Cfg, {MFA, ArgsFun, CallFun, FinalFun}).
-
--spec ordinary_cfg(cfg(), mfa()) -> cfg().
-
-ordinary_cfg(Cfg, MFA) ->
- Data = make_data(Cfg,MFA),
- common_rewrite(Cfg, Data).
-
--spec common_rewrite(cfg(), data()) -> cfg().
-
-common_rewrite(Cfg, Data) ->
- State = safe_analyse(Cfg, Data),
- State2 = rewrite_blocks(State),
- Cfg1 = state__cfg(State2),
- Cfg2 = hipe_icode_cfg:remove_unreachable_code(Cfg1),
- Cfg3 = convert_cfg_to_types(Cfg2),
- hipe_icode_type:specialize(Cfg3).
-
--spec make_data(cfg(), mfa()) -> data().
-
-make_data(Cfg, {_M,_F,A}=MFA) ->
- NoArgs =
- case hipe_icode_cfg:is_closure(Cfg) of
- true -> hipe_icode_cfg:closure_arity(Cfg)+1;
- false -> A
- end,
- Args = lists:duplicate(NoArgs, any_type()),
- ArgsFun = fun(_,_) -> Args end,
- CallFun = fun(_,_) -> any_type() end,
- FinalFun = fun(_,_) -> ok end,
- {MFA, ArgsFun, CallFun, FinalFun}.
-
--spec analyse(cfg(), data()) -> 'ok'.
-
-analyse(Cfg, Data) ->
- try
- #state{} = safe_analyse(Cfg, Data),
- ok
- catch throw:no_input -> ok
- end.
-
--spec safe_analyse(cfg(), data()) -> state().
-
-safe_analyse(CFG, Data={MFA,_,_,_}) ->
- State = state__init(CFG, Data),
- Work = init_work(State),
- NewState = analyse_blocks(State, Work),
- (state__result_action(NewState))(MFA, [state__ret_type(NewState)]),
- NewState.
-
--spec rewrite_blocks(state()) -> state().
-
-rewrite_blocks(State) ->
- CFG = state__cfg(State),
- Start = hipe_icode_cfg:start_label(CFG),
- rewrite_blocks([Start], State, set_from_list([Start])).
-
--spec rewrite_blocks([label()], state(), set(label())) -> state().
-
-rewrite_blocks([Next|Rest], State, Visited) ->
- Info = state__info_in(State, Next),
- {NewState, NewLabels} = analyse_block(Next, Info, State, true),
- RealNew = not_visited(NewLabels, Visited),
- NewVisited = set_union(set_from_list(RealNew), Visited),
- NewWork = RealNew ++ Rest,
- rewrite_blocks(NewWork, NewState, NewVisited);
-rewrite_blocks([], State, _) ->
- State.
-
--spec analyse_blocks(state(), work_list()) -> state().
-
-analyse_blocks(State, Work) ->
- case get_work(Work) of
- fixpoint ->
- State;
- {Label, NewWork} ->
- Info = state__info_in(State, Label),
- {NewState, NewLabels} =
- try analyse_block(Label, Info, State, false)
- catch throw:none_range ->
- {State, []}
- end,
- NewWork2 = add_work(NewWork, NewLabels),
- analyse_blocks(NewState, NewWork2)
- end.
-
--spec analyse_block(label(), info(), state(), boolean()) -> {state(), [label()]}.
-
-analyse_block(Label, Info, State, Rewrite) ->
- BB = state__bb(State, Label),
- Code = hipe_bb:code(BB),
- {NewCode, InfoList, RetType} =
- analyse_BB(Code, Info, [], Rewrite, state__lookup_fun(State)),
- State1 = state__bb_add(State, Label, hipe_bb:mk_bb(NewCode)),
- State2 = state__ret_type_update(State1, RetType),
- state__update_info(State2, InfoList, Rewrite).
-
--spec analyse_BB([icode_instr()], info(), [icode_instr()], boolean(), call_fun()) ->
- {[icode_instr()], [{label(),info()}], range()}.
-
-analyse_BB([Last], Info, Code, Rewrite, LookupFun) ->
- {{NewI, LabelInfoList}, RetType} =
- analyse_last_insn(Last, Info, Rewrite, LookupFun),
- {lists:reverse([NewI|Code]), LabelInfoList, RetType};
-analyse_BB([Insn|InsnList], Info, Code, Rewrite, LookupFun) ->
- {NewInfo, NewI} = analyse_insn(Insn, Info, LookupFun),
- analyse_BB(InsnList, NewInfo, [NewI|Code], Rewrite, LookupFun).
-
--spec analyse_insn(icode_instr(), info(), call_fun()) -> {info(), icode_instr()}.
-
-analyse_insn(I, Info, LookupFun) ->
- %% io:format("~w Info: ~p~n", [I, Info]),
- NewI = handle_args(I,Info),
- FinalI =
- case NewI of
- #icode_call{} -> analyse_call(NewI, LookupFun);
- #icode_move{} -> analyse_move(NewI);
- #icode_phi{} -> analyse_phi(NewI);
- #icode_begin_handler{} -> analyse_begin_handler(NewI);
- #icode_comment{} -> NewI
- end,
- {enter_vals(FinalI, Info), FinalI}.
-
--spec handle_args(icode_instr(), info()) -> icode_instr().
-
-handle_args(I, Info) ->
- WidenFun = fun update_three/3,
- handle_args(I, Info, WidenFun).
-
--spec handle_args(icode_instr(), info(), three_range_fun()) -> icode_instr().
-
-handle_args(I, Info, WidenFun) ->
- Uses = hipe_icode:uses(I),
- PresentRanges = [lookup(V, Info) || V <- Uses],
- %% io:format("Uses: ~p~nRanges: ~p~n", [Uses, PresentRanges]),
- JoinFun = fun(Var, Range) -> update_info(Var, Range, WidenFun) end,
- NewUses = lists:zipwith(JoinFun, Uses, PresentRanges),
- hipe_icode:subst_uses(lists:zip(Uses, NewUses), I).
-
--spec join_info(ann(), range(), three_range_fun()) -> ann().
-
-join_info(Ann = #ann{range = R1, type = Type, count = ?WIDEN}, R2, Fun) ->
- Ann#ann{range = Fun(R1, R2, range_from_simple_type(Type))};
-join_info(Ann = #ann{range = R1, type = Type, count = C}, R2, _Fun) when C < ?WIDEN ->
- case join_three(R1, R2, range_from_simple_type(Type)) of
- R1 -> Ann;
- NewR -> Ann#ann{range = NewR, count = C+1}
- end.
-
--spec join_three(range(), range(), range()) -> range().
-
-join_three(R1, R2, R3) ->
- inf(sup(R1, R2), R3).
-
--spec update_info(variable(), range()) -> annotated_variable().
-
-update_info(Var, Range) ->
- update_info(Var, Range, fun update_three/3).
-
--spec update_info(variable(), range(), three_range_fun()) -> annotated_variable().
-
-update_info(Arg, R, Fun) ->
- case hipe_icode:is_annotated_variable(Arg) of
- true ->
- Ann = hipe_icode:variable_annotation(Arg),
- hipe_icode:annotate_variable(Arg, update_info1(Ann, R, Fun));
- false ->
- Arg
- end.
-
--spec update_info1(any(), range(), three_range_fun()) -> range_anno().
-
-update_info1({range_anno, Ann, _}, R2, Fun) ->
- make_range_anno(update_ann(Ann,R2,Fun));
-update_info1({type_anno, Type, _}, R2, Fun) ->
- make_range_anno(update_ann(type_to_ann(Type), R2, Fun)).
-
-update_ann(Ann = #ann{range = R1, type = Type, count = ?WIDEN}, R2, Fun) ->
- Ann#ann{range = Fun(R1,R2,range_from_simple_type(Type))};
-update_ann(Ann = #ann{range = R1, type = Type, count = C}, R2, _Fun) ->
- case update_three(R1, R2, range_from_simple_type(Type)) of
- R1 -> Ann;
- NewR -> Ann#ann{range = NewR, count = C+1}
- end.
-
--spec type_to_ann(erl_types:erl_type()) -> ann().
-
-type_to_ann(Type) ->
- #ann{range = range_from_simple_type(Type), type = t_limit(Type,1), count = 1}.
-
--spec make_range_anno(ann()) -> range_anno().
-
-make_range_anno(Ann) ->
- {range_anno, Ann, fun pp_ann/1}.
-
--spec update_three(range(), range(), range()) -> range().
-
-update_three(_R1, R2, R3) ->
- inf(R2, R3).
-
--spec safe_widen(range(), range(), range()) -> range().
-
-safe_widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) ->
- ResRange =
- case {Old, New, Wide} of
- {{Min,Max1}, {Min,Max2}, {_,Max}} ->
- case inf_geq(OMax = next_up_limit(inf_max([Max1, Max2])), Max) of
- true -> {Min,Max};
- false -> {Min,OMax}
- end;
- {{Min1,Max}, {Min2,Max}, {Min,_}} ->
- case inf_geq(Min, OMin = next_down_limit(inf_min([Min1, Min2]))) of
- true -> {Min,Max};
- false -> {OMin,Max}
- end;
- {{Min1,Max1}, {Min2,Max2}, {Min,Max}} ->
- RealMax =
- case inf_geq(OMax = next_up_limit(inf_max([Max1, Max2])), Max) of
- true -> Max;
- false -> OMax
- end,
- RealMin =
- case inf_geq(Min, OMin = next_down_limit(inf_min([Min1, Min2]))) of
- true -> Min;
- false -> OMin
- end,
- {RealMin, RealMax};
- _ ->
- Wide
- end,
- T#range{range = ResRange}.
-
--spec widen(range(), range(), range()) -> range().
-
-widen(#range{range=Old}, #range{range=New}, T = #range{range=Wide}) ->
- ResRange =
- case {Old, New, Wide} of
- {{Min,_}, {Min,Max2}, {_,Max}} ->
- case inf_geq(OMax = next_up_limit(Max2), Max) of
- true -> {Min,Max};
- false -> {Min,OMax}
- end;
- {{_,Max}, {Min2,Max}, {Min,_}} ->
- case inf_geq(Min, OMin = next_down_limit(Min2)) of
- true -> {Min,Max};
- false -> {OMin,Max}
- end;
- {_, {Min2,Max2}, {Min,Max}} ->
- RealMax =
- case inf_geq(OMax = next_up_limit(Max2), Max) of
- true -> Max;
- false -> OMax
- end,
- RealMin =
- case inf_geq(Min, OMin = next_down_limit(Min2)) of
- true -> Min;
- false -> OMin
- end,
- {RealMin, RealMax};
- _ ->
- Wide
- end,
- T#range{range = ResRange}.
-
--spec analyse_call(#icode_call{}, call_fun()) -> #icode_call{}.
-
-analyse_call(Call, LookupFun) ->
- Args = hipe_icode:args(Call),
- Fun = hipe_icode:call_fun(Call),
- Type = hipe_icode:call_type(Call),
- %% This call has side-effects (it might call LookupFun which sends messages to
- %% hipe_icode_coordinator to update the argument ranges of Fun), and must thus
- %% not be moved into the case statement.
- DstRanges = analyse_call_or_enter_fun(Fun, Args, Type, LookupFun),
- case hipe_icode:call_dstlist(Call) of
- [] ->
- Call;
- Dsts ->
- NewDefs = [update_info(Var, R) || {Var,R} <- lists:zip(Dsts, DstRanges)],
- hipe_icode:subst_defines(lists:zip(Dsts, NewDefs), Call)
- end.
-
--spec analyse_move(#icode_move{}) -> #icode_move{}.
-
-analyse_move(Move) ->
- Src = hipe_icode:move_src(Move),
- Dst = hipe_icode:move_dst(Move),
- Range = get_range_from_arg(Src),
- NewDst = update_info(Dst, Range),
- hipe_icode:subst_defines([{Dst,NewDst}], Move).
-
--spec analyse_begin_handler(#icode_begin_handler{}) -> #icode_begin_handler{}.
-
-analyse_begin_handler(Handler) ->
- SubstList =
- [{Dst, update_info(Dst, any_type())} ||
- Dst <- hipe_icode:begin_handler_dstlist(Handler)],
- hipe_icode:subst_defines(SubstList, Handler).
-
--spec analyse_phi(#icode_phi{}) -> #icode_phi{}.
-
-analyse_phi(Phi) ->
- {_, Args} = lists:unzip(hipe_icode:phi_arglist(Phi)),
- Dst = hipe_icode:phi_dst(Phi),
- ArgRanges = get_range_from_args(Args),
- %% io:format("Phi-Arg_ranges: ~p ~n", [Arg_ranges]),
- DstRange = sup(ArgRanges),
- NewDst = update_info(Dst, DstRange, fun widen/3),
- hipe_icode:subst_defines([{Dst, NewDst}], Phi).
-
--spec analyse_last_insn(icode_instr(), info(), boolean(), call_fun()) ->
- last_instr_return().
-
-analyse_last_insn(I, Info, Rewrite, LookupFun) ->
- %% io:format("~w Info: ~p~n",[I,Info]),
- NewI = handle_args(I, Info),
- %% io:format("~w -> ~w~n",[NewI,I]),
- case NewI of
- #icode_return{} -> analyse_return(NewI, Info);
- #icode_enter{} -> analyse_enter(NewI, Info, LookupFun);
- #icode_switch_val{} ->
- {analyse_switch_val(NewI, Info, Rewrite), none_type()};
- #icode_if{} -> {analyse_if(NewI, Info, Rewrite), none_type()};
- #icode_goto{} -> {analyse_goto(NewI, Info), none_type()};
- #icode_type{} -> {analyse_type(NewI, Info, Rewrite), none_type()};
- #icode_fail{} -> {analyse_fail(NewI, Info), none_type()};
- #icode_call{} -> {analyse_last_call(NewI, Info, LookupFun), none_type()};
- #icode_switch_tuple_arity{} ->
- {analyse_switch_tuple_arity(NewI, Info), none_type()};
- #icode_begin_try{} -> {analyse_begin_try(NewI, Info), none_type()}
- end.
-
--spec analyse_return(#icode_return{}, info()) -> last_instr_return().
-
-analyse_return(Insn, _Info) ->
- [RetRange] = get_range_from_args(hipe_icode:return_vars(Insn)),
- {{Insn,[]}, RetRange}.
-
--spec analyse_enter(#icode_enter{}, info(), call_fun()) -> last_instr_return().
-
-analyse_enter(Insn, _Info, LookupFun) ->
- Args = hipe_icode:args(Insn),
- Fun = hipe_icode:enter_fun(Insn),
- CallType = hipe_icode:enter_type(Insn),
- [RetRange] = analyse_call_or_enter_fun(Fun, Args, CallType, LookupFun),
- {{Insn,[]}, RetRange}.
-
--spec analyse_switch_val(#icode_switch_val{}, info(), boolean()) -> instr_split_info().
-
-analyse_switch_val(Switch, Info, Rewrite) ->
- Var = hipe_icode:switch_val_term(Switch),
- SwitchRange = get_range_from_arg(Var),
- Cases = hipe_icode:switch_val_cases(Switch),
- {FailRange, LabelRangeList} = get_range_label_list(Cases, SwitchRange, []),
- case range__is_none(FailRange) of
- true ->
- InfoList = update_infos(Var, Info, LabelRangeList),
- if Rewrite -> {update_switch(Switch, LabelRangeList, false), InfoList};
- true -> {Switch, InfoList}
- end;
- false ->
- FailLabel = hipe_icode:switch_val_fail_label(Switch),
- InfoList = update_infos(Var, Info, [{FailRange, FailLabel}|LabelRangeList]),
- if Rewrite -> {update_switch(Switch, LabelRangeList, true), InfoList};
- true -> {Switch, InfoList}
- end
- end.
-
--spec update_infos(argument(), info(), [{range(),label()}]) -> [{label(),info()}].
-
-update_infos(Arg, Info, [{Range, Label}|Rest]) ->
- [{Label,enter_define({Arg,Range},Info)} | update_infos(Arg, Info, Rest)];
-update_infos(_, _, []) -> [].
-
--spec get_range_label_list([{argument(),label()}], range(), [{range(),label()}]) ->
- {range(),[{range(),label()}]}.
-
-get_range_label_list([{Val,Label}|Cases], SRange, Acc) ->
- VRange = get_range_from_arg(Val),
- None = none_type(),
- case inf(SRange, VRange) of
- None ->
- get_range_label_list(Cases, SRange, Acc);
- ResRange ->
- get_range_label_list(Cases, SRange, [{ResRange,Label}|Acc])
- end;
-get_range_label_list([], SRange, Acc) ->
- {PointTypes, _} = lists:unzip(Acc),
- {remove_point_types(SRange, PointTypes), Acc}.
-
--spec update_switch(#icode_switch_val{}, [{range(),label()}], boolean()) ->
- #icode_switch_val{}.
-
-update_switch(Switch, LabelRangeList, KeepFail) ->
- S2 =
- case label_range_list_to_cases(LabelRangeList, []) of
- no_update ->
- Switch;
- Cases ->
- hipe_icode:switch_val_cases_update(Switch, Cases)
- end,
- if KeepFail -> S2;
- true -> S2
- end.
-
--spec label_range_list_to_cases([{range(),label()}], [{#icode_const{},label()}]) ->
- 'no_update' | [{#icode_const{},label()}].
-
-label_range_list_to_cases([{#range{range={C,C},other=false},Label}|Rest],
- Acc) when is_integer(C) ->
- label_range_list_to_cases(Rest, [{hipe_icode:mk_const(C),Label}|Acc]);
-label_range_list_to_cases([{_NotAConstantRange,_Label}|_Rest], _Acc) ->
- no_update;
-label_range_list_to_cases([], Acc) ->
- lists:reverse(Acc).
-
--spec analyse_switch_tuple_arity(#icode_switch_tuple_arity{}, info()) ->
- {#icode_switch_tuple_arity{}, [{label(),info()}]}.
-
-analyse_switch_tuple_arity(Switch, Info) ->
- Var = hipe_icode:switch_tuple_arity_term(Switch),
- NewInfo = enter_define({Var, get_range_from_arg(Var)}, Info),
- Cases = hipe_icode:switch_tuple_arity_cases(Switch),
- Fail = hipe_icode:switch_tuple_arity_fail_label(Switch),
- {_, Case_labels} = lists:unzip(Cases),
- Labels = [Fail|Case_labels],
- {Switch, [{Label,NewInfo} || Label <- Labels]}.
-
--spec analyse_goto(#icode_goto{}, info()) -> {#icode_goto{}, [{label(),info()},...]}.
-
-analyse_goto(Insn, Info) ->
- GotoLabel = hipe_icode:goto_label(Insn),
- {Insn, [{GotoLabel,Info}]}.
-
--spec analyse_fail(#icode_fail{}, info()) -> {#icode_fail{}, [{label(),info()}]}.
-
-analyse_fail(Fail, Info) ->
- case hipe_icode:fail_label(Fail) of
- [] -> {Fail, []};
- Label -> {Fail, [{Label,Info}]}
- end.
-
--spec analyse_begin_try(#icode_begin_try{}, info()) ->
- {#icode_begin_try{}, [{label(),info()},...]}.
-
-analyse_begin_try(Insn, Info) ->
- Label = hipe_icode:begin_try_label(Insn),
- Successor = hipe_icode:begin_try_successor(Insn),
- {Insn, [{Label,Info},{Successor,Info}]}.
-
--spec analyse_last_call(#icode_call{}, info(), call_fun()) ->
- {#icode_call{}, [{label(),info()},...]}.
-
-analyse_last_call(Call, Info, LookupFun) ->
- %% hipe_icode_pp:pp_block([Insn]),
- NewI = analyse_call(Call, LookupFun),
- Continuation = hipe_icode:call_continuation(Call),
- NewInfo = enter_vals(NewI, Info),
- case hipe_icode:call_fail_label(Call) of
- [] ->
- {NewI, [{Continuation, NewInfo}]};
- Fail ->
- {NewI, [{Continuation, NewInfo}, {Fail, Info}]}
- end.
-
--spec analyse_if(#icode_if{}, info(), boolean()) ->
- {#icode_goto{} | #icode_if{}, [{label(),info()}]}.
-
-analyse_if(If, Info, Rewrite) ->
- case hipe_icode:if_args(If) of
- [_, _] = Args ->
- analyse_sane_if(If, Info, Args, get_range_from_args(Args), Rewrite);
- _ ->
- TrueLabel = hipe_icode:if_true_label(If),
- FalseLabel = hipe_icode:if_false_label(If),
- {If, [{TrueLabel, Info}, {FalseLabel, Info}]}
- end.
-
--spec analyse_sane_if(#icode_if{}, info(), [argument(),...],
- [range(),...], boolean()) ->
- {#icode_goto{} | #icode_if{}, [{label(), info()}]}.
-
-analyse_sane_if(If, Info, [Arg1, Arg2], [Range1, Range2], Rewrite) ->
- {TrueRange1, TrueRange2, FalseRange1, FalseRange2} =
- case normalize_name(hipe_icode:if_op(If)) of
- '>' ->
- {TR2, TR1, FR2, FR1} = range_inequality_propagation(Range2, Range1),
- {TR1, TR2, FR1, FR2};
- '<' ->
- range_inequality_propagation(Range1, Range2);
- '>=' ->
- {FR1, FR2, TR1, TR2} = range_inequality_propagation(Range1, Range2),
- {TR1, TR2, FR1, FR2};
- '=<' ->
- {FR2, FR1, TR2, TR1} = range_inequality_propagation(Range2, Range1),
- {TR1, TR2, FR1, FR2};
- '=:=' ->
- {TR1, TR2, FR1, FR2} = range_equality_propagation(Range1, Range2),
- {TR1, TR2, FR1, FR2};
- '=/=' ->
- {FR1, FR2, TR1, TR2} = range_equality_propagation(Range1, Range2),
- {TR1, TR2, FR1, FR2};
- '==' ->
- {TR1, TR2, FR1, FR2} = range_equality_propagation(Range1, Range2),
- {set_other(TR1,other(Range1)), set_other(TR2,other(Range2)), FR1, FR2};
- '/=' ->
- {FR1, FR2, TR1, TR2} = range_equality_propagation(Range1, Range2),
- {TR1, TR2, set_other(FR1,other(Range1)), set_other(FR2,other(Range2))}
- end,
- %% io:format("TR1 = ~w\nTR2 = ~w\n", [TrueRange1, TrueRange2]),
- True =
- case lists:all(fun range__is_none/1, [TrueRange1, TrueRange2]) of
- true -> [];
- false ->
- TrueLabel = hipe_icode:if_true_label(If),
- TrueArgRanges = [{Arg1, TrueRange1}, {Arg2, TrueRange2}],
- TrueInfo = enter_defines(TrueArgRanges, Info),
- [{TrueLabel, TrueInfo}]
- end,
- %% io:format("FR1 = ~w\nFR2 = ~w\n", [FalseRange1, FalseRange2]),
- False =
- case lists:all(fun range__is_none/1, [FalseRange1, FalseRange2]) of
- true -> [];
- false ->
- FalseLabel = hipe_icode:if_false_label(If),
- FalseArgRanges = [{Arg1, FalseRange1}, {Arg2, FalseRange2}],
- FalseInfo = enter_defines(FalseArgRanges, Info),
- [{FalseLabel, FalseInfo}]
- end,
- UpdateInfo = True ++ False,
- NewIF =
- if Rewrite ->
- case UpdateInfo of
- [] -> %% This is weird
- If;
- [{Label, _Info}] ->
- hipe_icode:mk_goto(Label);
- [_, _] ->
- If
- end;
- true ->
- If
- end,
- {NewIF, UpdateInfo}.
-
--spec normalize_name(atom()) -> atom().
-
-normalize_name(Name) ->
- case Name of
- 'fixnum_eq' -> '=:=';
- 'fixnum_neq' -> '=/=';
- 'fixnum_gt' -> '>';
- 'fixnum_lt' -> '<';
- 'fixnum_ge' -> '>=';
- 'fixnum_le' -> '=<';
- Name -> Name
- end.
-
--spec range_equality_propagation(range(), range()) ->
- {range(), range(), range(), range()}.
-
-range_equality_propagation(Range1, Range2) ->
- TrueRange = inf(Range1, Range2),
- {FalseRange1, FalseRange2} =
- case {range(Range1), range(Range2)} of
- {{N,N}, {N,N}} ->
- {none_range(), none_range()};
- {{N1,N1}, {N2,N2}} ->
- {Range1, Range2};
- {{N,N}, _} ->
- {_,FR2} = compare_with_integer(N, Range2),
- {Range1, FR2};
- {_, {N,N}} ->
- {_,FR1} = compare_with_integer(N, Range1),
- {FR1, Range2};
- {_, _} ->
- {Range1, Range2}
- end,
- {TrueRange, TrueRange, FalseRange1, FalseRange2}.
-
--spec range_inequality_propagation(range(), range()) ->
- {range(), range(), range(), range()}.
-
-%% Range1 < Range2
-range_inequality_propagation(Range1, Range2) ->
- R1_other = other(Range1),
- R2_other = other(Range2),
- {R1_true_range, R1_false_range, R2_true_range, R2_false_range} =
- case {range(Range1), range(Range2)} of
- {{N1,N1}, {N2,N2}} ->
- case inf_geq(N2,inf_add(N1,1)) of
- true ->
- {{N1,N1},empty,{N2,N2},empty};
- false ->
- {empty,{N1,N1},empty,{N2,N2}}
- end;
- {{N1,N1}, {Min2,Max2}} ->
- case inf_geq(Min2,inf_add(N1,1)) of
- true ->
- {{N1,N1},empty,{inf_add(N1,1),Max2},empty};
- false ->
- case inf_geq(N1,Max2) of
- true ->
- {empty,{N1,N1},empty,{Min2,N1}};
- false ->
- {{N1,N1},{N1,N1},{inf_add(N1,1),Max2},{Min2,N1}}
- end
- end;
- {{Min1,Max1}, {N2,N2}} ->
- case inf_geq(N2,inf_add(Max1,1)) of
- true ->
- {{Min1,inf_add(N2,-1)},empty,{N2,N2},empty};
- false ->
- case inf_geq(Min1,N2) of
- true ->
- {empty,{N2,Max1},empty,{N2,N2}};
- false ->
- {{Min1,inf_add(N2,-1)},{N2,Max1},{N2,N2},{N2,N2}}
- end
- end;
- {empty, {Min2,Max2}} ->
- {empty,empty,{Min2,Max2},{Min2,Max2}};
- {{Min1,Max1}, empty} ->
- {{Min1,Max1},{Min1,Max1},empty,empty};
- {empty, empty} ->
- {empty,empty,empty,empty};
- {{Min1,Max1}, {Min2,Max2}} ->
- {{Min1,inf_min([Max1,inf_add(Max2,-1)])},
- {inf_max([Min1,Min2]),Max1},
- {inf_max([inf_add(Min1,1),Min2]),Max2},
- {Min2,inf_min([Max1,Max2])}}
- end,
- {range_init(R1_true_range, R1_other),
- range_init(R2_true_range, R2_other),
- range_init(R1_false_range, R1_other),
- range_init(R2_false_range, R2_other)}.
-
--spec analyse_type(#icode_type{}, info(), boolean()) ->
- {#icode_goto{} | #icode_type{}, [{label(),info()}]}.
-
-analyse_type(Type, Info, Rewrite) ->
- TypeTest = hipe_icode:type_test(Type),
- [Arg|_] = hipe_icode:type_args(Type),
- OldVarRange = get_range_from_arg(Arg),
- {TrueRange, FalseRange} =
- case TypeTest of
- {integer, N} ->
- compare_with_integer(N, OldVarRange);
- integer ->
- {inf(any_range(), OldVarRange), inf(none_range(), OldVarRange)};
- number ->
- {OldVarRange, OldVarRange};
- _ ->
- {inf(none_range(), OldVarRange), OldVarRange}
- end,
- TrueLabel = hipe_icode:type_true_label(Type),
- FalseLabel = hipe_icode:type_false_label(Type),
- TrueInfo = enter_define({Arg, TrueRange}, Info),
- FalseInfo = enter_define({Arg, FalseRange}, Info),
- True =
- case range__is_none(TrueRange) of
- true -> [];
- false -> [{TrueLabel, TrueInfo}]
- end,
- False =
- case range__is_none(FalseRange) of
- true -> [];
- false -> [{FalseLabel, FalseInfo}]
- end,
- UpdateInfo = True ++ False,
- NewType =
- if Rewrite ->
- case UpdateInfo of
- [] -> %% This is weird
- Type;
- [{Label,_Info}] ->
- hipe_icode:mk_goto(Label);
- [_, _] ->
- Type
- end;
- true ->
- Type
- end,
- {NewType, True ++ False}.
-
--spec compare_with_integer(integer(), range()) -> {range(), range()}.
-
-compare_with_integer(N, OldVarRange) ->
- TestRange = range_init({N, N}, false),
- TrueRange = inf(TestRange, OldVarRange),
- %% False range
- TempFalseRange = range__remove_constant(OldVarRange, TestRange),
- BetterRange =
- case range(TempFalseRange) of
- {Min, Max} = MM ->
- New_small = inf_geq(Min, N),
- New_large = inf_geq(N, Max),
- if New_small and not New_large ->
- {N + 1, Max};
- New_large and not New_small ->
- {Min, N - 1};
- true ->
- MM
- end;
- Not_tuple ->
- Not_tuple
- end,
- FalseRange = range_init(BetterRange, other(TempFalseRange)),
- {TrueRange, FalseRange}.
-
-%%== Ranges ==================================================================
-
--spec pp_ann(ann() | erl_types:erl_type()) -> string().
-
-pp_ann(#ann{range = #range{range = R, other = false}}) ->
- pp_range(R);
-pp_ann(#ann{range = #range{range = empty, other = true}, type = Type}) ->
- t_to_string(Type);
-pp_ann(#ann{range = #range{range = R, other = true}, type = Type}) ->
- pp_range(R) ++ " | " ++ t_to_string(Type);
-pp_ann(Type) ->
- t_to_string(Type).
-
--spec pp_range(range_rep()) -> nonempty_string().
-
-pp_range(empty) ->
- "none";
-pp_range({Min, Max}) ->
- val_to_string(Min) ++ ".." ++ val_to_string(Max).
-
--spec val_to_string('pos_inf' | 'neg_inf' | integer()) -> string().
-
-val_to_string(pos_inf) -> "inf";
-val_to_string(neg_inf) -> "-inf";
-val_to_string(X) when is_integer(X) -> integer_to_list(X).
-
--spec range_from_type(erl_types:erl_type()) -> [range()].
-
-range_from_type(Type) ->
- [range_from_simple_type(T) || T <- t_to_tlist(Type)].
-
--spec range_from_simple_type(erl_types:erl_type()) -> range().
-
-range_from_simple_type(Type) ->
- None = t_none(),
- case t_inf(t_integer(), Type) of
- None ->
- #range{range = empty, other = true};
- Type ->
- Range = {number_min(Type), number_max(Type)},
- #range{range = Range, other = false};
- NewType ->
- Range = {number_min(NewType), number_max(NewType)},
- #range{range = Range, other = true}
- end.
-
--spec range_init(range_rep(), boolean()) -> range().
-
-range_init({Min, Max} = Range, Other) ->
- case inf_geq(Max, Min) of
- true ->
- #range{range = Range, other = Other};
- false ->
- #range{range = empty, other = Other}
- end;
-range_init(empty, Other) ->
- #range{range = empty, other = Other}.
-
--spec range(range()) -> range_rep().
-
-range(#range{range = R}) -> R.
-
--spec other(range()) -> boolean().
-
-other(#range{other = O}) -> O.
-
--spec set_other(range(), boolean()) -> range().
-
-set_other(R, O) -> R#range{other = O}.
-
--spec range__min(range()) -> 'empty' | 'neg_inf' | integer().
-
-range__min(#range{range = empty}) -> empty;
-range__min(#range{range = {Min,_}}) -> Min.
-
--spec range__max(range()) -> 'empty' | 'pos_inf' | integer().
-
-range__max(#range{range = empty}) -> empty;
-range__max(#range{range = {_,Max}}) -> Max.
-
--spec range__is_none(range()) -> boolean().
-
-range__is_none(#range{range = empty, other = false}) -> true;
-range__is_none(#range{}) -> false.
-
--spec range__is_empty(range()) -> boolean().
-
-range__is_empty(#range{range = empty}) -> true;
-range__is_empty(#range{range = {_,_}}) -> false.
-
--spec remove_point_types(range(), [range()]) -> range().
-
-remove_point_types(Range, Ranges) ->
- Sorted = lists:sort(Ranges),
- FoldFun = fun (R, Acc) -> range__remove_constant(Acc,R) end,
- Range1 = lists:foldl(FoldFun, Range, Sorted),
- lists:foldl(FoldFun, Range1, lists:reverse(Sorted)).
-
--spec range__remove_constant(range(), range()) -> range().
-
-range__remove_constant(#range{range = {C, C}} = R, #range{range = {C, C}}) ->
- R#range{range = empty};
-range__remove_constant(#range{range = {C, H}} = R, #range{range = {C, C}}) ->
- R#range{range = {C+1, H}};
-range__remove_constant(#range{range = {L, C}} = R, #range{range = {C, C}}) ->
- R#range{range = {L, C-1}};
-range__remove_constant(#range{} = R, #range{range = {C,C}}) ->
- R;
-range__remove_constant(#range{} = R, _) ->
- R.
-
--spec any_type() -> range().
-
-any_type() ->
- #range{range = any_r(), other = true}.
-
--spec any_range() -> range().
-
-any_range() ->
- #range{range = any_r(), other = false}.
-
--spec none_range() -> range().
-
-none_range() ->
- #range{range = empty, other = true}.
-
--spec none_type() -> range().
-
-none_type() ->
- #range{range = empty, other = false}.
-
--spec any_r() -> {'neg_inf','pos_inf'}.
-
-any_r() -> {neg_inf, pos_inf}.
-
--spec get_range_from_args([argument()]) -> [range()].
-
-get_range_from_args(Args) ->
- [get_range_from_arg(Arg) || Arg <- Args].
-
--spec get_range_from_arg(argument()) -> range().
-
-get_range_from_arg(Arg) ->
- case hipe_icode:is_const(Arg) of
- true ->
- Value = hipe_icode:const_value(Arg),
- case is_integer(Value) of
- true ->
- #range{range = {Value, Value}, other = false};
- false ->
- #range{range = empty, other = true}
- end;
- false ->
- case hipe_icode:is_annotated_variable(Arg) of
- true ->
- case hipe_icode:variable_annotation(Arg) of
- {range_anno, #ann{range = Range}, _} ->
- Range;
- {type_anno, Type, _} ->
- range_from_simple_type(Type)
- end;
- false ->
- any_type()
- end
- end.
-
-%% inf([R]) ->
-%% R;
-%% inf([R1,R2|Rest]) ->
-%% inf([inf(R1,R2)|Rest]).
-
--spec inf(range(), range()) -> range().
-
-inf(#range{range=R1, other=O1}, #range{range=R2, other=O2}) ->
- #range{range=range_inf(R1,R2), other=other_inf(O1,O2)}.
-
--spec range_inf(range_rep(), range_rep()) -> range_rep().
-
-range_inf(empty, _) -> empty;
-range_inf(_, empty) -> empty;
-range_inf({Min1,Max1}, {Min2,Max2}) ->
- NewMin = inf_max([Min1, Min2]),
- NewMax = inf_min([Max1, Max2]),
- case inf_geq(NewMax, NewMin) of
- true ->
- {NewMin, NewMax};
- false ->
- empty
- end.
-
--spec other_inf(boolean(), boolean()) -> boolean().
-
-other_inf(O1, O2) -> O1 and O2.
-
--spec sup([range(),...]) -> range().
-
-sup([R]) ->
- R;
-sup([R1,R2|Rest]) ->
- sup([sup(R1, R2)|Rest]).
-
--spec sup(range(), range()) -> range().
-
-sup(#range{range=R1,other=O1}, #range{range=R2,other=O2}) ->
- #range{range=range_sup(R1,R2), other=other_sup(O1,O2)}.
-
--spec range_sup(range_rep(), range_rep()) -> range_rep().
-
-range_sup(empty, R) -> R;
-range_sup(R, empty) -> R;
-range_sup({Min1,Max1}, {Min2,Max2}) ->
- NewMin = inf_min([Min1,Min2]),
- NewMax = inf_max([Max1,Max2]),
- {NewMin,NewMax}.
-
--spec other_sup(boolean(), boolean()) -> boolean().
-
-other_sup(O1, O2) -> O1 or O2.
-
-%%== Call Support =============================================================
-
--spec analyse_call_or_enter_fun(fun_name(), [argument()],
- icode_call_type(), call_fun()) -> [range()].
-
-analyse_call_or_enter_fun(Fun, Args, CallType, LookupFun) ->
- %%io:format("Fun: ~p~n Args: ~p~n CT: ~p~n LF: ~p~n", [Fun, Args, CallType, LookupFun]),
- case basic_type(Fun) of
- {bin, Operation} ->
- [Arg_range1,Arg_range2] = get_range_from_args(Args),
- A1_is_empty = range__is_empty(Arg_range1),
- A2_is_empty = range__is_empty(Arg_range2),
- case A1_is_empty orelse A2_is_empty of
- true ->
- [none_type()];
- false ->
- [Operation(Arg_range1, Arg_range2)]
- end;
- {unary, Operation} ->
- [Arg_range] = get_range_from_args(Args),
- case range__is_empty(Arg_range) of
- true ->
- [none_type()];
- false ->
- [Operation(Arg_range)]
- end;
- {fcall, MFA} ->
- case CallType of
- local ->
- Range = LookupFun(MFA, get_range_from_args(Args)),
- case range__is_none(Range) of
- true ->
- throw(none_range);
- false ->
- [Range]
- end;
- remote ->
- [any_type()]
- end;
- not_int ->
- [any_type()];
- not_analysed ->
- [any_type()];
- {hipe_bs_primop, {bs_get_integer, Size, Flags}} ->
- {Min, Max} = analyse_bs_get_integer(Size, Flags, length(Args) =:= 1),
- [#range{range = {Min, Max}, other = false}, any_type()];
- {hipe_bs_primop, _} = Primop ->
- Type = hipe_icode_primops:type(Primop),
- range_from_type(Type)
- end.
-
--type bin_operation() :: fun((range(), range()) -> range()).
--type unary_operation() :: fun((range()) -> range()).
-
--spec basic_type(fun_name()) -> 'not_int' | 'not_analysed'
- | {'bin', bin_operation()}
- | {'unary', unary_operation()}
- | {'fcall', mfa()} | {'hipe_bs_primop', _}.
-
-%% Arithmetic operations
-basic_type('+') -> {bin, fun(R1, R2) -> range_add(R1, R2) end};
-basic_type('-') -> {bin, fun(R1, R2) -> range_sub(R1, R2) end};
-basic_type('*') -> {bin, fun(R1, R2) -> range_mult(R1, R2) end};
-basic_type('/') -> not_int;
-basic_type('div') -> {bin, fun(R1, R2) -> range_div(R1, R2) end};
-basic_type('rem') -> {bin, fun(R1, R2) -> range_rem(R1, R2) end};
-basic_type('bor') -> {bin, fun(R1, R2) -> range_bor(R1, R2) end};
-basic_type('band') -> {bin, fun(R1, R2) -> range_band(R1, R2) end};
-basic_type('bxor') -> {bin, fun(R1, R2) -> range_bxor(R1, R2) end};
-basic_type('bnot') -> {unary, fun(R1) -> range_bnot(R1) end};
-basic_type('bsl') -> {bin, fun(R1, R2) -> range_bsl(R1, R2) end};
-basic_type('bsr') -> {bin, fun(R1, R2) -> range_bsr(R1, R2) end};
-%% unsafe_*
-basic_type('unsafe_bor') ->
- {bin, fun(R1, R2) -> range_bor(R1, R2) end};
-basic_type('unsafe_band') ->
- {bin, fun(R1, R2) -> range_band(R1, R2) end};
-basic_type('unsafe_bxor') ->
- {bin, fun(R1, R2) -> range_bxor(R1, R2) end};
-basic_type('unsafe_bnot') ->
- {unary, fun(R1) -> range_bnot(R1) end};
-basic_type('unsafe_bsl') ->
- {bin, fun(R1, R2) -> range_bsl(R1, R2) end};
-basic_type('unsafe_bsr') ->
- {bin, fun(R1, R2) -> range_bsr(R1, R2) end};
-basic_type('unsafe_add') ->
- {bin, fun(R1, R2) -> range_add(R1, R2) end};
-basic_type('unsafe_sub') ->
- {bin, fun(R1, R2) -> range_sub(R1, R2) end};
-basic_type('extra_unsafe_add') ->
- {bin, fun(R1, R2) -> range_add(R1, R2) end};
-basic_type('extra_unsafe_sub') ->
- {bin, fun(R1, R2) -> range_sub(R1, R2) end};
-%% Binaries
-basic_type({hipe_bs_primop, _} = Primop) -> Primop;
-%% Unknown, other
-basic_type(call_fun) -> not_analysed;
-basic_type(clear_timeout) -> not_analysed;
-basic_type(redtest) -> not_analysed;
-basic_type(set_timeout) -> not_analysed;
-basic_type(#apply_N{}) -> not_analysed;
-basic_type(#closure_element{}) -> not_analysed;
-basic_type(#gc_test{}) -> not_analysed;
-%% Message handling
-basic_type(check_get_msg) -> not_analysed;
-basic_type(next_msg) -> not_analysed;
-basic_type(recv_mark) -> not_analysed;
-basic_type(recv_set) -> not_analysed;
-basic_type(select_msg) -> not_analysed;
-basic_type(suspend_msg) -> not_analysed;
-%% Functions
-basic_type(enter_fun) -> not_analysed;
-basic_type(#mkfun{}) -> not_int;
-basic_type({_M,_F,_A} = MFA) -> {fcall, MFA};
-%% Floats
-basic_type(conv_to_float) -> not_int;
-basic_type(fclearerror) -> not_analysed;
-basic_type(fcheckerror) -> not_analysed;
-basic_type(fnegate) -> not_int;
-basic_type(fp_add) -> not_int;
-basic_type(fp_div) -> not_int;
-basic_type(fp_mul) -> not_int;
-basic_type(fp_sub) -> not_int;
-basic_type(unsafe_tag_float) -> not_int;
-basic_type(unsafe_untag_float) -> not_int;
-%% Lists, tuples, records
-basic_type(cons) -> not_int;
-basic_type(mktuple) -> not_int;
-basic_type(unsafe_hd) -> not_analysed;
-basic_type(unsafe_tl) -> not_int;
-basic_type(#element{}) -> not_analysed;
-basic_type(#unsafe_element{}) -> not_analysed;
-basic_type(#unsafe_update_element{}) -> not_analysed;
-basic_type(build_stacktrace) -> not_int;
-basic_type(raw_raise) -> not_int.
-
--spec analyse_bs_get_integer(integer(), integer(), boolean()) -> range_tuple().
-
-analyse_bs_get_integer(Size, Flags, true) ->
- Signed = Flags band 4,
- case Signed =:= 0 of
- true ->
- {0, inf_add(inf_bsl(1, Size), -1)}; % return {Min, Max}
- false ->
- {inf_inv(inf_bsl(1, Size-1)), inf_add(inf_bsl(1, Size-1), -1)}
- end;
-analyse_bs_get_integer(Size, Flags, false) when is_integer(Size),
- is_integer(Flags) ->
- any_r().
-
-%%---------------------------------------------------------------------------
-%% Range operations
-%%---------------------------------------------------------------------------
-
-%% Arithmetic
-
--spec range_add(range(), range()) -> range().
-
-range_add(Range1, Range2) ->
- NewMin = inf_add(range__min(Range1), range__min(Range2)),
- NewMax = inf_add(range__max(Range1), range__max(Range2)),
- Other = other(Range1) orelse other(Range2),
- range_init({NewMin, NewMax}, Other).
-
--spec range_sub(range(), range()) -> range().
-
-range_sub(Range1, Range2) ->
- Min_sub = inf_min([inf_inv(range__max(Range2)),
- inf_inv(range__min(Range2))]),
- Max_sub = inf_max([inf_inv(range__max(Range2)),
- inf_inv(range__min(Range2))]),
- NewMin = inf_add(range__min(Range1), Min_sub),
- NewMax = inf_add(range__max(Range1), Max_sub),
- Other = other(Range1) orelse other(Range2),
- range_init({NewMin, NewMax}, Other).
-
--spec range_mult(range(), range()) -> range().
-
-range_mult(#range{range=empty, other=true}, _Range2) ->
- range_init(empty, true);
-range_mult(_Range1, #range{range=empty, other=true}) ->
- range_init(empty, true);
-range_mult(Range1, Range2) ->
- Min1 = range__min(Range1),
- Min2 = range__min(Range2),
- Max1 = range__max(Range1),
- Max2 = range__max(Range2),
- GreaterMin1 = inf_greater_zero(Min1),
- GreaterMin2 = inf_greater_zero(Min2),
- GreaterMax1 = inf_greater_zero(Max1),
- GreaterMax2 = inf_greater_zero(Max2),
- Range =
- if GreaterMin1 ->
- if GreaterMin2 -> {inf_mult(Min1, Min2), inf_mult(Max1, Max2)};
- GreaterMax2 -> {inf_mult(Min2, Max1), inf_mult(Max2, Max1)};
- true -> {inf_mult(Min2, Max1), inf_mult(Max2, Min1)}
- end;
- %% Column 1 or 2
- GreaterMin2 -> % Column 1 or 2 row 3
- range(range_mult(Range2, Range1));
- GreaterMax1 -> % Column 2 Row 1 or 2
- if GreaterMax2 -> % Column 2 Row 2
- NewMin = inf_min([inf_mult(Min2, Max1), inf_mult(Max2, Min1)]),
- NewMax = inf_max([inf_mult(Min2, Min1), inf_mult(Max2, Max1)]),
- {NewMin, NewMax};
- true -> % Column 2 Row 1
- {inf_mult(Min2, Max1), inf_mult(Min2, Min1)}
- end;
- GreaterMax2 -> % Column 1 Row 2
- range(range_mult(Range2, Range1));
- true -> % Column 1 Row 1
- {inf_mult(Max1, Max2), inf_mult(Min2, Min1)}
- end,
- Other = other(Range1) orelse other(Range2),
- range_init(Range, Other).
-
--spec extreme_divisors(range()) -> range_tuple().
-
-extreme_divisors(#range{range={0,0}}) -> {0,0};
-extreme_divisors(#range{range={0,Max}}) -> {1,Max};
-extreme_divisors(#range{range={Min,0}}) -> {Min,-1};
-extreme_divisors(#range{range={Min,Max}}) ->
- case inf_geq(Min, 0) of
- true -> {Min, Max};
- false -> % Min < 0
- case inf_geq(0, Max) of
- true -> {Min,Max}; % Max < 0
- false -> {-1,1} % Max > 0
- end
- end.
-
--spec range_div(range(), range()) -> range().
-
-%% this is div, not /.
-range_div(_, #range{range={0,0}}) ->
- range_init(empty, false);
-range_div(#range{range=empty}, _) ->
- range_init(empty, false);
-range_div(_, #range{range=empty}) ->
- range_init(empty, false);
-range_div(Range1, Den) ->
- Min1 = range__min(Range1),
- Max1 = range__max(Range1),
- {Min2, Max2} = extreme_divisors(Den),
- Min_max_list = [inf_div(Min1, Min2), inf_div(Min1, Max2),
- inf_div(Max1, Min2), inf_div(Max1, Max2)],
- range_init({inf_min(Min_max_list), inf_max(Min_max_list)}, false).
-
--spec range_rem(range(), range()) -> range().
-
-range_rem(Range1, Range2) ->
- %% Range1 desides the sign of the answer.
- Min1 = range__min(Range1),
- Max1 = range__max(Range1),
- Min2 = range__min(Range2),
- Max2 = range__max(Range2),
- Min1_geq_zero = inf_geq(Min1, 0),
- Max1_leq_zero = inf_geq(0, Max1),
- Max_range2 = inf_max([inf_abs(Min2), inf_abs(Max2)]),
- New_min =
- if Min1_geq_zero -> 0;
- Max_range2 =:= 0 -> 0;
- true -> inf_add(inf_inv(Max_range2), 1)
- end,
- New_max =
- if Max1_leq_zero -> 0;
- Max_range2 =:= 0 -> 0;
- true -> inf_add(Max_range2, -1)
- end,
- range_init({New_min, New_max}, false).
-
-%%--- Bit operations ----------------------------
-
--spec range_bsr(range(), range()) -> range().
-
-range_bsr(Range1, Range2=#range{range={Min, Max}}) ->
- New_Range2 = range_init({inf_inv(Max), inf_inv(Min)}, other(Range2)),
- Ans = range_bsl(Range1, New_Range2),
- %% io:format("bsr res:~w~nInput:= ~w~n", [Ans, {Range1,Range2}]),
- Ans.
-
--spec range_bsl(range(), range()) -> range().
-
-range_bsl(Range1, Range2) ->
- Min1 = range__min(Range1),
- Min2 = range__min(Range2),
- Max1 = range__max(Range1),
- Max2 = range__max(Range2),
- Min1Geq0 = inf_geq(Min1, 0),
- Max1Less0 = not inf_geq(Max1, 0),
- MinMax =
- if Min1Geq0 ->
- {inf_bsl(Min1, Min2), inf_bsl(Max1, Max2)};
- true ->
- if Max1Less0 -> {inf_bsl(Min1, Max2), inf_bsl(Max1, Min2)};
- true -> {inf_bsl(Min1, Max2), inf_bsl(Max1, Max2)}
- end
- end,
- range_init(MinMax, false).
-
--spec range_bnot(range()) -> range().
-
-range_bnot(Range) ->
- Minus_one = range_init({-1,-1}, false),
- range_add(range_mult(Range, Minus_one), Minus_one).
-
--spec width(range_rep() | inf_integer()) -> 'pos_inf' | non_neg_integer().
-
-width({Min, Max}) -> inf_max([width(Min), width(Max)]);
-width(pos_inf) -> pos_inf;
-width(neg_inf) -> pos_inf;
-width(X) when is_integer(X), X >= 0 -> poswidth(X, 0);
-width(X) when is_integer(X), X < 0 -> negwidth(X, 0).
-
--spec poswidth(non_neg_integer(), non_neg_integer()) -> non_neg_integer().
-
-poswidth(X, N) ->
- case X < (1 bsl N) of
- true -> N;
- false -> poswidth(X, N+1)
- end.
-
--spec negwidth(neg_integer(), non_neg_integer()) -> non_neg_integer().
-
-negwidth(X, N) ->
- case X > (-1 bsl N) of
- true -> N;
- false -> negwidth(X, N+1)
- end.
-
--spec range_band(range(), range()) -> range().
-
-range_band(R1, R2) ->
- {_Min1, Max1} = MM1 = range(R1),
- {_Min2, Max2} = MM2 = range(R2),
- Width1 = width(MM1),
- Width2 = width(MM2),
- Range =
- case {classify_range(R1), classify_range(R2)} of
- {minus_minus, minus_minus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), -1};
- {minus_minus, minus_plus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), Max2};
- {minus_minus, plus_plus} ->
- {0, Max2};
- {minus_plus, minus_minus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), Max1};
- {minus_plus, minus_plus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), inf_max([Max1, Max2])};
- {minus_plus, plus_plus} ->
- {0, Max2};
- {plus_plus, minus_minus} ->
- {0, Max1};
- {plus_plus, minus_plus} ->
- {0, Max1};
- {plus_plus, plus_plus} ->
- {0, inf_min([Max1, Max2])}
- end,
- range_init(Range, false).
-
--spec range_bor(range(), range()) -> range().
-
-range_bor(R1, R2) ->
- {Min1, _Max1} = MM1 = range(R1),
- {Min2, _Max2} = MM2 = range(R2),
- Width1 = width(MM1),
- Width2 = width(MM2),
- Range =
- case {classify_range(R1), classify_range(R2)} of
- {minus_minus, minus_minus} ->
- {inf_max([Min1, Min2]), -1};
- {minus_minus, minus_plus} ->
- {Min1, -1};
- {minus_minus, plus_plus} ->
- {Min1, -1};
- {minus_plus, minus_minus} ->
- {Min2, -1};
- {minus_plus, minus_plus} ->
- Width = inf_max([Width1, Width2]),
- {inf_min([Min1, Min2]), inf_add(-1, inf_bsl(1, Width))};
- {minus_plus, plus_plus} ->
- Width = inf_max([Width1, Width2]),
- {Min1, inf_add(-1, inf_bsl(1, Width))};
- {plus_plus, minus_minus} ->
- {Min2, -1};
- {plus_plus, minus_plus} ->
- Width = inf_max([Width1, Width2]),
- {Min2, inf_add(-1, inf_bsl(1, Width))};
- {plus_plus, plus_plus} ->
- Width = inf_max([Width1, Width2]),
- {0, inf_add(-1, inf_bsl(1, Width))}
- end,
- range_init(Range, false).
-
--spec classify_range(range()) -> 'minus_minus' | 'minus_plus' | 'plus_plus'.
-
-classify_range(Range) ->
- case range(Range) of
- {neg_inf, Number} when is_integer(Number), Number < 0 -> minus_minus;
- {neg_inf, Number} when is_integer(Number), Number >= 0 -> minus_plus;
- {Number, pos_inf} when is_integer(Number), Number < 0 -> minus_plus;
- {Number, pos_inf} when is_integer(Number), Number >= 0 -> plus_plus;
- {neg_inf, pos_inf} -> minus_plus;
- {Number1,Number2} when is_integer(Number1), is_integer(Number2) ->
- classify_int_range(Number1, Number2)
- end.
-
--spec classify_int_range(integer(), integer()) ->
- 'minus_minus' | 'minus_plus' | 'plus_plus'.
-
-classify_int_range(Number1, _Number2) when Number1 >= 0 ->
- plus_plus;
-classify_int_range(_Number1, Number2) when Number2 < 0 ->
- minus_minus;
-classify_int_range(_Number1, _Number2) ->
- minus_plus.
-
--spec range_bxor(range(), range()) -> range().
-
-range_bxor(R1, R2) ->
- {Min1, Max1} = MM1 = range(R1),
- {Min2, Max2} = MM2 = range(R2),
- Width1 = width(MM1),
- Width2 = width(MM2),
- Range =
- case {classify_range(R1), classify_range(R2)} of
- {minus_minus, minus_minus} ->
- Width = inf_max([Width1, Width2]),
- {0, inf_add(-1, inf_bsl(1, Width))};
- {minus_minus, minus_plus} ->
- MinWidth = inf_max([Width1, width({0,Max2})]),
- MaxWidth = inf_max([Width1, width({Min2,-1})]),
- {inf_bsl(-1, MinWidth), inf_add(-1, inf_bsl(1, MaxWidth))};
- {minus_minus, plus_plus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), -1};
- {minus_plus, minus_minus} ->
- MinWidth = inf_max([Width2,width({0,Max1})]),
- MaxWidth = inf_max([Width2,width({Min1,-1})]),
- {inf_bsl(-1, MinWidth), inf_add(-1, inf_bsl(1, MaxWidth))};
- {minus_plus, minus_plus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), inf_add(-1, inf_bsl(1, Width))};
- {minus_plus, plus_plus} ->
- MinWidth = inf_max([Width2,width({Min1,-1})]),
- MaxWidth = inf_max([Width2,width({0,Max1})]),
- {inf_bsl(-1, MinWidth), inf_add(-1, inf_bsl(1, MaxWidth))};
- {plus_plus, minus_minus} ->
- Width = inf_max([Width1, Width2]),
- {inf_bsl(-1, Width), -1};
- {plus_plus, minus_plus} ->
- MinWidth = inf_max([Width1,width({Min2,-1})]),
- MaxWidth = inf_max([Width1,width({0,Max2})]),
- {inf_bsl(-1, MinWidth), inf_add(-1, inf_bsl(1, MaxWidth))};
- {plus_plus, plus_plus} ->
- Width = inf_max([Width1, Width2]),
- {0, inf_add(-1, inf_bsl(1, Width))}
- end,
- range_init(Range, false).
-
-%%---------------------------------------------------------------------------
-%% Inf operations
-%%---------------------------------------------------------------------------
-
--spec inf_max([inf_integer(),...]) -> inf_integer().
-
-inf_max([H|T]) ->
- lists:foldl(fun (Elem, Max) ->
- case inf_geq(Elem, Max) of
- false -> Max;
- true -> Elem
- end
- end, H, T).
-
--spec inf_min([inf_integer(),...]) -> inf_integer().
-
-inf_min([H|T]) ->
- lists:foldl(fun (Elem, Min) ->
- case inf_geq(Elem, Min) of
- true -> Min;
- false -> Elem
- end
- end, H, T).
-
--spec inf_abs(inf_integer()) -> 'pos_inf' | integer().
-
-inf_abs(pos_inf) -> pos_inf;
-inf_abs(neg_inf) -> pos_inf;
-inf_abs(Number) when is_integer(Number), (Number < 0) -> - Number;
-inf_abs(Number) when is_integer(Number) -> Number.
-
--spec inf_add(inf_integer(), inf_integer()) -> inf_integer().
-
-inf_add(pos_inf, _Number) -> pos_inf;
-inf_add(neg_inf, _Number) -> neg_inf;
-inf_add(_Number, pos_inf) -> pos_inf;
-inf_add(_Number, neg_inf) -> neg_inf;
-inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
- Number1 + Number2.
-
--spec inf_inv(inf_integer()) -> inf_integer().
-
-inf_inv(pos_inf) -> neg_inf;
-inf_inv(neg_inf) -> pos_inf;
-inf_inv(Number) -> -Number.
-
--spec inf_geq(inf_integer(), inf_integer()) -> boolean().
-
-inf_geq(pos_inf, _) -> true;
-inf_geq(_, pos_inf) -> false;
-inf_geq(_, neg_inf) -> true;
-inf_geq(neg_inf, _) -> false;
-inf_geq(A, B) -> A >= B.
-
--spec inf_greater_zero(inf_integer()) -> boolean().
-
-inf_greater_zero(pos_inf) -> true;
-inf_greater_zero(neg_inf) -> false;
-inf_greater_zero(Number) when is_integer(Number), Number >= 0 -> true;
-inf_greater_zero(Number) when is_integer(Number), Number < 0 -> false.
-
--spec inf_div(inf_integer(), inf_integer()) -> inf_integer().
-
-inf_div(Number, 0) ->
- Greater = inf_greater_zero(Number),
- if Greater -> pos_inf;
- true -> neg_inf
- end;
-inf_div(pos_inf, Number) ->
- Greater = inf_greater_zero(Number),
- if Greater -> pos_inf;
- true -> neg_inf
- end;
-inf_div(neg_inf, Number) ->
- Greater = inf_greater_zero(Number),
- if Greater -> neg_inf;
- true -> pos_inf
- end;
-inf_div(Number, pos_inf) ->
- Greater = inf_greater_zero(Number),
- if Greater -> pos_inf;
- true -> neg_inf
- end;
-inf_div(Number, neg_inf) ->
- Greater = inf_greater_zero(Number),
- if Greater -> neg_inf;
- true -> pos_inf
- end;
-inf_div(Number1, Number2) -> Number1 div Number2.
-
--spec inf_mult(inf_integer(), inf_integer()) -> inf_integer().
-
-inf_mult(neg_inf, Number) ->
- Greater = inf_greater_zero(Number),
- if Greater -> neg_inf;
- true -> pos_inf
- end;
-inf_mult(pos_inf, Number) ->
- Greater = inf_greater_zero(Number),
- if Greater -> pos_inf;
- true -> neg_inf
- end;
-inf_mult(Number, pos_inf) -> inf_mult(pos_inf, Number);
-inf_mult(Number, neg_inf) -> inf_mult(neg_inf, Number);
-inf_mult(Number1, Number2) -> Number1 * Number2.
-
--spec inf_bsl(inf_integer(), inf_integer()) -> inf_integer().
-
-inf_bsl(pos_inf, _) -> pos_inf;
-inf_bsl(neg_inf, _) -> neg_inf;
-inf_bsl(Number, pos_inf) when is_integer(Number), Number >= 0 -> pos_inf;
-inf_bsl(_, pos_inf) -> neg_inf;
-inf_bsl(Number, neg_inf) when is_integer(Number), Number >= 0 -> 0;
-inf_bsl(_Number, neg_inf) -> -1;
-inf_bsl(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
- %% We cannot shift left with a number which is not a fixnum. We
- %% don't have enough memory.
- Bits = ?BITS,
- if Number2 > (Bits bsl 1) -> inf_bsl(Number1, pos_inf);
- Number2 < (-Bits bsl 1) -> inf_bsl(Number1, neg_inf);
- true -> Number1 bsl Number2
- end.
-
-%% State
-
--spec state__init(cfg(), data()) -> state().
-
-state__init(Cfg, {MFA, ArgsFun, CallFun, FinalFun}) ->
- Start = hipe_icode_cfg:start_label(Cfg),
- Params = hipe_icode_cfg:params(Cfg),
- Ranges = ArgsFun(MFA, Cfg),
- %% io:format("MFA: ~w~nRanges: ~w~n", [MFA, Ranges]),
- Liveness =
- hipe_icode_ssa:ssa_liveness__analyze(hipe_icode_type:unannotate_cfg(Cfg)),
- case lists:any(fun range__is_none/1, Ranges) of
- true ->
- FinalFun(MFA, [none_type()]),
- throw(no_input);
- false ->
- NewParams = lists:zipwith(fun update_info/2, Params, Ranges),
- NewCfg = hipe_icode_cfg:params_update(Cfg, NewParams),
- Info = enter_defines(NewParams, #{}),
- InfoMap = #{{Start, in} => Info},
- #state{info_map=InfoMap, cfg=NewCfg, liveness=Liveness,
- ret_type=none_type(),
- lookup_fun=CallFun, result_action=FinalFun}
- end.
-
--spec state__cfg(state()) -> cfg().
-
-state__cfg(#state{cfg=Cfg}) ->
- Cfg.
-
--spec state__bb(state(), label()) -> bb().
-
-state__bb(#state{cfg=Cfg}, Label) ->
- BB = hipe_icode_cfg:bb(Cfg, Label),
- true = hipe_bb:is_bb(BB), % Just an assert
- BB.
-
--spec state__bb_add(state(), label(), bb()) -> state().
-
-state__bb_add(S=#state{cfg=Cfg}, Label, BB) ->
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, BB),
- S#state{cfg=NewCfg}.
-
-state__lookup_fun(#state{lookup_fun=LF}) -> LF.
-
-state__result_action(#state{result_action=RA}) -> RA.
-
-state__ret_type(#state{ret_type=RT}) -> RT.
-
-state__ret_type_update(#state{ret_type=RT} = State, NewType) ->
- TotType = sup(RT, NewType),
- State#state{ret_type=TotType}.
-
-state__info_in(S, Label) ->
- state__info(S, {Label, in}).
-
-state__info(#state{info_map=IM}, Key) ->
- maps:get(Key, IM).
-
-state__update_info(State, LabelInfo, Rewrite) ->
- update_info(LabelInfo, State, [], Rewrite).
-
-update_info([{Label,InfoIn}|Rest], State, LabelAcc, Rewrite) ->
- case state__info_in_update(State, Label, InfoIn) of
- fixpoint ->
- if Rewrite ->
- update_info(Rest, State, [Label|LabelAcc], Rewrite);
- true ->
- update_info(Rest, State, LabelAcc, Rewrite)
- end;
- NewState ->
- update_info(Rest, NewState, [Label|LabelAcc], Rewrite)
- end;
-update_info([], State, LabelAcc, _Rewrite) ->
- {State, LabelAcc}.
-
-state__info_in_update(S=#state{info_map=IM,liveness=Liveness}, Label, Info) ->
- LabelIn = {Label, in},
- case IM of
- #{LabelIn := OldInfo} ->
- OldVars = maps:keys(OldInfo),
- case join_info_in(OldVars, OldInfo, Info) of
- fixpoint ->
- fixpoint;
- NewInfo ->
- S#state{info_map=IM#{LabelIn := NewInfo}}
- end;
- _ ->
- LiveIn = hipe_icode_ssa:ssa_liveness__livein(Liveness, Label),
- NamesLiveIn = [hipe_icode:var_name(Var) || Var <- LiveIn,
- hipe_icode:is_var(Var)],
- OldInfo = #{},
- case join_info_in(NamesLiveIn, OldInfo, Info) of
- fixpoint ->
- S#state{info_map=IM#{LabelIn => OldInfo}};
- NewInfo ->
- S#state{info_map=IM#{LabelIn => NewInfo}}
- end
- end.
-
-join_info_in(Vars, OldInfo, NewInfo) ->
- case join_info_in(Vars, OldInfo, NewInfo, #{}, false) of
- {Res, true} -> Res;
- {_, false} -> fixpoint
- end.
-
-join_info_in([Var|Left], Info1, Info2, Acc, Changed) ->
- case {Info1, Info2} of
- {#{Var := Val}, #{Var := Val}} ->
- NewTree = Acc#{Var => Val},
- join_info_in(Left, Info1, Info2, NewTree, Changed);
- {#{Var := Val1}, #{Var := Val2}} ->
- {NewChanged, NewVal} =
- case sup(Val1, Val2) of
- Val1 ->
- {Changed, Val1};
- Val ->
- {true, Val}
- end,
- NewTree = Acc#{Var => NewVal},
- join_info_in(Left, Info1, Info2, NewTree, NewChanged);
- {_, #{Var := Val}} ->
- NewTree = Acc#{Var => Val},
- join_info_in(Left, Info1, Info2, NewTree, true);
- {#{Var := Val}, _} ->
- NewTree = Acc#{Var => Val},
- join_info_in(Left, Info1, Info2, NewTree, Changed);
- {_, _} ->
- NewTree = Acc#{Var => none_type()},
- join_info_in(Left, Info1, Info2, NewTree, true)
- end;
-join_info_in([], _Info1, _Info2, Acc, NewChanged) ->
- {Acc, NewChanged}.
-
-enter_defines([Def|Rest], Info) ->
- enter_defines(Rest, enter_define(Def, Info));
-enter_defines([], Info) -> Info.
-
-enter_define({PossibleVar, Range = #range{}}, Info) ->
- case hipe_icode:is_var(PossibleVar) of
- true ->
- Info#{hipe_icode:var_name(PossibleVar) => Range};
- false ->
- Info
- end;
-enter_define(PossibleVar, Info) ->
- case hipe_icode:is_var(PossibleVar) of
- true ->
- case hipe_icode:variable_annotation(PossibleVar) of
- {range_anno, #ann{range=Range}, _} ->
- Info#{hipe_icode:var_name(PossibleVar) => Range};
- _ ->
- Info
- end;
- false ->
- Info
- end.
-
-enter_vals(Ins, Info) ->
- NewInfo = enter_defines(hipe_icode:args(Ins), Info),
- enter_defines(hipe_icode:defines(Ins), NewInfo).
-
-lookup(PossibleVar, Info) ->
- case hipe_icode:is_var(PossibleVar) of
- true ->
- PossibleVarName = hipe_icode:var_name(PossibleVar),
- case Info of
- #{PossibleVarName := Val} -> Val;
- _ -> none_type()
- end;
- false ->
- none_type()
- end.
-
-%% _________________________________________________________________
-%%
-%% The worklist.
-%%
-
-init_work(State) ->
- %% Labels = hipe_icode_cfg:reverse_postorder(state__cfg(State)),
- Labels = [hipe_icode_cfg:start_label(state__cfg(State))],
- {Labels, [], set_from_list(Labels)}.
-
-get_work({[Label|Left], List, Set}) ->
- NewWork = {Left, List, maps:remove(Label, Set)},
- {Label, NewWork};
-get_work({[], [], _Set}) ->
- fixpoint;
-get_work({[], List, Set}) ->
- get_work({lists:reverse(List), [], Set}).
-
-add_work(Work = {List1, List2, Set}, [Label|Left]) ->
- case Set of
- #{Label := _} ->
- add_work(Work, Left);
- _ ->
- %% io:format("Adding work: ~w\n", [Label]),
- add_work({List1, [Label|List2], Set#{Label => []}}, Left)
- end;
-add_work(Work, []) ->
- Work.
-
-convert_cfg_to_types(Cfg) ->
- Lbls = hipe_icode_cfg:reverse_postorder(Cfg),
- lists:foldl(fun convert_lbl_to_type/2, Cfg, Lbls).
-
-convert_lbl_to_type(Lbl, Cfg) ->
- BB = hipe_icode_cfg:bb(Cfg, Lbl),
- Code = hipe_bb:code(BB),
- NewCode = [convert_instr_to_type(I) || I <- Code],
- hipe_icode_cfg:bb_add(Cfg, Lbl, hipe_bb:mk_bb(NewCode)).
-
-convert_instr_to_type(I) ->
- Uses = hipe_icode:uses(I),
- UseSubstList = [{Use, convert_to_types(Use)} ||
- Use <- Uses, hipe_icode:is_annotated_variable(Use)],
- NewI = hipe_icode:subst_uses(UseSubstList, I),
- Defs = hipe_icode:defines(NewI),
- DefSubstList = [{Def, convert_to_types(Def)} ||
- Def <- Defs, hipe_icode:is_annotated_variable(Def)],
- hipe_icode:subst_defines(DefSubstList, NewI).
-
-convert_to_types(VarOrReg) ->
- Annotation =
- case hipe_icode:variable_annotation(VarOrReg) of
- {range_anno, Ann, _} ->
- {type_anno, convert_ann_to_types(Ann), fun erl_types:t_to_string/1};
- {type_anno, _, _} = TypeAnn ->
- TypeAnn
- end,
- hipe_icode:annotate_variable(VarOrReg, Annotation).
-
-convert_ann_to_types(#ann{range=#range{range={Min,Max}, other=false}}) ->
- t_from_range_unsafe(Min, Max);
-convert_ann_to_types(#ann{range=#range{range=empty, other=false}}) ->
- t_none();
-convert_ann_to_types(#ann{range=#range{other=true}, type=Type}) ->
- Type.
-
-%%=====================================================================
-%% Icode Coordinator Callbacks
-%%=====================================================================
-
--spec replace_nones([range()]) -> [range()].
-replace_nones(Args) ->
- [replace_none(Arg) || Arg <- Args].
-
-replace_none(Arg) ->
- case range__is_none(Arg) of
- true -> any_type();
- false -> Arg
- end.
-
--spec update__info([range()], [range()]) -> {boolean(), [ann()]}.
-update__info(NewRanges, OldRanges) ->
- SupFun = fun (Ann, Range) ->
- join_info(Ann, Range, fun safe_widen/3)
- end,
- EqFun = fun (X, Y) -> X =:= Y end,
- ResRanges = lists:zipwith(SupFun, OldRanges, NewRanges),
- Change = lists:zipwith(EqFun, ResRanges, OldRanges),
- {lists:all(fun (X) -> X end, Change), ResRanges}.
-
--spec new__info([range()]) -> [ann()].
-new__info(NewRanges) ->
- [#ann{range=Range,count=1,type=t_any()} || Range <- NewRanges].
-
--spec return__info([ann()]) -> [range()].
-return__info(Ranges) ->
- [Range || #ann{range=Range} <- Ranges].
-
--spec return_none() -> [range(),...].
-return_none() ->
- [none_type()].
-
--spec return_none_args(cfg(), mfa()) -> [range()].
-return_none_args(Cfg, {_M,_F,A}) ->
- NoArgs =
- case hipe_icode_cfg:is_closure(Cfg) of
- true -> hipe_icode_cfg:closure_arity(Cfg) + 1;
- false -> A
- end,
- lists:duplicate(NoArgs, none_type()).
-
--spec return_any_args(cfg(), mfa()) -> [range()].
-return_any_args(Cfg, {_M,_F,A}) ->
- NoArgs =
- case hipe_icode_cfg:is_closure(Cfg) of
- true -> hipe_icode_cfg:closure_arity(Cfg) + 1;
- false -> A
- end,
- lists:duplicate(NoArgs, any_type()).
-
-%%=====================================================================
-
-next_up_limit(X) when is_integer(X), X < 0 -> 0;
-next_up_limit(X) when is_integer(X), X < 255 -> 255;
-next_up_limit(X) when is_integer(X), X < 16#10ffff -> 16#10ffff;
-next_up_limit(X) when is_integer(X), X < 16#7ffffff -> 16#7ffffff;
-next_up_limit(X) when is_integer(X), X < 16#7fffffff -> 16#7fffffff;
-next_up_limit(X) when is_integer(X), X < 16#ffffffff -> 16#ffffffff;
-next_up_limit(X) when is_integer(X), X < 16#fffffffffff -> 16#fffffffffff;
-next_up_limit(X) when is_integer(X), X < 16#7fffffffffffffff -> 16#7fffffffffffffff;
-next_up_limit(_X) -> pos_inf.
-
-next_down_limit(X) when is_integer(X), X > 0 -> 0;
-next_down_limit(X) when is_integer(X), X > -256 -> -256;
-next_down_limit(X) when is_integer(X), X > -16#10ffff -> -16#10ffff;
-next_down_limit(X) when is_integer(X), X > -16#8000000 -> -16#8000000;
-next_down_limit(X) when is_integer(X), X > -16#80000000 -> -16#80000000;
-next_down_limit(X) when is_integer(X), X > -16#800000000000000 -> -16#800000000000000;
-next_down_limit(_X) -> neg_inf.
-
-%%--------------------------------------------------------------------
-%% Sets
-
--type set(E) :: #{E => []}.
-
-set_from_list([]) -> #{};
-set_from_list(L) ->
- maps:from_list([{E, []} || E <- L]).
-
-not_visited([], _) -> [];
-not_visited([E|T], M) ->
- case M of
- #{E := []} -> not_visited(T, M);
- _ -> [E|not_visited(T, M)]
- end.
-
-set_union(A, B) -> maps:merge(A, B).
diff --git a/lib/hipe/icode/hipe_icode_split_arith.erl b/lib/hipe/icode/hipe_icode_split_arith.erl
deleted file mode 100644
index 44c1a9578d..0000000000
--- a/lib/hipe/icode/hipe_icode_split_arith.erl
+++ /dev/null
@@ -1,548 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-------------------------------------------------------------------
-%% File : hipe_icode_split_arith.erl
-%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%% Description :
-%%
-%% Created : 12 Nov 2003 by Tobias Lindahl <tobiasl@it.uu.se>
-%%-------------------------------------------------------------------
--module(hipe_icode_split_arith).
-
--export([cfg/3]).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
-
--define(MIN_RATIO, 0.005).
-
-%%-------------------------------------------------------------------
-
--spec cfg(#cfg{}, mfa(), comp_options()) -> #cfg{}.
-
-cfg(Cfg, _MFA, Options) ->
- Icode = hipe_icode_cfg:cfg_to_linear(Cfg),
- case proplists:get_bool(split_arith_unsafe, Options) of
- true -> make_split_unsafe(Icode);
- _ ->
- case preprocess(Icode) of
- {do_not_split, _Ratio} ->
- Cfg;
- {split, _Ratio, Icode1} ->
- NewCfg = split(Icode1),
- %% hipe_icode_cfg:pp(NewCfg),
- NewCfg
- end
- end.
-
-check_nofix_const([Arg1|Arg2]) ->
- case hipe_icode:is_const(Arg1) of
- true ->
- Val1 = hipe_tagscheme:fixnum_val(hipe_icode:const_value(Arg1)),
- case hipe_tagscheme:is_fixnum(Val1) of
- true ->
- check_nofix_const(Arg2);
- false -> {no}
- end;
- false ->
- check_nofix_const(Arg2)
- end;
-check_nofix_const([]) -> true.
-
-check_const([I|Left]) ->
- case I of
- #icode_call{} ->
- case is_arith(I) of
- true ->
- Args = hipe_icode:call_args(I),
- case check_nofix_const(Args) of
- {no} -> {do_not_split};
- _ -> check_const(Left)
- end;
- _ -> check_const(Left)
- end;
- _ -> check_const(Left)
- end;
-check_const([]) -> {yes}.
-
-make_split_unsafe(Icode) ->
- LinearCode = hipe_icode:icode_code(Icode),
- NewLinearCode = change_unsafe(LinearCode),
- NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode),
- hipe_icode_cfg:linear_to_cfg(NewIcode).
-
-change_unsafe([I|Is]) ->
- case I of
- #icode_call{} ->
- case is_arith_extra_unsafe(I) of
- true ->
- NewOp = arithop_to_extra_unsafe(hipe_icode:call_fun(I)),
- NewI1 = hipe_icode:call_fun_update(I, NewOp),
- [NewI1|change_unsafe(Is)];
- false ->
- [I|change_unsafe(Is)]
- end;
- _ ->
- [I|change_unsafe(Is)]
- end;
-change_unsafe([]) -> [].
-
-preprocess(Icode) ->
- LinearCode = hipe_icode:icode_code(Icode),
- case check_const(LinearCode) of
- {do_not_split} -> %%io:format("NO FIXNUM....."),
- {do_not_split, 1.9849}; % Ratio val is ignored
- _ ->
- {NofArith, NofIns, NewLinearCode} = preprocess_code(LinearCode),
- case NofArith / NofIns of
- X when X >= ?MIN_RATIO ->
- NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode),
- {split, X, NewIcode};
- Y ->
- {do_not_split, Y}
- end
- end.
-
-preprocess_code([H|Code]) ->
- preprocess_code(Code, 0, 0, [H]).
-
-preprocess_code([I|Left], NofArith, NofIns, CodeAcc = [PrevI|_]) ->
- case I of
- #icode_call{} ->
- case is_arith(I) of
- true ->
- %% Note that we need to put these instructions in a separate
- %% basic block since we need the ability to fail to these
- %% instructions, but also fail from them. The basic block
- %% merger will take care of unnecessary splits.
-
- %% If call is an arithmetic operation replace the operation
- %% with the specified replacement operator.
- NewOp = arithop_to_split(hipe_icode:call_fun(I)),
- NewI = hipe_icode:call_fun_update(I, NewOp),
- case hipe_icode:is_label(PrevI) of
- true ->
- case (Left =:= []) orelse hipe_icode:is_label(hd(Left)) of
- true ->
- preprocess_code(Left, NofArith+1, NofIns+1, [NewI|CodeAcc]);
- false ->
- NewLabel = hipe_icode:mk_new_label(),
- NewLabelName = hipe_icode:label_name(NewLabel),
- NewI1 = hipe_icode:call_set_continuation(NewI, NewLabelName),
- preprocess_code(Left, NofArith+1, NofIns+1,
- [NewLabel, NewI1|CodeAcc])
- end;
- false ->
- RevPreCode =
- case hipe_icode:is_branch(PrevI) of
- true ->
- [hipe_icode:mk_new_label()];
- false ->
- NewLabel1 = hipe_icode:mk_new_label(),
- NewLabelName1 = hipe_icode:label_name(NewLabel1),
- [NewLabel1, hipe_icode:mk_goto(NewLabelName1)]
- end,
- case (Left =:= []) orelse hipe_icode:is_label(hd(Left)) of
- true ->
- preprocess_code(Left, NofArith+1, NofIns+1,
- [NewI|RevPreCode] ++ CodeAcc);
- false ->
- NewLabel2 = hipe_icode:mk_new_label(),
- NewLabelName2 = hipe_icode:label_name(NewLabel2),
- NewI1 = hipe_icode:call_set_continuation(NewI, NewLabelName2),
- preprocess_code(Left, NofArith+1, NofIns+1,
- [NewLabel2, NewI1|RevPreCode] ++ CodeAcc)
- end
- end;
- false ->
- preprocess_code(Left, NofArith, NofIns + 1, [I|CodeAcc])
- end;
- #icode_label{} ->
- %% Don't count labels as instructions.
- preprocess_code(Left, NofArith, NofIns, [I|CodeAcc]);
- _ ->
- preprocess_code(Left, NofArith, NofIns+1, [I|CodeAcc])
- end;
-preprocess_code([], NofArith, NofIns, CodeAcc) ->
- {NofArith, NofIns, lists:reverse(CodeAcc)}.
-
-split(Icode) ->
- LinearCode = hipe_icode:icode_code(Icode),
- %% create a new icode label for each existing icode label
- %% create mappings, NewToOld and OldToNew.
- AllLabels = lists:foldl(fun(I, Acc) ->
- case hipe_icode:is_label(I) of
- true -> [hipe_icode:label_name(I)|Acc];
- false -> Acc
- end
- end, [], LinearCode),
- {OldToNewMap, NewToOldMap} = new_label_maps(AllLabels),
-
- %% the call below doubles the number of basic blocks with the new
- %% labels instead of the old.
-
- NewLinearCode = map_code(LinearCode, OldToNewMap),
- NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode),
- NewCfg = hipe_icode_cfg:linear_to_cfg(NewIcode),
- NewCfg2 =
- insert_tests(NewCfg, [gb_trees:get(X, OldToNewMap) || X<-AllLabels],
- NewToOldMap, OldToNewMap),
- %% io:format("split(Cfg): Inserting testsL Done\n", []),
- NewCfg2.
-
-map_code(OldCode, LabelMap) ->
- AddedCode = map_code(OldCode, none, LabelMap, []),
- OldCode ++ AddedCode.
-
-map_code([I|Left], ArithFail, LabelMap, Acc) ->
- case I of
- #icode_call{} ->
- case is_arith(I) of
- true ->
- case hipe_icode:defines(I) of
- []->
- map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc]);
- _ ->
- NewOp = split_to_unsafe(I),
- NewI1 = hipe_icode:call_fun_update(I, NewOp),
- NewI2 = redirect(NewI1, LabelMap),
- NewI3 = hipe_icode:call_set_fail_label(NewI2, ArithFail),
- map_code(Left, ArithFail, LabelMap, [NewI3|Acc])
- end;
- false ->
- map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc])
- end;
- #icode_label{} ->
- LabelName = hipe_icode:label_name(I),
- NewLabel = hipe_icode:mk_label(gb_trees:get(LabelName, LabelMap)),
- map_code(Left, LabelName, LabelMap, [NewLabel|Acc]);
- _ ->
- map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc])
- end;
-map_code([], _ArithFail, _LabelMap, Acc) ->
- lists:reverse(Acc).
-
-insert_tests(Cfg, Labels,NewToOldMap, OldToNewMap) ->
- InfoMap = infomap_init(Labels),
- %%io:format("insert_tests/3: Finding testpoints ...\n", []),
- NewInfoMap = find_testpoints(Cfg, Labels, InfoMap),
- %%io:format("insert_tests/3: Finding testpoints: Done\n", []),
- %%io:format("insert_tests/3: Infomap: ~w\n", [gb_trees:to_list(NewInfoMap)]),
- make_tests(Cfg, NewInfoMap, NewToOldMap, OldToNewMap).
-
-find_testpoints(Cfg, Labels, InfoMap) ->
- case find_testpoints(Labels, InfoMap, Cfg, false) of
- {dirty, NewInfoMap} ->
- %%io:format("find_testpoints/3: Looping\n", []),
- find_testpoints(Cfg, Labels, NewInfoMap);
- fixpoint ->
- InfoMap
- end.
-
-find_testpoints([Lbl|Left], InfoMap, Cfg, Dirty) ->
- Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Lbl)),
- InfoOut = join_info(hipe_icode_cfg:succ(Cfg, Lbl), InfoMap),
- OldInfoIn = infomap_get_all(Lbl, InfoMap),
- NewInfoIn = traverse_code(lists:reverse(Code), InfoOut),
- case (gb_sets:is_subset(OldInfoIn, NewInfoIn) andalso
- gb_sets:is_subset(NewInfoIn, OldInfoIn)) of
- true ->
- find_testpoints(Left, InfoMap, Cfg, Dirty);
- false ->
- %%io:format("find_testpoints/4: Label: ~w: OldMap ~w\nNewMap: ~w\n",
- %% [Lbl, gb_sets:to_list(OldInfoIn), gb_sets:to_list(NewInfoIn)]),
- NewInfoMap = gb_trees:update(Lbl, NewInfoIn, InfoMap),
- find_testpoints(Left, NewInfoMap, Cfg, true)
- end;
-find_testpoints([], InfoMap, _Cfg, Dirty) ->
- if Dirty -> {dirty, InfoMap};
- true -> fixpoint
- end.
-
-traverse_code([I|Left], Info) ->
- NewInfo = kill_defines(I, Info),
- case I of
- #icode_call{} ->
- case is_unsafe_arith(I) of
- true ->
- %% The dst is sure to be a fixnum. Remove the 'killed' mark.
- Dst = hd(hipe_icode:call_dstlist(I)),
- NewInfo1 = gb_sets:delete_any({killed, Dst}, NewInfo),
- NewInfo2 =
- gb_sets:union(NewInfo1, gb_sets:from_list(hipe_icode:uses(I))),
- traverse_code(Left, NewInfo2);
- false ->
- traverse_code(Left, NewInfo)
- end;
- #icode_move{} ->
- Dst = hipe_icode:move_dst(I),
- case gb_sets:is_member(Dst, Info) of
- true ->
- %% The dst is an argument to an arith op. Transfer the test
- %% to the src and remove the 'killed' mark from the dst.
- NewInfo1 = gb_sets:delete({killed, Dst}, NewInfo),
- Src = hipe_icode:move_src(I),
- case hipe_icode:is_const(Src) of
- true ->
- traverse_code(Left, NewInfo1);
- false ->
- NewInfo2 = gb_sets:add(Src, NewInfo1),
- traverse_code(Left, NewInfo2)
- end;
- false ->
- traverse_code(Left, NewInfo)
- end;
- _ ->
- traverse_code(Left, NewInfo)
- end;
-traverse_code([], Info) ->
- Info.
-
-kill_defines(I, Info) ->
- Defines = hipe_icode:defines(I),
- case [X || X<-Defines, gb_sets:is_member(X, Info)] of
- [] ->
- Info;
- List ->
- TmpInfo = gb_sets:difference(Info, gb_sets:from_list(List)),
- gb_sets:union(gb_sets:from_list([{killed, X} || X <- List]), TmpInfo)
- end.
-
-make_tests(Cfg, InfoMap, NewToOldMap, OldToNewMap) ->
- %%io:format("make_tests 0:\n",[]),
- WorkList = make_worklist(gb_trees:keys(NewToOldMap), InfoMap,
- NewToOldMap, Cfg, []),
- %%io:format("make_tests 1:Worklist: ~w\n",[WorkList]),
- NewCfg = make_tests(WorkList, Cfg),
- %%io:format("make_tests 2\n",[]),
- %% If the arguments to this function are used in unsafe arith
- %% they should be marked as killed by a new start block.
- Args = hipe_icode_cfg:params(NewCfg),
- Start = hipe_icode_cfg:start_label(NewCfg),
- AltStart = gb_trees:get(Start, OldToNewMap),
- UnsafeIn = gb_sets:to_list(infomap_get(AltStart, InfoMap)),
- case [X || X <- UnsafeIn, Y <- Args, X =:= Y] of
- [] ->
- hipe_icode_cfg:start_label_update(NewCfg, AltStart);
- KilledArgs ->
- NewStart = hipe_icode:label_name(hipe_icode:mk_new_label()),
- NewCfg1 = insert_test_block(NewStart, AltStart, Start,
- KilledArgs, NewCfg),
- hipe_icode_cfg:start_label_update(NewCfg1, NewStart)
- end.
-
-make_worklist([Lbl|Left], InfoMap, LabelMap, Cfg, Acc) ->
- Vars = infomap_get_killed(Lbl, InfoMap),
- case gb_sets:is_empty(Vars) of
- true -> make_worklist(Left, InfoMap, LabelMap, Cfg, Acc);
- false ->
- %% io:format("make_worklist 1 ~w\n", [Vars]),
- NewAcc0 =
- [{Lbl, Succ, gb_trees:get(Succ, LabelMap),
- gb_sets:intersection(infomap_get(Succ, InfoMap), Vars)}
- || Succ <- hipe_icode_cfg:succ(Cfg, Lbl)],
- NewAcc = [{Label, Succ, FailLbl, gb_sets:to_list(PrunedVars)}
- || {Label, Succ, FailLbl, PrunedVars} <- NewAcc0,
- gb_sets:is_empty(PrunedVars) =:= false] ++ Acc,
- %% io:format("make_worklist 2\n", []),
- make_worklist(Left, InfoMap, LabelMap, Cfg, NewAcc)
- end;
-make_worklist([], _InfoMap, _LabelMap, _Cfg, Acc) ->
- Acc.
-
-make_tests([{FromLbl, ToLbl, FailLbl, Vars}|Left], Cfg) ->
- NewLbl = hipe_icode:label_name(hipe_icode:mk_new_label()),
- TmpCfg = insert_test_block(NewLbl, ToLbl, FailLbl, Vars, Cfg),
- NewCfg = hipe_icode_cfg:redirect(TmpCfg, FromLbl, ToLbl, NewLbl),
- make_tests(Left, NewCfg);
-make_tests([], Cfg) ->
- Cfg.
-
-insert_test_block(NewLbl, Succ, FailLbl, Vars, Cfg) ->
- Code = [hipe_icode:mk_type(Vars, fixnum, Succ, FailLbl, 0.99)],
- BB = hipe_bb:mk_bb(Code),
- hipe_icode_cfg:bb_add(Cfg, NewLbl, BB).
-
-infomap_init(Labels) ->
- infomap_init(Labels, gb_trees:empty()).
-
-infomap_init([Lbl|Left], Map) ->
- infomap_init(Left, gb_trees:insert(Lbl, gb_sets:empty(), Map));
-infomap_init([], Map) ->
- Map.
-
-join_info(Labels, Map) ->
- join_info(Labels, Map, gb_sets:empty()).
-
-join_info([Lbl|Left], Map, Set) ->
- join_info(Left, Map, gb_sets:union(Set, infomap_get(Lbl, Map)));
-join_info([], _Map, Set) ->
- Set.
-
-infomap_get(Lbl, Map) ->
- case gb_trees:lookup(Lbl, Map) of
- none -> gb_sets:empty();
- {value, Val} ->
- gb_sets:filter(fun(X) -> case X of
- {killed, _} -> false;
- _ -> true
- end
- end,
- Val)
- end.
-
-infomap_get_all(Lbl, Map) ->
- case gb_trees:lookup(Lbl, Map) of
- none -> gb_sets:empty();
- {value, Val} -> Val
- end.
-
-infomap_get_killed(Lbl, Map) ->
- case gb_trees:lookup(Lbl, Map) of
- none -> gb_sets:empty();
- {value, Val} ->
- Fun = fun(X, Acc) ->
- case X of
- {killed, Var} -> [Var|Acc];
- _ -> Acc
- end
- end,
- gb_sets:from_list(lists:foldl(Fun, [], gb_sets:to_list(Val)))
- end.
-
-%%%-------------------------------------------------------------------
-%%% General replace of '+'/'-' to super safe version
-
-arithop_to_split(Op) ->
- case Op of
- '+' -> gen_add;
- '-' -> gen_sub;
- _ -> Op
- end.
-
-%%%-------------------------------------------------------------------
-%%% Check if it's an arith op that needs to be split
-
-is_arith(I) ->
- case hipe_icode:call_fun(I) of
- '+' -> true;
- '-' -> true;
- gen_add -> true;
- gen_sub -> true;
- 'bor' -> true;
- 'bxor' -> true;
- 'bsr' ->
- %% Need to check that the second argument is a non-negative
- %% fixnum. We only allow for constants to simplify things.
- [_, Arg2] = hipe_icode:args(I),
- hipe_icode:is_const(Arg2) andalso (hipe_icode:const_value(Arg2) >= 0);
- 'bsl' ->
- %% There are major issues with bsl since it doesn't flag
- %% overflow. We cannot allow for this in this optimization pass.
- false;
- 'bnot' -> true;
- 'band' -> true;
- _ -> false
- end.
-
-%%%-------------------------------------------------------------------
-
-is_unsafe_arith(I) ->
- case hipe_icode:call_fun(I) of
- unsafe_add -> true;
- unsafe_sub -> true;
- unsafe_bor -> true;
- unsafe_bxor -> true;
- unsafe_bsr -> true;
- unsafe_bsl -> true;
- unsafe_bnot -> true;
- unsafe_band -> true;
- _ -> false
- end.
-
-split_to_unsafe(I) ->
- case hipe_icode:call_fun(I) of
- gen_add -> unsafe_add;
- gen_sub -> unsafe_sub;
- 'bor' -> unsafe_bor;
- 'bxor' -> unsafe_bxor;
- 'bsr' ->
- case is_arith(I) of
- true -> unsafe_bsr;
- false -> 'bsr'
- end;
- 'bsl' ->
- %% There are major issues with bsl since it doesn't flag
- %% overflow. We cannot allow for this in this optimization pass.
- 'bsl';
- 'bnot' -> unsafe_bnot;
- 'band' -> unsafe_band;
- Op -> Op
- end.
-
-%%%-------------------------------------------------------------------
-%%% FLAG = split_arith_unsafe
-
-is_arith_extra_unsafe(I) ->
- case hipe_icode:call_fun(I) of
- '+' -> true;
- '-' -> true;
- 'bor' -> true;
- 'bxor' -> true;
- 'bsr' -> is_arith(I);
- 'bsl' -> false; %% See comment in is_arith/1
- 'bnot' -> true;
- 'band' -> true;
- _ -> false
- end.
-
-arithop_to_extra_unsafe(Op) ->
- case Op of
- '+' -> extra_unsafe_add;
- '-' -> extra_unsafe_sub;
- 'bor' -> unsafe_bor;
- 'bxor' -> unsafe_bxor;
- 'bsr' -> unsafe_bsr;
- 'bsl' -> 'bsl'; %% See comment in split_to_unsafe/1
- 'bnot' -> unsafe_bnot;
- 'band' -> unsafe_band
- end.
-
-%%%-------------------------------------------------------------------
-
-redirect(I, LabelMap) ->
- case hipe_icode:successors(I) of
- [] -> I;
- Successors ->
- RedirectMap = [{X, gb_trees:get(X, LabelMap)} || X <- Successors],
- redirect_1(RedirectMap, I)
- end.
-
-redirect_1([{From, To}|Left], I) ->
- redirect_1(Left, hipe_icode:redirect_jmp(I, From, To));
-redirect_1([], I) ->
- I.
-
-new_label_maps(Labels) ->
- new_label_maps(Labels, gb_trees:empty(), gb_trees:empty()).
-
-new_label_maps([Lbl|Left], Map1, Map2) ->
- NewLabel = hipe_icode:label_name(hipe_icode:mk_new_label()),
- NewMap1 = gb_trees:insert(Lbl, NewLabel, Map1),
- NewMap2 = gb_trees:insert(NewLabel, Lbl, Map2),
- new_label_maps(Left, NewMap1, NewMap2);
-new_label_maps([], Map1, Map2) ->
- {Map1, Map2}.
diff --git a/lib/hipe/icode/hipe_icode_ssa.erl b/lib/hipe/icode/hipe_icode_ssa.erl
deleted file mode 100644
index 88317e9629..0000000000
--- a/lib/hipe/icode/hipe_icode_ssa.erl
+++ /dev/null
@@ -1,96 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_icode_ssa.erl
-%% Author :
-%% Created :
-%% Purpose : Provides interface functions for converting Icode into
-%% SSA form and back using the generic SSA converter.
-%%----------------------------------------------------------------------
-
--module(hipe_icode_ssa).
-
-%% The following defines are needed by the included file below
--define(CODE, hipe_icode).
--define(CFG, hipe_icode_cfg).
--define(LIVENESS, hipe_icode_liveness).
--define(LIVENESS_NEEDED, true).
-
--export_type([liveness/0]).
-
--include("hipe_icode.hrl").
--include("../ssa/hipe_ssa.inc").
-
-%% Declarations for exported functions which are Icode-specific.
--opaque liveness() :: liveness(icode_lbl(), #icode_variable{}).
--spec ssa_liveness__analyze(#cfg{}) -> liveness().
--spec ssa_liveness__livein(liveness(), icode_lbl()) -> [#icode_variable{}].
-%% -spec ssa_liveness__livein(liveness(), icode_lbl(), _) -> [#icode_var{}].
-
-%%----------------------------------------------------------------------
-%% Auxiliary operations which seriously differ between Icode and RTL.
-%%----------------------------------------------------------------------
-
-defs_to_rename(Statement) ->
- hipe_icode:defines(Statement).
-
-uses_to_rename(Statement) ->
- hipe_icode:uses(Statement).
-
-liveout_no_succ() ->
- [].
-
-%%----------------------------------------------------------------------
-
-reset_var_indx() ->
- hipe_gensym:set_var(icode, 0).
-
-%%----------------------------------------------------------------------
-
-is_fp_temp(Temp) ->
- hipe_icode:is_fvar(Temp).
-
-mk_new_fp_temp() ->
- hipe_icode:mk_new_fvar().
-
-%%----------------------------------------------------------------------
-%% Procedure : makePhiMove
-%% Purpose : Create an ICode-specific version of a move instruction
-%% depending on the type of the arguments.
-%% Arguments : Dst, Src - the arguments of a Phi instruction that is
-%% to be moved up the predecessor block as part
-%% of the SSA unconvert phase.
-%% Returns : Code
-%%----------------------------------------------------------------------
-
-makePhiMove(Dst, Src) ->
- case hipe_icode:is_fvar(Dst) of
- false ->
- case hipe_icode:is_fvar(Src) of
- false ->
- hipe_icode:mk_move(Dst, Src);
- true ->
- hipe_icode:mk_primop([Dst], unsafe_tag_float, [Src])
- end;
- true ->
- case hipe_icode:is_fvar(Src) of
- true ->
- hipe_icode:mk_move(Dst, Src);
- false ->
- hipe_icode:mk_primop([Dst], conv_to_float, [Src])
- end
- end.
-
-%%----------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode_ssa_const_prop.erl b/lib/hipe/icode/hipe_icode_ssa_const_prop.erl
deleted file mode 100644
index e2cd013b4c..0000000000
--- a/lib/hipe/icode/hipe_icode_ssa_const_prop.erl
+++ /dev/null
@@ -1,730 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% ============================================================================
-%% Filename : hipe_icode_ssa_const_prop.erl
-%% Authors : Daniel Luna, Erik Andersson
-%% Purpose : Perform sparse conditional constant propagation on Icode.
-%% Notes : Works on the control-flow graph.
-%%
-%% History : * 2003-03-05: Created.
-%% * 2003-08-11: Passed simple testsuite.
-%% * 2003-10-01: Passed compiler testsuite.
-%% ============================================================================
-%%
-%% Exports: propagate/1.
-%%
-%% ============================================================================
-%%
-%% TODO:
-%%
-%% Take care of failures in call and replace operation with appropriate
-%% failure.
-%%
-%% Handle ifs with non-binary operators
-%%
-%% We want multisets for easier (and faster) creation of env->ssa_edges
-%%
-%% Maybe do things with begin_handler, begin_try if possible
-%%
-%% Propagation of constant arguments when some of the arguments are bottom
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_icode_ssa_const_prop).
--export([propagate/1]).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
--include("hipe_icode_primops.hrl").
-
--define(CONST_PROP_MSG(Str,L), ok).
-%%-define(CONST_PROP_MSG(Str,L), io:format(Str,L)).
-
-%%-define(DEBUG, 1).
-
-%%-----------------------------------------------------------------------------
-%% Include stuff shared between SCCP on Icode and RTL.
-%% NOTE: Needs to appear after DEBUG is possibly defined.
-%%-----------------------------------------------------------------------------
-
--define(CODE, hipe_icode).
--define(CFG, hipe_icode_cfg).
-
--include("../ssa/hipe_ssa_const_prop.inc").
-
-%%-----------------------------------------------------------------------------
-
-visit_expression(Instruction, Environment) ->
- EvaluatedArguments = [lookup_lattice_value(Argument, Environment)
- || Argument <- hipe_icode:args(Instruction)],
- case Instruction of
- #icode_move{} ->
- visit_move (Instruction, EvaluatedArguments, Environment);
- #icode_if{} ->
- visit_if (Instruction, EvaluatedArguments, Environment);
- #icode_goto{} ->
- visit_goto (Instruction, EvaluatedArguments, Environment);
- #icode_type{} ->
- visit_type (Instruction, EvaluatedArguments, Environment);
- #icode_call{} ->
- visit_call (Instruction, EvaluatedArguments, Environment);
- #icode_switch_val{} ->
- visit_switch_val (Instruction, EvaluatedArguments, Environment);
- #icode_switch_tuple_arity{} ->
- visit_switch_tuple_arity(Instruction, EvaluatedArguments, Environment);
- #icode_begin_handler{} ->
- visit_begin_handler (Instruction, EvaluatedArguments, Environment);
- #icode_begin_try{} ->
- visit_begin_try (Instruction, EvaluatedArguments, Environment);
- #icode_fail{} ->
- visit_fail (Instruction, EvaluatedArguments, Environment);
- #icode_comment{} -> {[], [], Environment};
- #icode_end_try{} -> {[], [], Environment};
- #icode_enter{} -> {[], [], Environment};
- #icode_label{} -> {[], [], Environment};
- #icode_return{} -> {[], [], Environment}
- end.
-
-%%-----------------------------------------------------------------------------
-
-visit_begin_try(Instruction, [], Environment) ->
- Label = hipe_icode:begin_try_label(Instruction),
- Successor = hipe_icode:begin_try_successor(Instruction),
- {[Label, Successor], [], Environment}.
-
-%%-----------------------------------------------------------------------------
-
-visit_begin_handler(Instruction, _Arguments, Environment) ->
- Destinations = hipe_icode:begin_handler_dstlist(Instruction),
- {Environment1, SSAWork} =
- lists:foldl(fun (Dst, {Env0,Work0}) ->
- {Env, Work} = update_lattice_value({Dst, bottom}, Env0),
- {Env, Work ++ Work0}
- end,
- {Environment, []},
- Destinations),
- {[], SSAWork, Environment1}.
-
-%%-----------------------------------------------------------------------------
-
-visit_switch_val(Instruction, [Argument], Environment) ->
- Cases = hipe_icode:switch_val_cases(Instruction),
- FailLabel = hipe_icode:switch_val_fail_label(Instruction),
- case Argument of
- bottom ->
- FlowWork = [Label || {_Value, Label} <- Cases],
- FlowWork1 = [FailLabel | FlowWork],
- {FlowWork1, [], Environment};
- _ ->
- Target = get_switch_target(Cases, Argument, FailLabel),
- {[Target], [], Environment}
- end.
-
-%%-----------------------------------------------------------------------------
-
-visit_switch_tuple_arity(Instruction, [Argument], Environment) ->
- Cases = hipe_icode:switch_tuple_arity_cases(Instruction),
- FailLabel = hipe_icode:switch_tuple_arity_fail_label(Instruction),
- case Argument of
- bottom ->
- FlowWork = [Label || {_Value, Label} <- Cases],
- FlowWork1 = [FailLabel | FlowWork],
- {FlowWork1, [], Environment};
- Constant ->
- UnTagged = hipe_icode:const_value(Constant),
- case is_tuple(UnTagged) of
- true ->
- Target = get_switch_target(Cases, tuple_size(UnTagged), FailLabel),
- {[Target], [], Environment};
- false ->
- {[FailLabel], [], Environment}
- end
- end.
-
-%%-----------------------------------------------------------------------------
-
-get_switch_target([], _Argument, FailLabel) ->
- FailLabel;
-get_switch_target([{CaseValue, Target} | CaseList], Argument, FailLabel) ->
- case CaseValue =:= Argument of
- true ->
- Target;
- false ->
- get_switch_target(CaseList, Argument, FailLabel)
- end.
-
-%%-----------------------------------------------------------------------------
-
-visit_move(Instruction, [SourceValue], Environment) ->
- Destination = hipe_icode:move_dst(Instruction),
- {Environment1, SSAWork} = update_lattice_value({Destination, SourceValue},
- Environment),
- {[], SSAWork, Environment1}.
-
-%%-----------------------------------------------------------------------------
-
-visit_if(Instruction, Arguments, Environment) ->
- FlowWork =
- case evaluate_if(hipe_icode:if_op(Instruction), Arguments) of
- true ->
- TrueLabel = hipe_icode:if_true_label(Instruction),
- [TrueLabel];
- false ->
- FalseLabel = hipe_icode:if_false_label(Instruction),
- [FalseLabel];
- bottom ->
- TrueLabel = hipe_icode:if_true_label(Instruction),
- FalseLabel = hipe_icode:if_false_label(Instruction),
- [TrueLabel, FalseLabel]
- end,
- {FlowWork, [], Environment}.
-
-%%-----------------------------------------------------------------------------
-
-visit_goto(Instruction, _Arguments, Environment) ->
- GotoLabel = hipe_icode:goto_label(Instruction),
- FlowWork = [GotoLabel],
- {FlowWork, [], Environment}.
-
-%%-----------------------------------------------------------------------------
-
-visit_fail(Instruction, _Arguments, Environment) ->
- FlowWork = hipe_icode:successors(Instruction),
- {FlowWork, [], Environment}.
-
-%%-----------------------------------------------------------------------------
-
-visit_type(Instruction, Values, Environment) ->
- FlowWork =
- case evaluate_type(hipe_icode:type_test(Instruction), Values) of
- true ->
- TrueLabel = hipe_icode:type_true_label(Instruction),
- [TrueLabel];
- false ->
- FalseLabel = hipe_icode:type_false_label(Instruction),
- [FalseLabel];
- bottom ->
- TrueLabel = hipe_icode:type_true_label(Instruction),
- FalseLabel = hipe_icode:type_false_label(Instruction),
- [TrueLabel, FalseLabel]
- end,
- {FlowWork, [], Environment}.
-
-%%-----------------------------------------------------------------------------
-
-visit_call(Ins, Args, Environment) ->
- Dsts = hipe_icode:call_dstlist(Ins),
- Fun = hipe_icode:call_fun(Ins),
- Fail = call_fail_labels(Ins),
- Cont = call_continuation_labels(Ins),
- visit_call(Dsts, Args, Fun, Cont, Fail, Environment).
-
-visit_call(Dst, Args, Fun, Cont, Fail, Environment) ->
- {FlowWork, {Environment1, SSAWork}} =
- case lists:any(fun(X) -> (X =:= bottom) end, Args) of
- true ->
- {Fail ++ Cont, update_lattice_value({Dst, bottom}, Environment)};
- false ->
- ConstArgs = [hipe_icode:const_value(Argument) || Argument <- Args],
- try evaluate_call_or_enter(ConstArgs, Fun) of
- bottom ->
- {Fail ++ Cont, update_lattice_value({Dst, bottom}, Environment)};
- Constant ->
- {Cont, update_lattice_value({Dst, Constant}, Environment)}
- catch
- _:_ ->
- {Fail, update_lattice_value({Dst, bottom}, Environment)}
- end
- end,
- {FlowWork, SSAWork, Environment1}.
-
-%%-----------------------------------------------------------------------------
-
-call_fail_labels(I) ->
- case hipe_icode:call_fail_label(I) of
- [] -> [];
- Label -> [Label]
- end.
-
-call_continuation_labels(I) ->
- case hipe_icode:call_continuation(I) of
- [] -> [];
- Label -> [Label]
- end.
-
-%%-----------------------------------------------------------------------------
-
-%% Unary calls
-evaluate_call_or_enter([Argument], Fun) ->
- case Fun of
- mktuple ->
- hipe_icode:mk_const(list_to_tuple([Argument]));
- unsafe_untag_float ->
- hipe_icode:mk_const(float(Argument));
- conv_to_float ->
- hipe_icode:mk_const(float(Argument));
- fnegate ->
- hipe_icode:mk_const(0.0 - Argument);
- 'bnot' ->
- hipe_icode:mk_const(Argument);
- #unsafe_element{index=N} ->
- hipe_icode:mk_const(element(N, Argument));
- {erlang, hd, 1} ->
- hipe_icode:mk_const(hd(Argument));
- {erlang, tl, 1} ->
- hipe_icode:mk_const(tl(Argument));
- {erlang, atom_to_list, 1} ->
- hipe_icode:mk_const(atom_to_list(Argument));
- {erlang, list_to_atom, 1} ->
- hipe_icode:mk_const(list_to_atom(Argument));
- {erlang, tuple_to_list, 1} ->
- hipe_icode:mk_const(tuple_to_list(Argument));
- {erlang, list_to_tuple, 1} ->
- hipe_icode:mk_const(list_to_tuple(Argument));
- {erlang, length, 1} ->
- hipe_icode:mk_const(length(Argument));
- {erlang, size, 1} ->
- hipe_icode:mk_const(size(Argument));
- {erlang, bit_size, 1} ->
- hipe_icode:mk_const(bit_size(Argument));
- {erlang, byte_size, 1} ->
- hipe_icode:mk_const(byte_size(Argument));
- {erlang, tuple_size, 1} ->
- hipe_icode:mk_const(tuple_size(Argument));
- {erlang, abs, 1} ->
- hipe_icode:mk_const(abs(Argument));
- {erlang, round, 1} ->
- hipe_icode:mk_const(round(Argument));
- {erlang, trunc, 1} ->
- hipe_icode:mk_const(trunc(Argument));
- _ ->
- bottom
- end;
-%% Binary calls
-evaluate_call_or_enter([Argument1,Argument2], Fun) ->
- case Fun of
- '+' ->
- hipe_icode:mk_const(Argument1 + Argument2);
- '-' ->
- hipe_icode:mk_const(Argument1 - Argument2);
- '*' ->
- hipe_icode:mk_const(Argument1 * Argument2);
- '/' ->
- hipe_icode:mk_const(Argument1 / Argument2);
- 'band' ->
- hipe_icode:mk_const(Argument1 band Argument2);
- 'bor' ->
- hipe_icode:mk_const(Argument1 bor Argument2);
- 'bsl' ->
- hipe_icode:mk_const(Argument1 bsl Argument2);
- 'bsr' ->
- hipe_icode:mk_const(Argument1 bsr Argument2);
- 'bxor' ->
- hipe_icode:mk_const(Argument1 bxor Argument2);
- fp_add ->
- hipe_icode:mk_const(float(Argument1 + Argument2));
- fp_sub ->
- hipe_icode:mk_const(float(Argument1 - Argument2));
- fp_mul ->
- hipe_icode:mk_const(float(Argument1 * Argument2));
- fp_div ->
- hipe_icode:mk_const(Argument1 / Argument2);
- cons ->
- hipe_icode:mk_const([Argument1 | Argument2]);
- mktuple ->
- hipe_icode:mk_const(list_to_tuple([Argument1,Argument2]));
- #unsafe_update_element{index=N} ->
- hipe_icode:mk_const(setelement(N, Argument1, Argument2));
- {erlang, '++', 2} ->
- hipe_icode:mk_const(Argument1 ++ Argument2);
- {erlang, '--', 2} ->
- hipe_icode:mk_const(Argument1 -- Argument2);
- {erlang, 'div', 2} ->
- hipe_icode:mk_const(Argument1 div Argument2);
- {erlang, 'rem', 2} ->
- hipe_icode:mk_const(Argument1 rem Argument2);
- {erlang, append_element, 2} ->
- hipe_icode:mk_const(erlang:append_element(Argument1, Argument2));
- {erlang, element, 2} ->
- hipe_icode:mk_const(element(Argument1, Argument2));
- _Other ->
- %% io:format("In ~w(~w,~w)~n", [_Other,Argument1,Argument2]),
- bottom
- end;
-
-%% The rest of the calls
-evaluate_call_or_enter(Arguments, Fun) ->
- case Fun of
- mktuple ->
- hipe_icode:mk_const(list_to_tuple(Arguments));
- {erlang, setelement, 3} ->
- [Argument1, Argument2, Argument3] = Arguments,
- hipe_icode:mk_const(setelement(Argument1, Argument2, Argument3));
- _ ->
- bottom
- end.
-
-%%-----------------------------------------------------------------------------
-
-evaluate_if(Conditional, [Argument1, Argument2]) ->
- case ((Argument1 =:= bottom) or (Argument2 =:= bottom)) of
- true -> bottom;
- false -> evaluate_if_const(Conditional, Argument1, Argument2)
- end;
-evaluate_if(_Conditional, _Arguments) ->
- bottom.
-
-%%-----------------------------------------------------------------------------
-
-evaluate_if_const(Conditional, Argument1, Argument2) ->
- case Conditional of
- '=:=' -> Argument1 =:= Argument2;
- '==' -> Argument1 == Argument2;
- '=/=' -> Argument1 =/= Argument2;
- '/=' -> Argument1 /= Argument2;
- '<' -> Argument1 < Argument2;
- '>=' -> Argument1 >= Argument2;
- '=<' -> Argument1 =< Argument2;
- '>' -> Argument1 > Argument2;
- _ -> bottom
- end.
-
-%%-----------------------------------------------------------------------------
-
-evaluate_type(Type, Vals) ->
- case [X || X <- Vals, X =:= bottom] of
- [] -> evaluate_type_const(Type, Vals);
- _ -> bottom
- end.
-
-%%-----------------------------------------------------------------------------
-
-evaluate_type_const(Type, [Arg|Left]) ->
- Test =
- case {Type, hipe_icode:const_value(Arg)} of
- {nil, [] } -> true;
- {nil, _ } -> false;
- {cons, [_|_]} -> true;
- {cons, _ } -> false;
- {{tuple, N}, T} when tuple_size(T) =:= N -> true;
- {atom, A} when is_atom(A) -> true;
- {{atom, A}, A} when is_atom(A) -> true;
- {{record, A, S}, R} when tuple_size(R) =:= S,
- element(1, R) =:= A -> true;
- {{record, _, _}, _} -> false;
- _ -> bottom
- end,
- case Test of
- bottom -> bottom;
- false -> false;
- true -> evaluate_type_const(Type, Left)
- end;
-evaluate_type_const(_Type, []) ->
- true.
-
-%%-----------------------------------------------------------------------------
-%% Icode-specific code below
-%%-----------------------------------------------------------------------------
-
-update_instruction(Instruction, Environment) ->
- case Instruction of
- #icode_call{} ->
- update_call(Instruction, Environment);
- #icode_enter{} ->
- update_enter(Instruction, Environment);
- #icode_if{} ->
- update_if(Instruction, Environment);
- #icode_move{} ->
- update_move(Instruction, Environment);
- #icode_phi{} ->
- update_phi(Instruction, Environment);
- #icode_switch_val{} ->
- update_switch_val(Instruction, Environment);
- #icode_type{} ->
- update_type(Instruction, Environment);
- #icode_switch_tuple_arity{} ->
- update_switch_tuple_arity(Instruction, Environment);
- %% We could but don't handle: catch?, fail?
- #icode_begin_handler{} -> [Instruction];
- #icode_begin_try{} -> [Instruction];
- #icode_comment{} -> [Instruction];
- #icode_end_try{} -> [Instruction];
- #icode_fail{} -> [Instruction];
- #icode_goto{} -> [Instruction];
- #icode_label{} -> [Instruction];
- #icode_return{} -> [Instruction]
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_call(Instruction, Environment) ->
- DestList = hipe_icode:call_dstlist(Instruction),
- case DestList of
- [Destination] ->
- case lookup_lattice_value(Destination, Environment) of
- bottom ->
- NewArguments = update_arguments(
- hipe_icode:call_args(Instruction),
- Environment),
- [hipe_icode:call_args_update(Instruction, NewArguments)];
- X ->
- NewInstructions =
- case is_call_to_fp_op(Instruction) of
- true ->
- TmpIns =
- hipe_icode:call_fun_update(Instruction, unsafe_untag_float),
- [hipe_icode:call_args_update(TmpIns, [X])];
- false ->
- case hipe_icode:call_continuation(Instruction) of
- [] ->
- [hipe_icode:mk_move(Destination, X)];
- ContinuationLabel ->
- [hipe_icode:mk_move(Destination, X),
- hipe_icode:mk_goto(ContinuationLabel)]
- end
- end,
- ?CONST_PROP_MSG("call: ~w ---> ~w\n",
- [Instruction, NewInstructions]),
- NewInstructions
- end;
- %% [] -> %% No destination; we don't touch this
- %% List-> %% Means register allocation; not implemented at this point
- _ ->
- NewArguments = update_arguments(hipe_icode:call_args(Instruction),
- Environment),
- [hipe_icode:call_args_update(Instruction, NewArguments)]
- end.
-
-%%-----------------------------------------------------------------------------
-
-is_call_to_fp_op(Instruction) ->
- case hipe_icode:call_fun(Instruction) of
- fp_add -> true;
- fp_sub -> true;
- fp_mul -> true;
- fp_div -> true;
- fnegate -> true;
- conv_to_float -> true;
- unsafe_untag_float -> true;
- _ -> false
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_enter(Instruction, Environment) ->
- Args = hipe_icode:enter_args(Instruction),
- EvalArgs = [lookup_lattice_value(X, Environment) || X <- Args],
- Fun = hipe_icode:enter_fun(Instruction),
- case lists:any(fun(X) -> (X =:= bottom) end, EvalArgs) of
- true ->
- update_enter_arguments(Instruction, Environment);
- false ->
- ConstVals = [hipe_icode:const_value(X) || X <- EvalArgs],
- try evaluate_call_or_enter(ConstVals, Fun) of
- bottom ->
- update_enter_arguments(Instruction, Environment);
- Const ->
- Dst = hipe_icode:mk_new_var(),
- [hipe_icode:mk_move(Dst, Const),
- hipe_icode:mk_return([Dst])]
- catch
- _:_ ->
- update_enter_arguments(Instruction, Environment)
- end
- end.
-
-update_enter_arguments(Instruction, Env) ->
- NewArguments = update_arguments(hipe_icode:enter_args(Instruction), Env),
- [hipe_icode:enter_args_update(Instruction, NewArguments)].
-
-%%-----------------------------------------------------------------------------
-
-update_if(Instruction, Environment) ->
- Args = hipe_icode:if_args(Instruction),
- EvaluatedArguments = [lookup_lattice_value(Argument, Environment)
- || Argument <- Args],
- Op = hipe_icode:if_op(Instruction),
- case evaluate_if(Op, EvaluatedArguments) of
- true ->
- TrueLabel = hipe_icode:if_true_label(Instruction),
- ?CONST_PROP_MSG("ifT: ~w ---> goto ~w\n", [Instruction, TrueLabel]),
- [hipe_icode:mk_goto(TrueLabel)];
- false ->
- FalseLabel = hipe_icode:if_false_label(Instruction),
- ?CONST_PROP_MSG("ifF: ~w ---> goto ~w\n", [Instruction, FalseLabel]),
- [hipe_icode:mk_goto(FalseLabel)];
- bottom ->
- %% Convert the if-test to a type test if possible.
- Op = hipe_icode:if_op(Instruction),
- case Op =:= '=:=' orelse Op =:= '=/=' of
- false ->
- [hipe_icode:if_args_update(
- Instruction, update_arguments(Args, Environment))];
- true ->
- [Arg1, Arg2] = Args,
- case EvaluatedArguments of
- [bottom, bottom] ->
- [Instruction];
- [bottom, X] ->
- conv_if_to_type(Instruction, hipe_icode:const_value(X), Arg1);
- [X, bottom] ->
- conv_if_to_type(Instruction, hipe_icode:const_value(X), Arg2)
- end
- end
- end.
-
-conv_if_to_type(I, Const, Arg) when is_atom(Const);
- is_integer(Const);
- Const =:= [] ->
- Test =
- if is_atom(Const) -> {atom, Const};
- is_integer(Const) -> {integer, Const};
- true -> nil
- end,
- {T, F} =
- case hipe_icode:if_op(I) of
- '=:=' -> {hipe_icode:if_true_label(I),hipe_icode:if_false_label(I)};
- '=/=' -> {hipe_icode:if_false_label(I),hipe_icode:if_true_label(I)}
- end,
- NewI = hipe_icode:mk_type([Arg], Test, T, F),
- ?CONST_PROP_MSG("if: ~w ---> type ~w\n", [I, NewI]),
- [NewI];
-conv_if_to_type(I, Const, Arg) ->
- %% Note: we are potentially commuting the (equality) comparison here
- [hipe_icode:if_args_update(I, [Arg, hipe_icode:mk_const(Const)])].
-
-%%-----------------------------------------------------------------------------
-
-update_move(Instruction, Environment) ->
- Destination = hipe_icode:move_dst(Instruction),
- case lookup_lattice_value(Destination, Environment) of
- bottom ->
- [Instruction];
- X ->
- case hipe_icode:move_src(Instruction) of
- X ->
- [Instruction];
- _ ->
- ?CONST_PROP_MSG("move: ~w ---> ~w\n", [Instruction, X]),
- [hipe_icode:move_src_update(Instruction, X)]
- end
- %% == [hipe_icode:mk_move(Destination, X)]
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_phi(Instruction, Environment) ->
- Destination = hipe_icode:phi_dst(Instruction),
- case lookup_lattice_value(Destination, Environment) of
- bottom ->
- [Instruction];
- X ->
- ?CONST_PROP_MSG("phi: ~w ---> ~w\n", [Instruction, X]),
- [hipe_icode:mk_move(Destination, X)]
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_type(Instruction, Environment) ->
- EvaluatedArguments = [lookup_lattice_value(Argument, Environment) ||
- Argument <- hipe_icode:type_args(Instruction)],
- case evaluate_type(hipe_icode:type_test(Instruction), EvaluatedArguments) of
- true ->
- TrueLabel = hipe_icode:type_true_label(Instruction),
- ?CONST_PROP_MSG("typeT: ~w ---> goto ~w\n", [Instruction, TrueLabel]),
- [hipe_icode:mk_goto(TrueLabel)];
- false ->
- FalseLabel = hipe_icode:type_false_label(Instruction),
- ?CONST_PROP_MSG("typeF: ~w ---> goto ~w\n", [Instruction, FalseLabel]),
- [hipe_icode:mk_goto(FalseLabel)];
- bottom ->
- [Instruction]
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_switch_val(Instruction, Environment) ->
- Argument = hipe_icode:switch_val_term(Instruction),
- Value = lookup_lattice_value(Argument, Environment),
- case Value of
- bottom ->
- [Instruction];
- _ ->
- Cases = hipe_icode:switch_val_cases(Instruction),
- FailLabel = hipe_icode:switch_val_fail_label(Instruction),
- Target = get_switch_target(Cases, Value, FailLabel),
- ?CONST_PROP_MSG("sv: ~w ---> goto ~w\n", [Instruction, Target]),
- [hipe_icode:mk_goto(Target)]
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_switch_tuple_arity(Instruction, Environment) ->
- Argument = hipe_icode:switch_tuple_arity_term(Instruction),
- Value = lookup_lattice_value(Argument, Environment),
- case Value of
- bottom ->
- [Instruction];
- Constant ->
- UnTagged = hipe_icode:const_value(Constant),
- case is_tuple(UnTagged) of
- true ->
- Cases = hipe_icode:switch_tuple_arity_cases(Instruction),
- FailLabel = hipe_icode:switch_tuple_arity_fail_label(Instruction),
- Target = get_switch_target(Cases, tuple_size(UnTagged), FailLabel),
- ?CONST_PROP_MSG("sta: ~w ---> goto ~w\n", [Instruction, Target]),
- [hipe_icode:mk_goto(Target)];
- false ->
- [Instruction]
- %% TODO: Can the above be replaced with below??? Perhaps
- %% together with some sort of "generate failure".
- %% [hipe_icode:mk_goto(FailLabel)]
- end
- end.
-
-%%-----------------------------------------------------------------------------
-
-lookup_lattice_value(X, Environment) ->
- LatticeValues = env__lattice_values(Environment),
- case hipe_icode:is_const(X) of
- true ->
- X;
- false ->
- case gb_trees:lookup(X, LatticeValues) of
- none ->
- ?WARNING_MSG("Earlier compiler steps generated erroneous "
- "code for X = ~w. We are ignoring this.\n",[X]),
- bottom;
- {value, top} ->
- ?EXIT({"lookup_lattice_value, top", X});
- {value, Y} ->
- Y
- end
- end.
-
-%%-----------------------------------------------------------------------------
-
-update_arguments(ArgumentList, Environment) ->
- [case lookup_lattice_value(X, Environment) of
- bottom ->
- X;
- Constant ->
- Constant
- end || X <- ArgumentList].
-
-%%----------------------------- End of file -----------------------------------
diff --git a/lib/hipe/icode/hipe_icode_ssa_copy_prop.erl b/lib/hipe/icode/hipe_icode_ssa_copy_prop.erl
deleted file mode 100644
index b92b7cfa7a..0000000000
--- a/lib/hipe/icode/hipe_icode_ssa_copy_prop.erl
+++ /dev/null
@@ -1,36 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-------------------------------------------------------------------
-%% File : hipe_icode_ssa_copy_prop.erl
-%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%% Description : Performs copy propagation on SSA form.
-%%
-%% Created : 4 Apr 2003 by Tobias Lindahl <tobiasl@it.uu.se>
-%%-------------------------------------------------------------------
-
--module(hipe_icode_ssa_copy_prop).
-
-%%
-%% modules given as parameters
-%%
--define(code, hipe_icode).
--define(cfg, hipe_icode_cfg).
-
-%%
-%% appropriate include files
-%%
--include("hipe_icode.hrl").
--include("../flow/cfg.hrl").
--include("../ssa/hipe_ssa_copy_prop.inc").
diff --git a/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl b/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
deleted file mode 100644
index ec4840980d..0000000000
--- a/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
+++ /dev/null
@@ -1,1439 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%=======================================================================
-%% File : hipe_icode_ssa_struct_reuse.erl
-%% Author : Ragnar Osterlund <ragoster@gmail.com>
-%% student at the compiler techniques 2 course at UU 2007
-%% Description : HiPE module that removes redundant or partially redundant
-%% structure creations from Icode.
-%% It does so by inserting redundant expressions as late
-%% as possible in the CFG, with the exception of loops where
-%% expressions are moved to just before the loop head.
-%% Current Icode instructions that can be moved are mktuple()
-%% and cons() primop calls. It also handles cases like
-%% f({Z}) -> {Z}. It does so by looking at the structure of
-%% the match, and recognizes tuples and conses.
-%%=======================================================================
-
--module(hipe_icode_ssa_struct_reuse).
-
--export([struct_reuse/1]).
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
--include("../flow/cfg.hrl").
-
--define(SET, ordset).
--define(SETS, ordsets).
-%%-define(DEBUG, true).
-
--define(MKTUPLE, mktuple).
--define(CONS, cons).
--define(SR_INSTR_TYPE, sr_instr_type).
--define(SR_STRUCT_INSTR_TYPE, sr_struct_instr_type).
-
--type struct_type() :: {?CONS | ?MKTUPLE, icode_term_arg(), any()}.
--type struct_elems() :: {icode_var(), non_neg_integer(), icode_term_arg()}.
-
-%% DATATYPE AREA
-
-%%-----------------------------------------------------------------------------
-%% maps
-%% The maps are used to identify variables and expressions.
-%% The maps are:
-%%
-%% expr - a map that contains value numbered structure expressions, ie
-%% mktuple and cons expression. The key is the value number and the value
-%% is an expr record.
-%%
-%% instr - maps the semantic instruction to an expression value number,
-%% that is, a key in the expr map above.
-%%
-%% var - maps variables to expression value numbers. These variables are
-%% defined or used by the structure expressions.
-
--record(maps, {var = gb_trees:empty() :: gb_trees:tree(),
- instr = gb_trees:empty() :: gb_trees:tree(),
- expr = gb_trees:empty() :: gb_trees:tree()}).
-
-maps_var(#maps{var = Out}) -> Out.
-maps_instr(#maps{instr = Out}) -> Out.
-maps_expr(#maps{expr = Out}) -> Out.
-
-maps_expr_keys(Maps) -> gb_trees:keys(maps_expr(Maps)).
-maps_expr_values(Maps) -> gb_trees:values(maps_expr(Maps)).
-
-maps_instr_lookup(Instr, Maps) -> gb_trees:lookup(Instr, maps_instr(Maps)).
-maps_instr_enter(Instr, ExprId, Maps) ->
- NewInstr = gb_trees:enter(Instr, ExprId, maps_instr(Maps)),
- Maps#maps{instr = NewInstr}.
-
-maps_expr_get(Id, Maps) -> gb_trees:get(Id, maps_expr(Maps)).
-maps_expr_enter(Expr, Maps) ->
- NewExprMap = gb_trees:enter(expr_id(Expr), Expr, maps_expr(Maps)),
- Maps#maps{expr = NewExprMap}.
-
-maps_var_get(Var, Maps) -> gb_trees:get(Var, maps_var(Maps)).
-maps_var_lookup(Var, #maps{var = VarMap}) -> gb_trees:lookup(Var, VarMap).
-maps_var_enter(Var, Info, Maps = #maps{var = VarMap}) ->
- NewMap = gb_trees:enter(Var, Info, VarMap),
- Maps#maps{var = NewMap}.
-maps_var_insert(Var, Info, Maps = #maps{var = VarMap}) ->
- NewMap = gb_trees:insert(Var, Info, VarMap),
- Maps#maps{var = NewMap}.
-
-maps_balance(Maps) ->
- Maps#maps{instr = gb_trees:balance(maps_instr(Maps)),
- expr = gb_trees:balance(maps_expr(Maps)),
- var = gb_trees:balance(maps_var(Maps))}.
-
-maps_expr_key_enter(Expr, Maps) ->
- NewMaps = maps_instr_enter(expr_key(Expr), expr_id(Expr), Maps),
- maps_expr_enter(Expr, NewMaps).
-
-%%-----------------------------------------------------------------------------
-%% expr
-%% An expression record. Contains information about a structure expression.
-%% The fields are:
-%%
-%% id - the value number of the expression
-%% key - the semantic instruction, as defined in icode, with destination
-%% removed and arguments rewritten.
-%% defs - destination variable to hold the value of the expression.
-%% direct_replace - indicates whether the expression shall be replaced wherever
-%% it occurs, although it might not have been inserted. This is used for
-%% the expressions that are detected by the icode type constructs.
-%% inserts - a list of node labels that will insert this expression
-%% use - a list of expression value numbers that use the value of this
-%% expression
-
--record(expr, {id = none :: 'none' | non_neg_integer(),
- key = none :: 'none' | tuple(), % illegal_icode_instr()
- defs = none :: 'none' | [icode_var()],
- direct_replace = false :: boolean(),
- inserts = ?SETS:new() :: ?SETS:?SET(_),
- use = ?SETS:new() :: ?SETS:?SET(_)}).
-
-expr_id(#expr{id = Out}) -> Out.
-expr_defs(#expr{defs = Out}) -> Out.
-expr_key(#expr{key = Out}) -> Out.
-expr_inserts(#expr{inserts = Out}) -> Out.
-expr_use(#expr{use = Out}) -> Out.
-expr_direct_replace(#expr{direct_replace = Out}) -> Out.
-
-expr_use_add(Expr = #expr{use = UseSet}, Use) ->
- Expr#expr{use = ?SETS:add_element(Use, UseSet)}.
-
-%% expr_key_set(Expr, In) -> Expr#expr{key = In}.
-expr_direct_replace_set(Expr, In) -> Expr#expr{direct_replace = In}.
-expr_inserts_set(Expr, In) -> Expr#expr{inserts = In}.
-
-expr_create(Key, Defs) ->
- NewExprId = new_expr_id(),
- #expr{id = NewExprId, key = Key, defs = Defs}.
-
-%%-----------------------------------------------------------------------------
-%% varinfo
-%% A variable mapping info. Contains info about variable references.
-%% The fields are:
-%%
-%% use - a set of expression value numbers that use this variable
-%% ref - the variable which value this variable will be assigned
-%% when expression is replaced. This is encoded as {N, M} where
-%% N is the expression value number and M is the nth destination
-%% variable defined by the expression N.
-%% elem - indicates that this variable has been detected to be a part of
-%% a tuple. The field contains a {V, N} tuple where V is the variable
-%% that refers to the structure that this variable is an element in
-%% and N is the position that the element occurs on in the tuple. Eg.
-%% {{var, 3}, 2} means that the variable {var, 3} refers to a tuple
-%% in which this variable is on second place.
-%% exprid - a expression value number which is the expression that
-%% the variable is defined by.
-
--record(varinfo, {use = ?SETS:new() :: ?SETS:?SET(_),
- ref = none :: 'none' | {non_neg_integer(), non_neg_integer()},
- elem = none :: 'none' | {icode_var(), non_neg_integer()},
- exprid = none :: 'none' | non_neg_integer()}).
-
-varinfo_exprid(#varinfo{exprid = Out}) -> Out.
-
-varinfo_use_add(#varinfo{use = UseSet} = I, Use) ->
- I#varinfo{use = ?SETS:add_element(Use, UseSet)}.
-
-%%-----------------------------------------------------------------------------
-%% node - a node in the temp CFG.
-%%
-%% label - the label of the node in the original CFG
-%% pred - a list of predecessors to this node
-%% succ - a list of successors to this node
-%% code - code from CFG filtered to only contain structure instructions
-%% non_struct_defs - a list of variable definitions that are not defined
-%% by structures
-%% up_expr - upwards exposed expression value numbers
-%% killed_expr - killed expressions value numbers
-%% sub_inserts - a set of labels of nodes that defines one or more
-%% expressions and that are in a subtree of this node
-%% inserts - a set of expression value numbers to be inserted into the node
-%% antic_in - a set of expression value numbers that are anticipated into
-%% the node
-%% antic_out - a set of expression value numbers that are anticipated out of
-%% the node
-%% phi - a tree of node labels which is defined in phi functions in the node
-%% varmap - a list of variable tuples {V1, V2} that maps a variable that are
-%% the output of phi functions in sub blocks, V1, into a variable
-%% flowing from the block of this node, V2.
-%% struct_type - a list of {V, N} tuples that indicates that V is a tuple
-%% with N elements. These are added from the icode primop type().
-%% struct_elems - a list of {VD, N, VS} tuples where VD is a variable in the N'th position
-%% in VS. These are added from the icode primop unsafe_element()
-
--record(node, {
- label = none :: 'none' | icode_lbl(),
- pred = none :: 'none' | [icode_lbl()],
- succ = none :: 'none' | [icode_lbl()],
- code = [] :: [tuple()], % [illegal_icode_instr()]
- phi = gb_trees:empty() :: gb_trees:tree(),
- varmap = [] :: [{icode_var(), icode_var()}],
- pre_loop = false :: boolean(),
- non_struct_defs = gb_sets:new() :: gb_sets:set(),
- up_expr = none :: 'none' | ?SETS:?SET(_),
- killed_expr = none :: 'none' | ?SETS:?SET(_),
- sub_inserts = ?SETS:new() :: ?SETS:?SET(_),
- inserts = ?SETS:new() :: ?SETS:?SET(_),
- antic_in = none :: 'none' | ?SETS:?SET(_),
- antic_out = none :: 'none' | ?SETS:?SET(_),
- struct_type = [] :: [struct_type()],
- struct_elems = [] :: [struct_elems()]}).
-
-node_sub_inserts(#node{sub_inserts = Out}) -> Out.
-node_inserts(#node{inserts = Out}) -> Out.
-node_antic_out(#node{antic_out = Out}) -> Out.
-node_antic_in(#node{antic_in = Out}) -> Out.
-node_killed_expr(#node{killed_expr = Out}) -> Out.
-node_pred(#node{pred = Out}) -> Out.
-node_succ(#node{succ = Out}) -> Out.
-node_label(#node{label = Out}) -> Out.
-node_code(#node{code = Out}) -> Out.
-node_non_struct_defs(#node{non_struct_defs = Out}) -> Out.
-node_up_expr(#node{up_expr = Out}) -> Out.
-node_pre_loop(#node{pre_loop = Out}) -> Out.
-node_struct_type(#node{struct_type = Out}) -> Out.
-%% node_atom_type(#node{atom_type = Out}) -> Out.
-node_struct_elems(#node{struct_elems = Out}) -> Out.
-
-node_pre_loop_set(Node) -> Node#node{pre_loop = true}.
-
-node_phi_add(Node = #node{phi = Phi}, Pred, Value) ->
- NewList =
- case gb_trees:lookup(Pred, Phi) of
- {value, List} -> [Value | List];
- none -> [Value]
- end,
- Node#node{phi = gb_trees:enter(Pred, NewList, Phi)}.
-
-node_phi_get(#node{phi = Phi}, Pred) ->
- case gb_trees:lookup(Pred, Phi) of
- {value, List} -> List;
- none -> []
- end.
-
-node_code_add(Node = #node{code = Code}, Instr) ->
- Node#node{code = [Instr | Code]}.
-
-node_code_rev(Node = #node{code = Code}) ->
- Node#node{code = lists:reverse(Code)}.
-
-node_struct_type_add(Node = #node{struct_type = T}, Value) ->
- Node#node{struct_type = [Value | T]}.
-
-%% node_atom_type_add(Node = #node{atom_type = T}, Value) ->
-%% Node#node{atom_type = [Value | T]}.
-
-node_struct_elems_add(Node = #node{struct_elems = T}, Value) ->
- Node#node{struct_elems = [Value | T]}.
-
-node_non_struct_defs_list(Node) ->
- gb_sets:to_list(node_non_struct_defs(Node)).
-
-node_non_struct_instr_add(Node, Instr) ->
- DefList = hipe_icode:defines(Instr),
- Tmp = gb_sets:union(node_non_struct_defs(Node), gb_sets:from_list(DefList)),
- Node#node{non_struct_defs = Tmp}.
-
-node_set_sub_inserts(Node, In) -> Node#node{sub_inserts = In}.
-
-node_add_insert(Node, In) ->
- NewIns = ?SETS:add_element(In, node_inserts(Node)),
- Node#node{inserts = NewIns}.
-
-node_union_sub_inserts(Node, SubIns) ->
- NewSubIns = ?SETS:union(SubIns, node_sub_inserts(Node)),
- node_set_sub_inserts(Node, NewSubIns).
-
-node_varmap_set(Node, Vars) ->
- Node#node{varmap = Vars}.
-
-node_varmap_lookup(#node{varmap = Varmap}, Var) ->
- case lists:keyfind(Var, 1, Varmap) of
- {_, NewVar} -> NewVar;
- false -> Var
- end.
-
-node_create(Label, Pred, Succ) ->
- #node{label = Label, pred = Pred, succ = Succ}.
-
-%%-----------------------------------------------------------------------------
-%% nodes - describes the new temporary CFG
-%%
-%% domtree - the dominator tree of the original CFG
-%% labels - the labels of the original CFG, filtered to only contain non fail trace paths
-%% postorder - the postorder walk of labels of the original CFG, filtered to only contain non fail trace paths
-%% rev_postorder - reverse of postorder.
-%% start_label - the start basic block label.
-%% all_expr - all expression value numbers that the CFG defines
-%% tree - the tree of nodes, with labels as keys and node records as values
-
--record(nodes, {
- domtree = none :: 'none' | hipe_dominators:domTree(),
- labels = none :: 'none' | [icode_lbl()],
- postorder = none :: 'none' | [icode_lbl()],
- start_label = none :: 'none' | icode_lbl(),
- rev_postorder = none :: 'none' | [icode_lbl()],
- all_expr = none :: 'none' | [non_neg_integer()],
- tree = gb_trees:empty() :: gb_trees:tree()}).
-
-nodes_postorder(#nodes{postorder = Out}) -> Out.
-nodes_rev_postorder(#nodes{rev_postorder = Out}) -> Out.
-nodes_tree(#nodes{tree = Out}) -> Out.
-nodes_domtree(#nodes{domtree = Out}) -> Out.
-nodes_start_label(#nodes{start_label = Out}) -> Out.
-
-nodes_tree_is_empty(#nodes{tree = Tree}) ->
- gb_trees:is_empty(Tree).
-
-nodes_tree_set(Tree, Nodes) -> Nodes#nodes{tree = Tree}.
-nodes_all_expr_set(AllExpr, Nodes) -> Nodes#nodes{all_expr = AllExpr}.
-
-nodes_tree_values(Nodes) ->
- gb_trees:values(nodes_tree(Nodes)).
-
-get_node(Label, Nodes) ->
- gb_trees:get(Label, nodes_tree(Nodes)).
-
-enter_node(Node, Nodes) ->
- nodes_tree_set(gb_trees:enter(node_label(Node), Node, nodes_tree(Nodes)), Nodes).
-
-remove_node(Node, Nodes) ->
- nodes_tree_set(gb_trees:delete(node_label(Node), nodes_tree(Nodes)), Nodes).
-
-nodes_create() -> #nodes{}.
-
-%%-----------------------------------------------------------------------------
-%% update
-%% record used when updating the CFG, keeping track of which expressions
-%% have been inserted and their mappings to variable names.
-%%
-%% inserted - maps an expression to a list of variables
-%% del_red_test - flag that is set to true when the reduction test
-%% has been inserted is used to move the reduction test.
-
--record(update, {inserted = gb_trees:empty() :: gb_trees:tree(),
- del_red_test = false :: boolean()}).
-
-update_inserted_lookup(#update{inserted = Inserted}, ExprId) ->
- gb_trees:lookup(ExprId, Inserted).
-
-update_inserted_add_new(Update = #update{inserted = Inserted}, ExprId, Defs) ->
- VarList = [case hipe_icode:is_var(Def) of
- true -> hipe_icode:mk_new_var();
- false ->
- case hipe_icode:is_reg(Def) of
- true -> hipe_icode:mk_new_reg();
- false ->
- true = hipe_icode:is_fvar(Def),
- hipe_icode:mk_new_fvar()
- end
- end || Def <- Defs],
- NewInserted = gb_trees:enter(ExprId, VarList, Inserted),
- {Update#update{inserted = NewInserted}, VarList}.
-
-update_inserted_add(Update = #update{inserted = Inserted}, ExprId, Defs) ->
- Update#update{inserted = gb_trees:enter(ExprId, Defs, Inserted)}.
-
-update_del_red_test(#update{del_red_test = DelRed}) -> DelRed.
-update_del_red_test_set(Update) ->
- Update#update{del_red_test = true}.
-
-%%-----------------------------------------------------------------------------
-%% CODE AREA
-
-%%-----------------------------------------------------------------------------
-%% Main function called from the hipe_main module
-
--spec struct_reuse(cfg()) -> cfg().
-
-struct_reuse(CFG) ->
- %% debug_init_case_count(?SR_INSTR_TYPE),
- %% debug_init_case_count(?SR_STRUCT_INSTR_TYPE),
-
- %% debug_function({wings_ask,ask_unzip,3}, CFG),
- %% debug_function(nil, CFG),
- %% set_debug_flag(true),
- %% debug_struct("CFG In: ", CFG),
- %% debug_cfg_pp(CFG),
-
- init_expr_id(),
-
- Nodes = construct_nodes(CFG),
-
- case nodes_tree_is_empty(Nodes) of
- false ->
- Maps = create_maps(Nodes),
-
- Nodes3 = init_nodes(Nodes, Maps),
- Nodes4 = calc_anticipated(Nodes3),
-
- {Nodes5, Maps3} = calc_inserts(Nodes4, Maps),
-
- Nodes6 = update_nodes_inserts(Nodes5, Maps3),
-
- %% debug_list("ExprMap: ", gb_trees:to_list(Maps3#maps.expr)),
- %% debug_list("VarMap: ", gb_trees:to_list(maps_var(Maps3))),
- %% debug_nodes(Nodes6),
-
- %% update the cfg
- CFG1 = rewrite_cfg(CFG, Nodes6, Maps3),
- CFG2 = hipe_icode_ssa:remove_dead_code(CFG1),
- CFGOut = hipe_icode_ssa_copy_prop:cfg(CFG2),
- %% CFGOut = CFG1,
-
- %% print_struct("CFG: ", CFG),
- %% debug_cfg_pp(CFG),
- %% debug_cfg_pp(CFGOut),
-
- %% debug_print_case_count(?SR_STRUCT_INSTR_TYPE),
- %% debug_print_case_count(?SR_INSTR_TYPE),
- %% debug("Done~n"),
- %% debug_struct("CFG Out: ", CFGOut),
- CFGOut;
- true ->
- CFG
- end.
-
-%%-----------------------------------------------------------------------------
-%% Calculate simplified CFG with all fail paths removed
-
-construct_nodes(CFG) ->
- %% all important dominator tree
- DomTree = hipe_dominators:domTree_create(CFG),
-
- %% construct initial nodes
- {Nodes, NonFailSet} = nodes_from_cfg(CFG, DomTree),
-
- %% remove nodes on fail paths
- NewNodes = prune_nodes(Nodes, NonFailSet),
-
- %% fill in misc node tree info
- Postorder = [Label || Label <- hipe_icode_cfg:postorder(CFG),
- gb_sets:is_member(Label, NonFailSet)],
-
- %% check postorder is valid
- PostOrderTmp = hipe_icode_cfg:postorder(CFG),
- LabelsTmp = hipe_icode_cfg:labels(CFG),
- case length(PostOrderTmp) =/= length(LabelsTmp) of
- true ->
- print("Warning, Postorder and Labels differ!~n"),
- print_struct("Postorder: ", PostOrderTmp),
- print_struct("Labels: ", LabelsTmp);
- false ->
- done
- end,
-
- RevPostorder = lists:reverse(Postorder),
-
- StartLabel = hipe_icode_cfg:start_label(CFG),
- NewTree = gb_trees:balance(nodes_tree(NewNodes)),
-
- NewNodes#nodes{postorder = Postorder,
- rev_postorder = RevPostorder,
- start_label = StartLabel,
- tree = NewTree,
- domtree = DomTree}.
-
-%%-----------------------------------------------------------------------------
-%% Constructs a tree of nodes, one node for each basic block in CFG
-
-nodes_from_cfg(CFG, DomTree) ->
- lists:foldl(fun(Label, {NodesAcc, NonFailAcc}) ->
- Code = hipe_bb:code(hipe_icode_cfg:bb(CFG, Label)),
- Pred = hipe_icode_cfg:pred(CFG, Label),
- Succ = hipe_icode_cfg:succ(CFG, Label),
- %% debug_struct("Label: ", Label),
- %% debug_struct("Code: ", Code),
-
- %% Find all structures and phi functions.
- %% Find all defines in this bb that are not from structures
- %% and add them to NonStructDefs, later to be used for calculating upwards
- %% exposed expressions, and killed expressions.
- %% Also find all non fail blocks, ie backtrace from return blocks,
- %% and add them to NewNonFailAcc
-
- Node = node_create(Label, Pred, Succ),
-
- {NewNode, NewNonFailAcc, PreLoopPreds} =
- lists:foldl(fun(Instr, {NodeAcc, NFAcc, PLPAcc}) ->
- case instr_type(Instr) of
- struct ->
- {node_code_add(NodeAcc, Instr), NFAcc, PLPAcc};
- return ->
- {NodeAcc, get_back_trace_rec(CFG, Label, NFAcc), PLPAcc};
- {struct_elems, NumElem, DstVar, SrcVar} ->
- NewNodeAcc = node_struct_elems_add(NodeAcc, {DstVar, NumElem, SrcVar}),
- {node_non_struct_instr_add(NewNodeAcc, Instr), NFAcc, PLPAcc};
- {struct_type, NumElems, Var, Type} ->
- {node_struct_type_add(NodeAcc, {Type, Var, NumElems}), NFAcc, PLPAcc};
- {tuple_arity, Var, Cases} ->
- NewNodeAcc =
- lists:foldl(fun(Case, NAcc) ->
- case Case of
- {{const, {flat, Arity}}, _} ->
- Tuple = {?MKTUPLE, Var, Arity},
- node_struct_type_add(NAcc, Tuple);
- _ -> NAcc
- end
- end, NodeAcc, Cases),
- {NewNodeAcc, NFAcc, PLPAcc};
- %% {atom_type, Atom, Var} ->
- %% {node_atom_type_add(NodeAcc, {Var, Atom}), NFAcc, PLPAcc};
- phi ->
- Def = hipe_icode:phi_dst(Instr),
- Part = lists:foldl(fun(P = {Pr, PredVar}, {IsDef, NotDom}) ->
- case hipe_dominators:domTree_dominates(Label, Pr, DomTree) of
- false ->
- {IsDef, [P | NotDom]};
- true ->
- {IsDef andalso PredVar =:= Def, NotDom}
- end
- end, {true, []}, hipe_icode:phi_arglist(Instr)),
-
- case Part of
- {true, [{P, V}]} ->
- %% This is the only case recognized so far. All phi
- %% sub block references a static variable that is
- %% assigned the same value again in the phi function.
- {node_phi_add(NodeAcc, P, {Def, V}),
- NFAcc, ?SETS:add_element(P, PLPAcc)};
-
- {false, [{P, _}]} ->
- {node_non_struct_instr_add(NodeAcc, Instr),
- NFAcc, ?SETS:add_element(P, PLPAcc)};
-
- _ ->
- {node_non_struct_instr_add(NodeAcc, Instr), NFAcc, PLPAcc}
- end;
- _ ->
- {node_non_struct_instr_add(NodeAcc, Instr), NFAcc, PLPAcc}
- end
- end, {Node, NonFailAcc, ?SETS:new()}, Code),
-
- %% insert the new node
- NewNodesAcc = enter_node(node_code_rev(NewNode), NodesAcc),
-
- %% Set the pre loop flag of all nodes that are predecessor to this node
- %% and that are the first nodes prior to a loop.
- NewNodesAcc2 =
- lists:foldl(fun(Lbl, NsAcc) ->
- PredNode = get_node(Lbl, NsAcc),
- NewPredNode = node_pre_loop_set(PredNode),
- NewPredNode2 = node_varmap_set(NewPredNode, node_phi_get(NewNode, Lbl)),
-
- enter_node(NewPredNode2, NsAcc)
- end, NewNodesAcc, PreLoopPreds),
-
- {NewNodesAcc2, NewNonFailAcc}
- end, {nodes_create(), gb_sets:new()}, hipe_icode_cfg:reverse_postorder(CFG)).
-
-%%-----------------------------------------------------------------------------
-%% Get all labels from Label to root of CFG, ie backtraces from Label.
-
-get_back_trace_rec(CFG, Label, LabelSet) ->
- %% debug_struct("Label :", Label),
- %% debug_struct("Set :", gb_sets:to_list(LabelSet)),
- case gb_sets:is_member(Label, LabelSet) of
- false ->
- Preds = hipe_icode_cfg:pred(CFG, Label),
- lists:foldl(fun(Lbl, SetAcc) ->
- get_back_trace_rec(CFG, Lbl, SetAcc)
- end, gb_sets:add(Label, LabelSet), Preds);
- true -> LabelSet
- end.
-
-%%-----------------------------------------------------------------------------
-%% Remove all fail block paths and successors and predecessors
-%% That are on fail paths
-
-prune_nodes(Nodes, NonFailSet) ->
- lists:foldl(fun(Node, NodesAcc) ->
- case gb_sets:is_member(node_label(Node), NonFailSet) of
- true ->
- NewSucc = [L || L <- node_succ(Node), gb_sets:is_member(L, NonFailSet)],
- NewPred = [L || L <- node_pred(Node), gb_sets:is_member(L, NonFailSet)],
- enter_node(Node#node{succ = NewSucc, pred = NewPred}, NodesAcc);
- false ->
- remove_node(Node, NodesAcc)
- end
- end, Nodes, nodes_tree_values(Nodes)).
-
-%%-----------------------------------------------------------------------------
-%% Map calculations.
-
-%%-----------------------------------------------------------------------------
-%% Create a maps structure from the Nodes record
-
-create_maps(Nodes) ->
- Maps = lists:foldl(fun(Label, MapsAcc) ->
- Node = get_node(Label, Nodes),
- NewMapsAcc = maps_from_node_struct_type(MapsAcc, Node),
- NewMapsAcc2 = maps_from_node_struct_elems(NewMapsAcc, Node),
- %% NewMapsAcc3 = maps_from_node_atom_type(NewMapsAcc2, Node),
- maps_from_node_code(NewMapsAcc2, Node)
- end, #maps{}, nodes_rev_postorder(Nodes)),
- maps_balance(Maps).
-
-%%-----------------------------------------------------------------------------
-%% Add all elements in the struct_type list of Node to Maps as expressions
-
-maps_from_node_struct_type(Maps, Node) ->
- %% debug_struct("Node Label: ", node_label(Node)),
- %% debug_struct("Node Tuple Type: ", node_struct_type(Node)),
- lists:foldl(fun({Type, Var, Size}, MapsAcc) ->
- Key = create_elem_expr_key(Size, Var, []),
- InstrKey = hipe_icode:mk_primop([], Type, Key),
- NewExpr2 = expr_create(InstrKey, [Var]),
- NewExpr3 = expr_direct_replace_set(NewExpr2, true),
- maps_expr_key_enter(NewExpr3, MapsAcc)
- end, Maps, node_struct_type(Node)).
-
-create_elem_expr_key(0, _, Key) -> Key;
-create_elem_expr_key(N, Var, Key) ->
- create_elem_expr_key(N - 1, Var, [{Var, N} | Key]).
-
-%%-----------------------------------------------------------------------------
-%%maps_from_node_atom_type(Maps, Node) ->
-%% lists:foldl(fun({Var, Atom}, MapsAcc) ->
-%% case maps_var_lookup(Var, MapsAcc) of
-%% none ->
-%% MapsAcc;
-%% {value, #varinfo{elem = none}} ->
-%% MapsAcc;
-%% {value, #varinfo{elem = {Src, Num, ExprId}}} ->
-%% Expr = maps_expr_get(ExprId, MapsAcc),
-%% Key = expr_key(Expr),
-%%
-%% Filter = fun(Arg) ->
-%% case Arg of
-%% {Src, Num, ExprId} ->
-%% hipe_icode:mk_const(Atom);
-%% _ ->
-%% Arg
-%% end end,
-%%
-%% NewKey = replace_call_variables(Filter, Key),
-%% NewExpr = expr_create(NewKey, expr_defs(Expr)),
-%% maps_expr_key_enter(NewExpr, MapsAcc)
-%% end
-%% end, Maps, node_atom_type(Node)).
-
-%%-----------------------------------------------------------------------------
-%% Add all struct_elemns in Node to Maps as variables
-
-maps_from_node_struct_elems(Maps, Node) ->
- lists:foldl(fun({Dst, Num, Src}, MapsAcc) ->
- VarInfo = #varinfo{elem = {Src, Num}},
- maps_var_insert(Dst, VarInfo, MapsAcc)
- end, Maps, node_struct_elems(Node)).
-
-%%-----------------------------------------------------------------------------
-%% Get all expressions defined by the Node and insert them into Maps.
-%% Also insert information about all affected variables into Maps.
-
-maps_from_node_code(Maps, Node) ->
- %% debug_struct("Node Label: ", Label),
- %% debug_struct("Node Code: ", Code),
- %% Label = node_label(Node),
- lists:foldl(fun(Instr, MapsAcc) ->
- %% create two keys that are used to reference this structure creation
- %% instruction, so that we can lookup its expression value number
- %% later.
- InstrKey = hipe_icode:call_dstlist_update(Instr, []),
-
- %% Fetch the two keys from the instruction
- {HasElems, RefKey, ElemKey} =
- replace_call_vars_elems(MapsAcc, InstrKey),
-
- %% create a new expr record or lookup an existing one.
- case HasElems of
- true ->
- %% The instruction contains uses of variables that are
- %% part of another structure.
- case maps_instr_lookup(ElemKey, MapsAcc) of
- {value, ExprId} ->
- %% The instruction is equal to a structure that has
- %% already been created. This is the f({Z}) -> {Z}
- %% optimization. I.e. there is no need to create {Z} again.
- %% Also lookup if ExprId is defining a variable that is
- %% already an element in another structure. If so,
- %% use that element. This takes care of nested structures
- %% such as f({X, {Y, Z}}) -> {X, {Y, Z}}.
-
- #expr{defs = [Var]} = maps_expr_get(ExprId, MapsAcc),
- StructElem =
- case maps_var_lookup(Var, MapsAcc) of
- {value, #varinfo{elem = Elem, exprid = none}} when Elem =/= none ->
- Elem;
- _ -> none
- end,
- Defines = hipe_icode:defines(Instr),
- maps_varinfos_create(Defines, ExprId, StructElem, MapsAcc);
- none ->
- %% create a new expression
- maps_expr_varinfos_create(Instr, RefKey, MapsAcc)
- end;
- false ->
- %% create a new expression
- maps_expr_varinfos_create(Instr, RefKey, MapsAcc)
- end
- end, Maps, node_code(Node)).
-
-%%-----------------------------------------------------------------------------
-%% Creates varinfo structures with exprid set to ExprId for all
-%% variables contained in Defines. These are put into MapsIn.
-
-maps_varinfos_create(Defines, ExprId, Elem, MapsIn) ->
- VarInfo = #varinfo{exprid = ExprId, elem = Elem},
- {MapsOut, _} =
- lists:foldl(fun (Def, {Maps, NumAcc}) ->
- NewVarInfo = VarInfo#varinfo{ref = {ExprId, NumAcc}},
- {maps_var_insert(Def, NewVarInfo, Maps), NumAcc + 1}
- end, {MapsIn, 1}, Defines),
- MapsOut.
-
-%%-----------------------------------------------------------------------------
-%% Creates a new expression from RefKey if RefKey is not already reffering
-%% to an expression. Also creates varinfo structures for all variables defined
-%% and used by Instr. Result is put in Maps.
-
-maps_expr_varinfos_create(Instr, RefKey, Maps) ->
- Defines = hipe_icode:defines(Instr),
- {ExprId, Maps2} =
- case maps_instr_lookup(RefKey, Maps) of
- {value, EId} ->
- {EId, Maps};
- none ->
- NewExpr = expr_create(RefKey, Defines),
- {expr_id(NewExpr), maps_expr_key_enter(NewExpr, Maps)}
- end,
- Maps3 = maps_varinfos_create(Defines, ExprId, none, Maps2),
- update_maps_var_use(Instr, ExprId, Maps3).
-
-%%-----------------------------------------------------------------------------
-%% A variable replacement function that returns a tuple of three elements
-%% {T, K1, K2}, where T indicates if Instr contained variables that where
-%% elements of other structures, K1 is the Instr with all variables that
-%% references another structure replaced, and K2 is K1 but also with all
-%% variables that are elements of other structures replaced.
-
-replace_call_vars_elems(Maps, Instr) ->
- VarMap = maps_var(Maps),
- {HasElems, Vars, Elems} =
- lists:foldr(fun(Arg, {HasElems, Vars, Elems}) ->
- case hipe_icode:is_const(Arg) of
- false ->
- case gb_trees:lookup(Arg, VarMap) of
- none ->
- {HasElems, [Arg | Vars], [Arg | Elems]};
- {value, #varinfo{ref = none, elem = none}} ->
- {HasElems, [Arg | Vars], [Arg | Elems]};
- {value, #varinfo{ref = Ref, elem = none}} ->
- {HasElems, [Ref | Vars], [Ref | Elems]};
- {value, #varinfo{ref = none, elem = Elem}} ->
- {true, [Arg | Vars], [Elem | Elems]};
- {value, #varinfo{ref = Ref, elem = Elem}} ->
- {true, [Ref | Vars], [Elem | Elems]}
- end;
- true ->
- {HasElems, [Arg | Vars], [Arg | Elems]}
- end end, {false, [], []}, hipe_icode:args(Instr)),
- {HasElems, hipe_icode:call_args_update(Instr, Vars),
- hipe_icode:call_args_update(Instr, Elems)}.
-
-%%-----------------------------------------------------------------------------
-%% Updates the usage information of all variables used by Instr to also
-%% contain Id and updates Maps to contain the new variable information.
-%% Also updates the expressions where the updated variables are used to
-%% contain the use information.
-
-update_maps_var_use(Instr, Id, Maps) ->
- lists:foldl(fun(Use, MapsAcc) ->
- VarInfo = get_varinfo(Use, MapsAcc),
- NewVarInfo = varinfo_use_add(VarInfo, Id),
- MapsAcc2 = maps_var_enter(Use, NewVarInfo, MapsAcc),
- case varinfo_exprid(VarInfo) of
- none ->
- MapsAcc2;
- VarExprId ->
- Expr = maps_expr_get(VarExprId, MapsAcc2),
- NewExpr = expr_use_add(Expr, Id),
- maps_expr_enter(NewExpr, MapsAcc2)
- end
- end, Maps, hipe_icode:uses(Instr)).
-
-%%-----------------------------------------------------------------------------
-%% Looks up an old variable info or creates a new one if none is found.
-
-get_varinfo(Var, Maps) ->
- case maps_var_lookup(Var, Maps) of
- {value, Info} ->
- Info;
- none ->
- #varinfo{}
- end.
-
-%%-----------------------------------------------------------------------------
-%% filters all arguments to a function call Instr that are not constants
-%% through the Filter function, and replaces the arguments in Instr with
-%% the result.
-
-replace_call_variables(Filter, Instr) ->
- NewArgs = [case hipe_icode:is_const(Arg) of
- false -> Filter(Arg);
- true -> Arg
- end || Arg <- hipe_icode:args(Instr)],
- hipe_icode:call_args_update(Instr, NewArgs).
-
-%%-----------------------------------------------------------------------------
-%% Init nodes from node local expression information
-
-init_nodes(Nodes, Maps) ->
- AllExpr = maps_expr_keys(Maps),
- lists:foldl(fun(Node, NodesAcc) ->
- UEExpr = calc_up_exposed_expr(maps_var(Maps), Node),
- %% print_list("Up ExprSet: ", ?SETS:to_list(UEExpr)),
-
- KilledExpr = calc_killed_expr(Node, Maps),
- %% print_list("Killed: ", ?SETS:to_list(KilledExpr)),
-
- %% End nodes have no anticipated out
- AnticOut =
- case node_succ(Node) of
- [] ->
- ?SETS:new();
- _ ->
- AllExpr
- end,
- enter_node(Node#node{up_expr = UEExpr,
- killed_expr = KilledExpr,
- antic_out = AnticOut}, NodesAcc)
- end, nodes_all_expr_set(AllExpr, Nodes), nodes_tree_values(Nodes)).
-
-%%-----------------------------------------------------------------------------
-%% Calculate the upwards exposed expressions for a node.
-
-calc_up_exposed_expr(VarMap, Node) ->
- %% debug_struct("UpExpr label: ", node_label(Node)),
- NonStructDefs = node_non_struct_defs(Node),
- {_, ExprIdSet} =
- lists:foldl(fun(Instr, {NotToUseAcc, ExprIdAcc}) ->
- Defs = hipe_icode:defines(Instr),
- Uses = hipe_icode:uses(Instr),
- IsNotToUse =
- lists:any(fun(Use) -> gb_sets:is_member(Use, NotToUseAcc) end, Uses),
- case IsNotToUse of
- false ->
- NewExprIdAcc =
- lists:foldl(fun(Def, Acc) ->
- #varinfo{exprid = Id} = gb_trees:get(Def, VarMap),
- ?SETS:add_element(Id, Acc) end, ExprIdAcc, Defs),
- {NotToUseAcc, NewExprIdAcc};
- true ->
- NewNotToUse =
- gb_sets:union(gb_sets:from_list(Defs), NotToUseAcc),
- {NewNotToUse, ExprIdAcc}
- end
- end, {NonStructDefs, ?SETS:new()}, node_code(Node)),
- ExprIdSet.
-
-%%-----------------------------------------------------------------------------
-%% Calculate killed expression for node
-
-calc_killed_expr(Node, Maps) ->
- calc_killed_expr_defs(node_non_struct_defs_list(Node), ?SETS:new(), Maps).
-
-calc_killed_expr_defs(Defs, UseSet, Maps) ->
- lists:foldl(fun(Def, Acc) ->
- case maps_var_lookup(Def, Maps) of
- none ->
- Acc;
- {value, #varinfo{use = Use}} ->
- ?SETS:union(Acc, calc_killed_expr_use(Use, Maps))
- end
- end, UseSet, Defs).
-
-calc_killed_expr_use(ExprIds, Maps) ->
- ?SETS:fold(fun(Id, Acc) ->
- Expr = maps_expr_get(Id, Maps),
- ?SETS:union(Acc, calc_killed_expr_use(expr_use(Expr), Maps))
- end, ExprIds, ExprIds).
-
-%%-----------------------------------------------------------------------------
-%% Calculate the anticipated in and anticipated out sets for each node
-
-calc_anticipated(NodesIn) ->
- calc_anticipated_rec(NodesIn, nodes_postorder(NodesIn)).
-
-calc_anticipated_rec(NodesIn, []) -> NodesIn;
-calc_anticipated_rec(NodesIn, WorkIn) ->
- {NodesOut, WorkOut} =
- lists:foldl(fun(Label, {NodesAcc, WorkAcc}) ->
- Node = get_node(Label, NodesAcc),
-
- %debug_struct("~nNode Label: ", Label),
-
- AnticIn = ?SETS:union(node_up_expr(Node),
- ?SETS:subtract(node_antic_out(Node), node_killed_expr(Node))),
-
- %debug_struct("AnticIn: ", AnticIn),
- case (node_antic_in(Node) =:= AnticIn) of
- false ->
- NewNodes1 = enter_node(Node#node{antic_in = AnticIn}, NodesAcc),
- Preds = node_pred(Node),
- %debug_struct("Preds: ", Preds),
-
- NewNodes2 =
- lists:foldl(fun(Label2, NodesAcc2) ->
- PredNode = get_node(Label2, NodesAcc2),
- AnticOut = ?SETS:intersection(AnticIn, node_antic_out(PredNode)),
- %debug_struct("Pred Node Label: ", Label2),
- %debug_struct("Pred AnticOut: ", AnticOut),
-
- enter_node(PredNode#node{antic_out = AnticOut}, NodesAcc2)
- end, NewNodes1, Preds),
-
- NewWork = add_work_list(Preds, WorkAcc),
- %debug_struct("New Work: ", NewWork),
-
- {NewNodes2, NewWork};
- true ->
- {NodesAcc, WorkAcc}
- end
- end, {NodesIn, new_work()}, WorkIn),
-
- calc_anticipated_rec(NodesOut, get_work_list(WorkOut)).
-
-%%-----------------------------------------------------------------------------
-%% Function that adds inserts to expressions from nodes which either
-%% have an upwards exposed expression or dominate more than one node
-%% that inserts the same expression or the node is a prior to loop
-%% node. The inserted info is stored in the #expr records in the expr
-%% map of the #maps structure.
-
-calc_inserts(NodesIn, MapsIn) ->
- DomTree = nodes_domtree(NodesIn),
-
- lists:foldl(fun(Label, {NodesAcc, MapsAcc}) ->
- Node = get_node(Label, NodesAcc),
-
- %% get some basic properties.
- UpExpr = node_up_expr(Node),
- AnticOut = node_antic_out(Node),
- SubIns = node_sub_inserts(Node),
-
- %% debug_struct("Label: ", Label),
-
- {HasIns, NewMapsAcc} =
- ?SETS:fold(fun(ExprId, {HasInsAcc, MapsAcc2}) ->
- Expr = maps_expr_get(ExprId, MapsAcc2),
-
- ExprIns = expr_inserts(Expr),
- ExprSubIns = ?SETS:intersection(ExprIns, SubIns),
-
- %% There are three cases when to insert an expression
- %% 1. The expression is defined at least twice in the subtree of this
- %% node, that is length(ExprSubIns) > 1.
- %% 2. It is defined in the node and is upwards exposed.
- %% 3. The node is a block just above a loop, so we should move
- %% all anticipated expressions to the node.
-
- case length(ExprSubIns) > 1 orelse ?SETS:is_element(ExprId, UpExpr)
- orelse node_pre_loop(Node) of
- true ->
- %% get labels of all sub blocks that inserts the expression and
- %% that are dominated by the current node.
- Dominates =
- ?SETS:filter(fun(SubLabel) ->
- hipe_dominators:domTree_dominates(Label, SubLabel, DomTree)
- end, ExprSubIns),
-
- %% remove inserts labels from insert labelset.
- NewIns = ?SETS:subtract(ExprIns, Dominates),
- NewIns2 = ?SETS:add_element(Label, NewIns),
-
- %% update the node.
- NewMaps =
- maps_expr_enter(expr_inserts_set(Expr, NewIns2), MapsAcc2),
- {true, NewMaps};
- false ->
- {HasInsAcc, MapsAcc2}
- end
- end, {false, MapsAcc}, ?SETS:union(AnticOut, UpExpr)),
-
- %% Check if there was an insert into this node,
- %% and if so add to the sub inserts set.
- NewSubIns =
- case HasIns of
- true ->
- ?SETS:add_element(Label, SubIns);
- false ->
- SubIns
- end,
-
- %% update sub inserts for all predecessors to the node.
- NewNodes2 =
- lists:foldl(fun(PredLabel, NodesAcc2) ->
- PredNode = get_node(PredLabel, NodesAcc2),
- enter_node(node_union_sub_inserts(PredNode, NewSubIns), NodesAcc2)
- end, NodesAcc, node_pred(Node)),
-
- {NewNodes2, NewMapsAcc}
-
- end, {NodesIn, MapsIn}, nodes_postorder(NodesIn)).
-
-%%-----------------------------------------------------------------------------
-%% Update the insert sets of each node in the node tree.
-%% That is, move the insert information from the expressions to
-%% the actual nodes that perform the inserts.
-
-update_nodes_inserts(Nodes, Maps) ->
- lists:foldl(fun(Expr, NodesAcc) ->
- ExprId = expr_id(Expr),
- ?SETS:fold(fun(Label, NsAcc) ->
- Nd = get_node(Label, NsAcc),
- enter_node(node_add_insert(Nd, ExprId), NsAcc)
- end, NodesAcc, expr_inserts(Expr))
- end, Nodes, maps_expr_values(Maps)).
-
-%%-----------------------------------------------------------------------------
-%% Rewrite CFG functions
-
-%%-----------------------------------------------------------------------------
-%% Do the code updating from the info in the nodes and maps structures. This
-%% is a proxy function for rewrite_cfg/6
-rewrite_cfg(CFG, Nodes, Maps) ->
- {NewCFG, _Visited} =
- rewrite_cfg(CFG, ?SETS:new(), #update{}, Nodes, Maps, [nodes_start_label(Nodes)]),
- %% debug_struct("Visited: ", _Visited),
- NewCFG.
-
-%%-----------------------------------------------------------------------------
-%% rewrite_cfg
-%% traverse the CFG in reverse postorder and rewrite each basic block before
-%% rewriteing its children. Pass along to each BB update the mappings of
-%% inserted expressions in the Update record.
-
-rewrite_cfg(CFG, Visited, Update, Nodes, Maps, Labels) ->
- lists:foldl(fun(Label, {CFGAcc, VisitedAcc}) ->
- case ?SETS:is_element(Label, VisitedAcc) of
- false ->
- %% debug_struct("Visit: ", Label),
- Node = get_node(Label, Nodes),
- NewVisitedAcc = ?SETS:add_element(Label, VisitedAcc),
- {NewCFGAcc, NewUpdate} = rewrite_bb(CFGAcc, Update, Maps, Node),
- %% debug_struct("Update inserted: ", update_inserted_list(NewUpdate)),
- rewrite_cfg(NewCFGAcc, NewVisitedAcc, NewUpdate, Nodes, Maps, node_succ(Node));
- true ->
- {CFGAcc, VisitedAcc}
- end
- end, {CFG, Visited}, Labels).
-
-%%-----------------------------------------------------------------------------
-%% rewrite one single basic block in the CFG as described by the properties
-%% in the Node for that block. Uses the Maps and Update info to lookup
-%% the instructions and expressions to insert or delete.
-
-rewrite_bb(CFG, Update, Maps, Node) ->
- #node{pre_loop = PreLoop, label = Label, up_expr = UpExpr, inserts = Inserts} = Node,
-
- Code = hipe_bb:code(hipe_icode_cfg:bb(CFG, Label)),
-
- %debug_struct("RW Label: ", Label),
- %debug_struct("Inserts", Inserts),
-
- DelRed = update_del_red_test(Update),
- Delete = ?SETS:subtract(UpExpr, Inserts),
-
- %% local function that gets the instruction and defines list of an
- %% expression id in the current node and and returns them.
- GetInstrFunc = fun(Expr) ->
- Instr = expr_key(Expr),
- Defs = expr_defs(Expr),
- NewInstr =
- if
- PreLoop ->
- replace_call_variables(fun(Var) ->
- node_varmap_lookup(Node,
- Var)
- end,
- Instr);
- true ->
- Instr
- end,
- {NewInstr, Defs}
- end,
-
- %% go through all expressions defined by the node and replace
- %% or remove them as indicated by the delete set. Also perform
- %% reduction test replacement if neccessary.
- {[CodeLast | CodeRest], NewUpdate, LocalAcc} =
- lists:foldl(fun(Instr, {CodeAcc, UpdateAcc, LocalAcc}) ->
- case struct_instr_type(Instr) of
- struct ->
- Defs = hipe_icode:defines(Instr),
-
- #varinfo{exprid = ExprId} = maps_var_get(hd(Defs), Maps),
-
- Expr = maps_expr_get(ExprId, Maps),
- DirectReplace = expr_direct_replace(Expr),
-
- %% Creates move intstructions from Vars to Defs
- RemoveFuncVars = fun(Vars) ->
- CodeAcc2 = mk_defs_moves(CodeAcc, Defs, Vars),
- {CodeAcc2, UpdateAcc, LocalAcc} end,
-
- %% Looks up an already inserted ExprId and makes moves
- %% of variables from that expression to this expression.
- RemoveFunc = fun() ->
- {value, Vars} = update_inserted_lookup(UpdateAcc, ExprId),
- RemoveFuncVars(Vars) end,
-
- %% Is ExprId already inserted?
- IsLocal = ?SETS:is_element(ExprId, LocalAcc),
-
- case DirectReplace of
- true ->
- %% The Instr is reffering to an expression that is
- %% defined as an identical already present instruction,
- %% and can be removed directly.
- RemoveFuncVars(expr_defs(Expr));
- false when IsLocal ->
- %% The instruction has already been inserted.
- RemoveFunc();
- _ ->
- case ?SETS:is_element(ExprId, Delete) of
- true ->
- %% should not be inserted
- RemoveFunc();
- _ ->
- %% Should remain
- UpdateAcc2 = update_inserted_add(UpdateAcc, ExprId, Defs),
- LocalAcc2 = ?SETS:add_element(ExprId, LocalAcc),
- {[Instr | CodeAcc], UpdateAcc2, LocalAcc2}
- end
- end;
- redtest when DelRed ->
- %% delete reduction test
- {CodeAcc, UpdateAcc, LocalAcc};
- _ ->
- {[Instr | CodeAcc], UpdateAcc, LocalAcc}
- end
- end, {[], Update, ?SETS:new()}, Code),
-
- %debug_struct("RW Label 2: ", Label),
-
- %% calculate the inserts that are new to this node, that is
- %% the expressions that are in Inserts but not in UpExpr,
- %% and that have not been added already,
- %% that is not present in LocalAcc
- NewInserts = ?SETS:subtract(?SETS:subtract(Inserts, UpExpr), LocalAcc),
-
- {NewCodeRest, NewUpdate2} =
- ?SETS:fold(fun(ExprId, {CodeAcc, UpdateAcc}) ->
- Expr = maps_expr_get(ExprId, Maps),
- {ExprInstr, Defs} = GetInstrFunc(Expr),
- {UpdateAcc2, NewDefs} = update_inserted_add_new(UpdateAcc, ExprId, Defs),
-
- %% check if there exists an identical expression, so that
- %% this expression can be replaced directly.
- CodeAcc2 =
- case expr_direct_replace(Expr) of
- false ->
- NewInstr = rewrite_expr(UpdateAcc2, ExprInstr, NewDefs),
- [NewInstr | CodeAcc];
- true ->
- mk_defs_moves(CodeAcc, NewDefs, Defs)
- end,
- {CodeAcc2, UpdateAcc2}
- end, {CodeRest, NewUpdate}, NewInserts),
-
- NewCode = lists:reverse([CodeLast | NewCodeRest]),
-
- %% Check if we are to insert new reduction test here...
- {NewCode2, NewUpdate3} =
- case PreLoop andalso ?SETS:size(Inserts) > 0 andalso not DelRed of
- true ->
- {[hipe_icode:mk_primop([], redtest, []) | NewCode], update_del_red_test_set(NewUpdate2)};
- false ->
- {NewCode, NewUpdate2}
- end,
-
- NewBB = hipe_bb:mk_bb(NewCode2),
- NewCFG = hipe_icode_cfg:bb_add(CFG, Label, NewBB),
-
- {NewCFG, NewUpdate3}.
-
-%%-----------------------------------------------------------------------------
-%% Create a new structure instruction from Instr with destination Defs
-%% from the insert mapping in Update.
-
-rewrite_expr(Update, Instr, Defs) ->
- NewInstr =
- replace_call_variables(fun(Ref) ->
- case Ref of
- {ExprId, Num} when is_integer(ExprId) ->
- {value, DefList} = update_inserted_lookup(Update, ExprId),
- lists:nth(Num, DefList);
- _ -> Ref
- end end, Instr),
- hipe_icode:call_dstlist_update(NewInstr, Defs).
-
-%%-----------------------------------------------------------------------------
-%% Make move instructions from Defs list to all variables in
-%% the Refs list and insert into Code.
-
-mk_defs_moves(Code, [], []) -> Code;
-mk_defs_moves(Code, [Ref | Refs], [Def | Defs]) ->
- mk_defs_moves([hipe_icode:mk_move(Ref, Def) | Code], Refs, Defs).
-
-%%-----------------------------------------------------------------------------
-%% Utilities
-
-new_work() ->
- {[], gb_sets:new()}.
-
-add_work_list(List, Work) ->
- lists:foldl(fun(Label, WorkAcc) ->
- add_work_label(Label, WorkAcc) end, Work, List).
-
-add_work_label(Label, {List, Set}) ->
- case gb_sets:is_member(Label, Set) of
- false ->
- {[Label | List], gb_sets:add(Label, Set)};
- true ->
- {List, Set}
- end.
-
-get_work_list({List, _}) ->
- lists:reverse(List).
-
-%%-----------------------------------------------------------------------------
-%% instr_type
-%% gets a tag for the type of instruction that is passed in I
-
-struct_instr_type(I) ->
- case I of
- #icode_call{type = primop, 'fun' = mktuple} ->
- %%debug_count_case(?SR_STRUCT_INSTR_TYPE, #call{type = primop, 'fun' = mktuple}),
- struct;
- #icode_call{type = primop, 'fun' = cons} ->
- %%debug_count_case(?SR_STRUCT_INSTR_TYPE, #call{type = primop, 'fun' = cons}),
- struct;
- #icode_call{type = primop, 'fun' = redtest} ->
- %%debug_count_case(?SR_STRUCT_INSTR_TYPE, #call{type = primop, 'fun' = redtest}),
- redtest;
- _ ->
- %%debug_count_case(?SR_STRUCT_INSTR_TYPE, other),
- other
- end.
-
-instr_type(I) ->
- case I of
- %#call{type = primop, dstlist = List} when length(List) >= 1 -> struct;
- #icode_call{type = primop, 'fun' = {unsafe_element, Elem}, dstlist = [DstVar], args = [SrcVar]} ->
- %%debug_count_case(?SR_INSTR_TYPE, #call{type = primop, 'fun' = {unsafe_element, num}}),
- {struct_elems, Elem, DstVar, SrcVar};
- #icode_phi{} ->
- %%debug_count_case(?SR_INSTR_TYPE,#phi{}),
- phi;
- #icode_enter{} ->
- %%debug_count_case(?SR_INSTR_TYPE,#enter{}),
- return;
- #icode_return{} ->
- %%debug_count_case(?SR_INSTR_TYPE,#return{}),
- return;
- #icode_call{type = primop, 'fun' = mktuple} ->
- %%debug_count_case(?SR_INSTR_TYPE, #call{type = primop, 'fun' = mktuple}),
- struct;
- #icode_call{type = primop, 'fun' = cons} ->
- %%debug_count_case(?SR_INSTR_TYPE, #call{type = primop, 'fun' = cons}),
- struct;
- #icode_call{type = primop, 'fun' = redtest} ->
- %%debug_count_case(?SR_INSTR_TYPE, #call{type = primop, 'fun' = redtest}),
- redtest;
- #icode_type{test = {tuple, Size}, args = [Var]} ->
- %%debug_count_case(?SR_INSTR_TYPE, #type{type = {tuple, size}}),
- {struct_type, Size, Var, ?MKTUPLE};
- #icode_type{test = cons, args = [Var]} ->
- %%debug_count_case(?SR_INSTR_TYPE,#type{type = cons}),
- {struct_type, 2, Var, ?CONS};
- %#type{type = {atom, Atom}, args = [Var]} -> {atom_type, Atom, Var};
- #icode_call{type = primop, 'fun' = unsafe_hd,
- dstlist = [DstVar], args = [SrcVar]} ->
- %%debug_count_case(?SR_INSTR_TYPE,#call{type = primop, 'fun' = unsafe_hd}),
- {struct_elems, 1, DstVar, SrcVar};
- #icode_call{type = primop, 'fun' = unsafe_tl,
- dstlist = [DstVar], args = [SrcVar]} ->
- %%debug_count_case(?SR_INSTR_TYPE, #call{type = primop, 'fun' = unsafe_tl}),
- {struct_elems, 2, DstVar, SrcVar};
- #icode_switch_tuple_arity{term = Var, cases = Cases} ->
- %%debug_count_case(?SR_INSTR_TYPE,#switch_tuple_arity{}),
- {tuple_arity, Var, Cases};
- _ -> other
- end.
-
-%%-----------------------------------------------------------------------------
-%% Expression ID counter
-
-init_expr_id() ->
- put({struct_reuse, expr_id_count}, 0).
-
--spec new_expr_id() -> non_neg_integer().
-new_expr_id() ->
- V = get({struct_reuse, expr_id_count}),
- put({struct_reuse, expr_id_count}, V+1),
- V.
-
-%%-----------------------------------------------------------------------------
-%% Debug and print functions
-
-print_struct(String, Struct) ->
- io:format(String),
- erlang:display(Struct).
-
-print(String) ->
- io:format(String).
-
--ifdef(DEBUG).
-
-debug_count_case(Type, Case) ->
- Cases = get(Type),
- NewCases =
- case gb_trees:lookup(Case, Cases) of
- {value, Value} -> gb_trees:enter(Case, Value + 1, Cases);
- none -> gb_trees:insert(Case, 1, Cases)
- end,
- put(Type, NewCases).
-
-debug_init_case_count(Type) ->
- case get(Type) of
- undefined -> put(Type, gb_trees:empty());
- _ -> ok
- end.
-
-debug_print_case_count(Type) ->
- Cases = get(Type),
- debug_struct("Case type: ", Type),
- debug_list("Cases: ", gb_trees:to_list(Cases)).
-
-set_debug_flag(Value) ->
- put({struct_reuse, debug}, Value).
-
-get_debug_flag() -> get({struct_reuse, debug}).
-
-debug_function(FuncName, CFG) ->
- Linear = hipe_icode_cfg:cfg_to_linear(CFG),
- Func = hipe_icode:icode_fun(Linear),
- case Func =:= FuncName orelse FuncName =:= nil of
- true ->
- set_debug_flag(true),
- %% debug_struct("Code: ", hipe_icode_cfg:bb(CFG, 15)),
- debug_struct("~nFunction name :", Func);
- false ->
- set_debug_flag(undefined)
- end.
-
-debug_cfg_pp(CFG) ->
- case get_debug_flag() of
- true -> hipe_icode_cfg:pp(CFG);
- _ -> none
- end.
-
-debug_struct(String, Struct) ->
- case get_debug_flag() of
- true ->
- io:format(String),
- erlang:display(Struct);
- _ -> none
- end.
-
-debug(String) ->
- case get_debug_flag() of
- true -> io:format(String);
- _ -> none
- end.
-
-debug_list(String, List) ->
- case get_debug_flag() of
- true -> print_list(String, List);
- _ -> none
- end.
-
-print_list(String, List) ->
- io:format(String),
- io:format("~n"),
- print_list_rec(List),
- io:format("~n").
-
-print_list_rec([]) -> ok;
-print_list_rec([Struct | List]) ->
- erlang:display(Struct),
- print_list_rec(List).
-
-debug_nodes(Nodes) ->
- lists:foreach(fun(Node) -> debug_node(Node) end, nodes_tree_values(Nodes)).
-
-debug_node(Node) ->
- case get_debug_flag() of
- true ->
- print_struct("Node Label: ", Node#node.label),
- print_struct("Code: ", Node#node.code),
- print_struct("Phi: ", Node#node.phi),
- print_struct("PreLoop: ", Node#node.pre_loop),
- print_struct("Preds: ", Node#node.pred),
- print_struct("Succ: ", Node#node.succ),
- print_struct("Up Expr: ", Node#node.up_expr),
- print_struct("Kill : ", Node#node.killed_expr),
- print_struct("AnticIn: ", Node#node.antic_in),
- print_struct("AnticOut: ", Node#node.antic_out),
- print_struct("SubInserts: ", Node#node.sub_inserts),
- print_struct("Inserts: ", Node#node.inserts),
- print_struct("NonStructDefs: ", Node#node.non_struct_defs),
- print_struct("Params: ", Node#node.struct_type),
- print_struct("Elems: ", Node#node.struct_elems),
- io:format("~n");
- _ -> none
- end.
-
--endif.
diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl
deleted file mode 100644
index aafaeb5a0a..0000000000
--- a/lib/hipe/icode/hipe_icode_type.erl
+++ /dev/null
@@ -1,2259 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%--------------------------------------------------------------------
-%%% File : hipe_icode_type.erl
-%%% Author : Tobias Lindahl <Tobias.Lindahl@it.uu.se>
-%%% Description : Propagate type information.
-%%%
-%%% Created : 25 Feb 2003 by Tobias Lindahl <Tobias.Lindahl@it.uu.se>
-%%%--------------------------------------------------------------------
-
--module(hipe_icode_type).
-
--export([cfg/4, unannotate_cfg/1, specialize/1]).
-
-%%=====================================================================
-%% Icode Coordinator Callbacks
-%%=====================================================================
-
--export([replace_nones/1,
- update__info/2, new__info/1, return__info/1,
- return_none/0, return_none_args/2, return_any_args/2]).
-
-%%=====================================================================
-
--include("../main/hipe.hrl").
--include("hipe_icode.hrl").
--include("hipe_icode_primops.hrl").
--include("hipe_icode_type.hrl").
--include("../flow/cfg.hrl").
-
--type args_fun() :: fun((mfa(), cfg()) -> [erl_types:erl_type()]).
--type call_fun() :: fun((mfa(), [_]) -> erl_types:erl_type()).
--type final_fun() :: fun((mfa(), [_]) -> 'ok').
--type data() :: {mfa(), args_fun(), call_fun(), final_fun()}.
-
-%-define(DO_HIPE_ICODE_TYPE_TEST, false).
-
--ifdef(DO_HIPE_ICODE_TYPE_TEST).
--export([test/0]).
--endif.
-
--define(MFA_debug, fun(_, _, _) -> ok end).
-
-%-define(debug, fun(X, Y) -> io:format("~s ~p~n", [X, Y]) end).
--define(debug, fun(_, _) -> ok end).
-
-%-define(flow_debug, fun(X, Y) -> io:format("flow: ~s ~p~n", [X, Y]) end).
--define(flow_debug, fun(_, _) -> ok end).
-
-%-define(widening_debug, fun(X, Y) -> io:format("wid: ~s ~p~n", [X, Y]) end).
--define(widening_debug, fun(_, _) -> ok end).
-
-%-define(call_debug, fun(X, Y) -> io:format("call: ~s ~p~n", [X, Y]) end).
--define(call_debug, fun(_, _) -> ok end).
-
-%-define(ineq_debug, fun(X, Y) -> io:format("ineq: ~s ~p~n", [X, Y]) end).
--define(ineq_debug, fun(_, _) -> ok end).
-
-%-define(server_debug, fun(X, Y) -> io:format("~p server: ~s ~p~n", [self(), X, Y]) end).
--define(server_debug, fun(_, _) -> ok end).
-
--import(erl_types, [number_min/1, number_max/1,
- t_any/0, t_atom/1, t_atom/0, t_atom_vals/1,
- t_binary/0, t_bitstr/0, t_bitstr_base/1, t_bitstr_unit/1,
- t_boolean/0, t_cons/0,
- t_float/0, t_from_term/1, t_from_range/2,
- t_fun/0, t_fun/1, t_fun/2, t_fun_args/1, t_fun_arity/1,
- t_inf/2, t_inf_lists/2, t_integer/0,
- t_integer/1, t_is_atom/1, t_is_any/1,
- t_is_binary/1, t_is_bitstr/1, t_is_bitwidth/1,
- t_is_boolean/1, t_is_fixnum/1, t_is_cons/1, t_is_map/1,
- t_is_maybe_improper_list/1, t_is_equal/2, t_is_float/1,
- t_is_fun/1, t_is_integer/1, t_is_non_neg_integer/1,
- t_is_number/1, t_is_matchstate/1,
- t_is_none/1, t_is_port/1, t_is_pid/1,
- t_is_reference/1, t_is_subtype/2, t_is_tuple/1,
- t_limit/2, t_matchstate_present/1, t_matchstate/0,
- t_matchstate_slots/1, t_maybe_improper_list/0, t_map/0,
- t_nil/0, t_none/0, t_number/0, t_number/1, t_number_vals/1,
- t_pid/0, t_port/0, t_reference/0, t_subtract/2, t_sup/2,
- t_to_tlist/1, t_tuple/0, t_tuple/1, t_tuple_sizes/1]).
-
--record(state, {info_map = gb_trees:empty() :: gb_trees:tree(),
- cfg :: cfg(),
- liveness :: hipe_icode_ssa:liveness(),
- arg_types :: [erl_types:erl_type()],
- ret_type = [t_none()] :: [erl_types:erl_type()],
- lookupfun :: call_fun(),
- resultaction :: final_fun()}).
--type state() :: #state{}.
-
-%%-----------------------------------------------------------------------
-%% The main exported function
-%%-----------------------------------------------------------------------
-
--spec cfg(cfg(), mfa(), comp_options(), #comp_servers{}) -> cfg().
-
-cfg(Cfg, MFA, Options, Servers) ->
- case proplists:get_bool(concurrent_comp, Options) of
- true ->
- concurrent_cfg(Cfg, MFA, Servers#comp_servers.type);
- false ->
- ordinary_cfg(Cfg, MFA)
- end.
-
-concurrent_cfg(Cfg, MFA, CompServer) ->
- CompServer ! {ready, {MFA, self()}},
- {ArgsFun, CallFun, FinalFun} = do_analysis(Cfg, MFA),
- Ans = do_rewrite(Cfg, MFA, ArgsFun, CallFun, FinalFun),
- CompServer ! {done_rewrite, MFA},
- Ans.
-
-do_analysis(Cfg, MFA) ->
- receive
- {analyse, {ArgsFun,CallFun,FinalFun}} ->
- analyse(Cfg, {MFA,ArgsFun,CallFun,FinalFun}),
- do_analysis(Cfg, MFA);
- {done, {_NewArgsFun,_NewCallFun,_NewFinalFun} = Done} ->
- Done
- end.
-
-do_rewrite(Cfg, MFA, ArgsFun, CallFun, FinalFun) ->
- common_rewrite(Cfg, {MFA,ArgsFun,CallFun,FinalFun}).
-
-ordinary_cfg(Cfg, MFA) ->
- Data = make_data(Cfg,MFA),
- common_rewrite(Cfg, Data).
-
-common_rewrite(Cfg, Data) ->
- State = safe_analyse(Cfg, Data),
- NewState = simplify_controlflow(State),
- NewCfg = state__cfg(annotate_cfg(NewState)),
- hipe_icode_cfg:remove_unreachable_code(specialize(NewCfg)).
-
-make_data(Cfg, {_M,_F,A}=MFA) ->
- NoArgs =
- case hipe_icode_cfg:is_closure(Cfg) of
- true -> hipe_icode_cfg:closure_arity(Cfg);
- false -> A
- end,
- Args = lists:duplicate(NoArgs, t_any()),
- ArgsFun = fun(_,_) -> Args end,
- CallFun = fun(_,_) -> t_any() end,
- FinalFun = fun(_,_) -> ok end,
- {MFA,ArgsFun,CallFun,FinalFun}.
-
-%%debug_make_data(Cfg, {_M,_F,A}=MFA) ->
-%% NoArgs =
-%% case hipe_icode_cfg:is_closure(Cfg) of
-%% true -> hipe_icode_cfg:closure_arity(Cfg);
-%% false -> A
-%% end,
-%% Args = lists:duplicate(NoArgs, t_any()),
-%% ArgsFun = fun(MFA,_Cfg) -> io:format("Start:~p~n",[MFA]),Args end,
-%% CallFun = fun(MFA,Types) -> io:format("Call With:~p~nTo:~p~n",[Types,MFA]), t_any() end,
-%% FinalFun = fun(MFA,Type) -> io:format("ResType:~p~nFor:~p~n",[Type,MFA]),ok end,
-%% {MFA,ArgsFun,CallFun,FinalFun}.
-
-
-%%-------------------------------------------------------------------
-%% Global type analysis on the whole function. Demands that the code
-%% is in SSA form. When we encounter a phi node, the types of the
-%% arguments are joined. At the end of a block the information out is
-%% joined with the current information in for all _valid_ successors,
-%% that is, of all successors that actually can be reached. If the
-%% join produces new information in for the successor, this
-%% information is added to the worklist.
-%%-------------------------------------------------------------------
-
--spec analyse(cfg(), data()) -> 'ok'.
-
-analyse(Cfg, Data) ->
- try
- #state{} = safe_analyse(Cfg, Data),
- ok
- catch throw:no_input -> ok % No need to do anything since we have no input
- end.
-
--spec safe_analyse(cfg(), data()) -> state().
-
-safe_analyse(Cfg, {MFA,_,_,_}=Data) ->
- State = new_state(Cfg, Data),
- NewState = analyse_blocks(State,MFA),
- (state__resultaction(NewState))(MFA,state__ret_type(NewState)),
- NewState.
-
-analyse_blocks(State, MFA) ->
- Work = init_work(State),
- analyse_blocks(Work, State, MFA).
-
-analyse_blocks(Work, State, MFA) ->
- case get_work(Work) of
- fixpoint ->
- State;
- {Label, NewWork} ->
- Info = state__info_in(State, Label),
- {NewState, NewLabels} =
- try analyse_block(Label, Info, State)
- catch throw:none_type ->
- %% io:format("received none type at label: ~p~n", [Label]),
- {State,[]}
- end,
- NewWork2 = add_work(NewWork, NewLabels),
- analyse_blocks(NewWork2, NewState, MFA)
- end.
-
-analyse_block(Label, InfoIn, State) ->
- BB = state__bb(State, Label),
- Code = hipe_bb:butlast(BB),
- Last = hipe_bb:last(BB),
- InfoOut = analyse_insns(Code, InfoIn, state__lookupfun(State)),
- NewState = state__info_out_update(State, Label, InfoOut),
- case Last of
- #icode_if{} ->
- UpdateInfo = do_if(Last, InfoOut),
- do_updates(NewState, UpdateInfo);
- #icode_type{} ->
- UpdateInfo = do_type(Last, InfoOut),
- do_updates(NewState, UpdateInfo);
- #icode_switch_tuple_arity{} ->
- UpdateInfo = do_switch_tuple_arity(Last, InfoOut),
- do_updates(NewState, UpdateInfo);
- #icode_switch_val{} ->
- UpdateInfo = do_switch_val(Last, InfoOut),
- do_updates(NewState, UpdateInfo);
- #icode_enter{} ->
- NewState1 = do_enter(Last, InfoOut, NewState, state__lookupfun(NewState)),
- do_updates(NewState1,[]);
- #icode_call{} ->
- {NewState1,UpdateInfo} = do_last_call(Last, InfoOut, NewState, Label),
- do_updates(NewState1, UpdateInfo);
- #icode_return{} ->
- NewState1 = do_return(Last, InfoOut, NewState),
- do_updates(NewState1,[]);
- _ ->
- UpdateInfo = [{X, InfoOut} || X <- state__succ(NewState, Label)],
- do_updates(NewState, UpdateInfo)
- end.
-
-analyse_insns([I|Insns], Info, LookupFun) ->
- NewInfo = analyse_insn(I, Info, LookupFun),
- analyse_insns(Insns, NewInfo, LookupFun);
-analyse_insns([], Info, _) ->
- Info.
-
-analyse_insn(I, Info, LookupFun) ->
- case I of
- #icode_move{} ->
- do_move(I, Info);
- #icode_call{} ->
- NewInfo = do_call(I, Info, LookupFun),
- %% io:format("Analysing Call: ~w~n~w~n", [I, NewInfo]),
- update_call_arguments(I, NewInfo);
- #icode_phi{} ->
- Type = t_limit(join_list(hipe_icode:args(I), Info), ?TYPE_DEPTH),
- enter_defines(I, Type, Info);
- #icode_begin_handler{} ->
- enter_defines(I, t_any(), Info);
- _ ->
- %% Just an assert
- case defines(I) of
- [] -> Info;
- _ -> exit({"Instruction with destination not analysed", I})
- end
- end.
-
-do_move(I, Info) ->
- %% Can't use uses/1 since we must keep constants.
- [Src] = hipe_icode:args(I),
- enter_defines(I, lookup(Src, Info), Info).
-
-do_basic_call(I, Info, LookupFun) ->
- case hipe_icode:call_type(I) of
- primop ->
- Fun = hipe_icode:call_fun(I),
- ArgTypes = lookup_list(hipe_icode:args(I), Info),
- primop_type(Fun, ArgTypes);
- remote ->
- {M, F, A} = hipe_icode:call_fun(I),
- ArgTypes = lookup_list(hipe_icode:args(I), Info),
- None = t_none(),
- case erl_bif_types:type(M, F, A, ArgTypes) of
- None ->
- NewArgTypes = add_funs_to_arg_types(ArgTypes),
- erl_bif_types:type(M, F, A, NewArgTypes);
- Other ->
- Other
- end;
- local ->
- MFA = hipe_icode:call_fun(I),
- ArgTypes = lookup_list(hipe_icode:args(I), Info),
- %% io:format("Call:~p~nTypes: ~p~n",[I,ArgTypes]),
- LookupFun(MFA,ArgTypes)
- end.
-
-do_call(I, Info, LookupFun) ->
- RetType = do_basic_call(I, Info, LookupFun),
- IsNone = t_is_none(RetType),
- %% io:format("RetType ~p~nIsNone ~p~n~p~n",[RetType,IsNone,I]),
- if IsNone -> throw(none_type);
- true -> enter_defines(I, RetType, Info)
- end.
-
-do_safe_call(I, Info, LookupFun) ->
- RetType = do_basic_call(I, Info, LookupFun),
- enter_defines(I, RetType, Info).
-
-do_last_call(Last, InfoOut, State, Label) ->
- try
- NewInfoOut = do_call(Last, InfoOut, state__lookupfun(State)),
- NewState = state__info_out_update(State, Label, NewInfoOut),
- ContInfo = update_call_arguments(Last, NewInfoOut),
- Cont = hipe_icode:call_continuation(Last),
- Fail = hipe_icode:call_fail_label(Last),
- ?call_debug("Continfo, NewInfoOut", {ContInfo, NewInfoOut}),
- UpdateInfo =
- case Fail of
- [] ->
- [{Cont, ContInfo}];
- _ ->
- case call_always_fails(Last, InfoOut) of
- true ->
- [{Fail, NewInfoOut}];
- false ->
- Fun = hipe_icode:call_fun(Last),
- case hipe_icode_primops:fails(Fun) of
- true ->
- [{Cont, ContInfo}, {Fail, NewInfoOut}];
- false ->
- [{Cont, ContInfo}]
- end
- end
- end,
- {NewState,UpdateInfo}
- catch throw:none_type ->
- State2 = state__info_out_update(State, Label, InfoOut),
- case hipe_icode:call_fail_label(Last) of
- [] -> throw(none_type);
- FailLbl ->
- {State2,[{FailLbl, InfoOut}]}
- end
- end.
-
-call_always_fails(#icode_call{} = I, Info) ->
- case hipe_icode:call_fun(I) of
- %% These can actually be calls too.
- {erlang, halt, 0} -> false;
- {erlang, halt, 1} -> false;
- {erlang, halt, 2} -> false;
- {erlang, exit, 1} -> false;
- {erlang, error, 1} -> false;
- {erlang, error, 2} -> false;
- {erlang, throw, 1} -> false;
- {erlang, hibernate, 3} -> false;
- Fun ->
- case hipe_icode:call_type(I) of
- primop ->
- Args = safe_lookup_list(hipe_icode:call_args(I), Info),
- ReturnType = primop_type(Fun, Args),
- t_is_none(ReturnType);
- _ -> false
- end
- end.
-
-do_enter(I, Info, State, LookupFun) ->
- %% io:format("Enter:~p~n",[I]),
- ArgTypes = lookup_list(hipe_icode:args(I), Info),
- RetTypes =
- case hipe_icode:enter_type(I) of
- local ->
- MFA = hipe_icode:enter_fun(I),
- LookupFun(MFA,ArgTypes);
- remote ->
- {M, F, A} = hipe_icode:enter_fun(I),
- None = t_none(),
- case erl_bif_types:type(M, F, A, ArgTypes) of
- None ->
- NewArgTypes = add_funs_to_arg_types(ArgTypes),
- erl_bif_types:type(M, F, A, NewArgTypes);
- Other ->
- Other
- end;
- primop ->
- Fun = hipe_icode:enter_fun(I),
- primop_type(Fun, ArgTypes)
- end,
- state__ret_type_update(State, RetTypes).
-
-do_return(I, Info, State) ->
- RetTypes = lookup_list(hipe_icode:args(I), Info),
- state__ret_type_update(State, RetTypes).
-
-do_if(I, Info) ->
- %% XXX: Could probably do better than this.
- TrueLab = hipe_icode:if_true_label(I),
- FalseLab = hipe_icode:if_false_label(I),
- case hipe_icode:if_args(I) of
- [Arg1, Arg2] = Args ->
- [Type1, Type2] = lookup_list(Args, Info),
- case t_is_none(Type1) orelse t_is_none(Type2) of
- true ->
- [{TrueLab, Info}, {FalseLab, Info}];
- false ->
- Inf = t_inf(Type1, Type2),
- case hipe_icode:if_op(I) of
- '=:='->
- case t_is_none(Inf) of
- true ->
- [{FalseLab, Info}];
- false ->
- [{TrueLab, enter(Arg1, Inf, enter(Arg2, Inf, Info))},
- {FalseLab, Info}]
- end;
- '=/=' ->
- case t_is_none(Inf) of
- true ->
- [{TrueLab, Info}];
- false ->
- [{FalseLab, enter(Arg1, Inf, enter(Arg2, Inf, Info))},
- {TrueLab, Info}]
- end;
- '==' ->
- [{TrueLab, Info}, {FalseLab, Info}];
- '/=' ->
- [{TrueLab, Info}, {FalseLab, Info}];
- Op ->
- integer_range_inequality_propagation(Op, Arg1, Arg2,
- TrueLab, FalseLab, Info)
- %%_ ->
- %% [{TrueLab, Info}, {FalseLab, Info}]
- end
- end;
- _ ->
- %% Only care for binary if:s
- [{TrueLab, Info}, {FalseLab, Info}]
- end.
-
-integer_range_inequality_propagation(Op, A1, A2, TrueLab, FalseLab, Info) ->
- Arg1 = lookup(A1, Info),
- Arg2 = lookup(A2, Info),
- ?ineq_debug("args", [Arg1,Arg2]),
- IntArg1 = t_inf(Arg1, t_integer()),
- IntArg2 = t_inf(Arg2, t_integer()),
- NonIntArg1 = t_subtract(Arg1, t_integer()),
- NonIntArg2 = t_subtract(Arg2, t_integer()),
- ?ineq_debug("nonintargs", [NonIntArg1,NonIntArg2]),
- case t_is_none(IntArg1) orelse t_is_none(IntArg2) of
- true ->
- ?ineq_debug("one is none", [IntArg1,IntArg2]),
- [{TrueLab, Info}, {FalseLab, Info}];
- false ->
- {TrueArg1, TrueArg2, FalseArg1, FalseArg2} =
- case Op of
- '>=' ->
- {FA1, FA2, TA1, TA2} = int_range_lt_propagator(IntArg1, IntArg2),
- {TA1, TA2, FA1, FA2};
- '>' ->
- {TA2, TA1, FA2, FA1} = int_range_lt_propagator(IntArg2, IntArg1),
- {TA1, TA2, FA1, FA2};
- '<' ->
- int_range_lt_propagator(IntArg1, IntArg2);
- '=<' ->
- {FA2, FA1, TA2, TA1} = int_range_lt_propagator(IntArg2, IntArg1),
- {TA1, TA2, FA1, FA2}
- end,
- ?ineq_debug("int res", [TrueArg1, TrueArg2, FalseArg1, FalseArg2]),
- False = {FalseLab, enter(A1, t_sup(FalseArg1, NonIntArg1),
- enter(A2, t_sup(FalseArg2, NonIntArg2), Info))},
- True = {TrueLab, enter(A1, t_sup(TrueArg1, NonIntArg1),
- enter(A2, t_sup(TrueArg2, NonIntArg2), Info))},
- [True, False]
- end.
-
-int_range_lt_propagator(IntArg1, IntArg2) ->
- Min1 = number_min(IntArg1),
- Max1 = number_max(IntArg1),
- Min2 = number_min(IntArg2),
- Max2 = number_max(IntArg2),
- %% is this the same as erl_types:t_subtract?? no ... ??
- TrueMax1 = erl_types:min(Max1, erl_bif_types:infinity_add(Max2, -1)),
- TrueMin2 = erl_types:max(erl_bif_types:infinity_add(Min1, 1), Min2),
- FalseMin1 = erl_types:max(Min1, Min2),
- FalseMax2 = erl_types:min(Max1, Max2),
- {t_from_range(Min1, TrueMax1),
- t_from_range(TrueMin2, Max2),
- t_from_range(FalseMin1, Max1),
- t_from_range(Min2, FalseMax2)}.
-
-do_type(I, Info) ->
- case hipe_icode:args(I) of
- [Var] -> do_type(I, Info, Var);
- [Var1,Var2] -> do_type2(I, Info, Var1, Var2)
- end.
-
-do_type2(I, Info, FunVar, ArityVar) -> % function2(Fun,Arity)
- %% Just for sanity.
- function2 = hipe_icode:type_test(I),
- FunType = lookup(FunVar, Info),
- ArityType = lookup(ArityVar, Info),
- TrueLab = hipe_icode:type_true_label(I),
- FalseLab = hipe_icode:type_false_label(I),
- SuccType1 = t_inf(t_fun(), FunType),
- case combine_test(test_type(function, FunType),
- test_type(integer, ArityType)) of
- true ->
- case t_number_vals(ArityType) of
- [Arity] ->
- case t_fun_arity(SuccType1) of
- unknown ->
- SuccType = t_inf(t_fun(Arity,t_any()),FunType),
- [{TrueLab, enter(FunVar, SuccType, Info)},
- {FalseLab, Info}];
- Arity when is_integer(Arity) ->
- FalseType = t_subtract(FunType, t_fun(Arity, t_any())),
- [{TrueLab, enter(FunVar, SuccType1, Info)},
- {FalseLab, enter(FunVar, FalseType, Info)}]
- end;
- _ ->
- case t_fun_arity(SuccType1) of
- unknown ->
- [{TrueLab, enter(FunVar,SuccType1,Info)},
- {FalseLab, Info}];
- Arity when is_integer(Arity) ->
- T = t_from_term(Arity),
- NewInfo = enter(ArityVar, T, Info),
- [{TrueLab, enter(FunVar, SuccType1, NewInfo)},
- {FalseLab, enter(ArityVar, t_subtract(T, ArityType), Info)}]
- end
- end;
- false ->
- [{FalseLab, Info}];
- maybe ->
- GenTrueArity = t_inf(t_integer(), ArityType),
- GenTrueFun = t_inf(t_fun(), FunType),
- case {t_number_vals(GenTrueArity), t_fun_arity(GenTrueFun)} of
- {unknown, unknown} ->
- TrueInfo = enter_list([FunVar, ArityVar],
- [GenTrueFun, GenTrueArity], Info),
- [{TrueLab, TrueInfo}, {FalseLab, Info}];
- {unknown, Arity} when is_integer(Arity) ->
- TrueInfo = enter_list([FunVar, ArityVar],
- [GenTrueFun, t_integer(Arity)], Info),
- [{TrueLab, TrueInfo}, {FalseLab, Info}];
- {[Val], unknown} when is_integer(Val) ->
- TrueInfo = enter_list([FunVar, ArityVar],
- [t_inf(GenTrueFun, t_fun(Val, t_any())),
- GenTrueArity], Info),
- [{TrueLab, TrueInfo}, {FalseLab, Info}];
- {Vals, unknown} when is_list(Vals) ->
- %% The function type gets widened when we have more than one arity.
- TrueInfo = enter_list([FunVar, ArityVar],
- [GenTrueFun, GenTrueArity], Info),
- [{TrueLab, TrueInfo}, {FalseLab, Info}];
- {Vals, Arity} when is_list(Vals), is_integer(Arity) ->
- case lists:member(Arity, Vals) of
- false ->
- [{FalseLab, Info}];
- true ->
- TrueInfo = enter_list([FunVar, ArityVar],
- [GenTrueFun, t_integer(Arity)], Info),
- [{TrueLab, TrueInfo}, {FalseLab, Info}]
- end
- end
- end.
-
-combine_test(true, true) -> true;
-combine_test(false, _) -> false;
-combine_test(_, false) -> false;
-combine_test(_, _) -> maybe.
-
-do_type(I, Info, Var) ->
- TrueLab = hipe_icode:type_true_label(I),
- FalseLab = hipe_icode:type_false_label(I),
- None = t_none(),
- case lookup(Var, Info) of
- None ->
- [{TrueLab, Info}, {FalseLab, Info}];
- VarInfo ->
- case hipe_icode:type_test(I) of
- cons ->
- test_cons_or_nil(t_cons(), Var, VarInfo, TrueLab, FalseLab, Info);
- nil ->
- test_cons_or_nil(t_nil(), Var, VarInfo, TrueLab, FalseLab, Info);
- {atom, A} = Test ->
- test_number_or_atom(fun(X) -> t_atom(X) end,
- A, Var, VarInfo, Test, TrueLab, FalseLab, Info);
- {integer, N} = Test ->
- test_number_or_atom(fun(X) -> t_number(X) end,
- N, Var, VarInfo, Test, TrueLab, FalseLab, Info);
- {record, Atom, Size} ->
- test_record(Atom, Size, Var, VarInfo, TrueLab, FalseLab, Info);
- Other ->
- case t_is_any(VarInfo) of
- true ->
- TrueType = t_inf(true_branch_info(Other), VarInfo),
- TrueInfo = enter(Var, TrueType, Info),
- [{TrueLab, TrueInfo}, {FalseLab, Info}];
- false ->
- case test_type(Other, VarInfo) of
- true ->
- [{TrueLab, Info}];
- false ->
- [{FalseLab, Info}];
- maybe ->
- TrueType = t_inf(true_branch_info(Other), VarInfo),
- TrueInfo = enter(Var, TrueType, Info),
- FalseType = t_subtract(VarInfo, TrueType),
- FalseInfo = enter(Var, FalseType, Info),
- [{TrueLab, TrueInfo}, {FalseLab, FalseInfo}]
- end
- end
- end
- end.
-
-do_switch_tuple_arity(I, Info) ->
- Var = hipe_icode:switch_tuple_arity_term(I),
- VarType = lookup(Var, Info),
- Cases = hipe_icode:switch_tuple_arity_cases(I),
- FailLabel = hipe_icode:switch_tuple_arity_fail_label(I),
- case legal_switch_tuple_arity_cases(Cases, VarType) of
- [] ->
- [{FailLabel, Info}];
- LegalCases ->
- {Fail, UpdateInfo} =
- switch_tuple_arity_update_info(LegalCases, Var, VarType,
- FailLabel, VarType, Info, []),
- case switch_tuple_arity_can_fail(LegalCases, VarType) of
- true -> [Fail|UpdateInfo];
- false -> UpdateInfo
- end
- end.
-
-legal_switch_tuple_arity_cases(Cases, Type) ->
- case t_is_tuple(Type) of
- false ->
- Inf = t_inf(t_tuple(), Type),
- case t_is_tuple(Inf) of
- true -> legal_switch_tuple_arity_cases_1(Cases, Inf);
- false -> []
- end;
- true ->
- legal_switch_tuple_arity_cases_1(Cases, Type)
- end.
-
-legal_switch_tuple_arity_cases_1(Cases, Type) ->
- case t_tuple_sizes(Type) of
- unknown ->
- Cases;
- TupleSizes ->
- [Case || {Size, _Label} = Case <- Cases,
- lists:member(hipe_icode:const_value(Size), TupleSizes)]
- end.
-
-switch_tuple_arity_can_fail(LegalCases, ArgType) ->
- case t_is_tuple(ArgType) of
- false -> true;
- true ->
- case t_tuple_sizes(ArgType) of
- unknown -> true;
- Sizes1 ->
- Sizes2 = [hipe_icode:const_value(X) || {X, _} <- LegalCases],
- Set1 = sets:from_list(Sizes1),
- Set2 = sets:from_list(Sizes2),
- not sets:is_subset(Set1, Set2)
- end
- end.
-
-switch_tuple_arity_update_info([{Arity, Label}|Left], Var, TupleType,
- FailLabel, FailType, Info, Acc) ->
- Inf = t_inf(TupleType, t_tuple(hipe_icode:const_value(Arity))),
- NewInfo = enter(Var, Inf, Info),
- NewFailType = t_subtract(FailType, Inf),
- switch_tuple_arity_update_info(Left, Var, TupleType, FailLabel, NewFailType,
- Info, [{Label, NewInfo}|Acc]);
-switch_tuple_arity_update_info([], Var, _TupleType,
- FailLabel, FailType, Info, Acc) ->
- {{FailLabel, enter(Var, FailType, Info)}, Acc}.
-
-do_switch_val(I, Info) ->
- Var = hipe_icode:switch_val_term(I),
- VarType = lookup(Var, Info),
- Cases = hipe_icode:switch_val_cases(I),
- FailLabel = hipe_icode:switch_val_fail_label(I),
- case legal_switch_val_cases(Cases, VarType) of
- [] ->
- [{FailLabel, Info}];
- LegalCases ->
- switch_val_update_info(LegalCases, Var, VarType,
- FailLabel, VarType, Info, [])
- end.
-
-legal_switch_val_cases(Cases, Type) ->
- legal_switch_val_cases(Cases, Type, []).
-
-legal_switch_val_cases([{Val, _Label} = VL|Left], Type, Acc) ->
- ConstType = t_from_term(hipe_icode:const_value(Val)),
- case t_is_subtype(ConstType, Type) of
- true ->
- legal_switch_val_cases(Left, Type, [VL|Acc]);
- false ->
- legal_switch_val_cases(Left, Type, Acc)
- end;
-legal_switch_val_cases([], _Type, Acc) ->
- lists:reverse(Acc).
-
-switch_val_update_info([{Const, Label}|Left], Arg, ArgType,
- FailLabel, FailType, Info, Acc) ->
- TrueType = t_from_term(hipe_icode:const_value(Const)),
- NewInfo = enter(Arg, TrueType, Info),
- NewFailType = t_subtract(FailType, TrueType),
- switch_val_update_info(Left, Arg, ArgType, FailLabel, NewFailType,
- Info, [{Label, NewInfo}|Acc]);
-switch_val_update_info([], Arg, _ArgType, FailLabel, FailType,Info, Acc) ->
- [{FailLabel, enter(Arg, FailType, Info)}|Acc].
-
-test_cons_or_nil(Type, Var, VarInfo, TrueLab, FalseLab, Info) ->
- case t_is_any(VarInfo) of
- true ->
- [{TrueLab, enter(Var, Type, Info)},
- {FalseLab, Info}];
- false ->
- TrueType = t_inf(VarInfo, Type),
- FalseType = t_subtract(VarInfo, TrueType),
- case t_is_none(FalseType) of
- true ->
- [{TrueLab, Info}];
- false ->
- case t_is_none(TrueType) of
- true ->
- [{FalseLab, Info}];
- false ->
- [{TrueLab, enter(Var, TrueType, Info)},
- {FalseLab, enter(Var, FalseType, Info)}]
- end
- end
- end.
-
-test_number_or_atom(Fun, X, Var, VarInfo, TypeTest,
- TrueLab, FalseLab, Info) ->
- case t_is_any(VarInfo) of
- true ->
- [{TrueLab, enter(Var, Fun(X), Info)},
- {FalseLab, Info}];
- false ->
- case test_type(TypeTest, VarInfo) of
- false ->
- [{FalseLab, Info}];
- true ->
- [{TrueLab, Info}];
- maybe ->
- FalseType = t_subtract(VarInfo, Fun(X)),
- [{TrueLab, enter(Var, Fun(X), Info)},
- {FalseLab, enter(Var, FalseType, Info)}]
- end
- end.
-
-test_record(Atom, Size, Var, VarInfo, TrueLab, FalseLab, Info) ->
- AnyList = lists:duplicate(Size - 1, t_any()),
- RecordType = t_tuple([t_atom(Atom)|AnyList]),
- Inf = t_inf(RecordType, VarInfo),
- case t_is_none(Inf) of
- true ->
- [{FalseLab, Info}];
- false ->
- Sub = t_subtract(VarInfo, Inf),
- case t_is_none(Sub) of
- true ->
- [{TrueLab, enter(Var, Inf, Info)}];
- false ->
- [{TrueLab, enter(Var, Inf, Info)},
- {FalseLab, enter(Var, Sub, Info)}]
- end
- end.
-
-test_type(Test, Type) ->
- %% io:format("Test is: ~w\n", [Test]),
- %% io:format("Type is: ~s\n", [format_type(Type)]),
- Ans =
- case t_is_any(Type) of
- true -> maybe;
- false ->
- TrueTest = true_branch_info(Test),
- Inf = t_inf(TrueTest, Type),
- %% io:format("TrueTest is: ~s\n", [format_type(TrueTest)]),
- %% io:format("Inf is: ~s\n", [format_type(Inf)]),
- case t_is_equal(Type, Inf) of
- true ->
- not t_is_none(Type);
- false ->
- case t_is_equal(TrueTest, Inf) of
- true ->
- case test_type0(Test, Type) of
- false ->
- maybe;
- true ->
- true;
- maybe ->
- maybe
- end;
- false ->
- case test_type0(Test, Inf) of
- true ->
- maybe;
- false ->
- false;
- maybe ->
- maybe
- end
- end
- end
- end,
- %% io:format("Result is: ~s\n\n", [Ans]),
- Ans.
-
-test_type0(integer, T) ->
- t_is_integer(T);
-test_type0({integer, N}, T) ->
- case t_is_integer(T) of
- true ->
- case t_number_vals(T) of
- unknown -> maybe;
- [N] -> true;
- List when is_list(List) ->
- case lists:member(N, List) of
- true -> maybe;
- false -> false
- end
- end;
- false -> false
- end;
-test_type0(float, T) ->
- t_is_float(T);
-test_type0(number, T) ->
- t_is_number(T);
-test_type0(atom, T) ->
- t_is_atom(T);
-test_type0({atom, A}, T) ->
- case t_is_atom(T) of
- true ->
- case t_atom_vals(T) of
- unknown -> maybe;
- [A] -> true;
- List when is_list(List) ->
- case lists:member(A, List) of
- true -> maybe;
- false -> false
- end
- end;
- false -> false
- end;
-test_type0(tuple, T) ->
- t_is_tuple(T);
-test_type0({tuple, N}, T) ->
- case t_is_tuple(T) of
- true ->
- case t_tuple_sizes(T) of
- unknown -> maybe;
- [X] when is_integer(X) -> X =:= N;
- List when is_list(List) ->
- case lists:member(N, List) of
- true -> maybe;
- false -> false
- end
- end;
- false -> false
- end;
-test_type0(pid, T) ->
- t_is_pid(T);
-test_type0(port, T) ->
- t_is_port(T);
-test_type0(binary, T) ->
- t_is_binary(T);
-test_type0(bitstr, T) ->
- t_is_bitstr(T);
-test_type0(reference, T) ->
- t_is_reference(T);
-test_type0(function, T) ->
- t_is_fun(T);
-test_type0(boolean, T) ->
- t_is_boolean(T);
-test_type0(list, T) ->
- t_is_maybe_improper_list(T);
-%% test_type0(cons, T) ->
-%% t_is_cons(T);
-%% test_type0(nil, T) ->
-%% t_is_nil(T).
-test_type0(map, T) ->
- t_is_map(T).
-
-true_branch_info(integer) ->
- t_integer();
-true_branch_info({integer, N}) ->
- t_integer(N);
-true_branch_info(float) ->
- t_float();
-true_branch_info(number) ->
- t_number();
-true_branch_info(atom) ->
- t_atom();
-true_branch_info({atom, A}) ->
- t_atom(A);
-true_branch_info(list) ->
- t_maybe_improper_list();
-true_branch_info(tuple) ->
- t_tuple();
-true_branch_info({tuple, N}) ->
- t_tuple(N);
-true_branch_info(pid) ->
- t_pid();
-true_branch_info(port) ->
- t_port();
-true_branch_info(binary) ->
- t_binary();
-true_branch_info(bitstr) ->
- t_bitstr();
-true_branch_info(reference) ->
- t_reference();
-true_branch_info(function) ->
- t_fun();
-%% true_branch_info(cons) ->
-%% t_cons();
-%% true_branch_info(nil) ->
-%% t_nil();
-true_branch_info(boolean) ->
- t_boolean();
-true_branch_info(map) ->
- t_map();
-true_branch_info(T) ->
- exit({?MODULE, unknown_typetest, T}).
-
-
-%% _________________________________________________________________
-%%
-%% Remove the redundant type tests. If a test is removed, the trace
-%% that isn't taken is explicitly removed from the CFG to simplify
-%% the handling of Phi nodes. If a Phi node is left and at least one
-%% branch into it has disappeared, the SSA propagation pass cannot
-%% handle it.
-%%
-%% If the CFG has changed at the end of this pass, the analysis is
-%% done again since we might be able to find more information because
-%% of the simplification of the CFG.
-%%
-
-simplify_controlflow(State) ->
- Cfg = state__cfg(State),
- simplify_controlflow(hipe_icode_cfg:reverse_postorder(Cfg), State).
-
-simplify_controlflow([Label|Left], State) ->
- Info = state__info_out(State, Label),
- NewState =
- case state__bb(State, Label) of
- not_found -> State;
- BB ->
- I = hipe_bb:last(BB),
- case I of
- #icode_if{} ->
- rewrite_if(State,I,BB,Info,Label);
- #icode_type{} ->
- rewrite_type(State,I,BB,Info,Label);
- #icode_switch_tuple_arity{} ->
- rewrite_switch_tuple_arity(State,I,BB,Info,Label);
- #icode_switch_val{} ->
- rewrite_switch_val(State,I,BB,Info,Label);
- #icode_call{} ->
- rewrite_call(State,I,BB,Info,Label);
- _ ->
- State
- end
- end,
- simplify_controlflow(Left, NewState);
-simplify_controlflow([], State) ->
- State.
-
-rewrite_if(State, I, BB, Info, Label) ->
- case do_if(I, Info) of
- [{Lab, _}] ->
- mk_goto(State, BB, Label, Lab);
- [_,_] ->
- State
- end.
-
-rewrite_type(State, I, BB, Info, Label) ->
- FalseLab = hipe_icode:type_false_label(I),
- case hipe_icode:type_true_label(I) of
- FalseLab ->
- %% true label = false label, this can occur!
- mk_goto(State, BB, Label, FalseLab);
- TrueLab ->
- case do_type(I, Info) of
- [{TrueLab, _}] ->
- mk_goto(State, BB, Label, TrueLab);
- [{FalseLab, _}] ->
- mk_goto(State, BB, Label, FalseLab);
- [_,_] -> %% Maybe
- State
- end
- end.
-
-rewrite_switch_tuple_arity(State, I, BB, Info, Label) ->
- Cases = hipe_icode:switch_tuple_arity_cases(I),
- Var = hipe_icode:switch_tuple_arity_term(I),
- Type = safe_lookup(Var, Info),
- case legal_switch_tuple_arity_cases(Cases, Type) of
- [] ->
- Fail = hipe_icode:switch_tuple_arity_fail_label(I),
- mk_goto(State, BB, Label, Fail);
- Cases ->
- %% Nothing changed.
- case switch_tuple_arity_can_fail(Cases, Type) of
- true -> State;
- false ->
- NewCases = butlast(Cases),
- {_Arity, NewFail} = lists:last(Cases),
- TmpI =
- hipe_icode:switch_tuple_arity_fail_label_update(I, NewFail),
- NewI =
- hipe_icode:switch_tuple_arity_cases_update(TmpI, NewCases),
- NewBB = hipe_bb:code_update(BB, hipe_bb:butlast(BB) ++ [NewI]),
- state__bb_add(State, Label, NewBB)
- end;
- LegalCases ->
- NewI =
- case switch_tuple_arity_can_fail(LegalCases, Type) of
- true ->
- hipe_icode:switch_tuple_arity_cases_update(I, LegalCases);
- false ->
- NewCases = butlast(LegalCases),
- {_Arity, NewFail} = lists:last(LegalCases),
- TmpI =
- hipe_icode:switch_tuple_arity_cases_update(I, NewCases),
- hipe_icode:switch_tuple_arity_fail_label_update(TmpI, NewFail)
- end,
- NewBB = hipe_bb:code_update(BB, hipe_bb:butlast(BB) ++ [NewI]),
- state__bb_add(State, Label, NewBB)
- end.
-
-rewrite_switch_val(State, I, BB, Info, Label) ->
- Cases = hipe_icode:switch_val_cases(I),
- Var = hipe_icode:switch_val_term(I),
- VarType = safe_lookup(Var, Info),
- case legal_switch_val_cases(Cases, VarType) of
- [] ->
- Fail = hipe_icode:switch_val_fail_label(I),
- mk_goto(State, BB, Label, Fail);
- Cases ->
- State;
- %% TODO: Find out whether switch_val can fail
- %% just as switch_tuple_arity
- LegalCases ->
- NewI = hipe_icode:switch_val_cases_update(I, LegalCases),
- NewBB = hipe_bb:code_update(BB, hipe_bb:butlast(BB) ++ [NewI]),
- state__bb_add(State, Label, NewBB)
- end.
-
-rewrite_call(State,I,BB,Info,Label) ->
- case call_always_fails(I, Info) of
- false ->
- Fun = hipe_icode:call_fun(I),
- case hipe_icode_primops:fails(Fun) of
- false ->
- case hipe_icode:call_fail_label(I) of
- [] -> State;
- _ -> unset_fail(State, BB, Label, I)
- end;
- true -> State
- end;
- true ->
- case hipe_icode:call_in_guard(I) of
- false -> State;
- true ->
- FailLabel = hipe_icode:call_fail_label(I),
- mk_goto(State, BB, Label, FailLabel)
- end
- end.
-
-mk_goto(State, BB, Label, Succ) ->
- NewI = hipe_icode:mk_goto(Succ),
- NewBB = hipe_bb:code_update(BB, hipe_bb:butlast(BB) ++ [NewI]),
- state__bb_add(State, Label, NewBB).
-
-unset_fail(State, BB, Label, I) ->
- %%io:format("Setting a guard that cannot fail\n", []),
- NewI = hipe_icode:call_set_fail_label(I, []),
- NewBB = hipe_bb:code_update(BB, hipe_bb:butlast(BB) ++ [NewI]),
- state__bb_add(State, Label, NewBB).
-
-%% _________________________________________________________________
-%%
-%% Make transformations (specialisations) based on the type knowledge.
-%%
-%% Annotate the variables with the local information. Since we have
-%% the code in SSA form and the type information can only depend on
-%% assignments or branches (type tests), we can use the information
-%% out of the block to annotate all variables in it.
-%%
-
--spec specialize(cfg()) -> cfg().
-
-specialize(Cfg) ->
- Labels = hipe_icode_cfg:reverse_postorder(Cfg),
- transform_bbs(Labels, Cfg).
-
-transform_bbs([Label|Left], Cfg) ->
- BB = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- NewCode = make_transformations(Code),
- NewBB = hipe_bb:code_update(BB, NewCode),
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB),
- transform_bbs(Left, NewCfg);
-transform_bbs([], Cfg) ->
- Cfg.
-
-make_transformations(Is) ->
- lists:flatten([transform_insn(I) || I <- Is]).
-
-transform_insn(I) ->
- case I of
- #icode_call{} ->
- handle_call_and_enter(I);
- #icode_enter{} ->
- handle_call_and_enter(I);
- #icode_if{} ->
- CurrentIfOp = hipe_icode:if_op(I),
- UsesFixnums = all_fixnums([get_type(A) || A <- hipe_icode:args(I)]),
- AnyImmediate = any_immediate([get_type(A) || A <- hipe_icode:args(I)]),
- ExactComp = is_exact_comp(CurrentIfOp),
- if UsesFixnums ->
- hipe_icode:if_op_update(I, fixnum_ifop(CurrentIfOp));
- AnyImmediate andalso ExactComp ->
- hipe_icode:if_op_update(I, fixnum_ifop(CurrentIfOp));
- true ->
- I
- end;
- _ ->
- I
- end.
-
-handle_call_and_enter(I) ->
- case call_or_enter_fun(I) of
- #element{} ->
- transform_insn(update_call_or_enter(I, {erlang, element, 2}));
- {erlang, element, 2} ->
- NewI1 = transform_element2(I),
- case is_record(I, icode_call) andalso hipe_icode:call_in_guard(I) of
- true ->
- case hipe_icode:call_fun(NewI1) of
- #unsafe_element{} -> NewI1;
- _ -> I
- end;
- false ->
- NewI1
- end;
- {erlang, hd, 1} -> transform_hd_or_tl(I, unsafe_hd);
- {erlang, tl, 1} -> transform_hd_or_tl(I, unsafe_tl);
- {hipe_bs_primop, BsOP} ->
- NewBsOp =
- bit_opts(BsOP, get_type_list(hipe_icode:args(I))),
- update_call_or_enter(I, {hipe_bs_primop, NewBsOp});
- conv_to_float ->
- [Src] = hipe_icode:args(I),
- case t_is_float(get_type(Src)) of
- true ->
- update_call_or_enter(I, unsafe_untag_float);
- false ->
- I
- end;
- FunName ->
- case is_arith_function(FunName) of
- true ->
- case strength_reduce(I, FunName) of
- NewIs when is_list(NewIs) ->
- [pos_transform_arith(NewI) || NewI <- NewIs];
- NewI ->
- pos_transform_arith(NewI)
- end;
- false ->
- I
- end
- end.
-
-pos_transform_arith(I) ->
- case hipe_icode:is_enter(I) orelse hipe_icode:is_call(I) of
- true ->
- FunName = call_or_enter_fun(I),
- transform_arith(I, FunName);
- false ->
- I
- end.
-
-is_arith_function(Name) ->
- case Name of
- 'band' -> true;
- 'bor' -> true;
- 'bxor' -> true;
- 'bnot' -> true;
- 'bsl' -> true;
- 'bsr' -> true;
- '+' -> true;
- '-' -> true;
- '*' -> true;
- 'div' -> true;
- 'rem' -> true;
- _ -> false
- end.
-
-%%---------------------------------------------------------------------
-%% Perform a limited form of strength reduction for multiplication and
-%% division of an integer with constants which are multiples of 2.
-%%---------------------------------------------------------------------
-
-strength_reduce(I, Op) ->
- case Op of
- '*' ->
- [Arg1, Arg2] = mult_args_const_second(I),
- ArgT1 = get_type(Arg1),
- case t_is_integer(ArgT1) of
- true ->
- case hipe_icode:is_const(Arg2) of
- true ->
- case hipe_icode:const_value(Arg2) of
- 0 -> case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [Dst] -> create_strength_reduce_move(I, Dst, Arg2)
- end;
- 1 -> case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [Dst] -> create_strength_reduce_move(I, Dst, Arg1)
- end;
- 2 -> strength_reduce_imult(I, Arg1, 1);
- 4 -> strength_reduce_imult(I, Arg1, 2);
- 8 -> strength_reduce_imult(I, Arg1, 3);
- 16 -> strength_reduce_imult(I, Arg1, 4);
- 32 -> strength_reduce_imult(I, Arg1, 5);
- 64 -> strength_reduce_imult(I, Arg1, 6);
- 128 -> strength_reduce_imult(I, Arg1, 7);
- 256 -> strength_reduce_imult(I, Arg1, 8);
- ___ -> I
- end;
- false -> I
- end;
- false -> I
- end;
- 'div' ->
- [Arg1, Arg2] = hipe_icode:args(I),
- ArgT1 = get_type(Arg1),
- case t_is_non_neg_integer(ArgT1) of
- true -> %% the optimization is NOT valid for negative integers
- case hipe_icode:is_const(Arg2) of
- true ->
- case hipe_icode:const_value(Arg2) of
- 0 -> io:fwrite("Integer division by 0 detected!\n"), I;
- 1 -> case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [Dst] -> create_strength_reduce_move(I, Dst, Arg1)
- end;
- 2 -> strength_reduce_div(I, Arg1, 1);
- 4 -> strength_reduce_div(I, Arg1, 2);
- 8 -> strength_reduce_div(I, Arg1, 3);
- 16 -> strength_reduce_div(I, Arg1, 4);
- 32 -> strength_reduce_div(I, Arg1, 5);
- 64 -> strength_reduce_div(I, Arg1, 6);
- 128 -> strength_reduce_div(I, Arg1, 7);
- 256 -> strength_reduce_div(I, Arg1, 8);
- ___ -> I
- end;
- false -> I
- end;
- false -> I
- end;
- 'rem' ->
- [Arg1, Arg2] = hipe_icode:args(I),
- ArgT1 = get_type(Arg1),
- case t_is_non_neg_integer(ArgT1) of
- true -> %% the optimization is NOT valid for negative integers
- case hipe_icode:is_const(Arg2) of
- true ->
- case hipe_icode:const_value(Arg2) of
- 0 -> io:fwrite("Remainder with 0 detected!\n"), I;
- 1 -> case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [Dst] -> create_strength_reduce_move(
- I, Dst, hipe_icode:mk_const(0))
- end;
- 2 -> strength_reduce_rem(I, Arg1, 1);
- 4 -> strength_reduce_rem(I, Arg1, 3);
- 8 -> strength_reduce_rem(I, Arg1, 7);
- 16 -> strength_reduce_rem(I, Arg1, 15);
- 32 -> strength_reduce_rem(I, Arg1, 31);
- 64 -> strength_reduce_rem(I, Arg1, 63);
- 128 -> strength_reduce_rem(I, Arg1, 127);
- 256 -> strength_reduce_rem(I, Arg1, 255);
- ___ -> I
- end;
- false -> I
- end;
- false -> I
- end;
- _ -> I
- end.
-
-remove_useless_arithmetic_instruction(_) ->
- [].
-
-create_strength_reduce_move(I, Dst, Val) ->
- case hipe_icode:call_continuation(I) of
- [] ->
- hipe_icode:mk_move(Dst, Val);
- Lbl ->
- [hipe_icode:mk_move(Dst, Val),
- hipe_icode:mk_goto(Lbl)]
- end.
-
-%% Puts the args of a multiplication in a form where the constant
-%% (if present) is always the second argument.
-mult_args_const_second(I) ->
- [Arg1, Arg2] = Args = hipe_icode:args(I),
- case hipe_icode:is_const(Arg1) of
- true -> [Arg2, Arg1];
- false -> Args
- end.
-
-%% In all three functions below:
-%% - Arg1 is a variable of integer type
-%% - N is a small positive integer that will be used in a bit shift operation
-strength_reduce_imult(I, Arg1, N) ->
- case t_number_vals(get_type(Arg1)) of
- [X] when is_integer(X) ->
- %% io:format("Multiplication with constant arguments:\n ~w\n", [I]),
- case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [D] -> create_strength_reduce_move(I, D, hipe_icode:mk_const(X bsl N))
- end;
- _ ->
- update_call_or_enter(I, 'bsl', [Arg1, hipe_icode:mk_const(N)])
- end.
-
-strength_reduce_div(I, Arg1, N) ->
- case t_number_vals(get_type(Arg1)) of
- [X] when is_integer(X) ->
- %% io:format("Division with constant arguments:\n ~w\n", [I]),
- case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [D] -> create_strength_reduce_move(I, D, hipe_icode:mk_const(X bsr N))
- end;
- _ ->
- update_call_or_enter(I, 'bsr', [Arg1, hipe_icode:mk_const(N)])
- end.
-
-strength_reduce_rem(I, Arg1, N) ->
- case t_number_vals(get_type(Arg1)) of
- [X] when is_integer(X) ->
- %% io:format("Remainder with constant arguments:\n ~w\n", [I]),
- case call_dstlist(I) of
- [] -> remove_useless_arithmetic_instruction(I);
- [D] -> create_strength_reduce_move(I, D, hipe_icode:mk_const(X band N))
- end;
- _ ->
- update_call_or_enter(I, 'band', [Arg1, hipe_icode:mk_const(N)])
- end.
-
-%%---------------------------------------------------------------------
-
-call_or_enter_fun(I) ->
- case hipe_icode:is_call(I) of
- true -> hipe_icode:call_fun(I);
- false -> hipe_icode:enter_fun(I)
- end.
-
-update_call_or_enter(I, NewFun) ->
- case hipe_icode:is_call(I) of
- true ->
- case hipe_icode_primops:fails(NewFun) of
- false ->
- NewI = hipe_icode:call_fun_update(I, NewFun),
- hipe_icode:call_set_fail_label(NewI, []);
- true ->
- hipe_icode:call_fun_update(I, NewFun)
- end;
- false -> hipe_icode:enter_fun_update(I, NewFun)
- end.
-
-update_call_or_enter(I, NewFun, NewArgs) ->
- case hipe_icode:is_call(I) of
- true ->
- I1 = hipe_icode:call_args_update(I, NewArgs),
- hipe_icode:call_fun_update(I1, NewFun);
- false ->
- I1 = hipe_icode:enter_args_update(I, NewArgs),
- hipe_icode:enter_fun_update(I1, NewFun)
- end.
-
-transform_element2(I) ->
- [Index, Tuple] = hipe_icode:args(I),
- IndexType = get_type(Index),
- TupleType = get_type(Tuple),
- ?debug("Tuple", TupleType),
- NewIndex =
- case test_type(integer, IndexType) of
- true ->
- case {number_min(IndexType), number_max(IndexType)} of
- {Lb0, Ub0} when is_integer(Lb0), is_integer(Ub0) ->
- {number, Lb0, Ub0};
- {_, _} -> unknown
- end;
- _ -> unknown
- end,
- MinSize =
- case test_type(tuple, TupleType) of
- true ->
- ?debug("is tuple", TupleType),
- case t_tuple_sizes(TupleType) of
- unknown -> unknown;
- Sizes -> {tuple, lists:min(Sizes)}
- end;
- _ -> unknown
- end,
- case {NewIndex, MinSize} of
- {{number, Lb, Ub}, {tuple, A}} when is_integer(A) ->
- case 0 < Lb andalso Ub =< A of
- true ->
- case {Lb, Ub} of
- {Idx, Idx} ->
- [_, Tuple] = hipe_icode:args(I),
- update_call_or_enter(I, #unsafe_element{index = Idx}, [Tuple]);
- {_, _} ->
- NewFun = {element, [MinSize, valid]},
- update_call_or_enter(I, NewFun)
- end;
- false ->
- case lists:all(fun(X) -> hipe_tagscheme:is_fixnum(X) end, [Lb, Ub]) of
- true ->
- NewFun = {element, [MinSize, fixnums]},
- update_call_or_enter(I, NewFun);
- false ->
- NewFun = {element, [MinSize, unknown]},
- update_call_or_enter(I, NewFun)
- end
- end;
- _ when (NewIndex =:= unknown) orelse (MinSize =:= unknown) ->
- case t_is_fixnum(IndexType) of
- true ->
- NewFun = {element, [MinSize, fixnums]},
- update_call_or_enter(I, NewFun);
- false ->
- NewFun = {element, [MinSize, NewIndex]},
- update_call_or_enter(I, NewFun)
- end
- end.
-
-transform_hd_or_tl(I, Primop) ->
- [Arg] = hipe_icode:args(I),
- case t_is_cons(get_type(Arg)) of
- true -> update_call_or_enter(I, Primop);
- false -> I
- end.
-
-transform_arith(I, Op) ->
- ArgTypes = get_type_list(hipe_icode:args(I)),
- %% io:format("Op = ~w, Args = ~w\n", [Op, ArgTypes]),
- DstTypes =
- case hipe_icode:is_call(I) of
- true -> get_type_list(call_dstlist(I));
- false -> [erl_bif_types:type(erlang, Op, length(ArgTypes), ArgTypes)]
- end,
- case valid_unsafe_args(ArgTypes, Op) of
- true ->
- case all_is_fixnum(DstTypes) of
- true ->
- update_call_or_enter(I, arithop_to_extra_unsafe(Op));
- false ->
- update_call_or_enter(I, arithop_to_unsafe(Op))
- end;
- false ->
- I
- end.
-
-all_is_fixnum(Types) ->
- lists:all(fun erl_types:t_is_fixnum/1, Types).
-
-valid_unsafe_args(Args, Op) ->
- if Op =:= 'bnot' ->
- [Arg] = Args,
- t_is_fixnum(Arg);
- true ->
- [LeftArg, RightArg] = Args,
- case Op of
- 'bsl' -> t_is_fixnum(LeftArg) and t_is_bitwidth(RightArg);
- 'bsr' -> t_is_fixnum(LeftArg) and t_is_bitwidth(RightArg);
- _ -> t_is_fixnum(LeftArg) and t_is_fixnum(RightArg)
- end
- end.
-
-arithop_to_extra_unsafe(Op) ->
- case Op of
- '+' -> extra_unsafe_add;
- '-' -> extra_unsafe_sub;
- '*' -> '*'; %% XXX: Revise?
- 'div' -> 'div'; %% XXX: Revise?
- 'rem' -> 'rem'; %% XXX: Revise?
- 'band' -> unsafe_band;
- 'bor' -> unsafe_bor;
- 'bxor' -> unsafe_bxor;
- 'bnot' -> unsafe_bnot;
- 'bsl' -> unsafe_bsl;
- 'bsr' -> unsafe_bsr
- end.
-
-arithop_to_unsafe(Op) ->
- case Op of
- '+' -> unsafe_add;
- '-' -> unsafe_sub;
- _ -> Op
- end.
-
-fixnum_ifop(Op) ->
- case Op of
- '=:=' -> 'fixnum_eq';
- '=/=' -> 'fixnum_neq';
- '==' -> 'fixnum_eq';
- '/=' -> 'fixnum_neq';
- '>' -> 'fixnum_gt';
- '<' -> 'fixnum_lt';
- '>=' -> 'fixnum_ge';
- '=<' -> 'fixnum_le';
- Op -> Op
- end.
-
-bit_opts({Name, Size, Flags} = I, [MSType]) when Name =:= bs_get_integer;
- Name =:= bs_get_float;
- Name =:= bs_get_binary ->
- Bits = t_matchstate_present(MSType),
- case t_is_bitstr(Bits) of
- true ->
- Base = t_bitstr_base(Bits),
- if Base >= Size ->
- {Name, Size, Flags bor 16};
- true -> I
- end;
- false -> I
- end;
-bit_opts({bs_get_binary_all, Size, Flags} = I, [MSType]) ->
- Bits = t_matchstate_present(MSType),
- case t_is_bitstr(Bits) of
- true ->
- Base = t_bitstr_base(Bits),
- Unit = t_bitstr_unit(Bits),
- if (Base rem Size) =:= 0 andalso (Unit rem Size) =:= 0 ->
- {bs_get_binary_all, Size, Flags bor 16};
- true -> I
- end;
- false -> I
- end;
-bit_opts({bs_test_unit, Size} = I, [MSType]) ->
- Bits = t_matchstate_present(MSType),
- case t_is_bitstr(Bits) of
- true ->
- Base = t_bitstr_base(Bits),
- Unit = t_bitstr_unit(Bits),
- if (Base rem Size) =:= 0 andalso (Unit rem Size) =:= 0 ->
- {bs_test_unit, 1};
- true -> I
- end;
- false -> I
- end;
-bit_opts({bs_put_integer, Size, Flags, ConstInfo} = I, [Src|_]) ->
- case t_is_fixnum(Src) of
- true ->
- {unsafe_bs_put_integer, Size, Flags, ConstInfo};
- false -> I
- end;
-bit_opts({bs_start_match, Max} = I, [Src]) ->
- case t_is_bitstr(Src) of
- true -> {{bs_start_match, bitstr}, Max};
- false ->
- MSorNone = t_inf(t_matchstate(), Src),
- case t_is_matchstate(MSorNone) of
- true ->
- Slots = t_matchstate_slots(MSorNone),
- case t_is_any(Slots) orelse (length(t_to_tlist(Slots)) =< Max) of
- true -> I;
- false -> {{bs_start_match, ok_matchstate}, Max}
- end;
- false -> I
- end
- end;
-bit_opts(I, _) -> I.
-
-is_exact_comp(Op) ->
- case Op of
- '=:=' -> true;
- '=/=' -> true;
- _Op -> false
- end.
-
-all_fixnums([Type|Types]) ->
- t_is_fixnum(Type) andalso all_fixnums(Types);
-all_fixnums([]) ->
- true.
-
-any_immediate([Type|Types]) ->
- t_is_fixnum(Type) orelse t_is_atom(Type) orelse any_immediate(Types);
-any_immediate([]) -> false.
-
-get_standard_primop(unsafe_bsl) -> 'bsl';
-get_standard_primop(unsafe_bsr) -> 'bsr';
-get_standard_primop(unsafe_add) -> '+';
-get_standard_primop(extra_unsafe_add) -> '+';
-get_standard_primop(unsafe_bnot) -> 'bnot';
-get_standard_primop(unsafe_bxor) -> 'bxor';
-get_standard_primop(unsafe_band) -> 'band';
-get_standard_primop(unsafe_bor) -> 'bor';
-get_standard_primop(unsafe_sub) -> '-';
-get_standard_primop(extra_unsafe_sub) -> '-';
-get_standard_primop(Op) -> Op.
-
-primop_type(Op, Args) ->
- case Op of
- #mkfun{mfa = MFA} ->
- t_inf(t_fun(), find_signature_mfa(MFA));
- _ ->
- None = t_none(),
- Primop = get_standard_primop(Op),
- RetType = hipe_icode_primops:type(Primop, Args),
- case RetType of
- None ->
- hipe_icode_primops:type(Primop, add_funs_to_arg_types(Args));
- Other ->
- Other
- end
- end.
-
-%%------------------------------------------------------------------
-%% Various help functions.
-%%------------------------------------------------------------------
-
-add_arg_types(Args, Types) ->
- add_arg_types(Args, Types, gb_trees:empty()).
-
-add_arg_types([Arg|Args], [Type|Types], Acc) ->
- Type1 =
- case t_is_none(Type) of
- true -> t_any();
- false -> Type
- end,
- add_arg_types(Args,Types, enter(Arg, Type1, Acc));
-add_arg_types(_, [], Acc) ->
- Acc.
-
-get_type_list(ArgList) ->
- [get_type(Arg) || Arg <- ArgList].
-
-get_type(Arg) ->
- case hipe_icode:is_annotated_variable(Arg) of
- true ->
- None = t_none(),
- case hipe_icode:variable_annotation(Arg) of
- {type_anno, None, _} -> t_any();
- {type_anno, Type, _} -> Type
- end;
- false ->
- case hipe_icode:is_const(Arg) of
- true -> const_type(Arg);
- false -> t_any()
- end
- end.
-
-%% Lookup treats anything that is neither in the map or a constant as
-%% t_none(). Use this during type propagation!
-
-lookup(Var, Tree) ->
- case gb_trees:lookup(Var, Tree) of
- none ->
- case hipe_icode:is_const(Var) of
- true -> const_type(Var);
- false -> t_none()
- end;
- {value, Type} ->
- Type
- end.
-
-lookup_list(List, Info) ->
- lookup_list0(List, Info, []).
-
-lookup_list0([H|T], Info, Acc) ->
- lookup_list0(T, Info, [lookup(H, Info)|Acc]);
-lookup_list0([], _, Acc) ->
- lists:reverse(Acc).
-
-%% safe_lookup treats anything that is neither in the map nor a
-%% constant as t_any(). Use this during transformations.
-
-safe_lookup(Var, Tree) ->
- case gb_trees:lookup(Var, Tree) of
- none ->
- case hipe_icode:is_const(Var) of
- true -> const_type(Var);
- false ->
- %% io:format("Expression has undefined type\n",[]),
- t_any()
- end;
- {value, Type} ->
- Type
- end.
-
-safe_lookup_list(List, Info) ->
- safe_lookup_list0(List, Info, []).
-
-safe_lookup_list0([H|T], Info, Acc) ->
- safe_lookup_list0(T, Info, [safe_lookup(H, Info)|Acc]);
-safe_lookup_list0([], _, Acc) ->
- lists:reverse(Acc).
-
-enter_list([Var|VarLeft], [Type|TypeLeft], Info) ->
- NewInfo = enter(Var, Type, Info),
- enter_list(VarLeft, TypeLeft, NewInfo);
-enter_list([], [], Info) ->
- Info.
-
-enter([Key], Value, Tree) ->
- enter(Key, Value, Tree);
-enter(Key, Value, Tree) ->
- case is_var_or_reg(Key) of
- true ->
- case t_is_none(Value) of
- true ->
- gb_trees:delete_any(Key, Tree);
- false ->
- gb_trees:enter(Key, Value, Tree)
- end;
- false ->
- Tree
- end.
-
-join_list(List, Info) ->
- join_list(List, Info, t_none()).
-
-join_list([H|T], Info, Acc) ->
- Type = t_sup(lookup(H, Info), Acc),
- join_list(T, Info, Type);
-join_list([], _, Acc) ->
- Acc.
-
-join_info_in([], _OldInfo, _NewInfo) ->
- %% No variables are live in. The information must be at a fixpoint.
- fixpoint;
-join_info_in(Vars, OldInfo, NewInfo) ->
- NewInfo2 = join_info_in(Vars, Vars, OldInfo, NewInfo, gb_trees:empty()),
- case info_is_equal(NewInfo2, OldInfo) of
- true -> fixpoint;
- false -> NewInfo2
- end.
-
-%% NOTE: Variables can be bound to other variables. Joining these is
-%% only possible if the binding is the same from both traces and this
-%% variable is still live.
-
-join_info_in([Var|Left], LiveIn, Info1, Info2, Acc) ->
- Type1 = gb_trees:lookup(Var, Info1),
- Type2 = gb_trees:lookup(Var, Info2),
- case {Type1, Type2} of
- {none, none} ->
- join_info_in(Left, LiveIn, Info1, Info2, Acc);
- {none, {value, Val}} ->
- NewTree = gb_trees:insert(Var, Val, Acc),
- join_info_in(Left, LiveIn, Info1, Info2, NewTree);
- {{value, Val}, none} ->
- NewTree = gb_trees:insert(Var, Val, Acc),
- join_info_in(Left, LiveIn, Info1, Info2, NewTree);
- {{value, Val1}, {value, Val2}} ->
- NewTree = gb_trees:insert(Var, t_sup(Val1, Val2), Acc),
- join_info_in(Left, LiveIn, Info1, Info2, NewTree)
- end;
-join_info_in([], _LiveIn, _Info1, _Info2, Acc) ->
- Acc.
-
-info_is_equal(Info1, Info2) ->
- compare(gb_trees:to_list(Info1), gb_trees:to_list(Info2)).
-
-compare([{Var, Type1}|Left1], [{Var, Type2}|Left2]) ->
- t_is_equal(Type1, Type2) andalso compare(Left1, Left2);
-compare([], []) ->
- true;
-compare(_, _) ->
- false.
-
-const_type(Const) ->
- t_from_term(hipe_icode:const_value(Const)).
-
-do_updates(State, List) ->
- do_updates(State, List, []).
-
-do_updates(State, [{Label, Info}|Tail], Worklist) ->
- case state__info_in_update(State, Label, Info) of
- fixpoint ->
- %% io:format("Info in for ~w is: fixpoint\n", [Label]),
- do_updates(State, Tail, Worklist);
- NewState ->
- %% io:format("Info in for ~w is:\n", [Label]),
- %% [io:format("~w: ~p\n", [X, format_type(Y)])
- %% || {X, Y} <- gb_trees:to_list(state__info_in(NewState, Label))],
- do_updates(NewState, Tail, [Label|Worklist])
- end;
-do_updates(State, [], Worklist) ->
- {State, Worklist}.
-
-enter_defines(I, Type, Info) ->
- case defines(I) of
- [] -> Info;
- [Def] ->
- enter(Def, Type, Info);
- Defs ->
- Pairs = case t_is_any(Type) of
- true ->
- [{Def, t_any()} || Def <- Defs];
- false ->
- case t_is_none(Type) of
- true ->
- [{Def, t_none()} || Def <- Defs];
- false ->
- lists:zip(Defs, t_to_tlist(Type))
- end
- end,
- lists:foldl(fun({X, T}, Inf) -> enter(X, T, Inf) end, Info, Pairs)
- end.
-
-defines(I) ->
- keep_vars_and_regs(hipe_icode:defines(I)).
-
-call_dstlist(I) ->
- hipe_icode:call_dstlist(I).
-
-uses(I) ->
- keep_vars_and_regs(hipe_icode:uses(I)).
-
-keep_vars_and_regs(Vars) ->
- [V || V <- Vars, is_var_or_reg(V)].
-
-butlast([_]) ->
- [];
-butlast([H|T]) ->
- [H|butlast(T)].
-
--spec any_is_none([erl_types:erl_type()]) -> boolean().
-
-any_is_none(Types) ->
- lists:any(fun (T) -> t_is_none(T) end, Types).
-
-is_var_or_reg(X) ->
- hipe_icode:is_var(X) orelse hipe_icode:is_reg(X).
-
-%% _________________________________________________________________
-%%
-%% Handling the state
-%%
-
-new_state(Cfg, {MFA, GetCallFun, GetResFun, FinalAction}) ->
- Start = hipe_icode_cfg:start_label(Cfg),
- Params = hipe_icode_cfg:params(Cfg),
- ParamTypes = GetCallFun(MFA, Cfg),
- case any_is_none(ParamTypes) of
- true ->
- FinalAction(MFA, [t_none()]),
- throw(no_input);
- false ->
- Info = add_arg_types(Params, ParamTypes),
- InfoMap = gb_trees:insert({Start, in}, Info, gb_trees:empty()),
- Liveness = hipe_icode_ssa:ssa_liveness__analyze(Cfg),
- #state{info_map = InfoMap, cfg = Cfg, liveness = Liveness,
- arg_types = ParamTypes, lookupfun = GetResFun,
- resultaction = FinalAction}
- end.
-
-state__cfg(#state{cfg = Cfg}) ->
- Cfg.
-
-state__succ(#state{cfg = Cfg}, Label) ->
- hipe_icode_cfg:succ(Cfg, Label).
-
-state__bb(#state{cfg = Cfg}, Label) ->
- hipe_icode_cfg:bb(Cfg, Label).
-
-state__bb_add(S = #state{cfg = Cfg}, Label, BB) ->
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, BB),
- S#state{cfg=NewCfg}.
-
-state__params_update(S = #state{cfg = Cfg}, NewParams) ->
- NewCfg = hipe_icode_cfg:params_update(Cfg, NewParams),
- S#state{cfg = NewCfg}.
-
-state__ret_type(#state{ret_type = RT}) -> RT.
-
-state__lookupfun(#state{lookupfun = LF}) -> LF.
-
-state__resultaction(#state{resultaction = RA}) -> RA.
-
-state__info_in(S, Label) ->
- state__info(S, {Label, in}).
-
-state__info_out(S, Label) ->
- state__info(S, {Label, out}).
-
-state__info(#state{info_map = IM}, Label) ->
- case gb_trees:lookup(Label, IM) of
- {value, Info} -> Info;
- none -> gb_trees:empty()
- end.
-
-state__ret_type_update(#state{ret_type = RT} = State, NewType) when
- is_list(NewType) ->
- TotType = lists:zipwith(fun erl_types:t_sup/2, RT, NewType),
- State#state{ret_type = TotType};
-state__ret_type_update(#state{ret_type = RT} = State, NewType) ->
- state__ret_type_update(State, [NewType || _ <- RT]).
-
-state__info_in_update(S=#state{info_map=IM, liveness=Liveness}, Label, Info) ->
- LiveIn = hipe_icode_ssa:ssa_liveness__livein(Liveness, Label),
- LabelIn = {Label, in},
- case gb_trees:lookup(LabelIn, IM) of
- none ->
- OldInfo = gb_trees:empty(),
- case join_info_in(LiveIn, OldInfo, Info) of
- fixpoint ->
- %% If the BB has not been handled we ignore the fixpoint.
- S#state{info_map = gb_trees:enter(LabelIn, OldInfo, IM)};
- NewInfo ->
- S#state{info_map = gb_trees:enter(LabelIn, NewInfo, IM)}
- end;
- {value, OldInfo} ->
- case join_info_in(LiveIn, OldInfo, Info) of
- fixpoint ->
- fixpoint;
- NewInfo ->
- S#state{info_map = gb_trees:enter(LabelIn, NewInfo, IM)}
- end
- end.
-
-state__info_out_update(#state{info_map = IM} = State, Label, Info) ->
- State#state{info_map = gb_trees:enter({Label, out}, Info, IM)}.
-
-%% _________________________________________________________________
-%%
-%% The worklist.
-%%
-
-init_work(State) ->
- %% Labels = hipe_icode_cfg:reverse_postorder(state__cfg(State)),
- Labels = [hipe_icode_cfg:start_label(state__cfg(State))],
- {Labels, [], gb_sets:from_list(Labels)}.
-
-get_work({[Label|Left], List, Set}) ->
- NewWork = {Left, List, gb_sets:delete(Label, Set)},
- {Label, NewWork};
-get_work({[], [], _Set}) ->
- fixpoint;
-get_work({[], List, Set}) ->
- get_work({lists:reverse(List), [], Set}).
-
-add_work(Work = {List1, List2, Set}, [Label|Left]) ->
- case gb_sets:is_member(Label, Set) of
- true ->
- add_work(Work, Left);
- false ->
- %% io:format("Adding work: ~w\n", [Label]),
- add_work({List1, [Label|List2], gb_sets:insert(Label, Set)}, Left)
- end;
-add_work(Work, []) ->
- Work.
-
-%% _________________________________________________________________
-%%
-%% Annotator
-%%
-
-annotate_cfg(State) ->
- Cfg = state__cfg(State),
- NewState = annotate_params(hipe_icode_cfg:params(Cfg), State,
- hipe_icode_cfg:start_label(Cfg)),
- Labels = hipe_icode_cfg:reverse_postorder(Cfg),
- annotate_bbs(Labels, NewState).
-
-annotate_params(Params, State, Start) ->
- Info = state__info_in(State, Start),
- AnnoFun = fun hipe_icode:annotate_variable/2,
- NewParams =
- lists:zipwith(AnnoFun, Params, [make_annotation(P,Info) || P <- Params]),
- state__params_update(State,NewParams).
-
-annotate_bbs([Label|Left], State) ->
- BB = state__bb(State, Label),
- Code = hipe_bb:code(BB),
- Info = state__info_in(State, Label),
- NewCode = annotate_instr_list(Code, Info, state__lookupfun(State), []),
- NewBB = hipe_bb:code_update(BB, NewCode),
- NewState = state__bb_add(State, Label, NewBB),
- annotate_bbs(Left, NewState);
-annotate_bbs([], State) ->
- State.
-
-annotate_instr_list([I], Info, LookupFun, Acc) ->
- NewInfo =
- case I of
- #icode_call{} ->
- do_safe_call(I, Info, LookupFun);
- _ ->
- analyse_insn(I, Info, LookupFun)
- end,
- NewI = annotate_instr(I, NewInfo, Info),
- lists:reverse([NewI|Acc]);
-annotate_instr_list([I|Left], Info, LookupFun, Acc) ->
- NewInfo =
- case I of
- #icode_call{} ->
- do_safe_call(I, Info, LookupFun);
- _ ->
- analyse_insn(I, Info, LookupFun)
- end,
- NewI = annotate_instr(I, NewInfo, Info),
- annotate_instr_list(Left, NewInfo, LookupFun, [NewI|Acc]).
-
-annotate_instr(I, DefInfo, UseInfo) ->
- Def = defines(I),
- Use = uses(I),
- Fun = fun hipe_icode:annotate_variable/2,
- DefSubst = [{X, Fun(X, make_annotation(X, DefInfo))} || X <- Def],
- UseSubst = [{X, Fun(X, make_annotation(X, UseInfo))} || X <- Use],
- case DefSubst ++ UseSubst of
- [] ->
- I;
- Subst ->
- hipe_icode:subst(Subst, I)
- end.
-
-make_annotation(X, Info) ->
- {type_anno, safe_lookup(X, Info), fun erl_types:t_to_string/1}.
-
--spec unannotate_cfg(cfg()) -> cfg().
-
-unannotate_cfg(Cfg) ->
- NewCfg = unannotate_params(Cfg),
- Labels = hipe_icode_cfg:labels(NewCfg),
- unannotate_bbs(Labels, NewCfg).
-
-unannotate_params(Cfg) ->
- Params = hipe_icode_cfg:params(Cfg),
- NewParams = [hipe_icode:unannotate_variable(X)
- || X <- Params, hipe_icode:is_variable(X)],
- hipe_icode_cfg:params_update(Cfg, NewParams).
-
-unannotate_bbs([Label|Left], Cfg) ->
- BB = hipe_icode_cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- NewCode = unannotate_instr_list(Code, []),
- NewBB = hipe_bb:code_update(BB, NewCode),
- NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB),
- unannotate_bbs(Left, NewCfg);
-unannotate_bbs([], Cfg) ->
- Cfg.
-
-unannotate_instr_list([I|Left], Acc) ->
- NewI = unannotate_instr(I),
- unannotate_instr_list(Left, [NewI|Acc]);
-unannotate_instr_list([], Acc) ->
- lists:reverse(Acc).
-
-unannotate_instr(I) ->
- DefUses = hipe_icode:defines(I) ++ hipe_icode:uses(I),
- Subst = [{X, hipe_icode:unannotate_variable(X)} || X <- DefUses,
- hipe_icode:is_variable(X)],
- if Subst =:= [] -> I;
- true -> hipe_icode:subst(Subst, I)
- end.
-
-%% _________________________________________________________________
-%%
-%% Find the types of the arguments to a call
-%%
-
-update_call_arguments(I, Info) ->
- Args = hipe_icode:call_args(I),
- ArgTypes = lookup_list(Args, Info),
- Signature = find_signature(hipe_icode:call_fun(I), length(Args)),
- case t_fun_args(Signature) of
- unknown ->
- Info;
- PltArgTypes ->
- NewArgTypes = t_inf_lists(ArgTypes, PltArgTypes),
- enter_list(Args, NewArgTypes, Info)
- end.
-
-%% _________________________________________________________________
-%%
-%% PLT info
-%%
-
-find_signature(MFA = {_, _, _}, _) -> find_signature_mfa(MFA);
-find_signature(Primop, Arity) -> find_signature_primop(Primop, Arity).
-
-find_signature_mfa(MFA) ->
- case get_mfa_arg_types(MFA) of
- any ->
- t_fun(get_mfa_type(MFA));
- BifArgs ->
- t_fun(BifArgs, get_mfa_type(MFA))
- end.
-
-find_signature_primop(Primop, Arity) ->
- case get_primop_arg_types(Primop) of
- any ->
- t_fun(Arity, get_primop_type(Primop));
- ArgTypes ->
- t_fun(ArgTypes, get_primop_type(Primop))
- end.
-
-get_primop_arg_types(Primop) ->
- case hipe_icode_primops:arg_types(Primop) of
- unknown -> any;
- ArgTypes -> add_tuple_to_args(ArgTypes)
- end.
-
-get_mfa_arg_types({M, F, A}) ->
- case erl_bif_types:arg_types(M, F, A) of
- unknown ->
- any;
- BifArgs ->
- add_tuple_to_args(BifArgs)
- end.
-
-get_mfa_type({M, F, A}) ->
- erl_bif_types:type(M, F, A).
-
-get_primop_type(Primop) ->
- hipe_icode_primops:type(get_standard_primop(Primop)).
-
-add_tuple_to_args(Types) ->
- [add_tuple_to_type(T) || T <- Types].
-
-add_tuple_to_type(T) ->
- None = t_none(),
- case t_inf(t_fun(), T) of
- None -> T;
- _Other -> t_sup(T, t_tuple([t_atom(),t_atom()]))
- end.
-
-add_funs_to_arg_types(Types) ->
- [add_fun_to_arg_type(T) || T <- Types].
-
-add_fun_to_arg_type(T) ->
- None = t_none(),
- case t_inf(t_tuple([t_atom(),t_atom()]), T) of
- None -> T;
- _Other -> t_sup(T, t_fun())
- end.
-
-%%=====================================================================
-%% Icode Coordinator Callbacks
-%%=====================================================================
-
--spec replace_nones([erl_types:erl_type()] | erl_types:erl_type()) ->
- [erl_types:erl_type()].
-
-replace_nones(Types) when is_list(Types) ->
- [replace_none(T) || T <- Types];
-replace_nones(Type) ->
- [replace_none(Type)].
-
--spec replace_none(erl_types:erl_type()) -> erl_types:erl_type().
-
-replace_none(Type) ->
- case erl_types:t_is_none(Type) of
- true ->
- erl_types:t_any();
- false ->
- Type
- end.
-
--spec update__info([erl_types:erl_type()], [erl_types:erl_type()]) ->
- {boolean(), [erl_types:erl_type()]}.
-
-update__info(NewTypes, OldTypes) ->
- SupFun =
- fun(T1, T2) -> erl_types:t_limit(erl_types:t_sup(T1,T2), ?TYPE_DEPTH) end,
- EqFun = fun erl_types:t_is_equal/2,
- ResTypes = lists:zipwith(SupFun, NewTypes, OldTypes),
- Change = lists:zipwith(EqFun, ResTypes, OldTypes),
- {lists:all(fun(X) -> X end, Change), ResTypes}.
-
--spec new__info([erl_types:erl_type()]) -> [erl_types:erl_type()].
-
-new__info(NewTypes) ->
- [erl_types:t_limit(T, ?TYPE_DEPTH) || T <- NewTypes].
-
--spec return__info(erl_types:erl_type()) -> erl_types:erl_type().
-
-return__info(Types) ->
- Types.
-
--spec return_none() -> [erl_types:erl_type(),...].
-
-return_none() ->
- [erl_types:t_none()].
-
--spec return_none_args(cfg(), mfa()) -> [erl_types:erl_type()].
-
-return_none_args(Cfg, {_M,_F,A}) ->
- NoArgs =
- case hipe_icode_cfg:is_closure(Cfg) of
- true -> hipe_icode_cfg:closure_arity(Cfg) - 1;
- false -> A
- end,
- lists:duplicate(NoArgs, erl_types:t_none()).
-
--spec return_any_args(cfg(), mfa()) -> [erl_types:erl_type()].
-
-return_any_args(Cfg, {_M,_F,A}) ->
- NoArgs =
- case hipe_icode_cfg:is_closure(Cfg) of
- true -> hipe_icode_cfg:closure_arity(Cfg);
- false -> A
- end,
- lists:duplicate(NoArgs, erl_types:t_any()).
-
-%%=====================================================================
-%% Testing function below
-%%=====================================================================
-
--ifdef(DO_HIPE_ICODE_TYPE_TEST).
-
-test() ->
- Range1 = t_from_range(1, pos_inf),
- Range2 = t_from_range(0, 5),
- Var1 = hipe_icode:mk_var(1),
- Var2 = hipe_icode:mk_var(2),
-
- Info = enter(Var1, Range1, enter(Var2, Range2, gb_trees:empty())),
- io:format("A1 ~p~n", [Info]),
- A = integer_range_inequality_propagation('<', Var1, Var2, 1, 2, Info),
- B = integer_range_inequality_propagation('>=', Var1, Var2, 1, 2, Info),
- C = integer_range_inequality_propagation('=<', Var1, Var2, 1, 2, Info),
- D = integer_range_inequality_propagation('>', Var1, Var2, 1, 2, Info),
-
- io:format("< ~p~n", [A]),
- io:format(">= ~p~n", [B]),
- io:format("<= ~p~n", [C]),
- io:format("> ~p~n", [D]).
-
--endif.
diff --git a/lib/hipe/icode/hipe_icode_type.hrl b/lib/hipe/icode/hipe_icode_type.hrl
deleted file mode 100644
index b7c200eef1..0000000000
--- a/lib/hipe/icode/hipe_icode_type.hrl
+++ /dev/null
@@ -1,19 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_icode_type.hrl
-%%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%%% Created : 2 Sep 2004 by Tobias Lindahl <tobiasl@it.uu.se>
-%%%-------------------------------------------------------------------
-
--define(TYPE_DEPTH, 3).
diff --git a/lib/hipe/info b/lib/hipe/info
deleted file mode 100644
index fe08fc8990..0000000000
--- a/lib/hipe/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: misc Miscellaneous Applications
-short: High Performance Erlang \ No newline at end of file
diff --git a/lib/hipe/llvm/Makefile b/lib/hipe/llvm/Makefile
deleted file mode 100644
index 5e8f2076db..0000000000
--- a/lib/hipe/llvm/Makefile
+++ /dev/null
@@ -1,119 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2020. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-ifdef HIPE_ENABLED
-HIPE_MODULES = elf_format \
- hipe_llvm \
- hipe_llvm_liveness \
- hipe_llvm_main \
- hipe_llvm_merge \
- hipe_rtl_to_llvm
-else
-HIPE_MODULES =
-endif
-
-MODULES = $(HIPE_MODULES)
-
-HRL_FILES= elf_format.hrl elf32_format.hrl elf64_format.hrl hipe_llvm_arch.hrl
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-# APP_FILE=
-# App_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS: Please keep +inline below
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += +inline +warn_export_vars #+warn_missing_spec
-ifneq ($(NATIVE_LIBS_ENABLED),yes)
-ERL_COMPILE_FLAGS += -Werror
-endif
-
-# if in 32 bit backend define BIT32 symbol
-ifneq ($(BITS64),yes)
-ERL_COMPILE_FLAGS += -DBIT32
-endif
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core erl_crash.dump
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/llvm
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/llvm
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
-
-release_docs_spec:
-
-$(EBIN)/elf_format.beam: elf_format.hrl elf32_format.hrl elf64_format.hrl
-$(EBIN)/hipe_llvm_main.beam: ../../kernel/src/hipe_ext_format.hrl \
- hipe_llvm_arch.hrl elf_format.hrl elf32_format.hrl elf64_format.hrl
-$(EBIN)/hipe_llvm_merge.beam: ../../kernel/src/hipe_ext_format.hrl \
- hipe_llvm_arch.hrl ../rtl/hipe_literals.hrl ../main/hipe.hrl
-$(EBIN)/hipe_rtl_to_llvm.beam: ../rtl/hipe_rtl.hrl ../rtl/hipe_literals.hrl \
- hipe_llvm_arch.hrl
diff --git a/lib/hipe/llvm/elf32_format.hrl b/lib/hipe/llvm/elf32_format.hrl
deleted file mode 100644
index af1d95bf5b..0000000000
--- a/lib/hipe/llvm/elf32_format.hrl
+++ /dev/null
@@ -1,59 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
-%%% @copyright 2011-2014 Yiannis Tsiouris <gtsiour@softlab.ntua.gr>,
-%%% Chris Stavrakakis <hydralisk.r@gmail.com>
-%%% @author Yiannis Tsiouris <gtsiour@softlab.ntua.gr>
-%%% [http://www.softlab.ntua.gr/~gtsiour/]
-
-%%% @doc This header file contains very very useful macros for handling
-%%% various segments of an ELF-32 formated object file, such as sizes,
-%%% offsets and predefined constants. For further information about
-%%% each field take a quick look at
-%%% "[http://www.sco.com/developers/gabi/latest/contents.html]"
-%%% that contain the current HP/Intel definition of the ELF object
-%%% file format.
-
-%%------------------------------------------------------------------------------
-%% ELF-32 Data Types (in bytes)
-%%------------------------------------------------------------------------------
--define(ELF_ADDR_SIZE, 4).
--define(ELF_OFF_SIZE, 4).
--define(ELF_HALF_SIZE, 2).
--define(ELF_WORD_SIZE, 4).
--define(ELF_SWORD_SIZE, 4).
--define(ELF_XWORD_SIZE, ?ELF_WORD_SIZE). % for compatibility
--define(ELF_SXWORD_SIZE, ?ELF_WORD_SIZE).
--define(ELF_UNSIGNED_CHAR_SIZE, 1).
-
-%%------------------------------------------------------------------------------
-%% ELF-32 Symbol Table Entries
-%%------------------------------------------------------------------------------
-%% Precomputed offset for Symbol Table entries in SymTab binary (needed because
-%% of the different offsets in 32 and 64 bit formats).
--define(ST_NAME_OFFSET, 0).
--define(ST_VALUE_OFFSET, (?ST_NAME_OFFSET + ?ST_NAME_SIZE) ).
--define(ST_SIZE_OFFSET, (?ST_VALUE_OFFSET + ?ST_VALUE_SIZE) ).
--define(ST_INFO_OFFSET, (?ST_SIZE_OFFSET + ?ST_SIZE_SIZE) ).
--define(ST_OTHER_OFFSET, (?ST_INFO_OFFSET + ?ST_INFO_SIZE) ).
--define(ST_SHNDX_OFFSET, (?ST_OTHER_OFFSET + ?ST_OTHER_SIZE) ).
-
-%%------------------------------------------------------------------------------
-%% ELF-64 Relocation Entries
-%%------------------------------------------------------------------------------
-%% Useful macros to extract information from r_info field
--define(ELF_R_SYM(I), (I bsr 8) ).
--define(ELF_R_TYPE(I), (I band 16#ff) ).
--define(ELF_R_INFO(S, T), ((S bsl 8) + (T band 16#ff)) ).
-
-%%------------------------------------------------------------------------------
-%% ELF-64 Program Header Table
-%%------------------------------------------------------------------------------
-%% Offsets of various fields in a Program Header Table entry binary.
--define(P_TYPE_OFFSET, 0).
--define(P_OFFSET_OFFSET, (?P_FLAGS_OFFSET + ?P_FLAGS_SIZE) ).
--define(P_VADDR_OFFSET, (?P_OFFSET_OFFSET + ?P_OFFSET_SIZE) ).
--define(P_PADDR_OFFSET, (?P_VADDR_OFFSET + ?P_VADDR_SIZE) ).
--define(P_FILESZ_OFFSET, (?P_PVADDR_OFFSET + ?P_PVADDR_SIZE) ).
--define(P_MEMSZ_OFFSET, (?P_FILESZ_OFFSET + ?P_FILESZ_SIZE) ).
--define(P_FLAGS_OFFSET, (?P_TYPE_OFFSET + ?P_TYPE_SIZE) ).
--define(P_ALIGN_OFFSET, (?P_MEMSZ_OFFSET + ?P_MEMSZ_SIZE) ).
diff --git a/lib/hipe/llvm/elf64_format.hrl b/lib/hipe/llvm/elf64_format.hrl
deleted file mode 100644
index 794746ffdc..0000000000
--- a/lib/hipe/llvm/elf64_format.hrl
+++ /dev/null
@@ -1,58 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
-%%% @copyright 2011-2014 Yiannis Tsiouris <gtsiour@softlab.ntua.gr>,
-%%% Chris Stavrakakis <hydralisk.r@gmail.com>
-%%% @author Yiannis Tsiouris <gtsiour@softlab.ntua.gr>
-%%% [http://www.softlab.ntua.gr/~gtsiour/]
-
-%%% @doc This header file contains very very useful macros for handling
-%%% various segments of an ELF-64 formated object file, such as sizes,
-%%% offsets and predefined constants. For further information about
-%%% each field take a quick look at
-%%% "[http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf]"
-%%% that contain the current HP/Intel definition of the ELF object
-%%% file format.
-
-%%------------------------------------------------------------------------------
-%% ELF-64 Data Types (in bytes)
-%%------------------------------------------------------------------------------
--define(ELF_ADDR_SIZE, 8).
--define(ELF_OFF_SIZE, 8).
--define(ELF_HALF_SIZE, 2).
--define(ELF_WORD_SIZE, 4).
--define(ELF_SWORD_SIZE, 4).
--define(ELF_XWORD_SIZE, 8).
--define(ELF_SXWORD_SIZE, 8).
--define(ELF_UNSIGNED_CHAR_SIZE, 1).
-
-%%------------------------------------------------------------------------------
-%% ELF-64 Symbol Table Entries
-%%------------------------------------------------------------------------------
-%% Precomputed offset for Symbol Table entries in SymTab binary
--define(ST_NAME_OFFSET, 0).
--define(ST_INFO_OFFSET, (?ST_NAME_OFFSET + ?ST_NAME_SIZE) ).
--define(ST_OTHER_OFFSET, (?ST_INFO_OFFSET + ?ST_INFO_SIZE) ).
--define(ST_SHNDX_OFFSET, (?ST_OTHER_OFFSET + ?ST_OTHER_SIZE) ).
--define(ST_VALUE_OFFSET, (?ST_SHNDX_OFFSET + ?ST_SHNDX_SIZE) ).
--define(ST_SIZE_OFFSET, (?ST_VALUE_OFFSET + ?ST_VALUE_SIZE) ).
-
-%%------------------------------------------------------------------------------
-%% ELF-64 Relocation Entries
-%%------------------------------------------------------------------------------
-%% Useful macros to extract information from r_info field
--define(ELF_R_SYM(I), (I bsr 32) ).
--define(ELF_R_TYPE(I), (I band 16#ffffffff) ).
--define(ELF_R_INFO(S, T), ((S bsl 32) + (T band 16#ffffffff)) ).
-
-%%------------------------------------------------------------------------------
-%% ELF-64 Program Header Table
-%%------------------------------------------------------------------------------
-%% Offsets of various fields in a Program Header Table entry binary.
--define(P_TYPE_OFFSET, 0).
--define(P_FLAGS_OFFSET, (?P_TYPE_OFFSET + ?P_TYPE_SIZE) ).
--define(P_OFFSET_OFFSET, (?P_FLAGS_OFFSET + ?P_FLAGS_SIZE) ).
--define(P_VADDR_OFFSET, (?P_OFFSET_OFFSET + ?P_OFFSET_SIZE) ).
--define(P_PADDR_OFFSET, (?P_VADDR_OFFSET + ?P_VADDR_SIZE) ).
--define(P_FILESZ_OFFSET, (?P_PVADDR_OFFSET + ?P_PVADDR_SIZE) ).
--define(P_MEMSZ_OFFSET, (?P_FILESZ_OFFSET + ?P_FILESZ_SIZE) ).
--define(P_ALIGN_OFFSET, (?P_MEMSZ_OFFSET + ?P_MEMSZ_SIZE) ).
diff --git a/lib/hipe/llvm/elf_format.erl b/lib/hipe/llvm/elf_format.erl
deleted file mode 100644
index 8cf6ea6250..0000000000
--- a/lib/hipe/llvm/elf_format.erl
+++ /dev/null
@@ -1,620 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
-%%% @copyright 2011-2014 Yiannis Tsiouris <gtsiour@softlab.ntua.gr>,
-%%% Chris Stavrakakis <hydralisk.r@gmail.com>,
-%%% Kostis Sagonas <kostis@cs.ntua.gr>
-%%% @author Yiannis Tsiouris <gtsiour@softlab.ntua.gr>
-%%% [http://www.softlab.ntua.gr/~gtsiour/]
-
-%%% @doc This module contains functions for extracting various pieces of
-%%% information from an ELF formated Object file. To fully understand
-%%% the ELF format and the use of these functions please read
-%%% "[http://www.linuxjournal.com/article/1060?page=0,0]" carefully.
-
--module(elf_format).
-
--export([%% Relocations
- extract_rela/2,
- %% Note
- extract_note/2,
- %% Executable code
- extract_text/1,
- %% GCC Exception Table
- get_exn_handlers/1,
- %% Symbols
- elf_symbols/1,
- %% Sections
- section_contents/2,
- %% Main interface
- read/1
- ]).
-
--include("elf_format.hrl").
-
-%%------------------------------------------------------------------------------
-%% Types
-%%------------------------------------------------------------------------------
-
--export_type([elf/0
- ,addend/0
- ,bitflags/0
- ,name/0
- ,offset/0
- ,reloc_type/0
- ,shdr_type/0
- ,size/0
- ,sym_bind/0
- ,sym_type/0
- ,valueoff/0
- ]).
-
--type bitflags() :: non_neg_integer().
--type index() :: non_neg_integer().
--type lp() :: non_neg_integer(). % landing pad
--type num() :: non_neg_integer().
--type offset() :: non_neg_integer().
--type size() :: non_neg_integer().
--type start() :: non_neg_integer().
-
--type addend() :: integer() | undefined.
--type name() :: string().
--type shdr_type() :: 'null' | 'progbits' | 'symtab' | 'strtab' | 'rela'
- | 'hash' | 'dynamic' | 'note' | 'nobits' | 'rel' | 'shlib'
- | 'dynsym' | {os, ?SHT_LOOS..?SHT_HIOS}
- | {proc, ?SHT_LOPROC..?SHT_HIPROC}.
--type sym_bind() :: 'local' | 'global' | 'weak' | {os, ?STB_LOOS..?STB_HIOS}
- | {proc, ?STB_LOPROC..?STB_HIPROC}.
--type sym_type() :: 'notype' | 'object' | 'func' | 'section' | 'file'
- | {os, ?STT_LOOS..?STT_HIOS}
- | {proc, ?STT_LOPROC..?STT_HIPROC}.
--type valueoff() :: offset().
-
--ifdef(BIT32). % 386
--type reloc_type() :: '32' | 'pc32'.
--else. % X86_64
--type reloc_type() :: '64' | 'pc32' | '32'.
--endif.
-
-%%------------------------------------------------------------------------------
-%% Abstract Data Types and Accessors for ELF Structures.
-%%------------------------------------------------------------------------------
-
--record(elf, {file :: binary()
- ,sections :: [elf_shdr()]
- ,sec_nam :: #{string() => elf_shdr()}
- ,symbols :: undefined | [elf_sym()]
- }).
--opaque elf() :: #elf{}.
-
-%% File header
--record(elf_ehdr, {ident, % ELF identification
- type, % Object file type
- machine, % Machine Type
- version, % Object file version
- entry, % Entry point address
- phoff, % Program header offset
- shoff :: offset(), % Section header offset
- flags, % Processor-specific flags
- ehsize :: size(), % ELF header size
- phentsize :: size(), % Size of program header entry
- phnum :: num(), % Number of program header entries
- shentsize :: size(), % Size of section header entry
- shnum :: num(), % Number of section header entries
- shstrndx :: index() % Section name string table index
- }).
--type elf_ehdr() :: #elf_ehdr{}.
-
--record(elf_ehdr_ident, {class, % File class
- data, % Data encoding
- version, % File version
- osabi, % OS/ABI identification
- abiversion, % ABI version
- pad, % Start of padding bytes
- nident % Size of e_ident[]
- }).
-%% -type elf_ehdr_ident() :: #elf_ehdr_ident{}.
-
-%% %% Program header table
-%% -record(elf_phdr, {type, % Type of segment
-%% flags, % Segment attributes
-%% offset, % Offset in file
-%% vaddr, % Virtual address in memory
-%% paddr, % Reserved
-%% filesz, % Size of segment in file
-%% memsz, % Size of segment in memory
-%% align % Alignment of segment
-%% }).
-
-%% %% GCC exception table
-%% -record(elf_gccexntab, {lpbenc, % Landing pad base encoding
-%% lpbase, % Landing pad base
-%% ttenc, % Type table encoding
-%% ttoff, % Type table offset
-%% csenc, % Call-site table encoding
-%% cstabsize, % Call-site table size
-%% cstab :: cstab() % Call-site table
-%% }).
-%% -type elf_gccexntab() :: #elf_gccexntab{}.
-
--record(elf_gccexntab_callsite, {start :: start(), % Call-site start
- size :: size(), % Call-site size
- lp :: lp(), % Call-site landing pad
- % (exception handler)
- onaction % On action (e.g. cleanup)
- }).
-%% -type elf_gccexntab_callsite() :: #elf_gccexntab_callsite{}.
-
-%%------------------------------------------------------------------------------
-%% Accessor Functions
-%%------------------------------------------------------------------------------
-
-%% File header
-%% -spec mk_ehdr(...) -> elf_ehrd().
-mk_ehdr(Ident, Type, Machine, Version, Entry, Phoff, Shoff, Flags, Ehsize,
- Phentsize, Phnum, Shentsize, Shnum, Shstrndx) ->
- #elf_ehdr{ident = Ident, type = Type, machine = Machine, version = Version,
- entry = Entry, phoff = Phoff, shoff = Shoff, flags = Flags,
- ehsize = Ehsize, phentsize = Phentsize, phnum = Phnum,
- shentsize = Shentsize, shnum = Shnum, shstrndx = Shstrndx}.
-
-%% -spec ehdr_shoff(elf_ehdr()) -> offset().
-%% ehdr_shoff(#elf_ehdr{shoff = Offset}) -> Offset.
-%%
-%% -spec ehdr_shentsize(elf_ehdr()) -> size().
-%% ehdr_shentsize(#elf_ehdr{shentsize = Size}) -> Size.
-%%
-%% -spec ehdr_shnum(elf_ehdr()) -> num().
-%% ehdr_shnum(#elf_ehdr{shnum = Num}) -> Num.
-%%
-%% -spec ehdr_shstrndx(elf_ehdr()) -> index().
-%% ehdr_shstrndx(#elf_ehdr{shstrndx = Index}) -> Index.
-
-
-%%-spec mk_ehdr_ident(...) -> elf_ehdr_ident().
-mk_ehdr_ident(Class, Data, Version, OsABI, AbiVersion, Pad, Nident) ->
- #elf_ehdr_ident{class = Class, data = Data, version = Version, osabi = OsABI,
- abiversion = AbiVersion, pad = Pad, nident = Nident}.
-
-%%%-------------------------
-%%% Section header entries
-%%%-------------------------
-mk_shdr(Name, Type, Flags, Addr, Offset, Size, Link, Info, AddrAlign, EntSize) ->
- #elf_shdr{name = Name, type = Type, flags = Flags, addr = Addr,
- offset = Offset, size = Size, link = Link, info = Info,
- addralign = AddrAlign, entsize = EntSize}.
-
-%% -spec shdr_offset(elf_shdr()) -> offset().
-%% shdr_offset(#elf_shdr{offset = Offset}) -> Offset.
-%%
-%% -spec shdr_size(elf_shdr()) -> size().
-%% shdr_size(#elf_shdr{size = Size}) -> Size.
-
-%%%-------------------------
-%%% Symbol Table Entries
-%%%-------------------------
-mk_sym(Name, Bind, Type, Section, Value, Size) ->
- #elf_sym{name = Name, bind = Bind, type = Type,
- section = Section, value = Value, size = Size}.
-
-%% -spec sym_name(elf_sym()) -> string().
-%% sym_name(#elf_sym{name = Name}) -> Name.
-%%
-%% -spec sym_value(elf_sym()) -> valueoff().
-%% sym_value(#elf_sym{value = Value}) -> Value.
-%%
-%% -spec sym_size(elf_sym()) -> size().
-%% sym_size(#elf_sym{size = Size}) -> Size.
-
-%% %%%-------------------------
-%% %%% GCC exception table
-%% %%%-------------------------
-%% -type cstab() :: [elf_gccexntab_callsite()].
-%%
-%% mk_gccexntab(LPbenc, LPbase, TTenc, TToff, CSenc, CStabsize, CStab) ->
-%% #elf_gccexntab{lpbenc = LPbenc, lpbase = LPbase, ttenc = TTenc,
-%% ttoff = TToff, csenc = CSenc, cstabsize = CStabsize,
-%% cstab = CStab}.
-%%
-%% -spec gccexntab_cstab(elf_gccexntab()) -> cstab().
-%% gccexntab_cstab(#elf_gccexntab{cstab = CSTab}) -> CSTab.
-
-mk_gccexntab_callsite(Start, Size, LP, Action) ->
- #elf_gccexntab_callsite{start = Start, size=Size, lp=LP, onaction=Action}.
-
-%% -spec gccexntab_callsite_start(elf_gccexntab_callsite()) -> start().
-%% gccexntab_callsite_start(#elf_gccexntab_callsite{start = Start}) -> Start.
-%%
-%% -spec gccexntab_callsite_size(elf_gccexntab_callsite()) -> size().
-%% gccexntab_callsite_size(#elf_gccexntab_callsite{size = Size}) -> Size.
-%%
-%% -spec gccexntab_callsite_lp(elf_gccexntab_callsite()) -> lp().
-%% gccexntab_callsite_lp(#elf_gccexntab_callsite{lp = LP}) -> LP.
-
-%%------------------------------------------------------------------------------
-%% Main interface function
-%%------------------------------------------------------------------------------
-
-%% @doc Parses an ELF file.
--spec read(binary()) -> elf().
-read(ElfBin) ->
- Header = extract_header(ElfBin),
- [_UndefinedSec|Sections] = extract_shdrtab(ElfBin, Header),
- SecNam = maps:from_list(
- [{Name, Sec} || Sec = #elf_shdr{name=Name} <- Sections]),
- Elf0 = #elf{file=ElfBin, sections=Sections, sec_nam=SecNam},
- [_UndefinedSym|Symbols] = extract_symtab(Elf0, extract_strtab(Elf0)),
- Elf0#elf{symbols=Symbols}.
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate the ELF File Header
-%%------------------------------------------------------------------------------
-
-%% @doc Extracts the File Header from an ELF formatted object file. Also sets
-%% the ELF class variable in the process dictionary (used by many functions
-%% in this and hipe_llvm_main modules).
--spec extract_header(binary()) -> elf_ehdr().
-extract_header(ElfBin) ->
- Ehdr_bin = get_binary_segment(ElfBin, 0, ?ELF_EHDR_SIZE),
- << %% Structural pattern matching on fields.
- Ident_bin:?E_IDENT_SIZE/binary,
- Type:?bits(?E_TYPE_SIZE)/integer-little,
- Machine:?bits(?E_MACHINE_SIZE)/integer-little,
- Version:?bits(?E_VERSION_SIZE)/integer-little,
- Entry:?bits(?E_ENTRY_SIZE)/integer-little,
- Phoff:?bits(?E_PHOFF_SIZE)/integer-little,
- Shoff:?bits(?E_SHOFF_SIZE)/integer-little,
- Flags:?bits(?E_FLAGS_SIZE)/integer-little,
- Ehsize:?bits(?E_EHSIZE_SIZE)/integer-little,
- Phentsize:?bits(?E_PHENTSIZE_SIZE)/integer-little,
- Phnum:?bits(?E_PHNUM_SIZE)/integer-little,
- Shentsize:?bits(?E_SHENTSIZE_SIZE)/integer-little,
- Shnum:?bits(?E_SHENTSIZE_SIZE)/integer-little,
- Shstrndx:?bits(?E_SHSTRNDX_SIZE)/integer-little
- >> = Ehdr_bin,
- <<16#7f, $E, $L, $F, Class, Data, Version, Osabi, Abiversion,
- Pad:6/binary, Nident
- >> = Ident_bin,
- Ident = mk_ehdr_ident(Class, Data, Version, Osabi,
- Abiversion, Pad, Nident),
- mk_ehdr(Ident, Type, Machine, Version, Entry, Phoff, Shoff, Flags,
- Ehsize, Phentsize, Phnum, Shentsize, Shnum, Shstrndx).
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate Section Header Entries
-%%------------------------------------------------------------------------------
-
--type shdrtab() :: [elf_shdr()].
-
-%% @doc Extracts the Section Header Table from an ELF formated Object File.
--spec extract_shdrtab(binary(), elf_ehdr()) -> shdrtab().
-extract_shdrtab(ElfBin, #elf_ehdr{shoff=ShOff, shentsize=?ELF_SHDRENTRY_SIZE,
- shnum=ShNum, shstrndx=ShStrNdx}) ->
- %% Get actual Section header table (binary)
- ShdrBin = get_binary_segment(ElfBin, ShOff, ShNum * ?ELF_SHDRENTRY_SIZE),
- %% We need to lookup the offset and size of the section header string table
- %% before we can fully parse the section table. We compute its offset and
- %% extract the fields we need here.
- ShStrEntryOffset = ShStrNdx * ?ELF_SHDRENTRY_SIZE,
- <<_:ShStrEntryOffset/binary, _:?SH_NAME_SIZE/binary,
- _:?SH_TYPE_SIZE/binary, _:?SH_FLAGS_SIZE/binary, _:?SH_ADDR_SIZE/binary,
- ShStrOffset:?bits(?SH_OFFSET_SIZE)/little,
- ShStrSize:?bits(?SH_SIZE_SIZE)/little,
- _/binary>> = ShdrBin,
- ShStrTab = parse_strtab(get_binary_segment(ElfBin, ShStrOffset, ShStrSize)),
- get_shdrtab_entries(ShdrBin, ShStrTab).
-
-get_shdrtab_entries(<<>>, _ShStrTab) -> [];
-get_shdrtab_entries(ShdrTab, ShStrTab) ->
- <<%% Structural pattern matching on fields.
- Name:?bits(?SH_NAME_SIZE)/integer-little,
- Type:?bits(?SH_TYPE_SIZE)/integer-little,
- Flags:?bits(?SH_FLAGS_SIZE)/integer-little,
- Addr:?bits(?SH_ADDR_SIZE)/integer-little,
- Offset:?bits(?SH_OFFSET_SIZE)/integer-little,
- Size:?bits(?SH_SIZE_SIZE)/integer-little,
- Link:?bits(?SH_LINK_SIZE)/integer-little,
- Info:?bits(?SH_INFO_SIZE)/integer-little,
- Addralign:?bits(?SH_ADDRALIGN_SIZE)/integer-little,
- Entsize:?bits(?SH_ENTSIZE_SIZE)/integer-little,
- Rest/binary
- >> = ShdrTab,
- Entry = mk_shdr(get_strtab_entry(Name, ShStrTab), decode_shdr_type(Type),
- Flags, Addr, Offset, Size, Link, Info, Addralign, Entsize),
- [Entry | get_shdrtab_entries(Rest, ShStrTab)].
-
-decode_shdr_type(?SHT_NULL) -> 'null';
-decode_shdr_type(?SHT_PROGBITS) -> 'progbits';
-decode_shdr_type(?SHT_SYMTAB) -> 'symtab';
-decode_shdr_type(?SHT_STRTAB) -> 'strtab';
-decode_shdr_type(?SHT_RELA) -> 'rela';
-decode_shdr_type(?SHT_HASH) -> 'hash'; %unused
-decode_shdr_type(?SHT_DYNAMIC) -> 'dynamic'; %unused
-decode_shdr_type(?SHT_NOTE) -> 'note'; %unused
-decode_shdr_type(?SHT_NOBITS) -> 'nobits';
-decode_shdr_type(?SHT_REL) -> 'rel';
-decode_shdr_type(?SHT_SHLIB) -> 'shlib'; %unused
-decode_shdr_type(?SHT_DYNSYM) -> 'dynsym'; %unused
-decode_shdr_type(OS) when ?SHT_LOOS =< OS, OS =< ?SHT_HIOS -> {os, OS};
-decode_shdr_type(Proc) when ?SHT_LOPROC =< Proc, Proc =< ?SHT_HIPROC ->
- {proc, Proc}.
-
--spec elf_section(non_neg_integer(), elf()) -> undefined | abs | elf_shdr().
-elf_section(0, #elf{}) -> undefined;
-elf_section(?SHN_ABS, #elf{}) -> abs;
-elf_section(Index, #elf{sections=SecIdx}) ->
- lists:nth(Index, SecIdx).
-
-%% Reads the contents of a section from an object
--spec section_contents(elf_shdr(), elf()) -> binary().
-section_contents(#elf_shdr{offset=Offset, size=Size}, #elf{file=ElfBin}) ->
- get_binary_segment(ElfBin, Offset, Size).
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate Symbol Table
-%%------------------------------------------------------------------------------
-
-%% @doc Function that extracts Symbol Table from an ELF Object file.
-extract_symtab(Elf, StrTab) ->
- Symtab = extract_segment_by_name(Elf, ?SYMTAB),
- [parse_sym(Sym, Elf, StrTab) || <<Sym:?ELF_SYM_SIZE/binary>> <= Symtab].
-
--ifdef(BIT32).
-parse_sym(<<%% Structural pattern matching on fields.
- Name:?bits(?ST_NAME_SIZE)/integer-little,
- Value:?bits(?ST_VALUE_SIZE)/integer-little,
- Size:?bits(?ST_SIZE_SIZE)/integer-little,
- Info:?bits(?ST_INFO_SIZE)/integer-little,
- _Other:?bits(?ST_OTHER_SIZE)/integer-little,
- Shndx:?bits(?ST_SHNDX_SIZE)/integer-little>>,
- Elf, StrTab) ->
- mk_sym(get_strtab_entry(Name, StrTab), decode_symbol_bind(?ELF_ST_BIND(Info)),
- decode_symbol_type(?ELF_ST_TYPE(Info)), elf_section(Shndx, Elf), Value,
- Size).
--else.
-parse_sym(<<%% Same fields in different order:
- Name:?bits(?ST_NAME_SIZE)/integer-little,
- Info:?bits(?ST_INFO_SIZE)/integer-little,
- _Other:?bits(?ST_OTHER_SIZE)/integer-little,
- Shndx:?bits(?ST_SHNDX_SIZE)/integer-little,
- Value:?bits(?ST_VALUE_SIZE)/integer-little,
- Size:?bits(?ST_SIZE_SIZE)/integer-little>>,
- Elf, StrTab) ->
- mk_sym(get_strtab_entry(Name, StrTab), decode_symbol_bind(?ELF_ST_BIND(Info)),
- decode_symbol_type(?ELF_ST_TYPE(Info)), elf_section(Shndx, Elf), Value,
- Size).
--endif.
-
-decode_symbol_bind(?STB_LOCAL) -> 'local';
-decode_symbol_bind(?STB_GLOBAL) -> 'global';
-decode_symbol_bind(?STB_WEAK) -> 'weak'; %unused
-decode_symbol_bind(OS) when ?STB_LOOS =< OS, OS =< ?STB_HIOS -> {os, OS};
-decode_symbol_bind(Proc) when ?STB_LOPROC =< Proc, Proc =< ?STB_HIPROC ->
- {proc, Proc}.
-
-decode_symbol_type(?STT_NOTYPE) -> 'notype';
-decode_symbol_type(?STT_OBJECT) -> 'object';
-decode_symbol_type(?STT_FUNC) -> 'func';
-decode_symbol_type(?STT_SECTION) -> 'section';
-decode_symbol_type(?STT_FILE) -> 'file';
-decode_symbol_type(OS) when ?STT_LOOS =< OS, OS =< ?STT_HIOS -> {os, OS};
-decode_symbol_type(Proc) when ?STT_LOPROC =< Proc, Proc =< ?STT_HIPROC ->
- {proc, Proc}.
-
-%% @doc Extracts a specific entry from the Symbol Table.
--spec elf_symbol(0, elf()) -> undefined;
- (pos_integer(), elf()) -> elf_sym().
-elf_symbol(0, #elf{}) -> undefined;
-elf_symbol(Index, #elf{symbols=Symbols}) -> lists:nth(Index, Symbols).
-
--spec elf_symbols(elf()) -> [elf_sym()].
-elf_symbols(#elf{symbols=Symbols}) -> Symbols.
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate String Table
-%%------------------------------------------------------------------------------
-
-%% ADT: get_strtab_entry/1 must be used to consume this type.
--type strtab() :: binary().
-
-%% @doc Extracts String Table from an ELF formated Object File.
--spec extract_strtab(elf()) -> strtab().
-extract_strtab(Elf) ->
- parse_strtab(extract_segment_by_name(Elf, ?STRTAB)).
-
--spec parse_strtab(binary()) -> strtab().
-parse_strtab(StrTabSectionBin) -> StrTabSectionBin.
-
-%% @doc Returns the name of the symbol at the given offset.
--spec get_strtab_entry(non_neg_integer(), strtab()) -> string().
-get_strtab_entry(Offset, StrTab) ->
- <<_:Offset/binary, StrBin/binary>> = StrTab,
- bin_get_string(StrBin).
-
-%% @doc Extracts a null-terminated string from a binary.
--spec bin_get_string(binary()) -> string().
-%% FIXME: No regard for encoding (just happens to work for ASCII and Latin-1)
-bin_get_string(<<0, _/binary>>) -> [];
-bin_get_string(<<Char, Rest/binary>>) -> [Char|bin_get_string(Rest)].
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate Relocations
-%%------------------------------------------------------------------------------
-
-%% @doc Extract the Relocations segment for section `Name' (that is passed
-%% as second argument) from an ELF formated Object file binary.
--spec extract_rela(elf(), name()) -> [elf_rel()].
-
--ifdef(BIT32).
-extract_rela(Elf, Name) ->
- SecData = extract_segment_by_name(Elf, Name),
- [#elf_rel{offset=Offset, symbol=elf_symbol(?ELF_R_SYM(Info), Elf),
- type=decode_reloc_type(?ELF_R_TYPE(Info)),
- addend=read_implicit_addend(Offset, SecData)}
- || <<Offset:?bits(?R_OFFSET_SIZE)/little,
- Info:?bits(?R_INFO_SIZE)/little % 386 uses ".rel"
- >> <= extract_segment_by_name(Elf, ?REL(Name))].
-
-%% The only types HiPE knows how to patch
-decode_reloc_type(1) -> '32';
-decode_reloc_type(2) -> 'pc32'.
-
-read_implicit_addend(Offset, Section) ->
- %% All x86 relocation types uses 'word32' relocation fields; i.e. 32-bit LE.
- <<_:Offset/binary, Addend:32/signed-little, _/binary>> = Section,
- Addend.
-
--else. %% BIT32
-extract_rela(Elf, Name) ->
- [#elf_rel{offset=Offset, symbol=elf_symbol(?ELF_R_SYM(Info), Elf),
- type=decode_reloc_type(?ELF_R_TYPE(Info)), addend=Addend}
- || <<Offset:?bits(?R_OFFSET_SIZE)/little,
- Info:?bits(?R_INFO_SIZE)/little,
- Addend:?bits(?R_ADDEND_SIZE)/signed-little % X86_64 uses ".rela"
- >> <= extract_segment_by_name(Elf, ?RELA(Name))].
-
-decode_reloc_type(1) -> '64';
-decode_reloc_type(2) -> 'pc32';
-decode_reloc_type(10) -> '32'.
--endif. %% BIT32
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate Executable Code segment
-%%------------------------------------------------------------------------------
-
-%% @doc This function gets as arguments an ELF formated binary file and
-%% returns the Executable Code (".text" segment) or an empty binary if it
-%% is not found.
--spec extract_text(elf()) -> binary().
-extract_text(Elf) ->
- extract_segment_by_name(Elf, ?TEXT).
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate Note Section
-%%------------------------------------------------------------------------------
-
-%% @doc Extract specific Note Section from an ELF Object file. The function
-%% takes as first argument the object file (`Elf') and the `Name' of the
-%% wanted Note Section (<b>without</b> the ".note" prefix!). It returns
-%% the specified binary segment or an empty binary if no such section
-%% exists.
--spec extract_note(elf(), string()) -> binary().
-extract_note(Elf, Name) ->
- extract_segment_by_name(Elf, ?NOTE(Name)).
-
-%%------------------------------------------------------------------------------
-%% Functions to manipulate GCC Exception Table segment
-%%------------------------------------------------------------------------------
-
-%% A description for the C++ exception table formats can be found at Exception
-%% Handling Tables (http://www.codesourcery.com/cxx-abi/exceptions.pdf).
-
-%% A list with `{Start, End, HandlerOffset}' for all call sites in the code
--spec get_exn_handlers(elf()) -> [{start(), start(), lp()}].
-get_exn_handlers(Elf) ->
- CallSites = extract_gccexntab_callsites(Elf),
- [{Start, Start + Size, LP}
- || #elf_gccexntab_callsite{start = Start, size = Size, lp = LP} <- CallSites].
-
-%% @doc This function gets as argument an ELF binary file and returns
-%% the table (list) of call sites which is stored in GCC
-%% Exception Table (".gcc_except_table") section.
-%% It returns an empty list if the Exception Table is not found.
-%% XXX: Assumes there is *no* Action Record Table.
-extract_gccexntab_callsites(Elf) ->
- case extract_segment_by_name(Elf, ?GCC_EXN_TAB) of
- <<>> ->
- [];
- ExnTab ->
- %% First byte of LSDA is Landing Pad base encoding.
- <<LBenc:8, More/binary>> = ExnTab,
- %% Second byte is the Landing Pad base (if its encoding is not
- %% DW_EH_PE_omit) (optional).
- {_LPBase, LSDACont} =
- case LBenc =:= ?DW_EH_PE_omit of
- true -> % No landing pad base byte. (-1 denotes that)
- {-1, More};
- false -> % Landing pad base.
- <<Base:8, More2/binary>> = More,
- {Base, More2}
- end,
- %% Next byte of LSDA is the encoding of the Type Table.
- <<TTenc:8, More3/binary>> = LSDACont,
- %% Next byte is the Types Table offset encoded in U-LEB128 (optional).
- {_TTOff, LSDACont2} =
- case TTenc =:= ?DW_EH_PE_omit of
- true -> % There is no Types Table pointer. (-1 denotes that)
- {-1, More3};
- false -> % The byte offset from this field to the start of the Types
- % Table used for exception matching.
- leb128_decode(More3)
- end,
- %% Next byte of LSDA is the encoding of the fields in the Call-site Table.
- <<_CSenc:8, More4/binary>> = LSDACont2,
- %% Sixth byte is the size (in bytes) of the Call-site Table encoded in
- %% U-LEB128.
- {_CSTabSize, CSTab} = leb128_decode(More4),
- %% Extract all call site information
- get_gccexntab_callsites(CSTab, [])
- end.
-
-get_gccexntab_callsites(<<>>, Acc) ->
- lists:reverse(Acc);
-get_gccexntab_callsites(CSTab, Acc) ->
- %% We are only interested in the Landing Pad of every entry.
- <<Start:32/integer-little, Size:32/integer-little,
- LP:32/integer-little, OnAction:8, More/binary
- >> = CSTab,
- GccCS = mk_gccexntab_callsite(Start, Size, LP, OnAction),
- get_gccexntab_callsites(More, [GccCS | Acc]).
-
-%%------------------------------------------------------------------------------
-%% Helper functions
-%%------------------------------------------------------------------------------
-
-%% @doc Returns the binary segment starting at `Offset' with length `Size'
-%% (bytes) from a binary file. If `Offset' is bigger than the byte size of
-%% the binary, an empty binary (`<<>>') is returned.
--spec get_binary_segment(binary(), offset(), size()) -> binary().
-get_binary_segment(Bin, Offset, _Size) when Offset > byte_size(Bin) ->
- <<>>;
-get_binary_segment(Bin, Offset, Size) ->
- <<_Hdr:Offset/binary, BinSeg:Size/binary, _More/binary>> = Bin,
- BinSeg.
-
-%% @doc This function gets as arguments an ELF formated binary object and
-%% a string with the segments' name and returns the specified segment or
-%% an empty binary (`<<>>') if there exists no segment with that name.
-%% There are handy macros defined in elf_format.hrl for all Standard
-%% Section Names.
--spec extract_segment_by_name(elf(), string()) -> binary().
-extract_segment_by_name(#elf{file=ElfBin, sec_nam=SecNam}, SectionName) ->
- %% Find Section Header Table entry by name
- case SecNam of
- #{SectionName := #elf_shdr{offset=Offset, size=Size}} ->
- get_binary_segment(ElfBin, Offset, Size);
- #{} -> %% Not found.
- <<>>
- end.
-
-%% @doc Little-Endian Base 128 (LEB128) Decoder
-%% This function extracts the <b>first</b> LEB128-encoded integer in a
-%% binary and returns that integer along with the remaining binary. This is
-%% done because a LEB128 number has variable bit-size and that is a way of
-%% extracting only one number in a binary and continuing parsing the binary
-%% for other kind of data (e.g. different encoding).
-%% FIXME: Only decodes unsigned data!
--spec leb128_decode(binary()) -> {integer(), binary()}.
-leb128_decode(LebNum) ->
- leb128_decode(LebNum, 0, <<>>).
-
--spec leb128_decode(binary(), integer(), binary()) -> {integer(), binary()}.
-leb128_decode(LebNum, NoOfBits, Acc) ->
- <<Sentinel:1/bits, NextBundle:7/bits, MoreLebNums/bits>> = LebNum,
- case Sentinel of
- <<1:1>> -> % more bytes to follow
- leb128_decode(MoreLebNums, NoOfBits+7, <<NextBundle:7/bits, Acc/bits>>);
- <<0:1>> -> % byte bundle stop
- Size = NoOfBits+7,
- <<Num:Size/integer>> = <<NextBundle:7/bits, Acc/bits>>,
- {Num, MoreLebNums}
- end.
diff --git a/lib/hipe/llvm/elf_format.hrl b/lib/hipe/llvm/elf_format.hrl
deleted file mode 100644
index 57a36f0c3e..0000000000
--- a/lib/hipe/llvm/elf_format.hrl
+++ /dev/null
@@ -1,528 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
-%%% @copyright 2011-2014 Yiannis Tsiouris <gtsiour@softlab.ntua.gr>,
-%%% Chris Stavrakakis <hydralisk.r@gmail.com>
-%%% @author Yiannis Tsiouris <gtsiour@softlab.ntua.gr>
-%%% [http://www.softlab.ntua.gr/~gtsiour/]
-
-%%------------------------------------------------------------------------------
-%%
-%% ELF Header File
-%%
-%%------------------------------------------------------------------------------
-
--ifdef(BIT32).
--include("elf32_format.hrl"). % ELF32-specific definitions.
--else.
--include("elf64_format.hrl"). % ELF64-specific definitions.
--endif.
-
-%%------------------------------------------------------------------------------
-%% ELF Data Types (in bytes)
-%%------------------------------------------------------------------------------
-%%XXX: Included in either elf32_format or elf64_format.
-
-%%------------------------------------------------------------------------------
-%% ELF File Header
-%%------------------------------------------------------------------------------
--define(ELF_EHDR_SIZE, (?E_IDENT_SIZE + ?E_TYPE_SIZE + ?E_MACHINE_SIZE
- +?E_VERSION_SIZE + ?E_ENTRY_SIZE + ?E_PHOFF_SIZE
- +?E_SHOFF_SIZE + ?E_FLAGS_SIZE + ?E_EHSIZE_SIZE
- +?E_PHENTSIZE_SIZE + ?E_PHNUM_SIZE + ?E_SHENTSIZE_SIZE
- +?E_SHNUM_SIZE + ?E_SHSTRNDX_SIZE) ).
-
--define(E_IDENT_SIZE, (16 * ?ELF_UNSIGNED_CHAR_SIZE) ).
--define(E_TYPE_SIZE, ?ELF_HALF_SIZE).
--define(E_MACHINE_SIZE, ?ELF_HALF_SIZE).
--define(E_VERSION_SIZE, ?ELF_WORD_SIZE).
--define(E_ENTRY_SIZE, ?ELF_ADDR_SIZE).
--define(E_PHOFF_SIZE, ?ELF_OFF_SIZE).
--define(E_SHOFF_SIZE, ?ELF_OFF_SIZE).
--define(E_FLAGS_SIZE, ?ELF_WORD_SIZE).
--define(E_EHSIZE_SIZE, ?ELF_HALF_SIZE).
--define(E_PHENTSIZE_SIZE, ?ELF_HALF_SIZE).
--define(E_PHNUM_SIZE, ?ELF_HALF_SIZE).
--define(E_SHENTSIZE_SIZE, ?ELF_HALF_SIZE).
--define(E_SHNUM_SIZE, ?ELF_HALF_SIZE).
--define(E_SHSTRNDX_SIZE, ?ELF_HALF_SIZE).
-
-%% Useful arithmetics for computing byte offsets for various File Header
-%% entries from a File Header (erlang) binary
--define(E_IDENT_OFFSET, 0).
--define(E_TYPE_OFFSET, (?E_IDENT_OFFSET + ?E_IDENT_SIZE) ).
--define(E_MACHINE_OFFSET, (?E_TYPE_OFFSET + ?E_TYPE_SIZE) ).
--define(E_VERSION_OFFSET, (?E_MACHINE_OFFSET + ?E_MACHINE_SIZE) ).
--define(E_ENTRY_OFFSET, (?E_VERSION_OFFSET + ?E_VERSION_SIZE) ).
--define(E_PHOFF_OFFSET, (?E_ENTRY_OFFSET + ?E_ENTRY_SIZE) ).
--define(E_SHOFF_OFFSET, (?E_PHOFF_OFFSET + ?E_PHOFF_SIZE) ).
--define(E_FLAGS_OFFSET, (?E_SHOFF_OFFSET + ?E_SHOFF_SIZE) ).
--define(E_EHSIZE_OFFSET, (?E_FLAGS_OFFSET + ?E_FLAGS_SIZE) ).
--define(E_PHENTSIZE_OFFSET, (?E_EHSIZE_OFFSET + ?E_EHSIZE_SIZE) ).
--define(E_PHNUM_OFFSET, (?E_PHENTSIZE_OFFSET + ?E_PHENTSIZE_SIZE) ).
--define(E_SHENTSIZE_OFFSET, (?E_PHNUM_OFFSET + ?E_PHNUM_SIZE) ).
--define(E_SHNUM_OFFSET, (?E_SHENTSIZE_OFFSET + ?E_SHENTSIZE_SIZE) ).
--define(E_SHSTRNDX_OFFSET, (?E_SHNUM_OFFSET + ?E_SHNUM_SIZE) ).
-
-%% Name aliases of File Header fields information used in get_header_field
-%% function of elf64_format module.
--define(E_IDENT, {?E_IDENT_OFFSET, ?E_IDENT_SIZE}).
--define(E_TYPE, {?E_TYPE_OFFSET, ?E_TYPE_SIZE}).
--define(E_MACHINE, {?E_MACHINE_OFFSET, ?E_MACHINE_SIZE}).
--define(E_VERSION, {?E_VERSION_OFFSET, ?E_VERSION_SIZE}).
--define(E_ENTRY, {?E_ENTRY_OFFSET, ?E_ENTRY_SIZE}).
--define(E_PHOFF, {?E_PHOFF_OFFSET, ?E_PHOFF_SIZE}).
--define(E_SHOFF, {?E_SHOFF_OFFSET, ?E_SHOFF_SIZE}).
--define(E_FLAGS, {?E_FLAGS_OFFSET, ?E_FLAGS_SIZE}).
--define(E_EHSIZE, {?E_EHSIZE_OFFSET, ?E_EHSIZE_SIZE}).
--define(E_PHENTSIZE, {?E_PHENTSIZE_OFFSET, ?E_PHENTSIZE_SIZE}).
--define(E_PHNUM, {?E_PHNUM_OFFSET, ?E_PHNUM_SIZE}).
--define(E_SHENTSIZE, {?E_SHENTSIZE_OFFSET, ?E_SHENTSIZE_SIZE}).
--define(E_SHNUM, {?E_SHNUM_OFFSET, ?E_SHNUM_SIZE}).
--define(E_SHSTRNDX, {?E_SHSTRNDX_OFFSET, ?E_SHSTRNDX_SIZE}).
-
-%% ELF Identification (e_ident)
--define(EI_MAG0, 0).
--define(EI_MAG1, 1).
--define(EI_MAG2, 2).
--define(EI_MAG3, 3).
--define(EI_CLASS, 4).
--define(EI_DATA, 5).
--define(EI_VERSION, 6).
--define(EI_OSABI, 7).
--define(EI_ABIVERSION, 8).
--define(EI_PAD, 9).
--define(EI_NIDENT, 16).
-
-%% Object File Classes (e_ident[EI_CLASS])
--define(ELFCLASSNONE, 0).
--define(ELFCLASS32, 1).
--define(ELFCLASS64, 2).
-
-%% Data Encodings (e_ident[EI_DATA])
--define(ELFDATA2LSB, 1).
--define(ELFDATA2MSB, 2).
-
-%% Operating System and ABI Identifiers (e_ident[EI_OSABI])
--define(ELFOSABI_SYSV, 0).
--define(ELFOSABI_HPUX, 1).
--define(ELFOSABI_STANDALONE, 255).
-
-%% Object File Types (e_type)
--define(ET_NONE, 0).
--define(ET_REL, 1).
--define(ET_EXEC, 2).
--define(ET_DYN, 3).
--define(ET_CORE, 4).
--define(ET_LOOS, 16#FE00).
--define(ET_HIOS, 16#FEFF).
--define(ET_LOPROC, 16#FF00).
--define(ET_HIPROC, 16#FFFF).
-
-%%------------------------------------------------------------------------------
-%% ELF Section Header
-%%------------------------------------------------------------------------------
--define(ELF_SHDRENTRY_SIZE, (?SH_NAME_SIZE + ?SH_TYPE_SIZE + ?SH_FLAGS_SIZE
- +?SH_ADDR_SIZE + ?SH_OFFSET_SIZE + ?SH_SIZE_SIZE
- +?SH_LINK_SIZE + ?SH_INFO_SIZE
- +?SH_ADDRALIGN_SIZE + ?SH_ENTSIZE_SIZE) ).
-
--define(SH_NAME_SIZE, ?ELF_WORD_SIZE).
--define(SH_TYPE_SIZE, ?ELF_WORD_SIZE).
--define(SH_FLAGS_SIZE, ?ELF_XWORD_SIZE).
--define(SH_ADDR_SIZE, ?ELF_ADDR_SIZE).
--define(SH_OFFSET_SIZE, ?ELF_OFF_SIZE).
--define(SH_SIZE_SIZE, ?ELF_XWORD_SIZE).
--define(SH_LINK_SIZE, ?ELF_WORD_SIZE).
--define(SH_INFO_SIZE, ?ELF_WORD_SIZE).
--define(SH_ADDRALIGN_SIZE, ?ELF_XWORD_SIZE).
--define(SH_ENTSIZE_SIZE, ?ELF_XWORD_SIZE).
-
-%% Useful arithmetics for computing byte offsets for various fields from a
-%% Section Header Entry (erlang) binary
--define(SH_NAME_OFFSET, 0).
--define(SH_TYPE_OFFSET, (?SH_NAME_OFFSET + ?SH_NAME_SIZE) ).
--define(SH_FLAGS_OFFSET, (?SH_TYPE_OFFSET + ?SH_TYPE_SIZE) ).
--define(SH_ADDR_OFFSET, (?SH_FLAGS_OFFSET + ?SH_FLAGS_SIZE) ).
--define(SH_OFFSET_OFFSET, (?SH_ADDR_OFFSET + ?SH_ADDR_SIZE) ).
--define(SH_SIZE_OFFSET, (?SH_OFFSET_OFFSET + ?SH_OFFSET_SIZE) ).
--define(SH_LINK_OFFSET, (?SH_SIZE_OFFSET + ?SH_SIZE_SIZE) ).
--define(SH_INFO_OFFSET, (?SH_LINK_OFFSET + ?SH_LINK_SIZE) ).
--define(SH_ADDRALIGN_OFFSET, (?SH_INFO_OFFSET + ?SH_INFO_SIZE) ).
--define(SH_ENTSIZE_OFFSET, (?SH_ADDRALIGN_OFFSET + ?SH_ADDRALIGN_SIZE) ).
-
-%% Name aliases of Section Header Table entry information used in
-%% get_shdrtab_entry function of elf64_format module.
--define(SH_NAME, {?SH_NAME_OFFSET, ?SH_NAME_SIZE}).
--define(SH_TYPE, {?SH_TYPE_OFFSET, ?SH_TYPE_SIZE}).
--define(SH_FLAGS, {?SH_FLAGS_OFFSET, ?SH_FLAGS_SIZE}).
--define(SH_ADDR, {?SH_ADDR_OFFSET, ?SH_ADDR_SIZE}).
--define(SH_OFFSET, {?SH_OFFSET_OFFSET, ?SH_OFFSET_SIZE}).
--define(SH_SIZE, {?SH_SIZE_OFFSET, ?SH_SIZE_SIZE}).
--define(SH_LINK, {?SH_LINK_OFFSET, ?SH_LINK_SIZE}).
--define(SH_INFO, {?SH_INFO_OFFSET, ?SH_INFO_SIZE}).
--define(SH_ADDRALIGN, {?SH_ADDRALIGN_OFFSET, ?SH_ADDRALIGN_SIZE}).
--define(SH_ENTSIZE, {?SH_ENTSIZE_OFFSET, ?SH_ENTSIZE_SIZE}).
-
-%% Section Indices
--define(SHN_UNDEF, 0).
--define(SHN_LOPROC, 16#FF00).
--define(SHN_HIPROC, 16#FF1F).
--define(SHN_LOOS, 16#FF20).
--define(SHN_HIOS, 16#FF3F).
--define(SHN_ABS, 16#FFF1).
--define(SHN_COMMON, 16#FFF2).
-
-%% Section Types (sh_type)
--define(SHT_NULL, 0).
--define(SHT_PROGBITS, 1).
--define(SHT_SYMTAB, 2).
--define(SHT_STRTAB, 3).
--define(SHT_RELA, 4).
--define(SHT_HASH, 5).
--define(SHT_DYNAMIC, 6).
--define(SHT_NOTE, 7).
--define(SHT_NOBITS, 8).
--define(SHT_REL, 9).
--define(SHT_SHLIB, 10).
--define(SHT_DYNSYM, 11).
--define(SHT_LOOS, 16#60000000).
--define(SHT_HIOS, 16#6FFFFFFF).
--define(SHT_LOPROC, 16#70000000).
--define(SHT_HIPROC, 16#7FFFFFFF).
-
-%% Section Attributes (sh_flags)
--define(SHF_WRITE, 16#1).
--define(SHF_ALLOC, 16#2).
--define(SHF_EXECINSTR, 16#4).
--define(SHF_MASKOS, 16#0F000000).
--define(SHF_MASKPROC, 16#F0000000).
-
-%%
-%% Standard Section names for Code and Data
-%%
--define(BSS, ".bss").
--define(DATA, ".data").
--define(INTERP, ".interp").
--define(RODATA, ".rodata").
--define(TEXT, ".text").
-%% Other Standard Section names
--define(COMMENT, ".comment").
--define(DYNAMIC, ".dynamic").
--define(DYNSTR, ".dynstr").
--define(GOT, ".got").
--define(HASH, ".hash").
--define(NOTE(Name), (".note" ++ Name)).
--define(PLT, ".plt").
--define(REL(Name), (".rel" ++ Name) ).
--define(RELA(Name), (".rela" ++ Name) ).
--define(SHSTRTAB, ".shstrtab").
--define(STRTAB, ".strtab").
--define(SYMTAB, ".symtab").
--define(GCC_EXN_TAB, ".gcc_except_table").
-
-%%------------------------------------------------------------------------------
-%% ELF Symbol Table Entries
-%%------------------------------------------------------------------------------
--define(ELF_SYM_SIZE, (?ST_NAME_SIZE + ?ST_INFO_SIZE + ?ST_OTHER_SIZE
- +?ST_SHNDX_SIZE + ?ST_VALUE_SIZE + ?ST_SIZE_SIZE) ).
-
--define(ST_NAME_SIZE, ?ELF_WORD_SIZE).
--define(ST_INFO_SIZE, ?ELF_UNSIGNED_CHAR_SIZE).
--define(ST_OTHER_SIZE, ?ELF_UNSIGNED_CHAR_SIZE).
--define(ST_SHNDX_SIZE, ?ELF_HALF_SIZE).
--define(ST_VALUE_SIZE, ?ELF_ADDR_SIZE).
--define(ST_SIZE_SIZE, ?ELF_XWORD_SIZE).
-
-%% Precomputed offset for Symbol Table entries in SymTab binary
-%%XXX: Included in either elf32_format or elf64_format.
-
-%% Name aliases for Symbol Table entry information
--define(ST_NAME, {?ST_NAME_OFFSET, ?ST_NAME_SIZE}).
--define(ST_INFO, {?ST_INFO_OFFSET, ?ST_INFO_SIZE}).
--define(ST_OTHER, {?ST_OTHER_OFFSET, ?ST_OTHER_SIZE}).
--define(ST_SHNDX, {?ST_SHNDX_OFFSET, ?ST_SHNDX_SIZE}).
--define(ST_VALUE, {?ST_VALUE_OFFSET, ?ST_VALUE_SIZE}).
--define(ST_SIZE, {?ST_SIZE_OFFSET, ?ST_SIZE_SIZE}).
-
-%% Macros to extract information from st_type
--define(ELF_ST_BIND(I), (I bsr 4) ).
--define(ELF_ST_TYPE(I), (I band 16#f) ).
--define(ELF_ST_INFO(B,T), (B bsl 4 + T band 16#f) ).
-
-%% Symbol Bindings
--define(STB_LOCAL, 0).
--define(STB_GLOBAL, 1).
--define(STB_WEAK, 2).
--define(STB_LOOS, 10).
--define(STB_HIOS, 12).
--define(STB_LOPROC, 13).
--define(STB_HIPROC, 15).
-
-%% Symbol Types
--define(STT_NOTYPE, 0).
--define(STT_OBJECT, 1).
--define(STT_FUNC, 2).
--define(STT_SECTION, 3).
--define(STT_FILE, 4).
--define(STT_LOOS, 10).
--define(STT_HIOS, 12).
--define(STT_LOPROC, 13).
--define(STT_HIPROC, 15).
-
-%%------------------------------------------------------------------------------
-%% ELF Relocation Entries
-%%------------------------------------------------------------------------------
--define(ELF_REL_SIZE, (?R_OFFSET_SIZE + ?R_INFO_SIZE) ).
--define(ELF_RELA_SIZE, (?R_OFFSET_SIZE + ?R_INFO_SIZE + ?R_ADDEND_SIZE) ).
-
--define(R_OFFSET_SIZE, ?ELF_ADDR_SIZE).
--define(R_INFO_SIZE, ?ELF_XWORD_SIZE).
--define(R_ADDEND_SIZE, ?ELF_SXWORD_SIZE).
-
-%% Arithmetics for computing byte offsets in a Relocation entry binary
--define(R_OFFSET_OFFSET, 0).
--define(R_INFO_OFFSET, (?R_OFFSET_OFFSET + ?R_OFFSET_SIZE) ).
--define(R_ADDEND_OFFSET, (?R_INFO_OFFSET + ?R_INFO_SIZE) ).
-
-%% Name aliases for Relocation field information
--define(R_OFFSET, {?R_OFFSET_OFFSET, ?R_OFFSET_SIZE}).
--define(R_INFO, {?R_INFO_OFFSET, ?R_INFO_SIZE}).
--define(R_ADDEND, {?R_ADDEND_OFFSET, ?R_ADDEND_SIZE}).
-
-%% Useful macros to extract information from r_info field
-%%XXX: Included in either elf32_format or elf64_format.
-
-%%------------------------------------------------------------------------------
-%% ELF Program Header Table
-%%------------------------------------------------------------------------------
--define(ELF_PHDR_SIZE, (?P_TYPE_SIZE + ?P_FLAGS_SIZE + ?P_OFFSET_SIZE
- +?P_VADDR_SIZE + ?P_PADDR_SIZE + ?P_FILESZ_SIZE
- +?P_MEMSZ_SIZE + ?P_ALIGN_SIZE) ).
-
--define(P_TYPE_SIZE, ?ELF_WORD_SIZE).
--define(P_FLAGS_SIZE, ?ELF_WORD_SIZE).
--define(P_OFFSET_SIZE, ?ELF_OFF_SIZE).
--define(P_VADDR_SIZE, ?ELF_ADDR_SIZE).
--define(P_PADDR_SIZE, ?ELF_ADDR_SIZE).
--define(P_FILESZ_SIZE, ?ELF_XWORD_SIZE).
--define(P_MEMSZ_SIZE, ?ELF_XWORD_SIZE).
--define(P_ALIGN_SIZE, ?ELF_XWORD_SIZE).
-
-%% Offsets of various fields in a Program Header Table entry binary.
-%%XXX: Included in either elf32_format or elf64_format.
-
-%% Name aliases for each Program Header Table entry field information.
--define(P_TYPE, {?P_TYPE_OFFSET, ?P_TYPE_SIZE} ).
--define(P_FLAGS, {?P_FLAGS_OFFSET, ?P_FLAGS_SIZE} ).
--define(P_OFFSET, {?P_OFFSET_OFFSET, ?P_OFFSET_SIZE} ).
--define(P_VADDR, {?P_VADDR_OFFSET, ?P_VADDR_SIZE} ).
--define(P_PADDR, {?P_PADDR_OFFSET, ?P_PADDR_SIZE} ).
--define(P_FILESZ, {?P_FILESZ_OFFSET, ?P_FILESZ_SIZE} ).
--define(P_MEMSZ, {?P_MEMSZ_OFFSET, ?P_MEMSZ_SIZE} ).
--define(P_ALIGN, {?P_ALIGN_OFFSET, ?P_ALIGN_SIZE} ).
-
-%% Segment Types (p_type)
--define(PT_NULL, 0).
--define(PT_LOAD, 1).
--define(PT_DYNAMIC, 2).
--define(PT_INTERP, 3).
--define(PT_NOTE, 4).
--define(PT_SHLIB, 5).
--define(PT_PHDR, 6).
--define(PT_LOOS, 16#60000000).
--define(PT_HIOS, 16#6FFFFFFF).
--define(PT_LOPROC, 16#70000000).
--define(PT_HIPROC, 16#7FFFFFFF).
-
-%% Segment Attributes (p_flags)
--define(PF_X, 16#1).
--define(PF_W, 16#2).
--define(PF_R, 16#4).
--define(PF_MASKOS, 16#00FF0000).
--define(PF_MASKPROC, 16#FF000000).
-
-%%------------------------------------------------------------------------------
-%% ELF Dynamic Table
-%%------------------------------------------------------------------------------
--define(ELF_DYN_SIZE, (?D_TAG_SIZE + ?D_VAL_PTR_SIZE) ).
-
--define(D_TAG_SIZE, ?ELF_SXWORD_SIZE).
--define(D_VAL_PTR_SIZE, ?ELF_ADDR_SIZE).
-
-%% Offsets of each field in Dynamic Table entry in binary
--define(D_TAG_OFFSET, 0).
--define(D_VAL_PTR_OFFSET, (?D_TAG_OFFSET + ?D_TAG_SIZE)).
-
-%% Name aliases for each field of a Dynamic Table entry information
--define(D_TAG, {?D_TAG_OFFSET, ?D_TAG_SIZE} ).
--define(D_VAL_PTR, {?D_VAL_PTR_OFFSET, ?D_VAL_PTR_SIZE} ).
-
-%% Dynamic Table Entries
--define(DT_NULL, 0).
--define(DT_NEEDED, 1).
--define(DT_PLTRELSZ, 2).
--define(DT_PLTGOT, 3).
--define(DT_HASH, 4).
--define(DT_STRTAB, 5).
--define(DT_SYMTAB, 6).
--define(DT_RELA, 7).
--define(DT_RELASZ, 8).
--define(DT_RELAENT, 9).
--define(DT_STRSZ, 10).
--define(DT_SYMENT, 11).
--define(DT_INIT, 12).
--define(DT_FINI, 13).
--define(DT_SONAME, 14).
--define(DT_RPATH, 15).
--define(DT_SYMBOLIC, 16).
--define(DT_REL, 17).
--define(DT_RELSZ, 18).
--define(DT_RELENT, 19).
--define(DT_PLTREL, 20).
--define(DT_DEBUG, 21).
--define(DT_TEXTREL, 22).
--define(DT_JMPREL, 23).
--define(DT_BIND_NOW, 24).
--define(DT_INIT_ARRAY, 25).
--define(DT_FINI_ARRAY, 26).
--define(DT_INIT_ARRAYSZ, 27).
--define(DT_FINI_ARRAYSZ, 28).
--define(DT_LOOS, 16#60000000).
--define(DT_HIOS, 16#6FFFFFFF).
--define(DT_LOPROC, 16#700000000).
--define(DT_HIPROC, 16#7FFFFFFFF).
-
-%%------------------------------------------------------------------------------
-%% ELF GCC Exception Table
-%%------------------------------------------------------------------------------
-
-%% The DWARF Exception Header Encoding is used to describe the type of data used
-%% in the .eh_frame_hdr (and .gcc_except_table) section. The upper 4 bits
-%% indicate how the value is to be applied. The lower 4 bits indicate the format
-%% of the data.
-
-%% DWARF Exception Header value format
--define(DW_EH_PE_omit, 16#ff). % No value is present.
--define(DW_EH_PE_uleb128, 16#01). % Unsigned value encoded using LEB128.
--define(DW_EH_PE_udata2, 16#02). % A 2 bytes unsigned value.
--define(DW_EH_PE_udata4, 16#03). % A 4 bytes unsigned value.
--define(DW_EH_PE_udata8, 16#04). % An 8 bytes unsigned value.
--define(DW_EH_PE_sleb128, 16#09). % Signed value encoded using LEB128.
--define(DW_EH_PE_sdata2, 16#0a). % A 2 bytes signed value.
--define(DW_EH_PE_sdata4, 16#0b). % A 4 bytes signed value.
--define(DW_EH_PE_sdata8, 16#0c). % An 8 bytes signed value.
-
-%% DWARF Exception Header application
--define(DW_EH_PE_absptr, 16#00). % Value is used with no modification.
--define(DW_EH_PE_pcrel, 16#10). % Value is relative to the current PC.
--define(DW_EH_PE_datarel, 16#30). % Value is relative to the beginning of the
- % section.
-
-%%------------------------------------------------------------------------------
-%% ELF Read-only data (constants, literlas etc.)
-%%------------------------------------------------------------------------------
--define(RO_ENTRY_SIZE, 8).
-
-%%------------------------------------------------------------------------------
-%% Custom Note section: ".note.gc" for Erlang GC
-%%------------------------------------------------------------------------------
-
-%% The structure of this section is the following:
-%%
-%% .short <n> # number of safe points in code
-%%
-%% .long .L<label1> # safe point address |
-%% .long .L<label2> # safe point address |-> safe point addrs
-%% ..... |
-%% .long .L<label3> # safe point address |
-%%
-%% .short <n> # stack frame size (in words) |-> fixed-size part
-%% .short <n> # stack arity |
-%% .short <n> # number of live roots that follow |
-%%
-%% .short <n> # live root's stack index |
-%% ..... |-> live root indices
-%% .short <n> # >> |
-
-%% The name of the custom Note Section
--define(NOTE_ERLGC_NAME, ".gc").
-
-%% The first word of a Note Section for Erlang GC (".note.gc") is always the
-%% number of safepoints in code.
--define(SP_COUNT, {?SP_COUNT_OFFSET, ?SP_COUNT_SIZE}).
--define(SP_COUNT_SIZE, ?ELF_HALF_SIZE).
--define(SP_COUNT_OFFSET, 0). %(always the first entry in sdesc)
-
-%% The fixed-size part of a safe point (SP) entry consists of 4 words: the SP
-%% address (offset in code), the stack frame size of the function (where the SP
-%% is located), the stack arity of the function (the registered values are *not*
-%% counted), the number of live roots in the specific SP.
--define(SP_FIXED, {?SP_FIXED_OFF, ?SP_FIXED_SIZE}).
--define(SP_FIXED_OFF, 0).
-%%XXX: Exclude SP_ADDR_SIZE from SP_FIXED_SIZE in lew of new GC layout
--define(SP_FIXED_SIZE, (?SP_STKFRAME_SIZE + ?SP_STKARITY_SIZE
- + ?SP_LIVEROOTCNT_SIZE)).
-
--define(SP_ADDR_SIZE, ?ELF_WORD_SIZE).
--define(SP_STKFRAME_SIZE, ?ELF_HALF_SIZE).
--define(SP_STKARITY_SIZE, ?ELF_HALF_SIZE).
--define(SP_LIVEROOTCNT_SIZE, ?ELF_HALF_SIZE).
-
-%%XXX: SP_STKFRAME is the first piece of information in the new GC layout
--define(SP_STKFRAME_OFFSET, 0).
--define(SP_STKARITY_OFFSET, (?SP_STKFRAME_OFFSET + ?SP_STKFRAME_SIZE) ).
--define(SP_LIVEROOTCNT_OFFSET, (?SP_STKARITY_OFFSET + ?SP_STKARITY_SIZE) ).
-
-%% Name aliases for safepoint fields.
--define(SP_STKFRAME, {?SP_STKFRAME_OFFSET, ?SP_STKFRAME_SIZE}).
--define(SP_STKARITY, {?SP_STKARITY_OFFSET, ?SP_STKARITY_SIZE}).
--define(SP_LIVEROOTCNT, {?SP_LIVEROOTCNT_OFFSET, ?SP_LIVEROOTCNT_SIZE}).
-
-%% After the fixed-size part a variable-size part exists. This part holds the
-%% stack frame index of every live root in the specific SP.
--define(LR_STKINDEX_SIZE, ?ELF_HALF_SIZE).
-
-%%------------------------------------------------------------------------------
-%% Misc.
-%%------------------------------------------------------------------------------
--define(bits(Bytes), ((Bytes) bsl 3)).
-
-%%------------------------------------------------------------------------------
-%% Exported record and type declarations for 'elf_format' module
-%%------------------------------------------------------------------------------
-
-%% Section header entries
--record(elf_shdr,
- {name :: elf_format:name() % Section name
- ,type :: elf_format:shdr_type() % Section type
- ,flags :: elf_format:bitflags() % Section attributes
- ,addr :: elf_format:offset() % Virtual address in memory
- ,offset :: elf_format:offset() % Offset in file
- ,size :: elf_format:size() % Size of section
- ,link :: non_neg_integer() % Link to other section
- ,info :: non_neg_integer() % Miscellaneous information
- ,addralign :: elf_format:size() % Address align boundary
- ,entsize :: elf_format:size() % Size of entries, if section has
- % table
- }).
--type elf_shdr() :: #elf_shdr{}.
-
-%% Symbol table entries
--record(elf_sym,
- {name :: elf_format:name() % Symbol name
- ,bind :: elf_format:sym_bind() % Symbol binding
- ,type :: elf_format:sym_type() % Symbol type
- ,value :: elf_format:valueoff() % Symbol value
- ,size :: elf_format:size() % Size of object
- ,section :: undefined | abs | elf_shdr()
- }).
--type elf_sym() :: #elf_sym{}.
-
-%% Relocations
--record(elf_rel,
- {offset :: elf_format:offset()
- ,type :: elf_format:reloc_type()
- ,addend :: elf_format:addend()
- ,symbol :: elf_sym()
- }).
--type elf_rel() :: #elf_rel{}.
diff --git a/lib/hipe/llvm/hipe_llvm.erl b/lib/hipe/llvm/hipe_llvm.erl
deleted file mode 100644
index 343ca94cb1..0000000000
--- a/lib/hipe/llvm/hipe_llvm.erl
+++ /dev/null
@@ -1,1144 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
--module(hipe_llvm).
-
--export([
- mk_ret/1,
- ret_ret_list/1,
-
- mk_br/1,
- br_dst/1,
-
- mk_br_cond/3,
- mk_br_cond/4,
- br_cond_cond/1,
- br_cond_true_label/1,
- br_cond_false_label/1,
- br_cond_meta/1,
-
- mk_indirectbr/3,
- indirectbr_type/1,
- indirectbr_address/1,
- indirectbr_label_list/1,
-
- mk_switch/4,
- switch_type/1,
- switch_value/1,
- switch_default_label/1,
- switch_value_label_list/1,
-
- mk_invoke/9,
- invoke_dst/1,
- invoke_cconv/1,
- invoke_ret_attrs/1,
- invoke_type/1,
- invoke_fnptrval/1,
- invoke_arglist/1,
- invoke_fn_attrs/1,
- invoke_to_label/1,
- invoke_unwind_label/1,
-
- mk_operation/6,
- operation_dst/1,
- operation_op/1,
- operation_type/1,
- operation_src1/1,
- operation_src2/1,
- operation_options/1,
-
- mk_extractvalue/5,
- extractvalue_dst/1,
- extractvalue_type/1,
- extractvalue_val/1,
- extractvalue_idx/1,
- extractvalue_idxs/1,
-
- mk_insertvalue/7,
- insertvalue_dst/1,
- insertvalue_val_type/1,
- insertvalue_val/1,
- insertvalue_elem_type/1,
- insertvalue_elem/1,
- insertvalue_idx/1,
- insertvalue_idxs/1,
-
- mk_alloca/4,
- alloca_dst/1,
- alloca_type/1,
- alloca_num/1,
- alloca_align/1,
-
- mk_load/6,
- load_dst/1,
- load_p_type/1,
- load_pointer/1,
- load_alignment/1,
- load_nontemporal/1,
- load_volatile/1,
-
- mk_store/7,
- store_type/1,
- store_value/1,
- store_p_type/1,
- store_pointer/1,
- store_alignment/1,
- store_nontemporal/1,
- store_volatile/1,
-
- mk_getelementptr/5,
- getelementptr_dst/1,
- getelementptr_p_type/1,
- getelementptr_value/1,
- getelementptr_typed_idxs/1,
- getelementptr_inbounds/1,
-
- mk_conversion/5,
- conversion_dst/1,
- conversion_op/1,
- conversion_src_type/1,
- conversion_src/1,
- conversion_dst_type/1,
-
- mk_sitofp/4,
- sitofp_dst/1,
- sitofp_src_type/1,
- sitofp_src/1,
- sitofp_dst_type/1,
-
- mk_ptrtoint/4,
- ptrtoint_dst/1,
- ptrtoint_src_type/1,
- ptrtoint_src/1,
- ptrtoint_dst_type/1,
-
- mk_inttoptr/4,
- inttoptr_dst/1,
- inttoptr_src_type/1,
- inttoptr_src/1,
- inttoptr_dst_type/1,
-
- mk_icmp/5,
- icmp_dst/1,
- icmp_cond/1,
- icmp_type/1,
- icmp_src1/1,
- icmp_src2/1,
-
- mk_fcmp/5,
- fcmp_dst/1,
- fcmp_cond/1,
- fcmp_type/1,
- fcmp_src1/1,
- fcmp_src2/1,
-
- mk_phi/3,
- phi_dst/1,
- phi_type/1,
- phi_value_label_list/1,
-
- mk_select/6,
- select_dst/1,
- select_cond/1,
- select_typ1/1,
- select_val1/1,
- select_typ2/1,
- select_val2/1,
-
- mk_call/8,
- call_dst/1,
- call_is_tail/1,
- call_cconv/1,
- call_ret_attrs/1,
- call_type/1,
- call_fnptrval/1,
- call_arglist/1,
- call_fn_attrs/1,
-
- mk_fun_def/10,
- fun_def_linkage/1,
- fun_def_visibility/1,
- fun_def_cconv/1,
- fun_def_ret_attrs/1,
- fun_def_type/1,
- fun_def_name/1,
- fun_def_arglist/1,
- fun_def_fn_attrs/1,
- fun_def_align/1,
- fun_def_body/1,
-
- mk_fun_decl/8,
- fun_decl_linkage/1,
- fun_decl_visibility/1,
- fun_decl_cconv/1,
- fun_decl_ret_attrs/1,
- fun_decl_type/1,
- fun_decl_name/1,
- fun_decl_arglist/1,
- fun_decl_align/1,
-
- mk_landingpad/0,
-
- mk_comment/1,
- comment_text/1,
-
- mk_label/1,
- label_label/1,
- is_label/1,
-
- mk_const_decl/4,
- const_decl_dst/1,
- const_decl_decl_type/1,
- const_decl_type/1,
- const_decl_value/1,
-
- mk_asm/1,
- asm_instruction/1,
-
- mk_adj_stack/3,
- adj_stack_offset/1,
- adj_stack_register/1,
- adj_stack_type/1,
-
- mk_meta/2,
- meta_id/1,
- meta_operands/1
- ]).
-
--export([
- mk_void/0,
-
- mk_label_type/0,
-
- mk_int/1,
- int_width/1,
-
- mk_double/0,
-
- mk_pointer/1,
- pointer_type/1,
-
- mk_array/2,
- array_size/1,
- array_type/1,
-
- mk_vector/2,
- vector_size/1,
- vector_type/1,
-
- mk_struct/1,
- struct_type_list/1,
-
- mk_fun/2,
- function_ret_type/1,
- function_arg_type_list/1
- ]).
-
--export([pp_ins_list/3, pp_ins/3]).
-
-
-%%-----------------------------------------------------------------------------
-%% Abstract Data Types for LLVM Assembly.
-%%-----------------------------------------------------------------------------
-
-%% Terminator Instructions
--record(llvm_ret, {ret_list=[]}).
--type llvm_ret() :: #llvm_ret{}.
-
--record(llvm_br, {dst}).
--type llvm_br() :: #llvm_br{}.
-
--record(llvm_br_cond, {'cond', true_label, false_label, meta=[]}).
--type llvm_br_cond() :: #llvm_br_cond{}.
-
--record(llvm_indirectbr, {type, address, label_list}).
--type llvm_indirectbr() :: #llvm_indirectbr{}.
-
--record(llvm_switch, {type, value, default_label, value_label_list=[]}).
--type llvm_switch() :: #llvm_switch{}.
-
--record(llvm_invoke, {dst, cconv=[], ret_attrs=[], type, fnptrval, arglist=[],
- fn_attrs=[], to_label, unwind_label}).
--type llvm_invoke() :: #llvm_invoke{}.
-
-%% Binary Operations
--record(llvm_operation, {dst, op, type, src1, src2, options=[]}).
--type llvm_operation() :: #llvm_operation{}.
-
-%% Aggregate Operations
--record(llvm_extractvalue, {dst, type, val, idx, idxs=[]}).
--type llvm_extractvalue() :: #llvm_extractvalue{}.
-
--record(llvm_insertvalue, {dst, val_type, val, elem_type, elem, idx, idxs=[]}).
--type llvm_insertvalue() :: #llvm_insertvalue{}.
-
-%% Memory Access and Addressing Operations
--record(llvm_alloca, {dst, type, num=[], align=[]}).
--type llvm_alloca() :: #llvm_alloca{}.
-
--record(llvm_load, {dst, p_type, pointer, alignment=[], nontemporal=[],
- volatile=false}).
--type llvm_load() :: #llvm_load{}.
-
--record(llvm_store, {type, value, p_type, pointer, alignment=[],
- nontemporal=[], volatile=false}).
--type llvm_store() :: #llvm_store{}.
-
--record(llvm_getelementptr, {dst, p_type, value, typed_idxs, inbounds}).
--type llvm_getelementptr() :: #llvm_getelementptr{}.
-
-%% Conversion Operations
--record(llvm_conversion, {dst, op, src_type, src, dst_type}).
--type llvm_conversion() :: #llvm_conversion{}.
-
--record(llvm_sitofp, {dst, src_type, src, dst_type}).
--type llvm_sitofp() :: #llvm_sitofp{}.
-
--record(llvm_ptrtoint, {dst, src_type, src, dst_type}).
--type llvm_ptrtoint() :: #llvm_ptrtoint{}.
-
--record(llvm_inttoptr, {dst, src_type, src, dst_type}).
--type llvm_inttoptr() :: #llvm_inttoptr{}.
-
-%% Other Operations
--record(llvm_icmp, {dst, 'cond', type, src1, src2}).
--type llvm_icmp() :: #llvm_icmp{}.
-
--record(llvm_fcmp, {dst, 'cond', type, src1, src2}).
--type llvm_fcmp() :: #llvm_fcmp{}.
-
--record(llvm_phi, {dst, type, value_label_list}).
--type llvm_phi() :: #llvm_phi{}.
-
--record(llvm_select, {dst, 'cond', typ1, val1, typ2, val2}).
--type llvm_select() :: #llvm_select{}.
-
--record(llvm_call, {dst=[], is_tail = false, cconv = [], ret_attrs = [], type,
- fnptrval, arglist = [], fn_attrs = []}).
--type llvm_call() :: #llvm_call{}.
-
--record(llvm_fun_def, {linkage=[], visibility=[], cconv=[], ret_attrs=[],
- type, 'name', arglist=[], fn_attrs=[], align=[], body=[]}).
--type llvm_fun_def() :: #llvm_fun_def{}.
-
--record(llvm_fun_decl, {linkage=[], visibility=[], cconv=[], ret_attrs=[],
- type, 'name', arglist=[], align=[]}).
--type llvm_fun_decl() :: #llvm_fun_decl{}.
-
--record(llvm_landingpad, {}).
--type llvm_landingpad() :: #llvm_landingpad{}.
-
--record(llvm_comment, {text}).
--type llvm_comment() :: #llvm_comment{}.
-
--record(llvm_label, {label}).
--type llvm_label() :: #llvm_label{}.
-
--record(llvm_const_decl, {dst, decl_type, type, value}).
--type llvm_const_decl() :: #llvm_const_decl{}.
-
--record(llvm_asm, {instruction}).
--type llvm_asm() :: #llvm_asm{}.
-
--record(llvm_adj_stack, {offset, 'register', type}).
--type llvm_adj_stack() :: #llvm_adj_stack{}.
-
--record(llvm_meta, {id :: string(),
- operands :: [string() | integer() | llvm_meta()]}).
--type llvm_meta() :: #llvm_meta{}.
-
-%% A type for any LLVM instruction
--type llvm_instr() :: llvm_ret() | llvm_br() | llvm_br_cond()
- | llvm_indirectbr() | llvm_switch() | llvm_invoke()
- | llvm_operation() | llvm_extractvalue()
- | llvm_insertvalue() | llvm_alloca() | llvm_load()
- | llvm_store() | llvm_getelementptr() | llvm_conversion()
- | llvm_sitofp() | llvm_ptrtoint() | llvm_inttoptr()
- | llvm_icmp() | llvm_fcmp() | llvm_phi() | llvm_select()
- | llvm_call() | llvm_fun_def() | llvm_fun_decl()
- | llvm_landingpad() | llvm_comment() | llvm_label()
- | llvm_const_decl() | llvm_asm() | llvm_adj_stack()
- | llvm_meta().
-
-%% Types
--record(llvm_void, {}).
-%-type llvm_void() :: #llvm_void{}.
-
--record(llvm_label_type, {}).
-%-type llvm_label_type() :: #llvm_label_type{}.
-
--record(llvm_int, {width}).
-%-type llvm_int() :: #llvm_int{}.
-
--record(llvm_float, {}).
-%-type llvm_float() :: #llvm_float{}.
-
--record(llvm_double, {}).
-%-type llvm_double() :: #llvm_double{}.
-
--record(llvm_fp80, {}).
-%-type llvm_fp80() :: #llvm_fp80{}.
-
--record(llvm_fp128, {}).
-%-type llvm_fp128() :: #llvm_fp128{}.
-
--record(llvm_ppc_fp128, {}).
-%-type llvm_ppc_fp128() :: #llvm_ppc_fp128{}.
-
--record(llvm_pointer, {type}).
-%-type llvm_pointer() :: #llvm_pointer{}.
-
--record(llvm_vector, {'size', type}).
-%-type llvm_vector() :: #llvm_vector{}.
-
--record(llvm_struct, {type_list}).
-%-type llvm_struct() :: #llvm_struct{}.
-
--record(llvm_array, {'size', type}).
-%-type llvm_array() :: #llvm_array{}.
-
--record(llvm_fun, {ret_type, arg_type_list}).
-%-type llvm_fun() :: #llvm_fun{}.
-
-%%-----------------------------------------------------------------------------
-%% Accessor Functions
-%%-----------------------------------------------------------------------------
-
-%% ret
-mk_ret(Ret_list) -> #llvm_ret{ret_list=Ret_list}.
-ret_ret_list(#llvm_ret{ret_list=Ret_list}) -> Ret_list.
-
-%% br
-mk_br(Dst) -> #llvm_br{dst=Dst}.
-br_dst(#llvm_br{dst=Dst}) -> Dst.
-
-%% br_cond
-mk_br_cond(Cond, True_label, False_label) ->
- #llvm_br_cond{'cond'=Cond, true_label=True_label, false_label=False_label}.
-mk_br_cond(Cond, True_label, False_label, Metadata) ->
- #llvm_br_cond{'cond'=Cond, true_label=True_label, false_label=False_label,
- meta=Metadata}.
-br_cond_cond(#llvm_br_cond{'cond'=Cond}) -> Cond.
-br_cond_true_label(#llvm_br_cond{true_label=True_label}) -> True_label.
-br_cond_false_label(#llvm_br_cond{false_label=False_label}) ->
- False_label.
-br_cond_meta(#llvm_br_cond{meta=Metadata}) -> Metadata.
-
-%% indirectbr
-mk_indirectbr(Type, Address, Label_list) -> #llvm_indirectbr{type=Type, address=Address, label_list=Label_list}.
-indirectbr_type(#llvm_indirectbr{type=Type}) -> Type.
-indirectbr_address(#llvm_indirectbr{address=Address}) -> Address.
-indirectbr_label_list(#llvm_indirectbr{label_list=Label_list}) -> Label_list.
-
-%% invoke
-mk_invoke(Dst, Cconv, Ret_attrs, Type, Fnptrval, Arglist, Fn_attrs, To_label, Unwind_label) ->
- #llvm_invoke{dst=Dst, cconv=Cconv, ret_attrs=Ret_attrs, type=Type,
- fnptrval=Fnptrval, arglist=Arglist, fn_attrs=Fn_attrs, to_label=To_label,
- unwind_label=Unwind_label}.
-invoke_dst(#llvm_invoke{dst=Dst}) -> Dst.
-invoke_cconv(#llvm_invoke{cconv=Cconv}) -> Cconv.
-invoke_ret_attrs(#llvm_invoke{ret_attrs=Ret_attrs}) -> Ret_attrs.
-invoke_type(#llvm_invoke{type=Type}) -> Type.
-invoke_fnptrval(#llvm_invoke{fnptrval=Fnptrval}) -> Fnptrval.
-invoke_arglist(#llvm_invoke{arglist=Arglist}) -> Arglist.
-invoke_fn_attrs(#llvm_invoke{fn_attrs=Fn_attrs}) -> Fn_attrs.
-invoke_to_label(#llvm_invoke{to_label=To_label}) -> To_label.
-invoke_unwind_label(#llvm_invoke{unwind_label=Unwind_label}) -> Unwind_label.
-
-%% switch
-mk_switch(Type, Value, Default_label, Value_label_list) ->
- #llvm_switch{type=Type, value=Value, default_label=Default_label,
- value_label_list=Value_label_list}.
-switch_type(#llvm_switch{type=Type}) -> Type.
-switch_value(#llvm_switch{value=Value}) -> Value.
-switch_default_label(#llvm_switch{default_label=Default_label}) ->
- Default_label.
-switch_value_label_list(#llvm_switch{value_label_list=Value_label_list}) ->
- Value_label_list.
-
-%% operation
-mk_operation(Dst, Op, Type, Src1, Src2, Options) ->
- #llvm_operation{dst=Dst, op=Op, type=Type, src1=Src1, src2=Src2,
- options=Options}.
-operation_dst(#llvm_operation{dst=Dst}) -> Dst.
-operation_op(#llvm_operation{op=Op}) -> Op.
-operation_type(#llvm_operation{type=Type}) -> Type.
-operation_src1(#llvm_operation{src1=Src1}) -> Src1.
-operation_src2(#llvm_operation{src2=Src2}) -> Src2.
-operation_options(#llvm_operation{options=Options}) -> Options.
-
-%% extractvalue
-mk_extractvalue(Dst, Type, Val, Idx, Idxs) ->
- #llvm_extractvalue{dst=Dst,type=Type,val=Val,idx=Idx,idxs=Idxs}.
-extractvalue_dst(#llvm_extractvalue{dst=Dst}) -> Dst.
-extractvalue_type(#llvm_extractvalue{type=Type}) -> Type.
-extractvalue_val(#llvm_extractvalue{val=Val}) -> Val.
-extractvalue_idx(#llvm_extractvalue{idx=Idx}) -> Idx.
-extractvalue_idxs(#llvm_extractvalue{idxs=Idxs}) -> Idxs.
-
-%% insertvalue
-mk_insertvalue(Dst, Val_type, Val, Elem_type, Elem, Idx, Idxs) ->
- #llvm_insertvalue{dst=Dst, val_type=Val_type, val=Val, elem_type=Elem_type,
- elem=Elem, idx=Idx, idxs=Idxs}.
-insertvalue_dst(#llvm_insertvalue{dst=Dst}) -> Dst.
-insertvalue_val_type(#llvm_insertvalue{val_type=Val_type}) -> Val_type.
-insertvalue_val(#llvm_insertvalue{val=Val}) -> Val.
-insertvalue_elem_type(#llvm_insertvalue{elem_type=Elem_type}) -> Elem_type.
-insertvalue_elem(#llvm_insertvalue{elem=Elem}) -> Elem.
-insertvalue_idx(#llvm_insertvalue{idx=Idx}) -> Idx.
-insertvalue_idxs(#llvm_insertvalue{idxs=Idxs}) -> Idxs.
-
-%% alloca
-mk_alloca(Dst, Type, Num, Align) ->
- #llvm_alloca{dst=Dst, type=Type, num=Num, align=Align}.
-alloca_dst(#llvm_alloca{dst=Dst}) -> Dst.
-alloca_type(#llvm_alloca{type=Type}) -> Type.
-alloca_num(#llvm_alloca{num=Num}) -> Num.
-alloca_align(#llvm_alloca{align=Align}) -> Align.
-
-%% load
-mk_load(Dst, Type, Pointer, Alignment, Nontemporal, Volatile) ->
- #llvm_load{dst=Dst, p_type=Type, pointer=Pointer, alignment=Alignment,
- nontemporal=Nontemporal, volatile=Volatile}.
-load_dst(#llvm_load{dst=Dst}) -> Dst.
-load_p_type(#llvm_load{p_type=Type}) -> Type.
-load_pointer(#llvm_load{pointer=Pointer}) -> Pointer.
-load_alignment(#llvm_load{alignment=Alignment}) -> Alignment.
-load_nontemporal(#llvm_load{nontemporal=Nontemporal}) -> Nontemporal.
-load_volatile(#llvm_load{volatile=Volatile}) -> Volatile.
-
-%% store
-mk_store(Type, Value, P_Type, Pointer, Alignment, Nontemporal, Volatile) ->
- #llvm_store{type=Type, value=Value, p_type=P_Type, pointer=Pointer, alignment=Alignment,
- nontemporal=Nontemporal, volatile=Volatile}.
-store_type(#llvm_store{type=Type}) -> Type.
-store_value(#llvm_store{value=Value}) -> Value.
-store_p_type(#llvm_store{p_type=P_Type}) -> P_Type.
-store_pointer(#llvm_store{pointer=Pointer}) -> Pointer.
-store_alignment(#llvm_store{alignment=Alignment}) -> Alignment.
-store_nontemporal(#llvm_store{nontemporal=Nontemporal}) -> Nontemporal.
-store_volatile(#llvm_store{volatile=Volatile}) -> Volatile.
-
-%% getelementptr
-mk_getelementptr(Dst, P_Type, Value, Typed_Idxs, Inbounds) ->
- #llvm_getelementptr{dst=Dst,p_type=P_Type, value=Value,
- typed_idxs=Typed_Idxs, inbounds=Inbounds}.
-getelementptr_dst(#llvm_getelementptr{dst=Dst}) -> Dst.
-getelementptr_p_type(#llvm_getelementptr{p_type=P_Type}) -> P_Type.
-getelementptr_value(#llvm_getelementptr{value=Value}) -> Value.
-getelementptr_typed_idxs(#llvm_getelementptr{typed_idxs=Typed_Idxs}) -> Typed_Idxs.
-getelementptr_inbounds(#llvm_getelementptr{inbounds=Inbounds}) -> Inbounds.
-
-%% conversion
-mk_conversion(Dst, Op, Src_type, Src, Dst_type) ->
- #llvm_conversion{dst=Dst, op=Op, src_type=Src_type, src=Src, dst_type=Dst_type}.
-conversion_dst(#llvm_conversion{dst=Dst}) -> Dst.
-conversion_op(#llvm_conversion{op=Op}) -> Op.
-conversion_src_type(#llvm_conversion{src_type=Src_type}) -> Src_type.
-conversion_src(#llvm_conversion{src=Src}) -> Src.
-conversion_dst_type(#llvm_conversion{dst_type=Dst_type}) -> Dst_type.
-
-%% sitofp
-mk_sitofp(Dst, Src_type, Src, Dst_type) ->
- #llvm_sitofp{dst=Dst, src_type=Src_type, src=Src, dst_type=Dst_type}.
-sitofp_dst(#llvm_sitofp{dst=Dst}) -> Dst.
-sitofp_src_type(#llvm_sitofp{src_type=Src_type}) -> Src_type.
-sitofp_src(#llvm_sitofp{src=Src}) -> Src.
-sitofp_dst_type(#llvm_sitofp{dst_type=Dst_type}) -> Dst_type.
-
-%% ptrtoint
-mk_ptrtoint(Dst, Src_Type, Src, Dst_Type) ->
- #llvm_ptrtoint{dst=Dst, src_type=Src_Type, src=Src, dst_type=Dst_Type}.
-ptrtoint_dst(#llvm_ptrtoint{dst=Dst}) -> Dst.
-ptrtoint_src_type(#llvm_ptrtoint{src_type=Src_Type}) -> Src_Type.
-ptrtoint_src(#llvm_ptrtoint{src=Src}) -> Src.
-ptrtoint_dst_type(#llvm_ptrtoint{dst_type=Dst_Type}) -> Dst_Type .
-
-%% inttoptr
-mk_inttoptr(Dst, Src_Type, Src, Dst_Type) ->
- #llvm_inttoptr{dst=Dst, src_type=Src_Type, src=Src, dst_type=Dst_Type}.
-inttoptr_dst(#llvm_inttoptr{dst=Dst}) -> Dst.
-inttoptr_src_type(#llvm_inttoptr{src_type=Src_Type}) -> Src_Type.
-inttoptr_src(#llvm_inttoptr{src=Src}) -> Src.
-inttoptr_dst_type(#llvm_inttoptr{dst_type=Dst_Type}) -> Dst_Type .
-
-%% icmp
-mk_icmp(Dst, Cond, Type, Src1, Src2) ->
- #llvm_icmp{dst=Dst,'cond'=Cond,type=Type,src1=Src1,src2=Src2}.
-icmp_dst(#llvm_icmp{dst=Dst}) -> Dst.
-icmp_cond(#llvm_icmp{'cond'=Cond}) -> Cond.
-icmp_type(#llvm_icmp{type=Type}) -> Type.
-icmp_src1(#llvm_icmp{src1=Src1}) -> Src1.
-icmp_src2(#llvm_icmp{src2=Src2}) -> Src2.
-
-%% fcmp
-mk_fcmp(Dst, Cond, Type, Src1, Src2) ->
- #llvm_fcmp{dst=Dst,'cond'=Cond,type=Type,src1=Src1,src2=Src2}.
-fcmp_dst(#llvm_fcmp{dst=Dst}) -> Dst.
-fcmp_cond(#llvm_fcmp{'cond'=Cond}) -> Cond.
-fcmp_type(#llvm_fcmp{type=Type}) -> Type.
-fcmp_src1(#llvm_fcmp{src1=Src1}) -> Src1.
-fcmp_src2(#llvm_fcmp{src2=Src2}) -> Src2.
-
-%% phi
-mk_phi(Dst, Type, Value_label_list) ->
- #llvm_phi{dst=Dst, type=Type,value_label_list=Value_label_list}.
-phi_dst(#llvm_phi{dst=Dst}) -> Dst.
-phi_type(#llvm_phi{type=Type}) -> Type.
-phi_value_label_list(#llvm_phi{value_label_list=Value_label_list}) ->
- Value_label_list.
-
-%% select
-mk_select(Dst, Cond, Typ1, Val1, Typ2, Val2) ->
- #llvm_select{dst=Dst, 'cond'=Cond, typ1=Typ1, val1=Val1, typ2=Typ2, val2=Val2}.
-select_dst(#llvm_select{dst=Dst}) -> Dst.
-select_cond(#llvm_select{'cond'=Cond}) -> Cond.
-select_typ1(#llvm_select{typ1=Typ1}) -> Typ1.
-select_val1(#llvm_select{val1=Val1}) -> Val1.
-select_typ2(#llvm_select{typ2=Typ2}) -> Typ2.
-select_val2(#llvm_select{val2=Val2}) -> Val2.
-
-%% call
-mk_call(Dst, Is_tail, Cconv, Ret_attrs, Type, Fnptrval, Arglist, Fn_attrs) ->
- #llvm_call{dst=Dst, is_tail=Is_tail, cconv=Cconv, ret_attrs=Ret_attrs,
- type=Type, fnptrval=Fnptrval, arglist=Arglist, fn_attrs=Fn_attrs}.
-call_dst(#llvm_call{dst=Dst}) -> Dst.
-call_is_tail(#llvm_call{is_tail=Is_tail}) -> Is_tail.
-call_cconv(#llvm_call{cconv=Cconv}) -> Cconv.
-call_ret_attrs(#llvm_call{ret_attrs=Ret_attrs}) -> Ret_attrs.
-call_type(#llvm_call{type=Type}) -> Type.
-call_fnptrval(#llvm_call{fnptrval=Fnptrval}) -> Fnptrval.
-call_arglist(#llvm_call{arglist=Arglist}) -> Arglist.
-call_fn_attrs(#llvm_call{fn_attrs=Fn_attrs}) -> Fn_attrs.
-
-%% fun_def
-mk_fun_def(Linkage, Visibility, Cconv, Ret_attrs, Type, Name, Arglist,
- Fn_attrs, Align, Body) ->
- #llvm_fun_def{
- linkage=Linkage,
- visibility=Visibility,
- cconv=Cconv,
- ret_attrs=Ret_attrs,
- type=Type,
- 'name'=Name,
- arglist=Arglist,
- fn_attrs=Fn_attrs,
- align=Align,
- body=Body
- }.
-
-fun_def_linkage(#llvm_fun_def{linkage=Linkage}) -> Linkage.
-fun_def_visibility(#llvm_fun_def{visibility=Visibility}) -> Visibility.
-fun_def_cconv(#llvm_fun_def{cconv=Cconv}) -> Cconv .
-fun_def_ret_attrs(#llvm_fun_def{ret_attrs=Ret_attrs}) -> Ret_attrs.
-fun_def_type(#llvm_fun_def{type=Type}) -> Type.
-fun_def_name(#llvm_fun_def{'name'=Name}) -> Name.
-fun_def_arglist(#llvm_fun_def{arglist=Arglist}) -> Arglist.
-fun_def_fn_attrs(#llvm_fun_def{fn_attrs=Fn_attrs}) -> Fn_attrs.
-fun_def_align(#llvm_fun_def{align=Align}) -> Align.
-fun_def_body(#llvm_fun_def{body=Body}) -> Body.
-
-%% fun_decl
-mk_fun_decl(Linkage, Visibility, Cconv, Ret_attrs, Type, Name, Arglist, Align)->
- #llvm_fun_decl{
- linkage=Linkage,
- visibility=Visibility,
- cconv=Cconv,
- ret_attrs=Ret_attrs,
- type=Type,
- 'name'=Name,
- arglist=Arglist,
- align=Align
- }.
-
-fun_decl_linkage(#llvm_fun_decl{linkage=Linkage}) -> Linkage.
-fun_decl_visibility(#llvm_fun_decl{visibility=Visibility}) -> Visibility.
-fun_decl_cconv(#llvm_fun_decl{cconv=Cconv}) -> Cconv .
-fun_decl_ret_attrs(#llvm_fun_decl{ret_attrs=Ret_attrs}) -> Ret_attrs.
-fun_decl_type(#llvm_fun_decl{type=Type}) -> Type.
-fun_decl_name(#llvm_fun_decl{'name'=Name}) -> Name.
-fun_decl_arglist(#llvm_fun_decl{arglist=Arglist}) -> Arglist.
-fun_decl_align(#llvm_fun_decl{align=Align}) -> Align.
-
-%% landingpad
-mk_landingpad() -> #llvm_landingpad{}.
-
-%% comment
-mk_comment(Text) -> #llvm_comment{text=Text}.
-comment_text(#llvm_comment{text=Text}) -> Text.
-
-%% label
-mk_label(Label) -> #llvm_label{label=Label}.
-label_label(#llvm_label{label=Label}) -> Label.
-
--spec is_label(llvm_instr()) -> boolean().
-is_label(#llvm_label{}) -> true;
-is_label(#llvm_ret{}) -> false;
-is_label(#llvm_br{}) -> false;
-is_label(#llvm_br_cond{}) -> false;
-is_label(#llvm_indirectbr{}) -> false;
-is_label(#llvm_switch{}) -> false;
-is_label(#llvm_invoke{}) -> false;
-is_label(#llvm_operation{}) -> false;
-is_label(#llvm_extractvalue{}) -> false;
-is_label(#llvm_insertvalue{}) -> false;
-is_label(#llvm_alloca{}) -> false;
-is_label(#llvm_load{}) -> false;
-is_label(#llvm_store{}) -> false;
-is_label(#llvm_getelementptr{}) -> false;
-is_label(#llvm_conversion{}) -> false;
-is_label(#llvm_sitofp{}) -> false;
-is_label(#llvm_ptrtoint{}) -> false;
-is_label(#llvm_inttoptr{}) -> false;
-is_label(#llvm_icmp{}) -> false;
-is_label(#llvm_fcmp{}) -> false;
-is_label(#llvm_phi{}) -> false;
-is_label(#llvm_select{}) -> false;
-is_label(#llvm_call{}) -> false;
-is_label(#llvm_fun_def{}) -> false;
-is_label(#llvm_fun_decl{}) -> false;
-is_label(#llvm_landingpad{}) -> false;
-is_label(#llvm_comment{}) -> false;
-is_label(#llvm_const_decl{}) -> false;
-is_label(#llvm_asm{}) -> false;
-is_label(#llvm_adj_stack{}) -> false;
-is_label(#llvm_meta{}) -> false.
-
-%% const_decl
-mk_const_decl(Dst, Decl_type, Type, Value) ->
- #llvm_const_decl{dst=Dst, decl_type=Decl_type, type=Type, value=Value}.
-const_decl_dst(#llvm_const_decl{dst=Dst}) -> Dst.
-const_decl_decl_type(#llvm_const_decl{decl_type=Decl_type}) -> Decl_type.
-const_decl_type(#llvm_const_decl{type=Type}) -> Type.
-const_decl_value(#llvm_const_decl{value=Value}) -> Value.
-
-%% asm
-mk_asm(Instruction) -> #llvm_asm{instruction=Instruction}.
-asm_instruction(#llvm_asm{instruction=Instruction}) -> Instruction.
-
-%% adj_stack
-mk_adj_stack(Offset, Register, Type) ->
- #llvm_adj_stack{offset=Offset, 'register'=Register, type=Type}.
-adj_stack_offset(#llvm_adj_stack{offset=Offset}) -> Offset.
-adj_stack_register(#llvm_adj_stack{'register'=Register}) -> Register.
-adj_stack_type(#llvm_adj_stack{type=Type}) -> Type.
-
-%% meta-data
-mk_meta(Id, Operands) ->
- #llvm_meta{id=Id, operands=Operands}.
-meta_id(#llvm_meta{id=Id}) -> Id.
-meta_operands(#llvm_meta{operands=Operands}) -> Operands.
-
-%% types
-mk_void() -> #llvm_void{}.
-
-mk_label_type() -> #llvm_label_type{}.
-
-mk_int(Width) -> #llvm_int{width=Width}.
-int_width(#llvm_int{width=Width}) -> Width.
-
-mk_double() -> #llvm_double{}.
-
-mk_pointer(Type) -> #llvm_pointer{type=Type}.
-pointer_type(#llvm_pointer{type=Type}) -> Type.
-
-mk_array(Size, Type) -> #llvm_array{'size'=Size, type=Type}.
-array_size(#llvm_array{'size'=Size}) -> Size.
-array_type(#llvm_array{type=Type}) -> Type.
-
-mk_vector(Size, Type) -> #llvm_vector{'size'=Size, type=Type}.
-vector_size(#llvm_vector{'size'=Size}) -> Size.
-vector_type(#llvm_vector{type=Type}) -> Type.
-
-mk_struct(Type_list) -> #llvm_struct{type_list=Type_list}.
-struct_type_list(#llvm_struct{type_list=Type_list}) -> Type_list.
-
-mk_fun(Ret_type, Arg_type_list) ->
- #llvm_fun{ret_type=Ret_type, arg_type_list=Arg_type_list}.
-function_ret_type(#llvm_fun{ret_type=Ret_type}) -> Ret_type.
-function_arg_type_list(#llvm_fun{arg_type_list=Arg_type_list}) ->
- Arg_type_list.
-
-%%----------------------------------------------------------------------------
-%% Pretty-printer Functions
-%%----------------------------------------------------------------------------
-
--type llvm_version() :: {Major :: integer(), Minor :: integer()}.
-
-%% @doc Pretty-print a list of LLVM instructions to a Device, using syntax
-%% compatible with LLVM v. Major.Minor
--spec pp_ins_list(file:io_device(), llvm_version(), [llvm_instr()]) -> ok.
-pp_ins_list(_Dev, _Ver, []) -> ok;
-pp_ins_list(Dev, Ver={_,_}, [I|Is]) ->
- pp_ins(Dev, Ver, I),
- pp_ins_list(Dev, Ver, Is).
-
-pp_ins(Dev, Ver, I) ->
- case indent(I) of
- true -> write(Dev, " ");
- false -> ok
- end,
- case I of
- #llvm_ret{} ->
- write(Dev, "ret "),
- case ret_ret_list(I) of
- [] -> write(Dev, "void");
- List -> pp_args(Dev, List)
- end,
- write(Dev, "\n");
- #llvm_br{} ->
- write(Dev, ["br label ", br_dst(I), "\n"]);
- #llvm_switch{} ->
- write(Dev, "switch "),
- pp_type(Dev, switch_type(I)),
- write(Dev, [" ", switch_value(I), ", label ", switch_default_label(I),
- " \n [\n"]),
- pp_switch_value_label_list(Dev, switch_type(I),
- switch_value_label_list(I)),
- write(Dev, " ]\n");
- #llvm_invoke{} ->
- write(Dev, [invoke_dst(I), " = invoke ", invoke_cconv(I), " "]),
- pp_options(Dev, invoke_ret_attrs(I)),
- pp_type(Dev, invoke_type(I)),
- write(Dev, [" ", invoke_fnptrval(I), "("]),
- pp_args(Dev, invoke_arglist(I)),
- write(Dev, ") "),
- pp_options(Dev, invoke_fn_attrs(I)),
- write(Dev, [" to label ", invoke_to_label(I)," unwind label ",
- invoke_unwind_label(I), " \n"]);
- #llvm_br_cond{} ->
- write(Dev, ["br i1 ", br_cond_cond(I), ", label ", br_cond_true_label(I),
- ", label ", br_cond_false_label(I)]),
- case br_cond_meta(I) of
- [] -> ok;
- Metadata ->
- write(Dev, [", !prof !", Metadata])
- end,
- write(Dev, "\n");
- #llvm_indirectbr{} ->
- write(Dev, "indirectbr "),
- pp_type(Dev, indirectbr_type(I)),
- write(Dev, [" ", indirectbr_address(I), ", [ "]),
- pp_args(Dev, indirectbr_label_list(I)),
- write(Dev, " ]\n");
- #llvm_operation{} ->
- write(Dev, [operation_dst(I), " = ", atom_to_list(operation_op(I)), " "]),
- case op_has_options(operation_op(I)) of
- true -> pp_options(Dev, operation_options(I));
- false -> ok
- end,
- pp_type(Dev, operation_type(I)),
- write(Dev, [" ", operation_src1(I), ", ", operation_src2(I), "\n"]);
- #llvm_extractvalue{} ->
- write(Dev, [extractvalue_dst(I), " = extractvalue "]),
- pp_type(Dev, extractvalue_type(I)),
- %% TODO Print idxs
- write(Dev, [" ", extractvalue_val(I), ", ", extractvalue_idx(I), "\n"]);
- #llvm_insertvalue{} ->
- write(Dev, [insertvalue_dst(I), " = insertvalue "]),
- pp_type(Dev, insertvalue_val_type(I)),
- write(Dev, [" ", insertvalue_val(I), ", "]),
- pp_type(Dev, insertvalue_elem_type(I)),
- %%TODO Print idxs
- write(Dev, [" ", insertvalue_elem(I), ", ", insertvalue_idx(I), "\n"]);
- #llvm_alloca{} ->
- write(Dev, [alloca_dst(I), " = alloca "]),
- pp_type(Dev, alloca_type(I)),
- case alloca_num(I) of
- [] -> ok;
- Num ->
- write(Dev, ", "),
- pp_type(Dev, alloca_type(I)),
- write(Dev, [" ", Num, " "])
- end,
- case alloca_align(I) of
- [] -> ok;
- Align -> write(Dev, [",align ", Align])
- end,
- write(Dev, "\n");
- #llvm_load{} ->
- write(Dev, [load_dst(I), " = "]),
- write(Dev, "load "),
- case load_volatile(I) of
- true -> write(Dev, "volatile ");
- false -> ok
- end,
- pp_dereference_type(Dev, load_p_type(I)),
- write(Dev, [" ", load_pointer(I), " "]),
- case load_alignment(I) of
- [] -> ok;
- Al -> write(Dev, [", align ", Al, " "])
- end,
- case load_nontemporal(I) of
- [] -> ok;
- In -> write(Dev, [", !nontemporal !", In])
- end,
- write(Dev, "\n");
- #llvm_store{} ->
- write(Dev, "store "),
- case store_volatile(I) of
- true -> write(Dev, "volatile ");
- false -> ok
- end,
- pp_type(Dev, store_type(I)),
- write(Dev, [" ", store_value(I), ", "]),
- pp_type(Dev, store_p_type(I)),
- write(Dev, [" ", store_pointer(I), " "]),
- case store_alignment(I) of
- [] -> ok;
- Al -> write(Dev, [", align ", Al, " "])
- end,
- case store_nontemporal(I) of
- [] -> ok;
- In -> write(Dev, [", !nontemporal !", In])
- end,
- write(Dev, "\n");
- #llvm_getelementptr{} ->
- write(Dev, [getelementptr_dst(I), " = getelementptr "]),
- case getelementptr_inbounds(I) of
- true -> write(Dev, "inbounds ");
- false -> ok
- end,
- pp_dereference_type(Dev, getelementptr_p_type(I)),
- write(Dev, [" ", getelementptr_value(I)]),
- pp_typed_idxs(Dev, getelementptr_typed_idxs(I)),
- write(Dev, "\n");
- #llvm_conversion{} ->
- write(Dev, [conversion_dst(I), " = ", atom_to_list(conversion_op(I)), " "]),
- pp_type(Dev, conversion_src_type(I)),
- write(Dev, [" ", conversion_src(I), " to "]),
- pp_type(Dev, conversion_dst_type(I)),
- write(Dev, "\n");
- #llvm_icmp{} ->
- write(Dev, [icmp_dst(I), " = icmp ", atom_to_list(icmp_cond(I)), " "]),
- pp_type(Dev, icmp_type(I)),
- write(Dev, [" ", icmp_src1(I), ", ", icmp_src2(I), "\n"]);
- #llvm_fcmp{} ->
- write(Dev, [fcmp_dst(I), " = fcmp ", atom_to_list(fcmp_cond(I)), " "]),
- pp_type(Dev, fcmp_type(I)),
- write(Dev, [" ", fcmp_src1(I), ", ", fcmp_src2(I), "\n"]);
- #llvm_phi{} ->
- write(Dev, [phi_dst(I), " = phi "]),
- pp_type(Dev, phi_type(I)),
- pp_phi_value_labels(Dev, phi_value_label_list(I)),
- write(Dev, "\n");
- #llvm_select{} ->
- write(Dev, [select_dst(I), " = select i1 ", select_cond(I), ", "]),
- pp_type(Dev, select_typ1(I)),
- write(Dev, [" ", select_val1(I), ", "]),
- pp_type(Dev, select_typ2(I)),
- write(Dev, [" ", select_val2(I), "\n"]);
- #llvm_call{} ->
- case call_dst(I) of
- [] -> ok;
- Dst -> write(Dev, [Dst, " = "])
- end,
- case call_is_tail(I) of
- true -> write(Dev, "tail ");
- false -> write(Dev, "notail ")
- end,
- write(Dev, ["call ", call_cconv(I), " "]),
- pp_options(Dev, call_ret_attrs(I)),
- pp_type(Dev, call_type(I)),
- write(Dev, [" ", call_fnptrval(I), "("]),
- pp_args(Dev, call_arglist(I)),
- write(Dev, ") "),
- pp_options(Dev, call_fn_attrs(I)),
- write(Dev, "\n");
- #llvm_fun_def{} ->
- write(Dev, "define "),
- pp_options(Dev, fun_def_linkage(I)),
- pp_options(Dev, fun_def_visibility(I)),
- case fun_def_cconv(I) of
- [] -> ok;
- Cc -> write(Dev, [Cc, " "])
- end,
- pp_options(Dev, fun_def_ret_attrs(I)),
- write(Dev, " "),
- pp_type(Dev, fun_def_type(I)),
- write(Dev, [" @", fun_def_name(I), "("]),
- pp_args(Dev, fun_def_arglist(I)),
- write(Dev, ") "),
- pp_options(Dev, fun_def_fn_attrs(I)),
- write(Dev, "personality i32 (i32, i64, i8*,i8*)* "
- "@__gcc_personality_v0 "),
- case fun_def_align(I) of
- [] -> ok;
- N -> write(Dev, ["align ", N])
- end,
- write(Dev, "{\n"),
- pp_ins_list(Dev, Ver, fun_def_body(I)),
- write(Dev, "}\n");
- #llvm_fun_decl{} ->
- write(Dev, "declare "),
- pp_options(Dev, fun_decl_linkage(I)),
- pp_options(Dev, fun_decl_visibility(I)),
- case fun_decl_cconv(I) of
- [] -> ok;
- Cc -> write(Dev, [Cc, " "])
- end,
- pp_options(Dev, fun_decl_ret_attrs(I)),
- pp_type(Dev, fun_decl_type(I)),
- write(Dev, [" ", fun_decl_name(I), "("]),
- pp_type_list(Dev, fun_decl_arglist(I)),
- write(Dev, ") "),
- case fun_decl_align(I) of
- [] -> ok;
- N -> write(Dev, ["align ", N])
- end,
- write(Dev, "\n");
- #llvm_comment{} ->
- write(Dev, ["; ", atom_to_list(comment_text(I)), "\n"]);
- #llvm_label{} ->
- write(Dev, [label_label(I), ":\n"]);
- #llvm_const_decl{} ->
- write(Dev, [const_decl_dst(I), " = ", const_decl_decl_type(I), " "]),
- pp_type(Dev, const_decl_type(I)),
- write(Dev, [" ", const_decl_value(I), "\n"]);
- #llvm_landingpad{} ->
- write(Dev, "landingpad { i8*, i32 } cleanup\n");
- #llvm_asm{} ->
- write(Dev, [asm_instruction(I), "\n"]);
- #llvm_adj_stack{} ->
- write(Dev, ["call void asm sideeffect \"sub $0, ",
- adj_stack_register(I), "\", \"r\"("]),
- pp_type(Dev, adj_stack_type(I)),
- write(Dev, [" ", adj_stack_offset(I),")\n"]);
- #llvm_meta{} ->
- write(Dev, ["!", meta_id(I), " = !{ "]),
- write(Dev, lists:join(", ",
- [if is_list(Op) -> ["!\"", Op, "\""];
- is_integer(Op) -> ["i32 ", integer_to_list(Op)];
- is_record(Op, llvm_meta) ->
- ["!", meta_id(Op)]
- end || Op <- meta_operands(I)])),
- write(Dev, " }\n");
- Other ->
- exit({?MODULE, pp_ins, {"Unknown LLVM instruction", Other}})
- end.
-
-%% @doc Print the type of a dereference in an LLVM instruction.
-pp_dereference_type(Dev, Type) ->
- pp_type(Dev, pointer_type(Type)),
- write(Dev, ", "),
- pp_type(Dev, Type).
-
-%% @doc Pretty-print a list of types
-pp_type_list(_Dev, []) -> ok;
-pp_type_list(Dev, [T]) ->
- pp_type(Dev, T);
-pp_type_list(Dev, [T|Ts]) ->
- pp_type(Dev, T),
- write(Dev, ", "),
- pp_type_list(Dev, Ts).
-
-pp_type(Dev, Type) ->
- case Type of
- #llvm_void{} ->
- write(Dev, "void");
- #llvm_label_type{} ->
- write(Dev, "label");
- %% Integer
- #llvm_int{} ->
- write(Dev, ["i", integer_to_list(int_width(Type))]);
- %% Float
- #llvm_float{} ->
- write(Dev, "float");
- #llvm_double{} ->
- write(Dev, "double");
- #llvm_fp80{} ->
- write(Dev, "x86_fp80");
- #llvm_fp128{} ->
- write(Dev, "fp128");
- #llvm_ppc_fp128{} ->
- write(Dev, "ppc_fp128");
- %% Pointer
- #llvm_pointer{} ->
- pp_type(Dev, pointer_type(Type)),
- write(Dev, "*");
- %% Function
- #llvm_fun{} ->
- pp_type(Dev, function_ret_type(Type)),
- write(Dev, " ("),
- pp_type_list(Dev, function_arg_type_list(Type)),
- write(Dev, ")");
- %% Aggregate
- #llvm_array{} ->
- write(Dev, ["[", integer_to_list(array_size(Type)), " x "]),
- pp_type(Dev, array_type(Type)),
- write(Dev, "]");
- #llvm_struct{} ->
- write(Dev, "{"),
- pp_type_list(Dev, struct_type_list(Type)),
- write(Dev, "}");
- #llvm_vector{} ->
- write(Dev, ["{", integer_to_list(vector_size(Type)), " x "]),
- pp_type(Dev, vector_type(Type)),
- write(Dev, "}")
- end.
-
-%% @doc Pretty-print a list of typed arguments
-pp_args(_Dev, []) -> ok;
-pp_args(Dev, [{Type, Arg} | []]) ->
- pp_type(Dev, Type),
- write(Dev, [" ", Arg]);
-pp_args(Dev, [{Type, Arg} | Args]) ->
- pp_type(Dev, Type),
- write(Dev, [" ", Arg, ", "]),
- pp_args(Dev, Args).
-
-%% @doc Pretty-print a list of options
-pp_options(_Dev, []) -> ok;
-pp_options(Dev, [O|Os]) ->
- write(Dev, [atom_to_list(O), " "]),
- pp_options(Dev, Os).
-
-%% @doc Pretty-print a list of phi value-labels
-pp_phi_value_labels(_Dev, []) -> ok;
-pp_phi_value_labels(Dev, [{Value, Label}|[]]) ->
- write(Dev, ["[ ", Value, ", ", Label, " ]"]);
-pp_phi_value_labels(Dev,[{Value, Label}|VL]) ->
- write(Dev, ["[ ", Value, ", ", Label, " ], "]),
- pp_phi_value_labels(Dev, VL).
-
-%% @doc Pretty-print a list of typed indexes
-pp_typed_idxs(_Dev, []) -> ok;
-pp_typed_idxs(Dev, [{Type, Id} | Tids]) ->
- write(Dev, ", "),
- pp_type(Dev, Type),
- write(Dev, [" ", Id]),
- pp_typed_idxs(Dev, Tids).
-
-%% @doc Pretty-print a switch label list
-pp_switch_value_label_list(_Dev, _Type, []) -> ok;
-pp_switch_value_label_list(Dev, Type, [{Value, Label} | VLs]) ->
- write(Dev, " "),
- pp_type(Dev, Type),
- write(Dev, [" ", Value, ", label ", Label, "\n"]),
- pp_switch_value_label_list(Dev, Type, VLs).
-
-%%----------------------------------------------------------------------------
-%% Auxiliary Functions
-%%----------------------------------------------------------------------------
-
-%% @doc Returns if an instruction needs to be intended
-indent(I) ->
- case I of
- #llvm_label{} -> false;
- #llvm_fun_def{} -> false;
- #llvm_fun_decl{} -> false;
- #llvm_const_decl{} -> false;
- #llvm_meta{} -> false;
- _ -> true
- end.
-
-op_has_options(Op) ->
- case Op of
- 'and' -> false;
- 'or' -> false;
- 'xor' -> false;
- _ -> true
- end.
-
-%% @doc Abstracts actual writing to file operations
-write(Dev, Msg) ->
- ok = file:write(Dev, Msg).
diff --git a/lib/hipe/llvm/hipe_llvm_arch.hrl b/lib/hipe/llvm/hipe_llvm_arch.hrl
deleted file mode 100644
index 689a5a52ea..0000000000
--- a/lib/hipe/llvm/hipe_llvm_arch.hrl
+++ /dev/null
@@ -1,11 +0,0 @@
--ifdef(BIT32).
--define(NR_PINNED_REGS, 2).
--define(NR_ARG_REGS, 3).
--define(ARCH_REGISTERS, hipe_x86_registers).
--define(FLOAT_OFFSET, 2).
--else.
--define(NR_PINNED_REGS, 2).
--define(NR_ARG_REGS, 4).
--define(ARCH_REGISTERS, hipe_amd64_registers).
--define(FLOAT_OFFSET, 6).
--endif.
diff --git a/lib/hipe/llvm/hipe_llvm_liveness.erl b/lib/hipe/llvm/hipe_llvm_liveness.erl
deleted file mode 100644
index d1c90ed4c9..0000000000
--- a/lib/hipe/llvm/hipe_llvm_liveness.erl
+++ /dev/null
@@ -1,112 +0,0 @@
--module(hipe_llvm_liveness).
-
--export([analyze/1]).
-
-%% @doc Find gc roots and explicitly mark when they go out of scope, based
-%% on the liveness analyzis performed by the hipe_rtl_liveness:analyze/1.
-analyze(RtlCfg) ->
- Liveness = hipe_rtl_liveness:analyze(RtlCfg),
- Roots = find_roots(RtlCfg, Liveness),
- %% erlang:display(Roots),
- NewRtlCfg = mark_dead_roots(RtlCfg, Liveness, Roots),
- {NewRtlCfg, Roots}.
-
-%% @doc Determine which are the GC Roots.Possible roots are all
-%% RTL variables (rtl_var). However, since safe points are function calls, we
-%% consider as possible GC roots only RTL variables that are live around
-%% function calls.
-find_roots(Cfg, Liveness) ->
- Labels = hipe_rtl_cfg:postorder(Cfg),
- Roots = find_roots_bb(Labels, Cfg, Liveness, []),
- lists:usort(lists:flatten(Roots)).
-
-find_roots_bb([], _Cfg, _Liveness, RootAcc) ->
- RootAcc;
-find_roots_bb([L|Ls], Cfg, Liveness, RootAcc) ->
- Block = hipe_rtl_cfg:bb(Cfg, L),
- BlockCode = hipe_bb:code(Block),
- LiveIn = ordsets:from_list(strip(hipe_rtl_liveness:livein(Liveness, L))),
- LiveOut = ordsets:from_list(strip(hipe_rtl_liveness:liveout(Liveness, L))),
- Roots = do_find_roots_bb(BlockCode, L, LiveOut, LiveIn, []),
- find_roots_bb(Ls, Cfg, Liveness, Roots++RootAcc).
-
-%% For each call inside a BB the GC roots are those RTL variables that
-%% are live before and after the call.
-%% --> Live Before Call: These are the RTL variables that belong to the
-%% LiveIn list or are initialized inside the BB before the call
-%% --> Live After Call: These are the RTL variables that belong to the
-%% LiveOut list or are used after the call inside the BB (they die
-%% inside the BB and so do not belong to the LiveOut list)
-do_find_roots_bb([], _Label, _LiveOut, _LiveBefore, RootAcc) ->
- RootAcc;
-do_find_roots_bb([I|Is], L, LiveOut, LiveBefore, RootAcc) ->
- case hipe_rtl:is_call(I) of
- true ->
- %% Used inside the BB after the call
- UsedAfterCall_ = strip(lists:flatten([hipe_rtl:uses(V) || V <- Is])),
- UsedAfterCall = ordsets:from_list(UsedAfterCall_),
- LiveAfter = ordsets:union(UsedAfterCall, LiveOut),
- %% The Actual Roots
- Roots = ordsets:intersection(LiveBefore, LiveAfter),
- %% The result of the instruction
- Defines = ordsets:from_list(strip(hipe_rtl:defines(I))),
- LiveBefore1 = ordsets:union(LiveBefore, Defines),
- do_find_roots_bb(Is, L, LiveOut, LiveBefore1, [Roots|RootAcc]);
- false ->
- %% The result of the instruction
- Defines = ordsets:from_list(strip(hipe_rtl:defines(I))),
- LiveBefore1 = ordsets:union(LiveBefore, Defines),
- do_find_roots_bb(Is, L, LiveOut, LiveBefore1, RootAcc)
- end.
-
-%% @doc This function is responsible for marking when GC Roots, which can be
-%% only RTL variables go out of scope (dead). This pass is needed for the LLVM
-%% back end because the LLVM framework forces us to explicit mark when gc roots
-%% are no longer live.
-mark_dead_roots(CFG, Liveness, Roots) ->
- Labels = hipe_rtl_cfg:postorder(CFG),
- mark_dead_bb(Labels, CFG, Liveness, Roots).
-
-mark_dead_bb([], Cfg, _Liveness, _Roots) ->
- Cfg;
-mark_dead_bb([L|Ls], Cfg, Liveness, Roots) ->
- Block = hipe_rtl_cfg:bb(Cfg, L),
- BlockCode = hipe_bb:code(Block),
- LiveOut = ordsets:from_list(strip(hipe_rtl_liveness:liveout(Liveness, L))),
- NewBlockCode = do_mark_dead_bb(BlockCode, LiveOut, Roots, []),
- %% Update the CFG
- NewBB = hipe_bb:code_update(Block, NewBlockCode),
- NewCFG = hipe_rtl_cfg:bb_add(Cfg, L, NewBB),
- mark_dead_bb(Ls, NewCFG, Liveness, Roots).
-
-do_mark_dead_bb([], _LiveOut, _Roots, NewBlockCode) ->
- lists:reverse(NewBlockCode);
-do_mark_dead_bb([I|Is], LiveOut ,Roots, NewBlockCode) ->
- Uses = ordsets:from_list(strip(hipe_rtl:uses(I))),
- %% GC roots that are used in this instruction
- RootsUsed = ordsets:intersection(Roots, Uses),
- UsedAfter_ = strip(lists:flatten([hipe_rtl:uses(V) || V <- Is])),
- UsedAfter = ordsets:from_list(UsedAfter_),
- %% GC roots that are live after this instruction
- LiveAfter = ordsets:union(LiveOut, UsedAfter),
- %% GC roots that their last use is in this instruction
- DeadRoots = ordsets:subtract(RootsUsed, LiveAfter),
- %% Recreate the RTL variable from the corresponding Index
- OldVars = [hipe_rtl:mk_var(V1) || V1 <- DeadRoots],
- %% Mark the RTL variable as DEAD (last use)
- NewVars = [kill_var(V2) || V2 <- OldVars],
- %% Create a list with the substitution of the old vars with the new
- %% ones which are marked with the dead keyword
- Subtitution = lists:zip(OldVars, NewVars),
- NewI = case Subtitution of
- [] -> I;
- _ -> hipe_rtl:subst_uses_llvm(Subtitution, I)
- end,
- do_mark_dead_bb(Is, LiveOut, Roots, [NewI|NewBlockCode]).
-
-%% Update the liveness of a var,in order to mark that this is the last use.
-kill_var(Var) -> hipe_rtl:var_liveness_update(Var, dead).
-
-%% We are only interested for rtl_vars, since only rtl_vars are possible gc
-%% roots.
-strip(L) -> [Y || {rtl_var, Y, _} <- L].
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
deleted file mode 100644
index 44f0566379..0000000000
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ /dev/null
@@ -1,552 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
--module(hipe_llvm_main).
-
--export([rtl_to_native/4]).
-
--include("../../kernel/src/hipe_ext_format.hrl").
--include("hipe_llvm_arch.hrl").
--include("elf_format.hrl").
-
-%% @doc Translation of RTL to a loadable object. This function takes the RTL
-%% code and calls hipe_rtl_to_llvm:translate/2 to translate the RTL code to
-%% LLVM code. After this, LLVM asm is printed to a file and the LLVM tool
-%% chain is invoked in order to produce an object file.
-rtl_to_native(MFA, RTL, Roots, Options) ->
- %% Compile to LLVM and get Instruction List (along with infos)
- {LLVMCode, RelocsDict0, ConstTab0} =
- hipe_rtl_to_llvm:translate(RTL, Roots),
- %% Fix function name to an acceptable LLVM identifier (needed for closures)
- {_Module, Fun, Arity} = hipe_rtl_to_llvm:fix_mfa_name(MFA),
- %% Write LLVM Assembly to intermediate file (on disk)
- {ok, Dir, ObjectFile} =
- compile_with_llvm(Fun, Arity, LLVMCode, Options, false),
- %%
- %% Extract information from object file
- %%
- ObjBin = open_object_file(ObjectFile),
- Obj = elf_format:read(ObjBin),
- %% Get labels info (for switches and jump tables)
- Labels = elf_format:extract_rela(Obj, ?RODATA),
- Tables = get_tables(Obj),
- %% Associate Labels with Switches and Closures with stack args
- {SwitchInfos, ExposedClosures} = correlate_labels(Tables, Labels),
- %% SwitchInfos: [{"table_50", [Labels]}]
- %% ExposedClosures: [{"table_closures", [Labels]}]
-
- %% Labelmap contains the offsets of the labels in the code that are
- %% used for switch's jump tables
- LabelMap = create_labelmap(MFA, SwitchInfos, RelocsDict0),
- {RelocsDict, ConstTab} = extract_constants(RelocsDict0, ConstTab0, Obj),
- %% Get relocation info
- TextRelocs = elf_format:extract_rela(Obj, ?TEXT),
- %% AccRefs contains the offsets of all references to relocatable symbols in
- %% the code:
- AccRefs = fix_relocations(TextRelocs, RelocsDict, MFA),
- %% Get stack descriptors
- SDescs = get_sdescs(Obj),
- %% FixedSDescs are the stack descriptors after correcting calls that have
- %% arguments in the stack
- FixedSDescs =
- fix_stack_descriptors(RelocsDict, AccRefs, SDescs, ExposedClosures),
- Refs = AccRefs ++ FixedSDescs,
- %% Get binary code from object file
- BinCode = elf_format:extract_text(Obj),
- %% Remove temp files (if needed)
- ok = remove_temp_folder(Dir, Options),
- %% Return the code together with information that will be used in the
- %% hipe_llvm_merge module to produce the final binary that will be loaded
- %% by the hipe unified loader.
- {MFA, BinCode, byte_size(BinCode), ConstTab, Refs, LabelMap}.
-
-%%------------------------------------------------------------------------------
-%% LLVM tool chain
-%%------------------------------------------------------------------------------
-
-%% @doc Compile function FunName/Arity to LLVM. Return Dir (in order to remove
-%% it if we do not want to store temporary files) and ObjectFile name that
-%% is created by the LLVM tools.
-compile_with_llvm(FunName, Arity, LLVMCode, Options, UseBuffer) ->
- Filename = atom_to_list(FunName) ++ "_" ++ integer_to_list(Arity),
- %% Save temp files in a unique folder
- Dir = unique_folder(FunName, Arity, Options),
- ok = file:make_dir(Dir),
- %% Print LLVM assembly to file
- OpenOpts = [append, raw] ++
- case UseBuffer of
- %% true -> [delayed_write]; % Use delayed_write!
- false -> []
- end,
- {ok, File_llvm} = file:open(Dir ++ Filename ++ ".ll", OpenOpts),
- Ver = hipe:get_llvm_version(), %% Should probably cache this
- hipe_llvm:pp_ins_list(File_llvm, Ver, LLVMCode),
- %% delayed_write can cause file:close not to do a close, hence the two calls
- ok = file:close(File_llvm),
- __ = file:close(File_llvm),
- %% Invoke LLVM compiler tools to produce an object file
- llvm_opt(Dir, Filename, Options),
- llvm_llc(Dir, Filename, Ver, Options),
- compile(Dir, Filename, "gcc"), %%FIXME: use llc -filetype=obj and skip this!
- {ok, Dir, Dir ++ Filename ++ ".o"}.
-
-%% @doc Invoke opt tool to optimize the bitcode (_name.ll -> _name.bc).
-llvm_opt(Dir, Filename, Options) ->
- Source = Dir ++ Filename ++ ".ll",
- Dest = Dir ++ Filename ++ ".bc",
- OptLevel = trans_optlev_flag(opt, Options),
- OptFlags = [OptLevel, "-mem2reg", "-strip"],
- Command = "opt " ++ fix_opts(OptFlags) ++ " " ++ Source ++ " -o " ++ Dest,
- %% io:format("OPT: ~s~n", [Command]),
- case os:cmd(Command) of
- "" -> ok;
- Error -> exit({?MODULE, opt, Error})
- end.
-
-%% @doc Invoke llc tool to compile the bitcode to object file
-%% (_name.bc -> _name.o).
-llvm_llc(Dir, Filename, Ver, Options) ->
- Source = Dir ++ Filename ++ ".bc",
- OptLevel = trans_optlev_flag(llc, Options),
- VerFlags = llc_ver_flags(Ver),
- Align = find_stack_alignment(),
- Target = llc_target_opt(),
- LlcFlags = [OptLevel, "-code-model=medium", "-stack-alignment=" ++ Align
- , "-tailcallopt", "-filetype=asm" %FIXME
- , Target
- | VerFlags],
- Command = "llc " ++ fix_opts(LlcFlags) ++ " " ++ Source,
- %% io:format("LLC: ~s~n", [Command]),
- case os:cmd(Command) of
- "" -> ok;
- Error -> exit({?MODULE, llc, Error})
- end.
-
-%% @doc Invoke the compiler tool ("gcc", "llvmc", etc.) to generate an object
-%% file from native assembly.
-compile(Dir, Fun_Name, Compiler) ->
- Source = Dir ++ Fun_Name ++ ".s",
- Dest = Dir ++ Fun_Name ++ ".o",
- Target = compiler_target_opt(),
- Command = Compiler ++ " " ++ Target ++ " -c " ++ Source ++ " -o " ++ Dest,
- %% io:format("~s: ~s~n", [Compiler, Command]),
- case os:cmd(Command) of
- "" -> ok;
- Error -> exit({?MODULE, cc, Error})
- end.
-
-find_stack_alignment() ->
- case get(hipe_target_arch) of
- x86 -> "4";
- amd64 -> "8";
- _ -> exit({?MODULE, find_stack_alignment, "Unimplemented architecture"})
- end.
-
-llc_target_opt() ->
- case get(hipe_target_arch) of
- x86 -> "-march=x86";
- amd64 -> "-march=x86-64"
- end.
-
-compiler_target_opt() ->
- case get(hipe_target_arch) of
- x86 -> "-m32";
- amd64 -> "-m64"
- end.
-
-%% @doc Join options.
-fix_opts(Opts) ->
- lists:flatten(lists:join(" ", Opts)).
-
-%% @doc Translate optimization-level flag (default is "O2").
-trans_optlev_flag(Tool, Options) ->
- Flag = case Tool of
- opt -> llvm_opt;
- llc -> llvm_llc
- end,
- case proplists:get_value(Flag, Options) of
- o0 -> ""; % "-O0" does not exist in opt tool
- o1 -> "-O1";
- o2 -> "-O2";
- o3 -> "-O3";
- undefined -> "-O2"
- end.
-
-llc_ver_flags(Ver = {_, _}) when Ver >= {3,9} ->
- %% Works around a bug in the x86-call-frame-opt pass (as of LLVM 3.9) that
- %% break the garbage collection stack descriptors.
- ["-no-x86-call-frame-opt"];
-llc_ver_flags({_, _}) -> [].
-
-%%------------------------------------------------------------------------------
-%% Functions to manage Relocations
-%%------------------------------------------------------------------------------
-
-%% @doc Get switch table and closure table.
--spec get_tables(elf_format:elf()) -> [elf_sym()].
-get_tables(Elf) ->
- %% Search Symbol Table for entries where name is prefixed with "table_":
- [S || S=#elf_sym{name="table_" ++ _} <- elf_format:elf_symbols(Elf)].
-
-%% @doc This function associates symbols who point to some table of labels with
-%% the corresponding offsets of the labels in the code. These tables can
-%% either be jump tables for switches or a table which contains the labels
-%% of blocks that contain closure calls with more than ?NR_ARG_REGS.
-correlate_labels([], _L) -> {[], []};
-correlate_labels(Tables, Labels) ->
- %% Assumes that the relocations are sorted
- RelocTree = gb_trees:from_orddict(
- [{Rel#elf_rel.offset, Rel#elf_rel.addend} || Rel <- Labels]),
- %% Lookup all relocations pertaining to each symbol
- NamesValues = [{Name, lookup_range(Value, Value+Size, RelocTree)}
- || #elf_sym{name=Name, value=Value, size=Size} <- Tables],
- case lists:keytake("table_closures", 1, NamesValues) of
- false -> %% No closures in the code, no closure table
- {NamesValues, []};
- {value, ClosureTableNV, SwitchesNV} ->
- {SwitchesNV, ClosureTableNV}
- end.
-
-%% Fetches all values with a key in [Low, Hi)
--spec lookup_range(_::K, _::K, gb_trees:tree(K,V)) -> [_::V].
-lookup_range(Low, Hi, Tree) ->
- lookup_range_1(Hi, gb_trees:iterator_from(Low, Tree)).
-
-lookup_range_1(Hi, Iter0) ->
- case gb_trees:next(Iter0) of
- {Key, Value, Iter} when Key < Hi -> [Value | lookup_range_1(Hi, Iter)];
- _ -> []
- end.
-
-%% @doc Create a gb_tree which contains information about the labels that used
-%% for switch's jump tables. The keys of the gb_tree are of the form
-%% {MFA, Label} and the values are the actual Offsets.
-create_labelmap(MFA, SwitchInfos, RelocsDict) ->
- create_labelmap(MFA, SwitchInfos, RelocsDict, gb_trees:empty()).
-
-create_labelmap(_, [], _, LabelMap) -> LabelMap;
-create_labelmap(MFA, [{Name, Offsets} | Rest], RelocsDict, LabelMap) ->
- case dict:fetch(Name, RelocsDict) of
- {switch, {_TableType, LabelList, _NrLabels, _SortOrder}, _JTabLab} ->
- KVDict = lists:ukeysort(1, lists:zip(LabelList, Offsets)),
- NewLabelMap = insert_to_labelmap(KVDict, LabelMap),
- create_labelmap(MFA, Rest, RelocsDict, NewLabelMap);
- _ ->
- exit({?MODULE, create_labelmap, "Not a jump table!"})
- end.
-
-%% @doc Insert a list of [{Key,Value}] to a LabelMap (gb_tree).
-insert_to_labelmap([], LabelMap) -> LabelMap;
-insert_to_labelmap([{Key, Value}|Rest], LabelMap) ->
- case gb_trees:lookup(Key, LabelMap) of
- none ->
- insert_to_labelmap(Rest, gb_trees:insert(Key, Value, LabelMap));
- {value, Value} -> %% Exists with the *exact* same Value.
- insert_to_labelmap(Rest, LabelMap)
- end.
-
-%% Find any LLVM-generated constants and add them to the constant table
-extract_constants(RelocsDict0, ConstTab0, Obj) ->
- TextRelocs = elf_format:extract_rela(Obj, ?TEXT),
- AnonConstSections =
- lists:usort([{Sec, Offset}
- || #elf_rel{symbol=#elf_sym{type=section, section=Sec},
- addend=Offset} <- TextRelocs]),
- lists:foldl(
- fun({#elf_shdr{name=Name, type=progbits, addralign=Align, entsize=EntSize,
- size=Size} = Section, Offset}, {RelocsDict1, ConstTab1})
- when EntSize > 0, 0 =:= Size rem EntSize, 0 =:= Offset rem EntSize ->
- SectionBin = elf_format:section_contents(Section, Obj),
- Constant = binary:part(SectionBin, Offset, EntSize),
- {ConstTab, ConstLbl} =
- hipe_consttab:insert_binary_const(ConstTab1, Align, Constant),
- {dict:store({anon, Name, Offset}, {constant, ConstLbl}, RelocsDict1),
- ConstTab}
- end, {RelocsDict0, ConstTab0}, AnonConstSections).
-
-%% @doc Correlate object file relocation symbols with info from translation to
-%% llvm code.
-fix_relocations(Relocs, RelocsDict, MFA) ->
- lists:map(fun(Reloc) -> fix_reloc(Reloc, RelocsDict, MFA) end, Relocs).
-
-%% Relocation types and expected addends for x86 and amd64
--define(PCREL_T, 'pc32').
--define(PCREL_A, -4). %% Hard-coded in hipe_x86.c and hipe_amd64.c
--ifdef(BIT32).
--define(ABS_T, '32').
--define(ABS_A, _). %% We support any addend
--else.
--define(ABS_T, '64').
--define(ABS_A, 0).
--endif.
-
-fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=undefined, type=notype},
- offset=Offset, type=?PCREL_T, addend=?PCREL_A},
- RelocsDict, {_,_,_}) when Name =/= "" ->
- case dict:fetch(Name, RelocsDict) of
- {call, _, {bif, BifName, _}} -> {?CALL_LOCAL, Offset, BifName};
- {call, not_remote, CallMFA} -> {?CALL_LOCAL, Offset, CallMFA};
- {call, remote, CallMFA} -> {?CALL_REMOTE, Offset, CallMFA}
- end;
-fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=undefined, type=notype},
- offset=Offset, type=?ABS_T, addend=?ABS_A},
- RelocsDict, _) when Name =/= "" ->
- case dict:fetch(Name, RelocsDict) of
- {atom, AtomName} -> {?LOAD_ATOM, Offset, AtomName};
- {constant, Label} -> {?LOAD_ADDRESS, Offset, {constant, Label}};
- {closure, _}=Closure -> {?LOAD_ADDRESS, Offset, Closure}
- end;
-fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=#elf_shdr{name=?TEXT},
- type=func},
- offset=Offset, type=?PCREL_T, addend=?PCREL_A},
- RelocsDict, MFA) when Name =/= "" ->
- case dict:fetch(Name, RelocsDict) of
- {call, not_remote, MFA} -> {?CALL_LOCAL, Offset, MFA}
- end;
-fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=#elf_shdr{name=?RODATA},
- type=object},
- offset=Offset, type=?ABS_T, addend=?ABS_A},
- RelocsDict, _) when Name =/= "" ->
- case dict:fetch(Name, RelocsDict) of
- {switch, _, JTabLab} -> %% Treat switch exactly as constant
- {?LOAD_ADDRESS, Offset, {constant, JTabLab}}
- end;
-fix_reloc(#elf_rel{symbol=#elf_sym{type=section, section=#elf_shdr{name=Name}},
- offset=Offset, type=?ABS_T, addend=Addend}, RelocsDict, _) ->
- case dict:fetch({anon, Name, Addend}, RelocsDict) of
- {constant, Label} -> {?LOAD_ADDRESS, Offset, {constant, Label}}
- end.
-
-%%------------------------------------------------------------------------------
-%% Functions to manage Stack Descriptors
-%%------------------------------------------------------------------------------
-
-%% @doc This function takes an ELF Object File binary and returns a proper sdesc
-%% list for Erlang/OTP System's loader. The return value should be of the
-%% form:
-%% {
-%% 4, Safepoint Address,
-%% {ExnLabel OR [], FrameSize, StackArity, {Liveroot stack frame indexes}},
-%% }
-get_sdescs(Elf) ->
- case elf_format:extract_note(Elf, ?NOTE_ERLGC_NAME) of
- <<>> -> % Object file has no ".note.gc" section!
- [];
- NoteGC_bin ->
- %% Get safe point addresses (stored in ".rela.note.gc" section):
- RelaNoteGC = elf_format:extract_rela(Elf, ?NOTE(?NOTE_ERLGC_NAME)),
- SPCount = length(RelaNoteGC),
- T = SPCount * ?SP_ADDR_SIZE,
- %% Pattern match fields of ".note.gc":
- <<SPCount:(?bits(?SP_COUNT_SIZE))/integer-little, % Sanity check!
- _SPAddrs:T/binary, % NOTE: In 64bit they are relocs!
- StkFrameSize:(?bits(?SP_STKFRAME_SIZE))/integer-little,
- StkArity:(?bits(?SP_STKARITY_SIZE))/integer-little,
- _LiveRootCount:(?bits(?SP_LIVEROOTCNT_SIZE))/integer-little, % Skip
- Roots/binary>> = NoteGC_bin,
- LiveRoots = get_liveroots(Roots, []),
- %% Extract the safe point offsets:
- SPOffs = [A || #elf_rel{addend=A} <- RelaNoteGC],
- %% Extract Exception Handler labels:
- ExnHandlers = elf_format:get_exn_handlers(Elf),
- %% Combine ExnHandlers and Safe point addresses (return addresses):
- ExnAndSPOffs = combine_ras_and_exns(ExnHandlers, SPOffs, []),
- create_sdesc_list(ExnAndSPOffs, StkFrameSize, StkArity, LiveRoots, [])
- end.
-
-%% @doc Extracts a bunch of integers (live roots) from a binary. Returns a tuple
-%% as need for stack descriptors.
-get_liveroots(<<>>, Acc) ->
- list_to_tuple(Acc);
-get_liveroots(<<Root:?bits(?LR_STKINDEX_SIZE)/integer-little,
- MoreRoots/binary>>, Acc) ->
- get_liveroots(MoreRoots, [Root | Acc]).
-
-combine_ras_and_exns(_, [], Acc) ->
- lists:reverse(Acc);
-combine_ras_and_exns(ExnHandlers, [RA | MoreRAs], Acc) ->
- %% FIXME: do something better than O(n^2) by taking advantage of the property
- %% ||ExnHandlers|| <= ||RAs||
- Handler = find_exn_handler(RA, ExnHandlers),
- combine_ras_and_exns(ExnHandlers, MoreRAs, [{Handler, RA} | Acc]).
-
-find_exn_handler(_, []) ->
- [];
-find_exn_handler(RA, [{Start, End, Handler} | MoreExnHandlers]) ->
- case (RA >= Start andalso RA =< End) of
- true ->
- Handler;
- false ->
- find_exn_handler(RA, MoreExnHandlers)
- end.
-
-create_sdesc_list([], _, _, _, Acc) ->
- lists:reverse(Acc);
-create_sdesc_list([{ExnLbl, SPOff} | MoreExnAndSPOffs],
- StkFrameSize, StkArity, LiveRoots, Acc) ->
- Hdlr = case ExnLbl of
- 0 -> [];
- N -> N
- end,
- create_sdesc_list(MoreExnAndSPOffs, StkFrameSize, StkArity, LiveRoots,
- [{?SDESC, SPOff, {Hdlr, StkFrameSize, StkArity, LiveRoots}}
- | Acc]).
-
-%% @doc This function is responsible for correcting the stack descriptors of
-%% the calls that are found in the code and have more than NR_ARG_REGS
-%% (thus, some of their arguments are passed to the stack). Because of the
-%% Reserved Call Frame feature that the LLVM uses, the stack descriptors
-%% are not correct since at the point of call the frame size is reduced
-%% by the number of arguments that are passed on the stack. Also, the
-%% offsets of the roots need to be re-adjusted.
-fix_stack_descriptors(_, _, [], _) ->
- [];
-fix_stack_descriptors(RelocsDict, Relocs, SDescs, ExposedClosures) ->
- %% NamedCalls are MFA and BIF calls that need fix
- NamedCalls = calls_with_stack_args(RelocsDict),
- NamedCallsOffs = calls_offsets_arity(Relocs, NamedCalls),
- ExposedClosures1 =
- case dict:is_key("table_closures", RelocsDict) of
- true -> %% A Table with closures exists
- {table_closures, ArityList} = dict:fetch("table_closures", RelocsDict),
- case ExposedClosures of
- {_, Offsets} ->
- lists:zip(Offsets, ArityList);
- _ ->
- exit({?MODULE, fix_stack_descriptors,
- {"Wrong exposed closures", ExposedClosures}})
- end;
- false ->
- []
- end,
- ClosuresOffs = closures_offsets_arity(ExposedClosures1, SDescs),
- fix_sdescs(NamedCallsOffs ++ ClosuresOffs, SDescs).
-
-%% @doc This function takes as argument the relocation dictionary as produced by
-%% the translation of RTL code to LLVM and finds the names of the calls
-%% (MFA and BIF calls) that have more than NR_ARG_REGS.
-calls_with_stack_args(Dict) ->
- calls_with_stack_args(dict:to_list(Dict), []).
-
-calls_with_stack_args([], Calls) -> Calls;
-calls_with_stack_args([ {_Name, {call, _, {M, F, A}}} | Rest], Calls)
- when A > ?NR_ARG_REGS ->
- Call =
- case M of
- bif -> {F,A};
- _ -> {M,F,A}
- end,
- calls_with_stack_args(Rest, [Call|Calls]);
-calls_with_stack_args([_|Rest], Calls) ->
- calls_with_stack_args(Rest, Calls).
-
-%% @doc This function extracts the stack arity and the offset in the code of
-%% the named calls (MFAs, BIFs) that have stack arguments.
-calls_offsets_arity(AccRefs, CallsWithStackArgs) ->
- calls_offsets_arity(AccRefs, CallsWithStackArgs, []).
-
-calls_offsets_arity([], _, Acc) -> Acc;
-calls_offsets_arity([{Type, Offset, Term} | Rest], CallsWithStackArgs, Acc)
- when Type =:= ?CALL_REMOTE orelse Type =:= ?CALL_LOCAL ->
- case lists:member(Term, CallsWithStackArgs) of
- true ->
- Arity =
- case Term of
- {_M, _F, A} -> A;
- {_F, A} -> A
- end,
- calls_offsets_arity(Rest, CallsWithStackArgs,
- [{Offset + 4, Arity - ?NR_ARG_REGS} | Acc]);
- false ->
- calls_offsets_arity(Rest, CallsWithStackArgs, Acc)
- end;
-calls_offsets_arity([_|Rest], CallsWithStackArgs, Acc) ->
- calls_offsets_arity(Rest, CallsWithStackArgs, Acc).
-
-%% @doc This function extracts the stack arity and the offsets of closures that
-%% have stack arity. The Closures argument represents the
-%% hipe_bifs:llvm_exposure_closure/0 calls in the code. The actual closure
-%% is the next call in the code, so the offset of the next call must be
-%% calculated from the stack descriptors.
-closures_offsets_arity([], _) ->
- [];
-closures_offsets_arity(ExposedClosures, SDescs) ->
- Offsets = [Offset || {_, Offset, _} <- SDescs],
- %% Offsets and closures must be sorted in order for find_offsets/3 to work
- SortedOffsets = lists:sort(Offsets),
- SortedExposedClosures = lists:keysort(1, ExposedClosures),
- find_offsets(SortedExposedClosures, SortedOffsets, []).
-
-find_offsets([], _, Acc) -> Acc;
-find_offsets([{Off,Arity}|Rest], Offsets, Acc) ->
- [I | RestOffsets] = lists:dropwhile(fun (Y) -> Y<Off end, Offsets),
- find_offsets(Rest, RestOffsets, [{I, Arity}|Acc]).
-
-%% The function below corrects the stack descriptors of calls with arguments
-%% that are passed on the stack (more than NR_ARG_REGS) by subtracting the
-%% number of stacked arguments from the frame size and from the offset of the
-%% roots.
-fix_sdescs([], SDescs) -> SDescs;
-fix_sdescs([{Offset, Arity} | Rest], SDescs) ->
- case lists:keyfind(Offset, 2, SDescs) of
- false ->
- fix_sdescs(Rest, SDescs);
- {?SDESC, Offset, {ExnHandler, FrameSize, StkArity, Roots}} ->
- FixedRoots = list_to_tuple([Ri - Arity || Ri <- tuple_to_list(Roots)]),
- FixedSDesc =
- {?SDESC, Offset, {ExnHandler, FrameSize - Arity, StkArity, FixedRoots}},
- fix_sdescs(Rest, [FixedSDesc | lists:keydelete(Offset, 2, SDescs)])
- end.
-
-%%------------------------------------------------------------------------------
-%% Miscellaneous functions
-%%------------------------------------------------------------------------------
-
-%% @doc A function that opens a file as binary. The function takes as argument
-%% the name of the file and returns an Erlang binary.
--spec open_object_file(string()) -> binary().
-open_object_file(ObjFile) ->
- case file:read_file(ObjFile) of
- {ok, Binary} ->
- Binary;
- {error, Reason} ->
- exit({?MODULE, open_file, Reason})
- end.
-
-remove_temp_folder(Dir, Options) ->
- case proplists:get_bool(llvm_save_temps, Options) of
- true -> ok;
- false -> spawn(fun () -> "" = os:cmd("rm -rf " ++ Dir) end), ok
- end.
-
-unique_id(FunName, Arity) ->
- integer_to_list(erlang:phash2({FunName, Arity, erlang:unique_integer()})).
-
-unique_folder(FunName, Arity, Options) ->
- DirName = "llvm_" ++ unique_id(FunName, Arity) ++ "/",
- Dir =
- case proplists:get_bool(llvm_save_temps, Options) of
- true -> %% Store folder in current directory
- DirName;
- false -> %% Temporarily store folder in tempfs or tmp dir
- tmpfs_folder() ++ DirName
- end,
- %% Make sure it does not exist
- case dir_exists(Dir) of
- true -> %% Dir already exists! Generate again.
- unique_folder(FunName, Arity, Options);
- false ->
- Dir
- end.
-
-tmpfs_folder() ->
- case os:type() of
- {unix, linux} ->
- "/dev/shm/";
- {unix, _} -> %% Fallback to tmp dir. e.g. FreeBSD
- "/tmp/"
- end.
-
-%% @doc Function that checks that a given Filename is an existing Directory
-%% Name (from http://rosettacode.org/wiki/Ensure_that_a_file_exists#Erlang)
-dir_exists(Filename) ->
- {Flag, Info} = file:read_file_info(Filename),
- (Flag =:= ok) andalso (element(3, Info) =:= directory).
diff --git a/lib/hipe/llvm/hipe_llvm_merge.erl b/lib/hipe/llvm/hipe_llvm_merge.erl
deleted file mode 100644
index 58d862fbb2..0000000000
--- a/lib/hipe/llvm/hipe_llvm_merge.erl
+++ /dev/null
@@ -1,114 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
--module(hipe_llvm_merge).
-
--export([finalize/3]).
-
--include("hipe_llvm_arch.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../rtl/hipe_literals.hrl").
--include("../main/hipe.hrl").
-
-finalize(CompiledCode, Closures, Exports) ->
- CompiledCode1 = [CodePack || {_, CodePack} <- CompiledCode],
- Code = [{MFA, [], ConstTab}
- || {MFA, _, _ , ConstTab, _, _} <- CompiledCode1],
- {ConstAlign, ConstSize, ConstMap, RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code),
- %% Compute total code size separately as a sanity check for alignment
- CodeSize = compute_code_size(CompiledCode1, 0),
- %% io:format("Code Size (pre-computed): ~w~n", [CodeSize]),
- {CodeBinary, ExportMap} = merge_mfas(CompiledCode1, 0, <<>>, []),
- %% io:format("Code Size (post-computed): ~w~n", [byte_size(CodeBinary)]),
- ?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)),
- AccRefs = merge_refs(CompiledCode1, ConstMap, 0, []),
- %% Bring CompiledCode to a combine_label_maps-acceptable form.
- LabelMap = combine_label_maps(CompiledCode1, 0, gb_trees:empty()),
- SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap, Closures, Exports),
- SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
- ConstAlign, ConstSize,
- SC, % ConstMap
- DataRelocs, % LabelMap
- SSE, % ExportMap
- CodeSize, CodeBinary, SlimRefs,
- 0,[] % ColdCodeSize, SlimColdRefs
- ]).
-
-%% Copied from hipe_x86_assemble.erl
-nr_pad_bytes(Address) ->
- (4 - (Address rem 4)) rem 4. % XXX: 16 or 32 instead?
-
-align_entry(Address) ->
- Address + nr_pad_bytes(Address).
-
-compute_code_size([{_MFA, _BinaryCode, CodeSize, _, _, _}|Code], Size) ->
- compute_code_size(Code, align_entry(Size+CodeSize));
-compute_code_size([], Size) -> Size.
-
-combine_label_maps([{MFA, _, CodeSize, _, _, LabelMap}|Code], Address, CLM) ->
- NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
- combine_label_maps(Code, align_entry(Address+CodeSize), NewCLM);
-combine_label_maps([], _Address, CLM) -> CLM.
-
-merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
- NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
- merge_label_map(Rest, MFA, Address, NewCLM);
-merge_label_map([], _MFA, _Address, CLM) -> CLM.
-
-%% @doc Merge the MFAs' binary code to one continuous binary and compute the
-%% size of this binary. At the same time create an exportmap in a form
-%% of {Address, M, F, A}.
-%% XXX: Is alignment correct/optimal for X86/AMD64?
-merge_mfas([{{M,F,A}, CodeBinary, CodeSize, _, _, _}|Code],
- Address, AccCode, AccExportMap) ->
- ?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)),
- {Address1, Code1} =
- case nr_pad_bytes(Address + CodeSize) of
- 0 -> %% Retains alignment:
- {Address + CodeSize, CodeBinary};
- NrPadBytes -> %% Needs padding!
- Padding = list_to_binary(lists:duplicate(NrPadBytes, 0)),
- {Address + CodeSize + NrPadBytes, % =:= align_entry(Address+CodeSize)
- <<CodeBinary/binary, Padding/binary>>}
- end,
- ?VERBOSE_ASSERT(Address1 =:=
- align_entry(Address + CodeSize)), %XXX: Should address be aligned?
- AccCode1 = <<AccCode/binary, Code1/binary>>,
- merge_mfas(Code, Address1, AccCode1, [{Address, M, F, A}|AccExportMap]);
-merge_mfas([], _Address, AccCode, AccExportMap) ->
- {AccCode, AccExportMap}.
-
-%% @doc Merge the references of relocatable symbols in the binary code. The
-%% offsets must be updated because of the merging of the code binaries!
-merge_refs([], _ConstMap, _Addr, AccRefs) -> AccRefs;
-merge_refs([{MFA, _, CodeSize, _, Refs, _}|Rest], ConstMap, Address, AccRefs) ->
- %% Important!: The hipe_pack_constants:pack_constants/2 function assignes
- %% unique numbers to constants (ConstNo). This numbers are used from now on,
- %% instead of labels that were used before. So, in order to be compatible, we
- %% must change all the constant labels in the Refs to the corresponding
- %% ConstNo, that can be found in the ConstMap (#pcm_entry{}).
- UpdatedRefs = [update_ref(label_to_constno(Ref, MFA, ConstMap), Address)
- || Ref <- Refs],
- merge_refs(Rest, ConstMap, align_entry(Address+CodeSize),
- UpdatedRefs++AccRefs).
-
-label_to_constno({Type, Offset, {constant, Label}}, MFA, ConstMap) ->
- ConstNo = hipe_pack_constants:find_const({MFA, Label}, ConstMap),
- {Type, Offset, {constant, ConstNo}};
-label_to_constno(Other, _MFA, _ConstMap) ->
- Other.
-
-%% @doc Update offset to a reference. In case of stack descriptors we must check
-%% if there exists an exception handler, because it must also be updated.
-update_ref({?SDESC, Offset, SDesc}, CodeAddr) ->
- NewRefAddr = Offset+CodeAddr,
- case SDesc of
- {[], _, _, _} -> % No handler; only update offset
- {?SDESC, NewRefAddr, SDesc};
- {ExnHandler, FrameSize, StackArity, Roots} -> % Update exception handler
- {?SDESC, NewRefAddr, {ExnHandler+CodeAddr, FrameSize, StackArity, Roots}}
- end;
-update_ref({Type, Offset, Term}, CodeAddr) ->
- {Type, Offset+CodeAddr, Term}.
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
deleted file mode 100644
index 934717efc1..0000000000
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ /dev/null
@@ -1,1638 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
--module(hipe_rtl_to_llvm).
--author("Chris Stavrakakis, Yiannis Tsiouris").
-
--export([translate/2]). % the main function of this module
--export([fix_mfa_name/1]). % a help function used in hipe_llvm_main
-
--include("../rtl/hipe_rtl.hrl").
--include("../rtl/hipe_literals.hrl").
--include("hipe_llvm_arch.hrl").
-
--define(BITS_IN_WORD, (?bytes_to_bits(hipe_rtl_arch:word_size()))).
--define(BITS_IN_BYTE, (?bytes_to_bits(1))).
--define(BRANCH_META_TAKEN, "0").
--define(BRANCH_META_NOT_TAKEN, "1").
--define(FIRST_FREE_META_NO, 2).
--define(HIPE_LITERALS_META, "hipe.literals").
-
-%%------------------------------------------------------------------------------
-%% @doc Main function for translating an RTL function to LLVM Assembly. Takes as
-%% input the RTL code and the variable indexes of possible garbage
-%% collection roots and returns the corresponing LLVM, a dictionary with
-%% all the relocations in the code and a hipe_consttab() with informaton
-%% about data.
-%%------------------------------------------------------------------------------
-translate(RTL, Roots) ->
- Fun = hipe_rtl:rtl_fun(RTL),
- Params = hipe_rtl:rtl_params(RTL),
- Data = hipe_rtl:rtl_data(RTL),
- Code = hipe_rtl:rtl_code(RTL),
- %% Init unique symbol generator and initialize the label counter to the last
- %% RTL label.
- hipe_gensym:init(llvm),
- {_, MaxLabel} = hipe_rtl:rtl_label_range(RTL),
- put({llvm,label_count}, MaxLabel + 1),
- %% Put first label of RTL code in process dictionary
- find_code_entry_label(Code),
- %% Initialize relocations symbol dictionary
- Relocs = dict:new(),
- %% Print RTL to file
- %% {ok, File_rtl} = file:open("rtl_" ++integer_to_list(random:uniform(2000))
- %% ++ ".rtl", [write]),
- %% hipe_rtl:pp(File_rtl, RTL),
- %% file:close(File_rtl),
-
- %% Pass on RTL code to handle exception handling and identify labels of Fail
- %% Blocks
- {Code1, FailLabels} = fix_code(Code),
- %% Allocate stack slots for each virtual register and declare gc roots
- AllocaStackCode = alloca_stack(Code1, Params, Roots),
- %% Translate Code
- {LLVM_Code1, Relocs1, NewData} =
- translate_instr_list(Code1, [], Relocs, Data),
- %% Create LLVM code to declare relocation symbols as external symbols along
- %% with local variables in order to use them as just any other variable
- {FinalRelocs, ExternalDecl0, LocalVars} =
- handle_relocations(Relocs1, Data, Fun),
- ExternalDecl = add_literals_metadata(ExternalDecl0),
- %% Pass on LLVM code in order to create Fail blocks and a landingpad
- %% instruction to each one
- LLVM_Code2 = add_landingpads(LLVM_Code1, FailLabels),
- %% Create LLVM Code for the compiled function
- LLVM_Code3 = create_function_definition(Fun, Params, LLVM_Code2,
- AllocaStackCode ++ LocalVars),
- %% Final Code = CompiledFunction + External Declarations
- FinalLLVMCode = [LLVM_Code3 | ExternalDecl],
- {FinalLLVMCode, FinalRelocs, NewData}.
-
-find_code_entry_label([]) ->
- exit({?MODULE, find_code_entry_label, "Empty code"});
-find_code_entry_label([I|_]) ->
- case hipe_rtl:is_label(I) of
- true ->
- put(first_label, hipe_rtl:label_name(I));
- false ->
- exit({?MODULE, find_code_entry_label, "First instruction is not a label"})
- end.
-
-%% @doc Create a stack slot for each virtual register. The stack slots
-%% that correspond to possible garbage collection roots must be
-%% marked as such.
-alloca_stack(Code, Params, Roots) ->
- %% Find all assigned virtual registers
- Destinations = collect_destinations(Code),
- %% Declare virtual registers, and declare garbage collection roots
- do_alloca_stack(Destinations++Params, Params, Roots).
-
-collect_destinations(Code) ->
- lists:usort(lists:flatmap(fun insn_dst/1, Code)).
-
-do_alloca_stack(Destinations, Params, Roots) ->
- do_alloca_stack(Destinations, Params, Roots, []).
-
-do_alloca_stack([], _, _, Acc) ->
- Acc;
-do_alloca_stack([D|Ds], Params, Roots, Acc) ->
- {Name, _I} = trans_dst(D),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
- case hipe_rtl:is_var(D) of
- true ->
- Num = hipe_rtl:var_index(D),
- I1 = hipe_llvm:mk_alloca(Name, WordTy, [], []),
- case lists:member(Num, Roots) of
- true -> %% Variable is a possible Root
- T1 = mk_temp(),
- BYTE_TYPE_PP = hipe_llvm:mk_pointer(ByteTyPtr),
- I2 =
- hipe_llvm:mk_conversion(T1, bitcast, WordTyPtr, Name, BYTE_TYPE_PP),
- GcRootArgs = [{BYTE_TYPE_PP, T1}, {ByteTyPtr, "@gc_metadata"}],
- I3 = hipe_llvm:mk_call([], false, [], [], hipe_llvm:mk_void(),
- "@llvm.gcroot", GcRootArgs, []),
- I4 = case lists:member(D, Params) of
- false ->
- hipe_llvm:mk_store(WordTy, "-5", WordTyPtr, Name,
- [], [], false);
- true -> []
- end,
- do_alloca_stack(Ds, Params, Roots, [I1, I2, I3, I4 | Acc]);
- false ->
- do_alloca_stack(Ds, Params, Roots, [I1|Acc])
- end;
- false ->
- case hipe_rtl:is_reg(D) andalso isPrecoloured(D) of
- true -> %% Precoloured registers are mapped to "special" stack slots
- do_alloca_stack(Ds, Params, Roots, Acc);
- false ->
- I1 = case hipe_rtl:is_fpreg(D) of
- true ->
- FloatTy = hipe_llvm:mk_double(),
- hipe_llvm:mk_alloca(Name, FloatTy, [], []);
- false -> hipe_llvm:mk_alloca(Name, WordTy, [], [])
- end,
- do_alloca_stack(Ds, Params, Roots, [I1|Acc])
- end
- end.
-
-%%------------------------------------------------------------------------------
-%% @doc Translation of the linearized RTL Code. Each RTL instruction is
-%% translated to a list of LLVM Assembly instructions. The relocation
-%% dictionary is updated when needed.
-%%------------------------------------------------------------------------------
-translate_instr_list([], Acc, Relocs, Data) ->
- {lists:reverse(lists:flatten(Acc)), Relocs, Data};
-translate_instr_list([I | Is], Acc, Relocs, Data) ->
- {Acc1, NewRelocs, NewData} = translate_instr(I, Relocs, Data),
- translate_instr_list(Is, [Acc1 | Acc], NewRelocs, NewData).
-
-translate_instr(I, Relocs, Data) ->
- case I of
- #alu{} ->
- {I2, Relocs2} = trans_alu(I, Relocs),
- {I2, Relocs2, Data};
- #alub{} ->
- {I2, Relocs2} = trans_alub(I, Relocs),
- {I2, Relocs2, Data};
- #call{} ->
- {I2, Relocs2} =
- case hipe_rtl:call_fun(I) of
- %% In AMD64 this instruction does nothing!
- %% TODO: chech use of fwait in other architectures!
- fwait ->
- {[], Relocs};
- _ ->
- trans_call(I, Relocs)
- end,
- {I2, Relocs2, Data};
- #comment{} ->
- {I2, Relocs2} = trans_comment(I, Relocs),
- {I2, Relocs2, Data};
- #enter{} ->
- {I2, Relocs2} = trans_enter(I, Relocs),
- {I2, Relocs2, Data};
- #fconv{} ->
- {I2, Relocs2} = trans_fconv(I, Relocs),
- {I2, Relocs2, Data};
- #fload{} ->
- {I2, Relocs2} = trans_fload(I, Relocs),
- {I2, Relocs2, Data};
- #fmove{} ->
- {I2, Relocs2} = trans_fmove(I, Relocs),
- {I2, Relocs2, Data};
- #fp{} ->
- {I2, Relocs2} = trans_fp(I, Relocs),
- {I2, Relocs2, Data};
- #fp_unop{} ->
- {I2, Relocs2} = trans_fp_unop(I, Relocs),
- {I2, Relocs2, Data};
- #fstore{} ->
- {I2, Relocs2} = trans_fstore(I, Relocs),
- {I2, Relocs2, Data};
- #goto{} ->
- {I2, Relocs2} = trans_goto(I, Relocs),
- {I2, Relocs2, Data};
- #label{} ->
- {I2, Relocs2} = trans_label(I, Relocs),
- {I2, Relocs2, Data};
- #load{} ->
- {I2, Relocs2} = trans_load(I, Relocs),
- {I2, Relocs2, Data};
- #load_address{} ->
- {I2, Relocs2} = trans_load_address(I, Relocs),
- {I2, Relocs2, Data};
- #load_atom{} ->
- {I2, Relocs2} = trans_load_atom(I, Relocs),
- {I2, Relocs2, Data};
- #move{} ->
- {I2, Relocs2} = trans_move(I, Relocs),
- {I2, Relocs2, Data};
- #return{} ->
- {I2, Relocs2} = trans_return(I, Relocs),
- {I2, Relocs2, Data};
- #store{} ->
- {I2, Relocs2} = trans_store(I, Relocs),
- {I2, Relocs2, Data};
- #switch{} -> %% Only switch instruction updates Data
- {I2, Relocs2, NewData} = trans_switch(I, Relocs, Data),
- {I2, Relocs2, NewData};
- Other ->
- exit({?MODULE, translate_instr, {"Unknown RTL instruction", Other}})
- end.
-
-%%
-%% alu
-%%
-trans_alu(I, Relocs) ->
- RtlDst = hipe_rtl:alu_dst(I),
- TmpDst = mk_temp(),
- {Src1, I1} = trans_src(hipe_rtl:alu_src1(I)),
- {Src2, I2} = trans_src(hipe_rtl:alu_src2(I)),
- Op = trans_op(hipe_rtl:alu_op(I)),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []),
- I4 = store_stack_dst(TmpDst, RtlDst),
- {[I4, I3, I2, I1], Relocs}.
-
-%%
-%% alub
-%%
-trans_alub(I, Relocs) ->
- case hipe_rtl:alub_cond(I) of
- Op when Op =:= overflow orelse Op =:= not_overflow ->
- trans_alub_overflow(I, signed, Relocs);
- ltu -> %% ltu means unsigned overflow
- trans_alub_overflow(I, unsigned, Relocs);
- _ ->
- trans_alub_no_overflow(I, Relocs)
- end.
-
-trans_alub_overflow(I, Sign, Relocs) ->
- {Src1, I1} = trans_src(hipe_rtl:alub_src1(I)),
- {Src2, I2} = trans_src(hipe_rtl:alub_src2(I)),
- TmpDst = mk_temp(),
- Name = trans_alub_op(I, Sign),
- NewRelocs = relocs_store(Name, {call, remote, {llvm, Name, 2}}, Relocs),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- ReturnType = hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]),
- T1 = mk_temp(),
- I3 = hipe_llvm:mk_call(T1, false, [], [], ReturnType, "@" ++ Name,
- [{WordTy, Src1}, {WordTy, Src2}], []),
- %% T1{0}: result of the operation
- I4 = hipe_llvm:mk_extractvalue(TmpDst, ReturnType, T1 , "0", []),
- I5 = case hipe_rtl:alub_has_dst(I) of
- false -> [];
- true -> store_stack_dst(TmpDst, hipe_rtl:alub_dst(I))
- end,
- T2 = mk_temp(),
- %% T1{1}: Boolean variable indicating overflow
- I6 = hipe_llvm:mk_extractvalue(T2, ReturnType, T1, "1", []),
- {TrueLabel, FalseLabel, MetaData} =
- case hipe_rtl:alub_cond(I) of
- Op when Op =:= overflow orelse Op =:= ltu ->
- {mk_jump_label(hipe_rtl:alub_true_label(I)),
- mk_jump_label(hipe_rtl:alub_false_label(I)),
- branch_metadata(hipe_rtl:alub_pred(I))};
- not_overflow ->
- {mk_jump_label(hipe_rtl:alub_false_label(I)),
- mk_jump_label(hipe_rtl:alub_true_label(I)),
- branch_metadata(1 - hipe_rtl:alub_pred(I))}
- end,
- I7 = hipe_llvm:mk_br_cond(T2, TrueLabel, FalseLabel, MetaData),
- {[I7, I6, I5, I4, I3, I2, I1], NewRelocs}.
-
-trans_alub_op(I, Sign) ->
- Name =
- case Sign of
- signed ->
- case hipe_rtl:alub_op(I) of
- add -> "llvm.sadd.with.overflow.";
- mul -> "llvm.smul.with.overflow.";
- sub -> "llvm.ssub.with.overflow.";
- Op -> exit({?MODULE, trans_alub_op, {"Unknown alub operator", Op}})
- end;
- unsigned ->
- case hipe_rtl:alub_op(I) of
- add -> "llvm.uadd.with.overflow.";
- mul -> "llvm.umul.with.overflow.";
- sub -> "llvm.usub.with.overflow.";
- Op -> exit({?MODULE, trans_alub_op, {"Unknown alub operator", Op}})
- end
- end,
- Type =
- case hipe_rtl_arch:word_size() of
- 4 -> "i32";
- 8 -> "i64"
- %% Other -> exit({?MODULE, trans_alub_op, {"Unknown type", Other}})
- end,
- Name ++ Type.
-
-trans_alub_no_overflow(I, Relocs) ->
- {Src1, I1} = trans_src(hipe_rtl:alub_src1(I)),
- {Src2, I2} = trans_src(hipe_rtl:alub_src2(I)),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- %% alu
- {CmpLhs, CmpRhs, I5, Cond} =
- case {hipe_rtl:alub_has_dst(I), hipe_rtl:alub_op(I)} of
- {false, 'sub'} ->
- Cond0 = trans_branch_rel_op(hipe_rtl:alub_cond(I)),
- {Src1, Src2, [], Cond0};
- {HasDst, AlubOp} ->
- TmpDst = mk_temp(),
- Op = trans_op(AlubOp),
- I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []),
- I4 = case HasDst of
- false -> [];
- true -> store_stack_dst(TmpDst, hipe_rtl:alub_dst(I))
- end,
- Cond0 = trans_alub_rel_op(hipe_rtl:alub_cond(I)),
- {TmpDst, "0", [I4, I3], Cond0}
- end,
- %% icmp
- T3 = mk_temp(),
- I6 = hipe_llvm:mk_icmp(T3, Cond, WordTy, CmpLhs, CmpRhs),
- %% br
- Metadata = branch_metadata(hipe_rtl:alub_pred(I)),
- True_label = mk_jump_label(hipe_rtl:alub_true_label(I)),
- False_label = mk_jump_label(hipe_rtl:alub_false_label(I)),
- I7 = hipe_llvm:mk_br_cond(T3, True_label, False_label, Metadata),
- {[I7, I6, I5, I2, I1], Relocs}.
-
-branch_metadata(X) when X =:= 0.5 -> [];
-branch_metadata(X) when X > 0.5 -> ?BRANCH_META_TAKEN;
-branch_metadata(X) when X < 0.5 -> ?BRANCH_META_NOT_TAKEN.
-
-%%
-%% call
-%%
-trans_call(I, Relocs) ->
- RtlCallArgList= hipe_rtl:call_arglist(I),
- RtlCallName = hipe_rtl:call_fun(I),
- {I0, Relocs1} = expose_closure(RtlCallName, RtlCallArgList, Relocs),
- TmpDst = mk_temp(),
- {CallArgs, I1} = trans_call_args(RtlCallArgList),
- FixedRegs = fixed_registers(),
- {LoadedFixedRegs, I2} = load_fixed_regs(FixedRegs),
- FinalArgs = fix_reg_args(LoadedFixedRegs) ++ CallArgs,
- {Name, I3, Relocs2} =
- trans_call_name(RtlCallName, hipe_rtl:call_type(I), Relocs1, CallArgs, FinalArgs),
- T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- I4 =
- case hipe_rtl:call_fail(I) of
- %% Normal Call
- [] ->
- hipe_llvm:mk_call(T1, false, "cc 11", [], FunRetTy, Name, FinalArgs,
- []);
- %% Call With Exception
- FailLabelNum ->
- TrueLabel = "L" ++ integer_to_list(hipe_rtl:call_normal(I)),
- FailLabel = "%FL" ++ integer_to_list(FailLabelNum),
- II1 =
- hipe_llvm:mk_invoke(T1, "cc 11", [], FunRetTy, Name, FinalArgs, [],
- "%" ++ TrueLabel, FailLabel),
- II2 = hipe_llvm:mk_label(TrueLabel),
- [II2, II1]
- end,
- I5 = store_fixed_regs(FixedRegs, T1),
- I6 =
- case hipe_rtl:call_dstlist(I) of
- [] -> []; %% No return value
- [Destination] ->
- II3 =
- hipe_llvm:mk_extractvalue(TmpDst, FunRetTy, T1,
- integer_to_list(?NR_PINNED_REGS), []),
- II4 = store_stack_dst(TmpDst, Destination),
- [II4, II3]
- end,
- I7 =
- case hipe_rtl:call_continuation(I) of
- [] -> []; %% No continuation
- CC ->
- {II5, _} = trans_goto(hipe_rtl:mk_goto(CC), Relocs2),
- II5
- end,
- {[I7, I6, I5, I4, I3, I2, I1, I0], Relocs2}.
-
-%% In case of call to a register (closure call) with more than ?NR_ARG_REGS
-%% arguments we must track the offset this call in the code, in order to
-%% to correct the stack descriptor. So, we insert a new Label and add this label
-%% to the "table_closures"
-%% --------------------------------|--------------------------------------------
-%% Old Code | New Code
-%% --------------------------------|--------------------------------------------
-%% | br %ClosureLabel
-%% call %reg(Args) | ClosureLabel:
-%% | call %reg(Args)
-expose_closure(CallName, CallArgs, Relocs) ->
- CallArgsNr = length(CallArgs),
- case hipe_rtl:is_reg(CallName) andalso CallArgsNr > ?NR_ARG_REGS of
- true ->
- LabelNum = hipe_gensym:new_label(llvm),
- ClosureLabel = hipe_llvm:mk_label(mk_label(LabelNum)),
- JumpIns = hipe_llvm:mk_br(mk_jump_label(LabelNum)),
- Relocs1 =
- relocs_store({CallName, LabelNum},
- {closure_label, LabelNum, CallArgsNr - ?NR_ARG_REGS},
- Relocs),
- {[ClosureLabel, JumpIns], Relocs1};
- false ->
- {[], Relocs}
- end.
-
-trans_call_name(RtlCallName, RtlCallType, Relocs, CallArgs, FinalArgs) ->
- case RtlCallName of
- PrimOp when is_atom(PrimOp) ->
- LlvmName = trans_prim_op(PrimOp),
- Relocs1 =
- relocs_store(LlvmName, {call, not_remote, {bif, PrimOp, length(CallArgs)}}, Relocs),
- {"@" ++ LlvmName, [], Relocs1};
- {M, F, A} when is_atom(M), is_atom(F), is_integer(A) ->
- LlvmName = trans_mfa_name({M, F, A}, RtlCallType),
- Relocs1 =
- relocs_store(LlvmName, {call, RtlCallType, {M, F, length(CallArgs)}}, Relocs),
- {"@" ++ LlvmName, [], Relocs1};
- Reg ->
- case hipe_rtl:is_reg(Reg) of
- true ->
- %% In case of a closure call, the register holding the address
- %% of the closure must be converted to function type in
- %% order to make the call
- TT1 = mk_temp(),
- {RegName, II1} = trans_src(Reg),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- II2 =
- hipe_llvm:mk_conversion(TT1, inttoptr, WordTy, RegName, WordTyPtr),
- TT2 = mk_temp(),
- ArgsTypeList = lists:duplicate(length(FinalArgs), WordTy),
- FunRetTy =
- hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- FunType = hipe_llvm:mk_fun(FunRetTy, ArgsTypeList),
- FunTypeP = hipe_llvm:mk_pointer(FunType),
- II3 = hipe_llvm:mk_conversion(TT2, bitcast, WordTyPtr, TT1, FunTypeP),
- {TT2, [II3, II2, II1], Relocs};
- false ->
- exit({?MODULE, trans_call, {"Unimplemented call to", RtlCallName}})
- end
- end.
-
-%%
-trans_call_args(ArgList) ->
- {Args, I} = lists:unzip(trans_args(ArgList)),
- %% Reverse arguments that are passed to stack to match with the Erlang
- %% calling convention. (Propably not needed in prim calls.)
- ReversedArgs =
- case erlang:length(Args) > ?NR_ARG_REGS of
- false ->
- Args;
- true ->
- {ArgsInRegs, ArgsInStack} = lists:split(?NR_ARG_REGS, Args),
- ArgsInRegs ++ lists:reverse(ArgsInStack)
- end,
- %% Reverse I, because some of the arguments may go out of scope and
- %% should be killed(store -5). When two or more arguments are they
- %% same, then order matters!
- {ReversedArgs, lists:reverse(I)}.
-
-%%
-%% trans_comment
-%%
-trans_comment(I, Relocs) ->
- I1 = hipe_llvm:mk_comment(hipe_rtl:comment_text(I)),
- {I1, Relocs}.
-
-%%
-%% enter
-%%
-trans_enter(I, Relocs) ->
- {CallArgs, I0} = trans_call_args(hipe_rtl:enter_arglist(I)),
- FixedRegs = fixed_registers(),
- {LoadedFixedRegs, I1} = load_fixed_regs(FixedRegs),
- FinalArgs = fix_reg_args(LoadedFixedRegs) ++ CallArgs,
- {Name, I2, NewRelocs} =
- trans_call_name(hipe_rtl:enter_fun(I), hipe_rtl:enter_type(I), Relocs, CallArgs, FinalArgs),
- T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- I3 = hipe_llvm:mk_call(T1, true, "cc 11", [], FunRetTy, Name, FinalArgs, []),
- I4 = hipe_llvm:mk_ret([{FunRetTy, T1}]),
- {[I4, I3, I2, I1, I0], NewRelocs}.
-
-%%
-%% fconv
-%%
-trans_fconv(I, Relocs) ->
- %% XXX: Can a fconv destination be a precoloured reg?
- RtlDst = hipe_rtl:fconv_dst(I),
- TmpDst = mk_temp(),
- {Src, I1} = trans_float_src(hipe_rtl:fconv_src(I)),
- FloatTy = hipe_llvm:mk_double(),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- I2 = hipe_llvm:mk_conversion(TmpDst, sitofp, WordTy, Src, FloatTy),
- I3 = store_float_stack(TmpDst, RtlDst),
- {[I3, I2, I1], Relocs}.
-
-
-%% TODO: fload, fstore, fmove, and fp are almost the same with load, store, move
-%% and alu. Maybe we should join them.
-
-%%
-%% fload
-%%
-trans_fload(I, Relocs) ->
- RtlDst = hipe_rtl:fload_dst(I),
- RtlSrc = hipe_rtl:fload_src(I),
- _Offset = hipe_rtl:fload_offset(I),
- TmpDst = mk_temp(),
- {Src, I1} = trans_float_src(RtlSrc),
- {Offset, I2} = trans_float_src(_Offset),
- T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()),
- I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
- T2 = mk_temp(),
- I4 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, FloatTyPtr),
- I5 = hipe_llvm:mk_load(TmpDst, FloatTyPtr, T2, [], [], false),
- I6 = store_float_stack(TmpDst, RtlDst),
- {[I6, I5, I4, I3, I2, I1], Relocs}.
-
-%%
-%% fmove
-%%
-trans_fmove(I, Relocs) ->
- RtlDst = hipe_rtl:fmove_dst(I),
- RtlSrc = hipe_rtl:fmove_src(I),
- {Src, I1} = trans_float_src(RtlSrc),
- I2 = store_float_stack(Src, RtlDst),
- {[I2, I1], Relocs}.
-
-%%
-%% fp
-%%
-trans_fp(I, Relocs) ->
- %% XXX: Just copied trans_alu...think again..
- RtlDst = hipe_rtl:fp_dst(I),
- RtlSrc1 = hipe_rtl:fp_src1(I),
- RtlSrc2 = hipe_rtl:fp_src2(I),
- %% Destination cannot be a precoloured register
- FloatTy = hipe_llvm:mk_double(),
- FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
- TmpDst = mk_temp(),
- {Src1, I1} = trans_float_src(RtlSrc1),
- {Src2, I2} = trans_float_src(RtlSrc2),
- Op = trans_fp_op(hipe_rtl:fp_op(I)),
- I3 = hipe_llvm:mk_operation(TmpDst, Op, FloatTy, Src1, Src2, []),
- I4 = store_float_stack(TmpDst, RtlDst),
- %% Synchronization for floating point exceptions
- I5 = hipe_llvm:mk_store(FloatTy, TmpDst, FloatTyPtr, "%exception_sync", [],
- [], true),
- T1 = mk_temp(),
- I6 = hipe_llvm:mk_load(T1, FloatTyPtr, "%exception_sync", [], [], true),
- {[I6, I5, I4, I3, I2, I1], Relocs}.
-
-%%
-%% fp_unop
-%%
-trans_fp_unop(I, Relocs) ->
- RtlDst = hipe_rtl:fp_unop_dst(I),
- RtlSrc = hipe_rtl:fp_unop_src(I),
- %% Destination cannot be a precoloured register
- TmpDst = mk_temp(),
- {Src, I1} = trans_float_src(RtlSrc),
- Op = trans_fp_op(hipe_rtl:fp_unop_op(I)),
- FloatTy = hipe_llvm:mk_double(),
- I2 = hipe_llvm:mk_operation(TmpDst, Op, FloatTy, "0.0", Src, []),
- I3 = store_float_stack(TmpDst, RtlDst),
- {[I3, I2, I1], Relocs}.
-%% TODO: Fix fp_unop in a way like the following. You must change trans_dest,
-%% in order to call float_to_list in a case of float constant. Maybe the type
-%% check is expensive...
-%% Dst = hipe_rtl:fp_unop_dst(I),
-%% Src = hipe_rtl:fp_unop_src(I),
-%% Op = hipe_rtl:fp_unop_op(I),
-%% Zero = hipe_rtl:mk_imm(0.0),
-%% I1 = hipe_rtl:mk_fp(Dst, Zero, Op, Src),
-%% trans_fp(I, Relocs1).
-
-%%
-%% fstore
-%%
-trans_fstore(I, Relocs) ->
- Base = hipe_rtl:fstore_base(I),
- case isPrecoloured(Base) of
- true ->
- trans_fstore_reg(I, Relocs);
- false ->
- exit({?MODULE, trans_fstore ,{"Not implemented yet", false}})
- end.
-
-trans_fstore_reg(I, Relocs) ->
- {Base, I0} = trans_reg(hipe_rtl:fstore_base(I), dst),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- FloatTy = hipe_llvm:mk_double(),
- FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
- T1 = mk_temp(),
- I1 = hipe_llvm:mk_load(T1, WordTyPtr, Base, [], [], false),
- {Offset, I2} = trans_src(hipe_rtl:fstore_offset(I)),
- T2 = mk_temp(),
- I3 = hipe_llvm:mk_operation(T2, add, WordTy, T1, Offset, []),
- T3 = mk_temp(),
- I4 = hipe_llvm:mk_conversion(T3, inttoptr, WordTy, T2, FloatTyPtr),
- {Value, I5} = trans_src(hipe_rtl:fstore_src(I)),
- I6 = hipe_llvm:mk_store(FloatTy, Value, FloatTyPtr, T3, [], [], false),
- {[I6, I5, I4, I3, I2, I1, I0], Relocs}.
-
-%%
-%% goto
-%%
-trans_goto(I, Relocs) ->
- I1 = hipe_llvm:mk_br(mk_jump_label(hipe_rtl:goto_label(I))),
- {I1, Relocs}.
-
-%%
-%% label
-%%
-trans_label(I, Relocs) ->
- Label = mk_label(hipe_rtl:label_name(I)),
- I1 = hipe_llvm:mk_label(Label),
- {I1, Relocs}.
-
-%%
-%% load
-%%
-trans_load(I, Relocs) ->
- RtlDst = hipe_rtl:load_dst(I),
- TmpDst = mk_temp(),
- %% XXX: Why translate them independently? ------------------------
- {Src, I1} = trans_src(hipe_rtl:load_src(I)),
- {Offset, I2} = trans_src(hipe_rtl:load_offset(I)),
- T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
- %%----------------------------------------------------------------
- I4 = case hipe_rtl:load_size(I) of
- word ->
- T2 = mk_temp(),
- II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, WordTyPtr),
- II2 = hipe_llvm:mk_load(TmpDst, WordTyPtr, T2, [], [], false),
- [II2, II1];
- Size ->
- LoadType = llvm_type_from_size(Size),
- LoadTypeP = hipe_llvm:mk_pointer(LoadType),
- T2 = mk_temp(),
- II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, LoadTypeP),
- T3 = mk_temp(),
- LoadTypePointer = hipe_llvm:mk_pointer(LoadType),
- II2 = hipe_llvm:mk_load(T3, LoadTypePointer, T2, [], [], false),
- Conversion =
- case hipe_rtl:load_sign(I) of
- signed -> sext;
- unsigned -> zext
- end,
- II3 =
- hipe_llvm:mk_conversion(TmpDst, Conversion, LoadType, T3, WordTy),
- [II3, II2, II1]
- end,
- I5 = store_stack_dst(TmpDst, RtlDst),
- {[I5, I4, I3, I2, I1], Relocs}.
-
-%%
-%% load_address
-%%
-trans_load_address(I, Relocs) ->
- RtlDst = hipe_rtl:load_address_dst(I),
- RtlAddr = hipe_rtl:load_address_addr(I),
- {Addr, NewRelocs} =
- case hipe_rtl:load_address_type(I) of
- constant ->
- {"%DL" ++ integer_to_list(RtlAddr) ++ "_var", Relocs};
- closure ->
- {{_, ClosureName, _}, _, _} = RtlAddr,
- FixedClosureName = fix_closure_name(ClosureName),
- Relocs1 = relocs_store(FixedClosureName, {closure, RtlAddr}, Relocs),
- {"%" ++ FixedClosureName ++ "_var", Relocs1};
- type ->
- exit({?MODULE, trans_load_address,
- {"Type not implemented in load_address", RtlAddr}})
- end,
- I1 = store_stack_dst(Addr, RtlDst),
- {[I1], NewRelocs}.
-
-%%
-%% load_atom
-%%
-trans_load_atom(I, Relocs) ->
- RtlDst = hipe_rtl:load_atom_dst(I),
- RtlAtom = hipe_rtl:load_atom_atom(I),
- AtomName = "atom_" ++ make_llvm_id(atom_to_list(RtlAtom)),
- AtomVar = "%" ++ AtomName ++ "_var",
- NewRelocs = relocs_store(AtomName, {atom, RtlAtom}, Relocs),
- I1 = store_stack_dst(AtomVar, RtlDst),
- {[I1], NewRelocs}.
-
-%%
-%% move
-%%
-trans_move(I, Relocs) ->
- RtlDst = hipe_rtl:move_dst(I),
- RtlSrc = hipe_rtl:move_src(I),
- {Src, I1} = trans_src(RtlSrc),
- I2 = store_stack_dst(Src, RtlDst),
- {[I2, I1], Relocs}.
-
-%%
-%% return
-%%
-trans_return(I, Relocs) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- {VarRet, I1} =
- case hipe_rtl:return_varlist(I) of
- [] ->
- {[], []};
- [A] ->
- {Name, II1} = trans_src(A),
- {[{WordTy, Name}], II1}
- end,
- FixedRegs = fixed_registers(),
- {LoadedFixedRegs, I2} = load_fixed_regs(FixedRegs),
- FixedRet = [{WordTy, X} || X <- LoadedFixedRegs],
- Ret = FixedRet ++ VarRet,
- {RetTypes, _RetNames} = lists:unzip(Ret),
- Type = hipe_llvm:mk_struct(RetTypes),
- {RetStruct, I3} = mk_return_struct(Ret, Type),
- I4 = hipe_llvm:mk_ret([{Type, RetStruct}]),
- {[I4, I3, I2, I1], Relocs}.
-
-%% @doc Create a structure to hold the return value and the precoloured
-%% registers.
-mk_return_struct(RetValues, Type) ->
- mk_return_struct(RetValues, Type, [], "undef", 0).
-
-mk_return_struct([], _, Acc, StructName, _) ->
- {StructName, Acc};
-mk_return_struct([{ElemType, ElemName}|Rest], Type, Acc, StructName, Index) ->
- T1 = mk_temp(),
- I1 = hipe_llvm:mk_insertvalue(T1, Type, StructName, ElemType, ElemName,
- integer_to_list(Index), []),
- mk_return_struct(Rest, Type, [I1 | Acc], T1, Index+1).
-
-%%
-%% store
-%%
-trans_store(I, Relocs) ->
- {Base, I1} = trans_src(hipe_rtl:store_base(I)),
- {Offset, I2} = trans_src(hipe_rtl:store_offset(I)),
- {Value, I3} = trans_src(hipe_rtl:store_src(I)),
- T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- I4 = hipe_llvm:mk_operation(T1, add, WordTy, Base, Offset, []),
- I5 =
- case hipe_rtl:store_size(I) of
- word ->
- T2 = mk_temp(),
- II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, WordTyPtr),
- II2 = hipe_llvm:mk_store(WordTy, Value, WordTyPtr, T2, [], [],
- false),
- [II2, II1];
- Size ->
- %% XXX: Is always trunc correct ?
- LoadType = llvm_type_from_size(Size),
- LoadTypePointer = hipe_llvm:mk_pointer(LoadType),
- T2 = mk_temp(),
- II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, LoadTypePointer),
- T3 = mk_temp(),
- II2 = hipe_llvm:mk_conversion(T3, 'trunc', WordTy, Value, LoadType),
- II3 = hipe_llvm:mk_store(LoadType, T3, LoadTypePointer, T2, [], [], false),
- [II3, II2, II1]
- end,
- {[I5, I4, I3, I2, I1], Relocs}.
-
-%%
-%% switch
-%%
-trans_switch(I, Relocs, Data) ->
- RtlSrc = hipe_rtl:switch_src(I),
- {Src, I1} = trans_src(RtlSrc),
- Labels = hipe_rtl:switch_labels(I),
- JumpLabels = [mk_jump_label(L) || L <- Labels],
- SortOrder = hipe_rtl:switch_sort_order(I),
- NrLabels = length(Labels),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
- TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
- TableTypeP = hipe_llvm:mk_pointer(TableType),
- TypedJumpLabels = [{hipe_llvm:mk_label_type(), X} || X <- JumpLabels],
- T1 = mk_temp(),
- {Src2, []} = trans_dst(RtlSrc),
- TableName = "table_" ++ tl(Src2),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- I2 = hipe_llvm:mk_getelementptr(T1, TableTypeP, "@"++TableName,
- [{WordTy, "0"}, {WordTy, Src}], false),
- T2 = mk_temp(),
- BYTE_TYPE_PP = hipe_llvm:mk_pointer(ByteTyPtr),
- I3 = hipe_llvm:mk_load(T2, BYTE_TYPE_PP, T1, [], [], false),
- I4 = hipe_llvm:mk_indirectbr(ByteTyPtr, T2, TypedJumpLabels),
- LMap = [{label, L} || L <- Labels],
- %% Update data with the info for the jump table
- {NewData, JTabLab} =
- case hipe_rtl:switch_sort_order(I) of
- [] ->
- hipe_consttab:insert_block(Data, word, LMap);
- SortOrder ->
- hipe_consttab:insert_sorted_block(Data, word, LMap, SortOrder)
- end,
- Relocs2 = relocs_store(TableName, {switch, {TableType, Labels, NrLabels,
- SortOrder}, JTabLab}, Relocs),
- {[I4, I3, I2, I1], Relocs2, NewData}.
-
-%% @doc Pass on RTL code in order to fix invoke and closure calls.
-fix_code(Code) ->
- fix_calls(Code).
-
-%% @doc Fix invoke calls and closure calls with more than ?NR_ARG_REGS
-%% arguments.
-fix_calls(Code) ->
- fix_calls(Code, [], []).
-
-fix_calls([], Acc, FailLabels) ->
- {lists:reverse(Acc), FailLabels};
-fix_calls([I | Is], Acc, FailLabels) ->
- case hipe_rtl:is_call(I) of
- true ->
- {NewCall, NewFailLabels} =
- case hipe_rtl:call_fail(I) of
- [] ->
- {I, FailLabels};
- FailLabel ->
- fix_invoke_call(I, FailLabel, FailLabels)
- end,
- fix_calls(Is, [NewCall|Acc], NewFailLabels);
- false ->
- fix_calls(Is, [I|Acc], FailLabels)
- end.
-
-%% @doc When a call has a fail continuation label it must be extended with a
-%% normal continuation label to go with the LLVM's invoke instruction.
-%% FailLabels is the list of labels of all fail blocks, which are needed to
-%% be declared as landing pads. Furtermore, we must add to fail labels a
-%% call to hipe_bifs:llvm_fix_pinned_regs/0 in order to avoid reloading old
-%% values of pinned registers. This may happen because the result of an
-%% invoke instruction is not available at fail-labels, and, thus, we cannot
-%% get the correct values of pinned registers. Finally, the stack needs to
-%% be re-adjusted when there are stack arguments.
-fix_invoke_call(I, FailLabel, FailLabels) ->
- NewLabel = hipe_gensym:new_label(llvm),
- NewCall1 = hipe_rtl:call_normal_update(I, NewLabel),
- SpAdj = find_sp_adj(hipe_rtl:call_arglist(I)),
- case lists:keyfind(FailLabel, 1, FailLabels) of
- %% Same fail label with same Stack Pointer adjustment
- {FailLabel, NewFailLabel, SpAdj} ->
- NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel),
- {NewCall2, FailLabels};
- %% Same fail label but with different Stack Pointer adjustment
- {_, _, _} ->
- NewFailLabel = hipe_gensym:new_label(llvm),
- NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel),
- {NewCall2, [{FailLabel, NewFailLabel, SpAdj} | FailLabels]};
- %% New Fail label
- false ->
- NewFailLabel = hipe_gensym:new_label(llvm),
- NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel),
- {NewCall2, [{FailLabel, NewFailLabel, SpAdj} | FailLabels]}
- end.
-
-find_sp_adj(ArgList) ->
- NrArgs = length(ArgList),
- case NrArgs > ?NR_ARG_REGS of
- true ->
- (NrArgs - ?NR_ARG_REGS) * hipe_rtl_arch:word_size();
- false ->
- 0
- end.
-
-%% @doc Add landingpad instruction in Fail Blocks.
-add_landingpads(LLVM_Code, FailLabels) ->
- FailLabels2 = [convert_label(T) || T <- FailLabels],
- add_landingpads(LLVM_Code, FailLabels2, []).
-
-add_landingpads([], _, Acc) ->
- lists:reverse(Acc);
-add_landingpads([I | Is], FailLabels, Acc) ->
- case hipe_llvm:is_label(I) of
- true ->
- Label = hipe_llvm:label_label(I),
- Ins = create_fail_blocks(Label, FailLabels),
- add_landingpads(Is, FailLabels, [I | Ins] ++ Acc);
- false ->
- add_landingpads(Is, FailLabels, [I | Acc])
- end.
-
-convert_label({X,Y,Z}) ->
- {"L" ++ integer_to_list(X), "FL" ++ integer_to_list(Y), Z}.
-
-%% @doc Create a fail block wich.
-create_fail_blocks(_, []) -> [];
-create_fail_blocks(Label, FailLabels) ->
- create_fail_blocks(Label, FailLabels, []).
-
-create_fail_blocks(Label, FailLabels, Acc) ->
- case lists:keytake(Label, 1, FailLabels) of
- false ->
- Acc;
- {value, {Label, FailLabel, SpAdj}, RestFailLabels} ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- I1 = hipe_llvm:mk_label(FailLabel),
- LP = hipe_llvm:mk_landingpad(),
- I2 =
- case SpAdj > 0 of
- true ->
- StackPointer = ?ARCH_REGISTERS:reg_name(?ARCH_REGISTERS:sp()),
- hipe_llvm:mk_adj_stack(integer_to_list(SpAdj), StackPointer,
- WordTy);
- false -> []
- end,
- T1 = mk_temp(),
- FixedRegs = fixed_registers(),
- FunRetTy =
- hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- I3 = hipe_llvm:mk_call(T1, false, "cc 11", [], FunRetTy,
- "@hipe_bifs.llvm_fix_pinned_regs.0", [], []),
- I4 = store_fixed_regs(FixedRegs, T1),
- I5 = hipe_llvm:mk_br("%" ++ Label),
- Ins = lists:flatten([I5, I4, I3, I2, LP,I1]),
- create_fail_blocks(Label, RestFailLabels, Ins ++ Acc)
- end.
-
-%%------------------------------------------------------------------------------
-%% Miscellaneous Functions
-%%------------------------------------------------------------------------------
-
-%% @doc Convert RTL argument list to LLVM argument list.
-trans_args(ArgList) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- MakeArg =
- fun(A) ->
- {Name, I1} = trans_src(A),
- {{WordTy, Name}, I1}
- end,
- [MakeArg(A) || A <- ArgList].
-
-%% @doc Convert a list of Precoloured registers to LLVM argument list.
-fix_reg_args(ArgList) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- [{WordTy, A} || A <- ArgList].
-
-%% @doc Load Precoloured registers.
-load_fixed_regs(RegList) ->
- Names = [mk_temp_reg(R) || R <- RegList],
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- Fun1 =
- fun (X, Y) ->
- hipe_llvm:mk_load(X, WordTyPtr, "%" ++ Y ++ "_reg_var", [], [], false)
- end,
- Ins = lists:zipwith(Fun1, Names, RegList),
- {Names, Ins}.
-
-%% @doc Store Precoloured registers.
-store_fixed_regs(RegList, Name) ->
- Names = [mk_temp_reg(R) || R <- RegList],
- Indexes = lists:seq(0, erlang:length(RegList) - 1),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- Fun1 =
- fun(X,Y) ->
- hipe_llvm:mk_extractvalue(X, FunRetTy, Name, integer_to_list(Y), [])
- end,
- I1 = lists:zipwith(Fun1, Names, Indexes),
- Fun2 =
- fun (X, Y) ->
- hipe_llvm:mk_store(WordTy, X, WordTyPtr, "%" ++ Y ++ "_reg_var", [], [],
- false)
- end,
- I2 = lists:zipwith(Fun2, Names, RegList),
- [I2, I1].
-
-%%------------------------------------------------------------------------------
-%% Translation of Names
-%%------------------------------------------------------------------------------
-
-%% @doc Fix F in MFA tuple to acceptable LLVM identifier (case of closure).
--spec fix_mfa_name(mfa()) -> mfa().
-fix_mfa_name({Mod_Name, Closure_Name, Arity}) ->
- Fun_Name = list_to_atom(fix_closure_name(Closure_Name)),
- {Mod_Name, Fun_Name, Arity}.
-
-%% @doc Make an acceptable LLVM identifier for a closure name.
-fix_closure_name(ClosureName) ->
- make_llvm_id(atom_to_list(ClosureName)).
-
-%% @doc Create an acceptable LLVM identifier.
-make_llvm_id(Name) ->
- case Name of
- "" -> "Empty";
- Other -> lists:flatten([llvm_id(C) || C <- Other])
- end.
-
-llvm_id(C) when C=:=46; C>47 andalso C<58; C>64 andalso C<91; C=:=95;
- C>96 andalso C<123 ->
- C;
-llvm_id(C) ->
- io_lib:format("_~2.16.0B_",[C]).
-
-%% @doc Create an acceptable LLVM identifier for an MFA.
-trans_mfa_name({M,F,A}, Linkage) ->
- N0 = atom_to_list(M) ++ "." ++ atom_to_list(F) ++ "." ++ integer_to_list(A),
- N = case Linkage of
- not_remote -> N0;
- remote -> "rem." ++ N0
- end,
- make_llvm_id(N).
-
-%%------------------------------------------------------------------------------
-%% Creation of Labels and Temporaries
-%%------------------------------------------------------------------------------
-mk_label(N) ->
- "L" ++ integer_to_list(N).
-
-mk_jump_label(N) ->
- "%L" ++ integer_to_list(N).
-
-mk_temp() ->
- "%t" ++ integer_to_list(hipe_gensym:new_var(llvm)).
-
-mk_temp_reg(Name) ->
- "%" ++ Name ++ integer_to_list(hipe_gensym:new_var(llvm)).
-
-%%----------------------------------------------------------------------------
-%% Translation of Operands
-%%----------------------------------------------------------------------------
-
-store_stack_dst(TempDst, Dst) ->
- {Dst2, II1} = trans_dst(Dst),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- II2 = hipe_llvm:mk_store(WordTy, TempDst, WordTyPtr, Dst2, [], [], false),
- [II2, II1].
-
-store_float_stack(TempDst, Dst) ->
- {Dst2, II1} = trans_dst(Dst),
- FloatTy = hipe_llvm:mk_double(),
- FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
- II2 = hipe_llvm:mk_store(FloatTy, TempDst, FloatTyPtr, Dst2, [], [], false),
- [II2, II1].
-
-trans_float_src(Src) ->
- case hipe_rtl:is_const_label(Src) of
- true ->
- Name = "@DL" ++ integer_to_list(hipe_rtl:const_label_label(Src)),
- T1 = mk_temp(),
- %% XXX: Hardcoded offset
- ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
- ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
- I1 = hipe_llvm:mk_getelementptr(T1, ByteTyPtr, Name,
- [{ByteTy, integer_to_list(?FLOAT_OFFSET)}], true),
- T2 = mk_temp(),
- FloatTy = hipe_llvm:mk_double(),
- FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
- I2 = hipe_llvm:mk_conversion(T2, bitcast, ByteTyPtr, T1, FloatTyPtr),
- T3 = mk_temp(),
- I3 = hipe_llvm:mk_load(T3, FloatTyPtr, T2, [], [], false),
- {T3, [I3, I2, I1]};
- false ->
- trans_src(Src)
- end.
-
-trans_src(A) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- case hipe_rtl:is_imm(A) of
- true ->
- Value = integer_to_list(hipe_rtl:imm_value(A)),
- {Value, []};
- false ->
- case hipe_rtl:is_reg(A) of
- true ->
- case isPrecoloured(A) of
- true -> trans_reg(A, src);
- false ->
- {Name, []} = trans_reg(A, src),
- T1 = mk_temp(),
- I1 = hipe_llvm:mk_load(T1, WordTyPtr, Name, [], [], false),
- {T1, [I1]}
- end;
- false ->
- case hipe_rtl:is_var(A) of
- true ->
- RootName = "%vr" ++ integer_to_list(hipe_rtl:var_index(A)),
- T1 = mk_temp(),
- I1 = hipe_llvm:mk_load(T1, WordTyPtr, RootName, [], [], false),
- I2 =
- case hipe_rtl:var_liveness(A) of
- live ->
- [];
- dead ->
- NilValue = hipe_tagscheme:mk_nil(),
- hipe_llvm:mk_store(WordTy, integer_to_list(NilValue), WordTyPtr, RootName,
- [], [], false)
- end,
- {T1, [I2, I1]};
- false ->
- case hipe_rtl:is_fpreg(A) of
- true ->
- {Name, []} = trans_dst(A),
- T1 = mk_temp(),
- FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()),
- I1 = hipe_llvm:mk_load(T1, FloatTyPtr, Name, [], [], false),
- {T1, [I1]};
- false -> trans_dst(A)
- end
- end
- end
- end.
-
-trans_dst(A) ->
- case hipe_rtl:is_reg(A) of
- true ->
- trans_reg(A, dst);
- false ->
- Name = case hipe_rtl:is_var(A) of
- true ->
- "%vr" ++ integer_to_list(hipe_rtl:var_index(A));
- false ->
- case hipe_rtl:is_fpreg(A) of
- true -> "%fr" ++ integer_to_list(hipe_rtl:fpreg_index(A));
- false ->
- case hipe_rtl:is_const_label(A) of
- true ->
- "%DL" ++ integer_to_list(hipe_rtl:const_label_label(A)) ++ "_var";
- false ->
- error(badarg, [A])
- end
- end
- end,
- {Name, []}
- end.
-
-%% @doc Translate a register. If it is precoloured it must be mapped to the
-%% correct stack slot that holds the precoloured register value.
-trans_reg(Arg, Position) ->
- Index = hipe_rtl:reg_index(Arg),
- case isPrecoloured(Arg) of
- true ->
- Name = map_precoloured_reg(Index),
- case Position of
- src -> fix_reg_src(Name);
- dst -> fix_reg_dst(Name)
- end;
- false ->
- {hipe_rtl_arch:reg_name(Index), []}
- end.
-
-map_precoloured_reg(Index) ->
- case hipe_rtl_arch:reg_name(Index) of
- "%r15" -> "%hp_reg_var";
- "%rbp" -> "%p_reg_var";
- "%esi" -> "%hp_reg_var";
- "%ebp" -> "%p_reg_var";
- "%fcalls" ->
- {"%p_reg_var", ?ARCH_REGISTERS:proc_offset(?ARCH_REGISTERS:fcalls())};
- "%hplim" ->
- {"%p_reg_var", ?ARCH_REGISTERS:proc_offset(?ARCH_REGISTERS:heap_limit())};
- _ ->
- exit({?MODULE, map_precoloured_reg, {"Register not mapped yet", Index}})
- end.
-
-%% @doc Load precoloured dst register.
-fix_reg_dst(Register) ->
- case Register of
- {Name, Offset} -> %% Case of %fcalls, %hplim
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- pointer_from_reg(Name, WordTy, Offset);
- Name -> %% Case of %p and %hp
- {Name, []}
- end.
-
-%% @doc Load precoloured src register.
-fix_reg_src(Register) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- case Register of
- {Name, Offset} -> %% Case of %fcalls, %hplim
- {T1, I1} = pointer_from_reg(Name, WordTy, Offset),
- T2 = mk_temp(),
- I2 = hipe_llvm:mk_load(T2, WordTyPtr, T1, [], [] , false),
- {T2, [I2, I1]};
- Name -> %% Case of %p and %hp
- T1 = mk_temp(),
- {T1, hipe_llvm:mk_load(T1, WordTyPtr, Name, [], [], false)}
- end.
-
-%% @doc Load %fcalls and %hplim.
-pointer_from_reg(RegName, Type, Offset) ->
- PointerType = hipe_llvm:mk_pointer(Type),
- T1 = mk_temp(),
- I1 = hipe_llvm:mk_load(T1, PointerType, RegName, [], [] ,false),
- T2 = mk_temp(),
- I2 = hipe_llvm:mk_conversion(T2, inttoptr, Type, T1, PointerType),
- T3 = mk_temp(),
- %% XXX: Offsets should be a power of 2.
- I3 = hipe_llvm:mk_getelementptr(T3, PointerType, T2,
- [{Type, integer_to_list(Offset div hipe_rtl_arch:word_size())}], true),
- {T3, [I3, I2, I1]}.
-
-isPrecoloured(X) ->
- hipe_rtl_arch:is_precoloured(X).
-
-%%------------------------------------------------------------------------------
-%% Translation of operators
-%%------------------------------------------------------------------------------
-
-trans_op(Op) ->
- case Op of
- add -> add;
- sub -> sub;
- 'or' -> 'or';
- 'and' -> 'and';
- 'xor' -> 'xor';
- sll -> shl;
- srl -> lshr;
- sra -> ashr;
- mul -> mul;
- 'fdiv' -> fdiv;
- 'sdiv' -> sdiv;
- 'srem' -> srem;
- Other -> exit({?MODULE, trans_op, {"Unknown RTL operator", Other}})
- end.
-
-trans_branch_rel_op(Op) ->
- case Op of
- gtu -> ugt;
- geu -> uge;
- ltu -> ult;
- leu -> ule;
- _ -> trans_alub_rel_op(Op)
- end.
-
-trans_alub_rel_op(Op) ->
- case Op of
- eq -> eq;
- ne -> ne;
- gt -> sgt;
- ge -> sge;
- lt -> slt;
- le -> sle
- end.
-
-trans_prim_op(Op) ->
- case Op of
- '+' -> "bif_add";
- '-' -> "bif_sub";
- '*' -> "bif_mul";
- 'div' -> "bif_div";
- '/' -> "bif_div";
- Other -> atom_to_list(Other)
- end.
-
-trans_fp_op(Op) ->
- case Op of
- fadd -> fadd;
- fsub -> fsub;
- fdiv -> fdiv;
- fmul -> fmul;
- fchs -> fsub;
- Other -> exit({?MODULE, trans_fp_op, {"Unknown RTL float operator",Other}})
- end.
-
-%% Misc.
-insn_dst(I) ->
- case I of
- #alu{} ->
- [hipe_rtl:alu_dst(I)];
- #alub{} ->
- case hipe_rtl:alub_has_dst(I) of
- true -> [hipe_rtl:alub_dst(I)];
- false -> []
- end;
- #call{} ->
- case hipe_rtl:call_dstlist(I) of
- [] -> [];
- [Dst] -> [Dst]
- end;
- #load{} ->
- [hipe_rtl:load_dst(I)];
- #load_address{} ->
- [hipe_rtl:load_address_dst(I)];
- #load_atom{} ->
- [hipe_rtl:load_atom_dst(I)];
- #move{} ->
- [hipe_rtl:move_dst(I)];
- #phi{} ->
- [hipe_rtl:phi_dst(I)];
- #fconv{} ->
- [hipe_rtl:fconv_dst(I)];
- #fload{} ->
- [hipe_rtl:fload_dst(I)];
- #fmove{} ->
- [hipe_rtl:fmove_dst(I)];
- #fp{} ->
- [hipe_rtl:fp_dst(I)];
- #fp_unop{} ->
- [hipe_rtl:fp_unop_dst(I)];
- _ ->
- []
- end.
-
-llvm_type_from_size(Size) ->
- case Size of
- byte -> hipe_llvm:mk_int(?BITS_IN_BYTE);
- int16 -> hipe_llvm:mk_int(16);
- int32 -> hipe_llvm:mk_int(32);
- word -> hipe_llvm:mk_int(?BITS_IN_WORD)
- end.
-
-%% @doc Create definition for the compiled function. The parameters that are
-%% passed to the stack must be reversed to match with the CC. Also
-%% precoloured registers that are passed as arguments must be stored to
-%% the corresonding stack slots.
-create_function_definition(Fun, Params, Code, LocalVars) ->
- FunctionName = trans_mfa_name(Fun, not_remote),
- FixedRegs = fixed_registers(),
- %% Reverse parameters to match with the Erlang calling convention
- ReversedParams =
- case erlang:length(Params) > ?NR_ARG_REGS of
- false ->
- Params;
- true ->
- {ParamsInRegs, ParamsInStack} = lists:split(?NR_ARG_REGS, Params),
- ParamsInRegs ++ lists:reverse(ParamsInStack)
- end,
- Args = header_regs(FixedRegs) ++ header_params(ReversedParams),
- EntryLabel = hipe_llvm:mk_label("Entry"),
- FloatTy = hipe_llvm:mk_double(),
- ExceptionSync = hipe_llvm:mk_alloca("%exception_sync", FloatTy, [], []),
- I2 = load_regs(FixedRegs),
- I3 = hipe_llvm:mk_br(mk_jump_label(get(first_label))),
- StoredParams = store_params(Params),
- EntryBlock =
- lists:flatten([EntryLabel, ExceptionSync, I2, LocalVars, StoredParams, I3]),
- Final_Code = EntryBlock ++ Code,
- FunctionOptions = [nounwind, noredzone, 'gc "erlang"'],
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- hipe_llvm:mk_fun_def([], [], "cc 11", [], FunRetTy, FunctionName, Args,
- FunctionOptions, [], Final_Code).
-
-header_params(Params) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- [{WordTy, "%v" ++ integer_to_list(hipe_rtl:var_index(P))} || P <- Params].
-
-store_params(Params) ->
- Fun1 =
- fun(X) ->
- Index = hipe_rtl:var_index(X),
- {Name, _} = trans_dst(X),
- ParamName = "%v" ++ integer_to_list(Index),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- hipe_llvm:mk_store(WordTy, ParamName, WordTyPtr, Name, [], [], false)
- end,
- lists:map(Fun1, Params).
-
-fixed_registers() ->
- case get(hipe_target_arch) of
- x86 ->
- ["hp", "p"];
- amd64 ->
- ["hp", "p"];
- Other ->
- exit({?MODULE, map_registers, {"Unknown architecture", Other}})
- end.
-
-header_regs(Registers) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- [{WordTy, "%" ++ X ++ "_in"} || X <- Registers].
-
-load_regs(Registers) ->
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- Fun1 =
- fun(X) ->
- I1 = hipe_llvm:mk_alloca("%" ++ X ++ "_reg_var", WordTy, [], []),
- I2 = hipe_llvm:mk_store(WordTy, "%" ++ X ++ "_in", WordTyPtr,
- "%" ++ X ++ "_reg_var", [], [], false),
- [I1, I2]
- end,
- lists:map(Fun1, Registers).
-
-%%------------------------------------------------------------------------------
-%% Relocation-specific Stuff
-%%------------------------------------------------------------------------------
-
-relocs_store(Key, Value, Relocs) ->
- dict:store(Key, Value, Relocs).
-
-relocs_to_list(Relocs) ->
- dict:to_list(Relocs).
-
-%% @doc This function is responsible for the actions needed to handle
-%% relocations:
-%% 1) Updates relocations with constants and switch jump tables.
-%% 2) Creates LLVM code to declare relocations as external
-%% functions/constants.
-%% 3) Creates LLVM code in order to create local variables for the external
-%% constants/labels.
-handle_relocations(Relocs, Data, Fun) ->
- RelocsList = relocs_to_list(Relocs),
- %% Separate Relocations according to their type
- {CallList, AtomList, ClosureList, ClosureLabels, SwitchList} =
- seperate_relocs(RelocsList),
- %% Create code to declare atoms
- AtomDecl = [declare_atom(A) || A <- AtomList],
- %% Create code to create local name for atoms
- AtomLoad = [load_atom(A) || A <- AtomList],
- %% Create code to declare closures
- ClosureDecl = [declare_closure(C) || C <- ClosureList],
- %% Create code to create local name for closures
- ClosureLoad = [load_closure(C) || C <- ClosureList],
- %% Find function calls
- IsExternalCall = fun (X) -> is_external_call(X, Fun) end,
- ExternalCallList = lists:filter(IsExternalCall, CallList),
- %% Create code to declare external function
- FunDecl = fixed_fun_decl() ++ [call_to_decl(C) || C <- ExternalCallList],
- %% Extract constant labels from Constant Map (remove duplicates)
- ConstLabels = hipe_consttab:labels(Data),
- %% Create code to declare constants
- ConstDecl = [declare_constant(C) || C <- ConstLabels],
- %% Create code to create local name for constants
- ConstLoad = [load_constant(C) || C <- ConstLabels],
- %% Create code to create jump tables
- SwitchDecl = declare_switches(SwitchList, Fun),
- %% Create code to create a table with the labels of all closure calls
- {ClosureLabelDecl, Relocs1} =
- declare_closure_labels(ClosureLabels, Relocs, Fun),
- %% Enter constants to relocations
- Relocs2 = lists:foldl(fun const_to_dict/2, Relocs1, ConstLabels),
- %% Temporary Store inc_stack and llvm_fix_pinned_regs to Dictionary
- %% TODO: Remove this
- Relocs3 = dict:store("inc_stack_0", {call, not_remote, {bif, inc_stack_0, 0}}, Relocs2),
- Relocs4 = dict:store("hipe_bifs.llvm_fix_pinned_regs.0",
- {call, remote, {hipe_bifs, llvm_fix_pinned_regs, 0}}, Relocs3),
- BranchMetaData = [
- hipe_llvm:mk_meta(?BRANCH_META_TAKEN, ["branch_weights", 99, 1])
- , hipe_llvm:mk_meta(?BRANCH_META_NOT_TAKEN, ["branch_weights", 1, 99])
- ],
- ExternalDeclarations = AtomDecl ++ ClosureDecl ++ ConstDecl ++ FunDecl ++
- ClosureLabelDecl ++ SwitchDecl ++ BranchMetaData,
- LocalVariables = AtomLoad ++ ClosureLoad ++ ConstLoad,
- {Relocs4, ExternalDeclarations, LocalVariables}.
-
-%% @doc Separate relocations according to their type.
-seperate_relocs(Relocs) ->
- seperate_relocs(Relocs, [], [], [], [], []).
-
-seperate_relocs([], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) ->
- {CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc};
-seperate_relocs([R|Rs], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) ->
- case R of
- {_, {call, _, _}} ->
- seperate_relocs(Rs, [R | CallAcc], AtomAcc, ClosureAcc, LabelAcc,
- JmpTableAcc);
-
- {_, {atom, _}} ->
- seperate_relocs(Rs, CallAcc, [R | AtomAcc], ClosureAcc, LabelAcc,
- JmpTableAcc);
- {_, {closure, _}} ->
- seperate_relocs(Rs, CallAcc, AtomAcc, [R | ClosureAcc], LabelAcc,
- JmpTableAcc);
- {_, {switch, _, _}} ->
- seperate_relocs(Rs, CallAcc, AtomAcc, ClosureAcc, LabelAcc,
- [R | JmpTableAcc]);
- {_, {closure_label, _, _}} ->
- seperate_relocs(Rs, CallAcc, AtomAcc, ClosureAcc, [R | LabelAcc],
- JmpTableAcc)
- end.
-
-%% @doc External declaration of an atom.
-declare_atom({AtomName, _}) ->
- %% The type has to be byte, or a backend might assume the constant is aligned
- %% and incorrectly optimise away type tests
- ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
- hipe_llvm:mk_const_decl("@" ++ AtomName, "external constant", ByteTy, "").
-
-%% @doc Creation of local variable for an atom.
-load_atom({AtomName, _}) ->
- Dst = "%" ++ AtomName ++ "_var",
- Name = "@" ++ AtomName,
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
- hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
-
-%% @doc External declaration of a closure.
-declare_closure({ClosureName, _})->
- ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
- hipe_llvm:mk_const_decl("@" ++ ClosureName, "external constant", ByteTy, "").
-
-%% @doc Creation of local variable for a closure.
-load_closure({ClosureName, _})->
- Dst = "%" ++ ClosureName ++ "_var",
- Name = "@" ++ ClosureName,
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
- hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
-
-%% @doc Declaration of a local variable for a switch jump table.
-declare_switches(JumpTableList, Fun) ->
- FunName = trans_mfa_name(Fun, not_remote),
- [declare_switch_table(X, FunName) || X <- JumpTableList].
-
-declare_switch_table({Name, {switch, {TableType, Labels, _, _}, _}}, FunName) ->
- LabelList = [mk_jump_label(L) || L <- Labels],
- Fun1 = fun(X) -> "i8* blockaddress(@" ++ FunName ++ ", " ++ X ++ ")" end,
- List2 = lists:map(Fun1, LabelList),
- List3 = lists:flatten(lists:join(",\n", List2)),
- List4 = "[\n" ++ List3 ++ "\n]\n",
- hipe_llvm:mk_const_decl("@" ++ Name, "constant", TableType, List4).
-
-%% @doc Declaration of a variable for a table with the labels of all closure
-%% calls in the code.
-declare_closure_labels([], Relocs, _Fun) ->
- {[], Relocs};
-declare_closure_labels(ClosureLabels, Relocs, Fun) ->
- FunName = trans_mfa_name(Fun, not_remote),
- {LabelList, ArityList} =
- lists:unzip([{mk_jump_label(Label), A} ||
- {_, {closure_label, Label, A}} <- ClosureLabels]),
- Relocs1 = relocs_store("table_closures", {table_closures, ArityList}, Relocs),
- List2 =
- ["i8* blockaddress(@" ++ FunName ++ ", " ++ L ++ ")" || L <- LabelList],
- List3 = lists:flatten(lists:join(",\n", List2)),
- List4 = "[\n" ++ List3 ++ "\n]\n",
- NrLabels = length(LabelList),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
- TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
- ConstDecl =
- hipe_llvm:mk_const_decl("@table_closures", "constant", TableType, List4),
- {[ConstDecl], Relocs1}.
-
-%% @doc A call is treated as non external only in a case of a local recursive
-%% function.
-is_external_call({_, {call, not_remote, MFA}}, MFA) -> false;
-is_external_call(_, _) -> true.
-
-%% @doc External declaration of a function.
-call_to_decl({Name, {call, _, MFA}}) ->
- {M, _F, A} = MFA,
- CConv = "cc 11",
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- {Type, Args} =
- case M of
- llvm ->
- {hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]), [1, 2]};
- %% +precoloured regs
- _ ->
- {FunRetTy, lists:seq(1, A + ?NR_PINNED_REGS)}
- end,
- ArgsTypes = lists:duplicate(length(Args), WordTy),
- hipe_llvm:mk_fun_decl([], [], CConv, [], Type, "@" ++ Name, ArgsTypes, []).
-
-%% @doc These functions are always declared, even if not used.
-fixed_fun_decl() ->
- ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
- ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
- LandPad = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_int(32),
- "@__gcc_personality_v0", [hipe_llvm:mk_int(32), hipe_llvm:mk_int(64),
- ByteTyPtr, ByteTyPtr], []),
- GCROOTDecl = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_void(),
- "@llvm.gcroot", [hipe_llvm:mk_pointer(ByteTyPtr), ByteTyPtr], []),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
- FixPinnedRegs = hipe_llvm:mk_fun_decl([], [], [], [], FunRetTy,
- "@hipe_bifs.llvm_fix_pinned_regs.0", [], []),
- GcMetadata = hipe_llvm:mk_const_decl("@gc_metadata", "external constant",
- ByteTy, ""),
- [LandPad, GCROOTDecl, FixPinnedRegs, GcMetadata].
-
-%% @doc Declare an External Consant. We declare all constants as i8 in order to
-%% be able to calcucate pointers of the form DL+6, with the getelementptr
-%% instruction. Otherwise we have to convert constants form pointers to
-%% values, add the offset and convert them again to pointers.
-declare_constant(Label) ->
- Name = "@DL" ++ integer_to_list(Label),
- ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
- hipe_llvm:mk_const_decl(Name, "external constant", ByteTy, "").
-
-%% @doc Load a constant is achieved by converting a pointer to an integer of
-%% the correct width.
-load_constant(Label) ->
- Dst = "%DL" ++ integer_to_list(Label) ++ "_var",
- Name = "@DL" ++ integer_to_list(Label),
- WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
- hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
-
-%% @doc Store external constants and calls to dictionary.
-const_to_dict(Elem, Dict) ->
- Name = "DL" ++ integer_to_list(Elem),
- dict:store(Name, {'constant', Elem}, Dict).
-
-%% @doc Export the hipe literals that LLVM needs to generate the prologue as
-%% metadata.
-add_literals_metadata(ExternalDecls) ->
- Pairs = [hipe_llvm:mk_meta(integer_to_list(?FIRST_FREE_META_NO),
- ["P_NSP_LIMIT", ?P_NSP_LIMIT])
- ,hipe_llvm:mk_meta(integer_to_list(?FIRST_FREE_META_NO + 1),
- ["X86_LEAF_WORDS", ?X86_LEAF_WORDS])
- ,hipe_llvm:mk_meta(integer_to_list(?FIRST_FREE_META_NO + 2),
- ["AMD64_LEAF_WORDS", ?AMD64_LEAF_WORDS])
- ],
- [hipe_llvm:mk_meta(?HIPE_LITERALS_META, Pairs) |
- Pairs ++ ExternalDecls].
diff --git a/lib/hipe/main/Makefile b/lib/hipe/main/Makefile
deleted file mode 100644
index 8ef31dbb46..0000000000
--- a/lib/hipe/main/Makefile
+++ /dev/null
@@ -1,125 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-ifdef HIPE_ENABLED
-HIPE_MODULES = hipe
-else
-HIPE_MODULES =
-endif
-MODULES = hipe_main $(HIPE_MODULES)
-
-## hipe.hrl is automatically generated from hipe.hrl.src -- see below
-HRL_FILES= hipe.hrl
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-APP_FILE= hipe.app
-APP_SRC= $(APP_FILE).src
-APP_TARGET= $(EBIN)/$(APP_FILE)
-
-APPUP_FILE= hipe.appup
-APPUP_SRC= $(APPUP_FILE).src
-APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +nowarn_shadow_vars +warn_export_vars +warn_missing_spec +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-hipe.hrl: ../vsn.mk hipe.hrl.src
- $(vsn_verbose)sed -e "s;%VSN%;$(HIPE_VSN);" ../../hipe/main/hipe.hrl.src > ../../hipe/main/hipe.hrl
-
-$(EBIN)/hipe.beam: hipe.hrl ../../compiler/src/beam_disasm.hrl
-$(EBIN)/hipe_main.beam: hipe.hrl ../icode/hipe_icode.hrl #../rtl/hipe_rtl.hrl
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES) $(DOC_FILES) $(HRL_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- $(gen_verbose)erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DATA) ../vsn.mk "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELSYSDIR)/main"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/main"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
deleted file mode 100644
index b579de66c0..0000000000
--- a/lib/hipe/main/hipe.app.src
+++ /dev/null
@@ -1,231 +0,0 @@
-%% This is an -*- erlang -*- file.
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-{application, hipe,
- [{description, "HiPE Native Code Compiler, version %VSN%"},
- {vsn, "%VSN%"},
- {modules, [cerl_cconv,
- cerl_hipeify,
- cerl_to_icode,
- elf_format,
- hipe,
- hipe_adj_list,
- hipe_amd64_assemble,
- hipe_amd64_defuse,
- hipe_amd64_encode,
- hipe_amd64_frame,
- hipe_amd64_liveness,
- hipe_amd64_main,
- hipe_amd64_pp,
- hipe_amd64_ra,
- hipe_amd64_ra_finalise,
- hipe_amd64_ra_ls,
- hipe_amd64_ra_naive,
- hipe_amd64_ra_postconditions,
- hipe_amd64_ra_sse2_postconditions,
- hipe_amd64_registers,
- hipe_amd64_specific,
- hipe_amd64_specific_sse2,
- hipe_amd64_specific_x87,
- hipe_amd64_spill_restore,
- hipe_amd64_sse2,
- hipe_amd64_subst,
- hipe_amd64_x87,
- hipe_arm,
- hipe_arm_assemble,
- hipe_arm_cfg,
- hipe_arm_defuse,
- hipe_arm_encode,
- hipe_arm_finalise,
- hipe_arm_frame,
- hipe_arm_liveness_gpr,
- hipe_arm_main,
- hipe_arm_pp,
- hipe_arm_ra,
- hipe_arm_ra_finalise,
- hipe_arm_ra_ls,
- hipe_arm_ra_naive,
- hipe_arm_ra_postconditions,
- hipe_arm_registers,
- hipe_arm_specific,
- hipe_arm_subst,
- hipe_bb,
- hipe_bb_weights,
- hipe_beam_to_icode,
- hipe_coalescing_regalloc,
- hipe_consttab,
- hipe_data_pp,
- hipe_digraph,
- hipe_dominators,
- hipe_dsets,
- hipe_gen_cfg,
- hipe_gensym,
- hipe_graph_coloring_regalloc,
- hipe_icode,
- hipe_icode2rtl,
- hipe_icode_bincomp,
- hipe_icode_callgraph,
- hipe_icode_call_elim,
- hipe_icode_cfg,
- hipe_icode_coordinator,
- hipe_icode_ebb,
- hipe_icode_exceptions,
- hipe_icode_fp,
- hipe_icode_heap_test,
- hipe_icode_inline_bifs,
- hipe_icode_instruction_counter,
- hipe_icode_liveness,
- hipe_icode_mulret,
- hipe_icode_pp,
- hipe_icode_primops,
- hipe_icode_range,
- hipe_icode_ssa,
- hipe_icode_ssa_const_prop,
- hipe_icode_ssa_copy_prop,
- hipe_icode_ssa_struct_reuse,
- hipe_icode_split_arith,
- hipe_icode_type,
- hipe_ig,
- hipe_ig_moves,
- hipe_jit,
- hipe_llvm,
- hipe_llvm_liveness,
- hipe_llvm_main,
- hipe_llvm_merge,
- hipe_ls_regalloc,
- hipe_main,
- hipe_moves,
- hipe_node_sets,
- hipe_optimistic_regalloc,
- hipe_pack_constants,
- hipe_ppc,
- hipe_ppc_assemble,
- hipe_ppc_cfg,
- hipe_ppc_defuse,
- hipe_ppc_encode,
- hipe_ppc_finalise,
- hipe_ppc_frame,
- hipe_ppc_liveness_all,
- hipe_ppc_liveness_fpr,
- hipe_ppc_liveness_gpr,
- hipe_ppc_main,
- hipe_ppc_pp,
- hipe_ppc_ra,
- hipe_ppc_ra_finalise,
- hipe_ppc_ra_ls,
- hipe_ppc_ra_naive,
- hipe_ppc_ra_postconditions,
- hipe_ppc_ra_postconditions_fp,
- hipe_ppc_registers,
- hipe_ppc_specific,
- hipe_ppc_specific_fp,
- hipe_ppc_subst,
- hipe_profile,
- hipe_range_split,
- hipe_reg_worklists,
- hipe_regalloc_loop,
- hipe_regalloc_prepass,
- hipe_restore_reuse,
- hipe_rtl,
- hipe_rtl_arch,
- hipe_rtl_arith_32,
- hipe_rtl_arith_64,
- hipe_rtl_binary,
- hipe_rtl_binary_match,
- hipe_rtl_binary_construct,
- hipe_rtl_cfg,
- hipe_rtl_cleanup_const,
- hipe_rtl_exceptions,
- hipe_rtl_lcm,
- hipe_rtl_liveness,
- hipe_rtl_mk_switch,
- hipe_rtl_primops,
- hipe_rtl_ssa,
- hipe_rtl_ssa_const_prop,
- hipe_rtl_ssa_avail_expr,
- hipe_rtl_ssapre,
- hipe_rtl_symbolic,
- hipe_rtl_to_amd64,
- hipe_rtl_to_arm,
- hipe_rtl_to_llvm,
- hipe_rtl_to_ppc,
- hipe_rtl_to_sparc,
- hipe_rtl_to_x86,
- hipe_rtl_varmap,
- hipe_rtl_verify_gcsafe,
- hipe_segment_trees,
- hipe_sdi,
- hipe_sparc,
- hipe_sparc_assemble,
- hipe_sparc_cfg,
- hipe_sparc_defuse,
- hipe_sparc_encode,
- hipe_sparc_finalise,
- hipe_sparc_frame,
- hipe_sparc_liveness_all,
- hipe_sparc_liveness_fpr,
- hipe_sparc_liveness_gpr,
- hipe_sparc_main,
- hipe_sparc_pp,
- hipe_sparc_ra,
- hipe_sparc_ra_finalise,
- hipe_sparc_ra_ls,
- hipe_sparc_ra_naive,
- hipe_sparc_ra_postconditions,
- hipe_sparc_ra_postconditions_fp,
- hipe_sparc_registers,
- hipe_sparc_specific,
- hipe_sparc_specific_fp,
- hipe_sparc_subst,
- hipe_spillcost,
- hipe_spillmin,
- hipe_spillmin_color,
- hipe_spillmin_scan,
- hipe_tagscheme,
- hipe_temp_map,
- hipe_timing,
- hipe_vectors,
- hipe_x86,
- hipe_x86_assemble,
- hipe_x86_cfg,
- hipe_x86_defuse,
- hipe_x86_encode,
- hipe_x86_frame,
- hipe_x86_liveness,
- hipe_x86_main,
- hipe_x86_postpass,
- hipe_x86_pp,
- hipe_x86_ra,
- hipe_x86_ra_finalise,
- hipe_x86_ra_ls,
- hipe_x86_ra_naive,
- hipe_x86_ra_postconditions,
- hipe_x86_registers,
- hipe_x86_specific,
- hipe_x86_specific_x87,
- hipe_x86_spill_restore,
- hipe_x86_subst,
- hipe_x86_x87]},
- {registered,[]},
- {applications, [kernel,stdlib]},
- {env, []},
- {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-3.4","kernel-5.3",
- "erts-9.3","compiler-5.0","dialyzer-@OTP-16719@"]}]}.
diff --git a/lib/hipe/main/hipe.appup.src b/lib/hipe/main/hipe.appup.src
deleted file mode 100644
index b297ba10db..0000000000
--- a/lib/hipe/main/hipe.appup.src
+++ /dev/null
@@ -1,19 +0,0 @@
-%% -*- erlang -*-
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-{"%VSN%", [], []}.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
deleted file mode 100644
index 86cb51008b..0000000000
--- a/lib/hipe/main/hipe.erl
+++ /dev/null
@@ -1,1638 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ====================================================================
-%% Copyright (c) 1998 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Filename : hipe.erl
-%% Module : hipe
-%% Purpose :
-%% Notes :
-%% History : * 1998-01-28 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%% @doc This is the direct interface to the HiPE compiler.
-%%
-%% <h3>Normal use</h3>
-%%
-%% <p>The normal way to native-compile an Erlang module using HiPE is to
-%% include the atom <code>native</code> in the Erlang compiler options,
-%% as in:
-%%
-%% <pre> 1> c(my_module, [native]).</pre></p>
-%%
-%% <p>Options to the HiPE compiler are then passed as follows:
-%%
-%% <pre> 1> c(my_module, [native,{hipe,Options}]).</pre></p>
-%%
-%% <p>For on-line help in the Erlang shell, call <a
-%% href="#help-0"><code>hipe:help()</code></a>. Details on HiPE compiler
-%% options are given by <a
-%% href="#help_options-0"><code>hipe:help_options()</code></a>.</p>
-%%
-%% <h3>Using the direct interface - for advanced users only</h3>
-%%
-%% To compile a module to native code and automatically load the code
-%% into memory, call <a href="#c-1"><code>hipe:c(Module)</code></a> or <a
-%% href="#c-2"><code>hipe:c(Module, Options)</code></a>. Note that all
-%% options are specific to the HiPE compiler. See the <a
-%% href="#index">function index</a> for other compiler functions.
-%%
-%% <h3>Main Options</h3>
-%%
-%% Options are processed in the order they appear in the list; an
-%% early option will shadow a later one.
-%% <dl>
-%% <dt><code>o0, 'O0', o1, 'O1', o2, 'O2', o3, 'O3'</code></dt>
-%% <dd>Set optimization level (default 2).</dd>
-%%
-%% <dt><code>load</code></dt>
-%% <dd>Automatically load the code into memory after compiling.</dd>
-%%
-%% <dt><code>time</code></dt>
-%% <dd>Reports the compilation times for the different stages
-%% of the compiler. Call <a
-%% href="#help_option-1"><code>hipe:help_option(time)</code></a> for
-%% details.</dd>
-%%
-%% <dt><code>{timeout, Time}</code></dt>
-%% <dd>Sets the time the compiler is allowed to use for the
-%% compilation. <code>Time</code> is time in ms or the atom
-%% <code>infinity</code> (the default).</dd>
-%%
-%% <dt><code>verbose</code></dt>
-%% <dd>Make the HiPE compiler output information about what it is
-%% being done.</dd>
-%% </dl>
-%%
-%% <h3>Advanced Options</h3>
-%%
-%% Note: You can also specify <code>{Option, false}</code> to turn a
-%% particular option off, or <code>{Option, true}</code> to force it on.
-%% Boolean-valued (<code>true</code>/<code>false</code>) options also
-%% have negative-form aliases, e.g. <code>no_load</code> = <code>{load,
-%% false}</code>.
-%%
-%% <p><dl>
-%% <dt><code>debug</code></dt>
-%% <dd>Outputs internal debugging information during
-%% compilation.</dd>
-%%
-%% <dt><code>icode_ssa_copy_prop</code></dt>
-%% <dd>Performs copy propagation on the SSA form on the Icode
-%% level.</dd>
-%%
-%% <dt><code>icode_ssa_const_prop</code></dt>
-%% <dd>Performs sparse conditional constant propagation on the SSA
-%% form on the Icode level.</dd>
-%%
-%% <dt><code>icode_ssa_struct_reuse</code></dt>
-%% <dd>Tries to factor out identical tuple and list constructions
-%% on the Icode level.</dd>
-%%
-%% <dt><code>icode_type</code></dt>
-%% <dd>Simplifies the code by employing type analysis and propagation
-%% on the Icode level.</dd>
-%%
-%% <dt><code>icode_range</code></dt>
-%% <dd>Performs integer range analysis on the Icode level.</dd>
-%%
-%% <dt><code>pp_all</code></dt>
-%% <dd>Equivalent to <code>[pp_beam, pp_icode, pp_rtl,
-%% pp_native]</code>.</dd>
-%%
-%% <dt><code>pp_asm</code></dt>
-%% <dd>Prints the assembly listing with addresses and bytecode.
-%% Currently available for x86 only.</dd>
-%%
-%% <dt><code>pp_beam, {pp_beam, {file, File}}</code></dt>
-%% <dd>Display the input Beam code to stdout or file.</dd>
-%%
-%% <dt><code>pp_icode, {pp_icode, {file, File}},
-%% {pp_icode, {only, Functions}}</code></dt>
-%% <dd>Pretty-print Icode intermediate code to stdout or file.</dd>
-%%
-%% <dt><code>pp_native, {pp_native, {file, File}},
-%% {pp_native, {only, Functions}}</code></dt>
-%% <dd>Pretty-print native code to stdout or file.</dd>
-%%
-%% <dt><code>pp_opt_icode, {pp_opt_icode, {file, File}},
-%% {pp_opt_icode, {only, Functions}}</code></dt>
-%% <dd>Pretty-print optimized Icode to stdout or file.</dd>
-%%
-%% <dt><code>pp_rtl, {pp_rtl, {file, File}},
-%% {pp_rtl, {only, Functions}}</code></dt>
-%% <dd>Pretty-print RTL intermediate code to stdout or file.</dd>
-%%
-%% <dt><code>regalloc</code></dt>
-%% <dd>Select register allocation algorithm. Used as
-%% <code>{regalloc, Method}</code>.
-%%
-%% <p><code>Method</code> is one of the following:
-%% <ul>
-%% <li><code>naive</code>: spills everything (for debugging and
-%% testing only).</li>
-%% <li><code>linear_scan</code>: fast compilation; not so good if
-%% only few registers available.</li>
-%% <li><code>graph_color</code>: slower, but gives better
-%% performance.</li>
-%% <li><code>coalescing</code>: tries hard to use registers; can be
-%% very slow, but typically results in code with best performance.</li>
-%% </ul></p></dd>
-%%
-%% <dt><code>remove_comments</code></dt>
-%% <dd>Remove comments from intermediate code.</dd>
-%%
-%% <dt><code>rtl_ssa_const_prop</code></dt>
-%% <dd>Performs sparse conditional constant propagation on the SSA
-%% form on the RTL level. </dd>
-%%
-%% <dt><code>rtl_lcm</code></dt>
-%% <dd>Lazy Code Motion on RTL.</dd>
-%%
-%% <dt><code>rtl_ssapre</code></dt>
-%% <dd>Lazy Partial Redundancy Elimination on RTL (SSA level).</dd>
-%%
-%% <dt><code>use_indexing</code></dt>
-%% <dd>Use indexing for multiple-choice branch selection.</dd>
-%%
-%% <dt><code>use_callgraph</code></dt>
-%% <dd>Use a static call graph for determining the order in which
-%% the functions of a module should be compiled (in reversed
-%% topological sort order).</dd>
-%% </dl></p>
-%%
-%% <h3>Debugging Options</h3>
-%% (May require that some modules have been
-%% compiled with the <code>DEBUG</code> flag.)
-%% <dl>
-%% <dt><code>rtl_show_translation</code></dt>
-%% <dd>Prints each step in the translation from Icode to RTL</dd>
-%% </dl>
-%%
-%% @end
-%% ====================================================================
-
--module(hipe).
-
--export([c/1,
- c/2,
- f/1,
- f/2,
- compile/1,
- compile/2,
- compile/4,
- compile_core/4,
- file/1,
- file/2,
- get_llvm_version/0,
- erllvm_is_supported/0,
- load/1,
- help/0,
- help_hiper/0,
- help_options/0,
- help_option/1,
- help_debug_options/0,
- version/0,
- erts_checksum/0]).
-
--ifndef(DEBUG).
--define(DEBUG,true).
--endif.
-
--include("hipe.hrl").
--include("../../compiler/src/beam_disasm.hrl").
--include("../rtl/hipe_literals.hrl").
-
-%%-------------------------------------------------------------------
-%% Basic type declaration for exported functions of the 'hipe' module
-%%-------------------------------------------------------------------
-
--type mod() :: module().
--type file_or_bin() :: file:filename() | binary().
--type ret_rtl() :: [_].
--type c_ret() :: {'ok', mod()} | {'error', term()} |
- {'ok', mod(), ret_rtl()}. %% The last for debugging only
--type compile_ret() :: {hipe_architecture(), binary()} | list().
-
-%%-------------------------------------------------------------------
-
--define(COMPILE_DEFAULTS, [o2]).
--define(DEFAULT_TIMEOUT, infinity).
-
-%%-------------------------------------------------------------------
-
-%% @spec load(Module) -> {module, Module} | {error, Reason}
-%% Module = mod()
-%% Reason = term()
-%%
-%% @doc Like load/2, but tries to locate a BEAM file automatically.
-%%
-%% @see load/2
-
--spec load(Module) -> {'module', Module} | {'error', Reason :: term()}
- when Module :: mod().
-
-load(Module) ->
- load(Module, beam_file(Module)).
-
-%% @spec load(Module, BeamFileName) -> {module, Module} | {error, Reason}
-%% Module = mod()
-%% BeamFileName = file:filename()
-%% Reason = term()
-%%
-%% @type mod() = module(). A module name.
-%%
-%% @doc User interface for loading code into memory. The code can be
-%% given as a native code binary or as the file name of a BEAM file
-%% which should contain a native-code chunk. If only the module name is
-%% given (see <code>load/1</code>), the BEAM file is located
-%% automatically.
-%%
-%% @see load/1
-
--spec load(Module, file:filename()) -> {'module', Module} | {'error', term()}
- when Module :: mod().
-
-load(Mod, BeamFileName) when is_list(BeamFileName) ->
- Architecture = erlang:system_info(hipe_architecture),
- ChunkName = hipe_unified_loader:chunk_name(Architecture),
- case beam_lib:chunks(BeamFileName, [ChunkName]) of
- {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> do_load(Mod, Bin, BeamFileName);
- Error -> {error, Error}
- end.
-
-%% @spec c(Mod) -> {ok, Mod} | {error, Reason}
-%% Mod = mod()
-%% Reason = term()
-%%
-%% @equiv c(Mod, [])
-
--spec c(mod()) -> c_ret().
-
-c(Mod) ->
- c(Mod, []).
-
-%% @spec c(Module, options()) -> {ok, Module} | {error, Reason}
-%% Module = mod()
-%% options() = [option()]
-%% option() = term()
-%% Reason = term()
-%%
-%% @doc User-friendly native code compiler interface. Reads BEAM code
-%% from the corresponding "Module<code>.beam</code>" file in the
-%% system path, and compiles the whole module to native code. By
-%% default, the compiled code is loaded directly. See above for
-%% documentation of options.
-%%
-%% @see c/1
-%% @see c/3
-%% @see f/2
-%% @see compile/2
-
--spec c(mod(), comp_options()) -> c_ret().
-
-c(Module, Options) ->
- c(Module, beam_file(Module), Options).
-
-%% @spec c(Module, File, options()) -> {ok, Module} | {error, Reason}
-%% Module = mod()
-%% File = file:filename() | binary()
-%% Reason = term()
-%%
-%% @doc Like <code>c/2</code>, but reads BEAM code from the specified
-%% <code>File</code>.
-%%
-%% @see c/2
-%% @see f/2
-
-c(Module, File, Opts) ->
- Opts1 = user_compile_opts(Opts),
- case compile(Module, File, Opts1) of
- {ok, Res} ->
- case proplists:get_bool(to_rtl, Opts1) of
- true -> {ok, Module, Res};
- false -> {ok, Module}
- end;
- Other ->
- Other
- end.
-
-%% @spec f(File) -> {ok, Name} | {error, Reason}
-%% File = file:filename() | binary()
-%% Name = mod()
-%% Reason = term()
-%%
-%% @equiv f(File, [])
-
--spec f(file_or_bin()) -> {'ok', mod()} | {'error', term()}.
-
-f(File) ->
- f(File, []).
-
-%% @spec f(File, options()) -> {ok, Name} | {error, Reason}
-%% File = file:filename() | binary()
-%% Name = mod()
-%% Reason = term()
-%%
-%% @doc Like <code>c/3</code>, but takes the module name from the
-%% specified <code>File</code>.
-%%
-%% @see c/3
-
--spec f(file_or_bin(), comp_options()) -> {'ok', mod()} | {'error', term()}.
-
-f(File, Opts) ->
- case file(File, user_compile_opts(Opts)) of
- {ok, Name, _} ->
- {ok, Name};
- Other ->
- Other
- end.
-
--define(USER_DEFAULTS, [load]).
-
-user_compile_opts(Opts) ->
- Opts ++ ?USER_DEFAULTS.
-
-
-%% @spec compile(Module) -> {ok, {Target,Binary}} | {error, Reason}
-%% Module = mod()
-%% Binary = binary()
-%% Reason = term()
-%%
-%% @equiv compile(Module, [])
-
--spec compile(mod()) -> {'ok', compile_ret()} | {'error', term()}.
-
-compile(Module) ->
- compile(Module, []).
-
-%% @spec compile(Module, options()) -> {ok, {Target,Binary}} | {error, Reason}
-%% Module = mod()
-%% Binary = binary()
-%% Reason = term()
-%%
-%% @doc Direct compiler interface, for advanced use. This just
-%% compiles the module, reading BEAM code from the corresponding
-%% "Module<code>.beam</code>" file in the system path. Returns
-%% <code>{ok, Binary}</code> if successful, or <code>{error,
-%% Reason}</code> otherwise. By default, it does <em>not</em> load the
-%% binary to memory (the <code>load</code> option can be used to
-%% activate automatic loading). <code>File</code> can be either a file
-%% name or a binary containing the BEAM code for the module.
-%%
-%% @see c/2
-%% @see compile/1
-%% @see compile/3
-%% @see file/2
-%% @see load/2
-
--spec compile(mod(), comp_options()) -> {'ok', compile_ret()} | {'error', term()}.
-
-compile(Module, Options) ->
- compile(Module, beam_file(Module), Options).
-
--spec beam_file(mod()) -> file:filename().
-
-beam_file(Module) when is_atom(Module) ->
- case code:which(Module) of
- non_existing ->
- ?error_msg("Cannot find ~w.beam file.", [Module]),
- ?EXIT({cant_find_beam_file,Module});
- File when is_list(File) ->
- File
- end.
-
-%% @spec compile(Name, File, options()) ->
-%% {ok, {Target, Binary}} | {error, Reason}
-%% Name = mod()
-%% File = file:filename() | binary()
-%% Binary = binary()
-%% Reason = term()
-%%
-%% @doc Like <code>compile/2</code>, but reads BEAM code from the
-%% specified <code>File</code>.
-%%
-%% @see compile/2
-
--spec compile(mod(), file_or_bin(), comp_options()) ->
- {'ok', compile_ret()} | {'error', term()}.
-
-compile(Name, File, Opts0) when is_atom(Name) ->
- Opts = expand_kt2(Opts0),
- case proplists:get_value(core, Opts) of
- true when is_binary(File) ->
- ?error_msg("Cannot get Core Erlang code from BEAM binary.",[]),
- ?EXIT({cant_compile_core_from_binary});
- true ->
- case filelib:find_source(filename:rootname(File,".beam") ++ ".beam") of
- {error, _} ->
- ?error_msg("Cannot find source code for ~p.", [File]),
- ?EXIT({cant_find_source_code});
- {Source, CompOpts} ->
- CoreOpts = [X || X = {core_transform, _} <- Opts],
- %% io:format("Using: ~w\n", [CoreOpts]),
- case compile:file(Source, CoreOpts ++ [to_core, binary|CompOpts]) of
- {ok, _, Core} ->
- compile_core(Name, Core, File, Opts);
- Error ->
- ?error_msg("Error compiling ~p:\n~p.", [File, Error]),
- ?EXIT({cant_compile_source_code})
- end
- end;
- {src_file, Source} ->
- CoreOpts1 = [X || X = {core_transform, _} <- Opts],
- CoreOpts2 = [report_errors, to_core, binary, {i,"../include"}|CoreOpts1],
- %% io:format("Using: ~w\n", [CoreOpts2]),
- case compile:file(Source, CoreOpts2) of
- {ok, _, Core} ->
- compile_core(Name, Core, File, Opts);
- Error ->
- ?error_msg("Error compiling ~p:\n~p\n", [Source, Error]),
- ?EXIT({cant_compile_source_code, Error})
- end;
- Other when Other =:= false; Other =:= undefined ->
- DisasmFun = fun (_) -> disasm(File) end,
- IcodeFun = fun (Code, Opts_) ->
- get_beam_icode(Name, Code, File, Opts_)
- end,
- run_compiler(Name, DisasmFun, IcodeFun, Opts)
- end.
-
--spec compile_core(mod(), cerl:c_module(), file_or_bin(), comp_options()) ->
- {'ok', compile_ret()} | {'error', term()}.
-
-compile_core(Name, Core0, File, Opts) ->
- Core = cerl:from_records(Core0),
- compile(Name, Core, File, Opts).
-
-%% @spec compile(Module, Core, File, options()) ->
-%% {ok, {Target, Binary}} | {error, Reason}
-%% Module = mod()
-%% Core = coreErlang() | []
-%% File = file:filename() | binary()
-%% Binary = binary()
-%% Reason = term()
-%%
-%% @doc Like <code>compile/3</code>, but unless <code>Core</code> is
-%% <code>[]</code>, low-level code is generated from the given Core
-%% Erlang code instead of from the BEAM code.
-%%
-%% <p>Note that only whole modules can be compiled with this
-%% function.</p>
-%%
-%% @see compile/3
-
--spec compile(mod(), cerl:c_module() | [], file_or_bin(), comp_options()) ->
- {'ok', compile_ret()} | {'error', term()}.
-
-compile(Name, [], File, Opts) ->
- compile(Name, File, Opts);
-compile(Name, Core, File, Opts) when is_atom(Name) ->
- DisasmFun = fun (_) -> {false, []} end,
- IcodeFun = fun (_, FOpts) ->
- get_core_icode(Name, Core, File, FOpts)
- end,
- run_compiler(Name, DisasmFun, IcodeFun, Opts).
-
-%% @spec file(File) -> {ok, Mod, {Target, Binary}} | {error, Reason}
-%% File = file:filename()
-%% Mod = mod()
-%% Binary = binary()
-%% Reason = term()
-%%
-%% @equiv file(File, [])
-
--spec file(file:filename()) -> {'ok', mod(), compile_ret()} | {'error', term()}.
-
-file(File) ->
- file(File, []).
-
-%% @spec file(File, options()) -> {ok, Mod, {Target, Binary}} | {error, Reason}
-%% File = file:filename()
-%% Mod = mod()
-%% Binary = binary()
-%% Reason = term()
-%%
-%% @doc Like <code>compile/2</code>, but takes the module name from the
-%% specified <code>File</code>. Returns both the module name and the final
-%% binary if successful.
-%%
-%% @see file/1
-%% @see compile/2
-
--spec file(file:filename(), comp_options()) -> {'ok', mod(), compile_ret()}
- | {'error', Reason :: term()}.
-file(File, Options) when is_list(File) ->
- case beam_lib:info(File) of
- L when is_list(L) ->
- {module, Mod} = lists:keyfind(module, 1, L),
- case compile(Mod, File, Options) of
- {ok, CompRet} ->
- {ok, Mod, CompRet};
- Other ->
- Other
- end;
- Error ->
- Error
- end.
-
-
-%%-----------------------------------------------------------------------
-%% The rest are internal functions:
-%%-----------------------------------------------------------------------
-
-%% @doc
-%% Get BEAM code from `.beam' files or directly from binaries.
-%% File is either a file name or a binary containing the BEAM code.
-
-disasm(File) ->
- case beam_disasm:file(File) of
- #beam_file{labeled_exports = LabeledExports,
- compile_info = CompInfo, code = BeamCode} ->
- CompOpts = proplists:get_value(options, CompInfo, []),
- HCompOpts = case lists:keyfind(hipe, 1, CompOpts) of
- {hipe, L} when is_list(L) -> L;
- {hipe, X} -> [X];
- _ -> []
- end,
- Exports = fix_beam_exports(LabeledExports),
- {{BeamCode, Exports}, HCompOpts};
- {error, _Mod, Error} ->
- io:format("~s\n", [beam_lib:format_error(Error)]),
- ?EXIT(no_beam_code)
- end.
-
-fix_beam_exports(BeamExports) ->
- fix_beam_exports(BeamExports, []).
-
-fix_beam_exports([{F,A,_}|BeamExports], Exports) ->
- fix_beam_exports(BeamExports, [{F,A} | Exports]);
-fix_beam_exports([], Exports) ->
- Exports.
-
-get_beam_icode(Mod, {BeamCode, Exports}, File, Options) ->
- Icode = ?option_time(hipe_beam_to_icode:module(BeamCode, Options),
- "BEAM-to-Icode", Options),
- BeamBin = get_beam_code(File),
- {{Mod, Exports, Icode}, BeamBin}.
-
-get_core_icode(Mod, Core, File, Options) ->
- {ok, Icode} =
- ?option_time((catch {ok, cerl_to_icode:module(Core, Options)}),
- "BEAM-to-Icode", Options),
- NeedBeamCode = not proplists:get_bool(load, Options),
- BeamBin =
- case NeedBeamCode of
- true -> [];
- false -> get_beam_code(File)
- end,
- Exports = [cerl:var_name(V) || V <- cerl:module_exports(Core)],
- {{Mod, Exports, Icode}, BeamBin}.
-
-get_beam_code(Bin) when is_binary(Bin) -> Bin;
-get_beam_code(FileName) ->
- case erl_prim_loader:get_file(FileName) of
- {ok, Bin, _} ->
- Bin;
- error ->
- ?EXIT(no_beam_file)
- end.
-
-
-%% ---------------------------------------------------------------------
-%% All compilations go through this function. Note that it receives only
-%% "basic" options. Name is just used for verbosity. The DisasmFun and
-%% IcodeFun only collect the Icode; most of the real work is done in the
-%% 'finalize' function.
-
-run_compiler(Name, DisasmFun, IcodeFun, Opts0) ->
- Opts = expand_basic_options(Opts0 ++ ?COMPILE_DEFAULTS),
- ?when_option(verbose, Opts, ?debug_msg("Compiling: ~p\n",[Name])),
- ?option_start_time("Compile", Opts),
- Res = run_compiler_1(Name, DisasmFun, IcodeFun, Opts),
- ?option_stop_time("Compile", Opts),
- Res.
-
-run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
- Parent = self(),
- {trap_exit,TrapExit} = process_info(Parent, trap_exit),
- %% Spawn a compilation process CompProc. In case this process gets
- %% killed, the trap_exit flag is restored to that of the Parent process.
- process_flag(trap_exit, true),
- CompProc =
- spawn_link(
- fun () ->
- try
- %% Compiler process
- set_architecture(Options),
- pre_init(Options),
- %% The full option expansion is not done
- %% until the DisasmFun returns.
- {Code, CompOpts} = DisasmFun(Options),
- Opts0 = expand_options(Options ++ CompOpts,
- get(hipe_target_arch)),
- Opts =
- case proplists:get_bool(to_llvm, Opts0) andalso
- not llvm_version_is_OK() of
- true ->
- ?error_msg("No LLVM version 3.9 or greater "
- "found in $PATH; aborting "
- "native code compilation.\n", []),
- ?EXIT(cant_find_required_llvm_version);
- false ->
- Opts0
- end,
- check_options(Opts),
- ?when_option(verbose, Options,
- ?debug_msg("Options: ~p.\n",[Opts])),
- init(Opts),
- {Icode, WholeModule} = IcodeFun(Code, Opts),
- CompRes = compile_finish(Icode, WholeModule, Opts),
- compiler_return(CompRes, Parent)
- catch
- error:Error:StackTrace ->
- print_crash_message(Name, Error, StackTrace),
- exit(Error);
- throw:{unimplemented_instruction,_Instruction}=Error ->
- exit(Error)
- end
- end),
- Timeout = case proplists:get_value(timeout, Options) of
- N when is_integer(N), N >= 0 -> N;
- undefined -> ?DEFAULT_TIMEOUT;
- infinity -> infinity;
- Other ->
- ?WARNING_MSG("Bad timeout value: ~P\n"
- "Using default timeout limit.\n",
- [Other, 5]),
- ?DEFAULT_TIMEOUT
- end,
- receive
- {'EXIT', CompProc, normal} -> ok;
- {'EXIT', CompProc, Reason} -> exit(Reason)
- after Timeout ->
- %% Kill the compilation process
- exit(CompProc, kill),
- receive {'EXIT', CompProc, _} -> ok end,
- flush(),
- ?error_msg("ERROR: Compilation of ~w timed out.\n",[Name]),
- exit(timed_out)
- end,
- Result = receive {CompProc, Res} -> Res end,
- process_flag(trap_exit, TrapExit),
- Result.
-
-flush() ->
- receive
- _ -> flush()
- after 0 ->
- ok
- end.
-
-compiler_return(Res, Client) ->
- Client ! {self(), Res}.
-
-compile_finish({Mod, Exports, Icode}, WholeModule, Options) ->
- Res = finalize(Icode, Mod, Exports, WholeModule, Options),
- post(Res, Icode, Options).
-
-
-%% -------------------------------------------------------------------------
-%% finalize/5
-%% compiles, assembles, and optionally loads a list of `{MFA, Icode}' pairs,
-%% and returns `{ok, {TargetArch, Binary}}' or `{error, Reason, Stack}'.
-
-finalize(OrigList, Mod, Exports, WholeModule, Opts) ->
- List = icode_multret(OrigList, Mod, Opts, Exports),
- {T1Compile,_} = erlang:statistics(runtime),
- CompiledCode =
- case proplists:get_value(use_callgraph, Opts) of
- true ->
- %% Compiling the functions bottom-up by using a call graph
- CallGraph = hipe_icode_callgraph:construct(List),
- OrdList = hipe_icode_callgraph:to_list(CallGraph),
- finalize_fun(OrdList, Exports, Opts);
- _ ->
- %% Compiling the functions bottom-up by reversing the list
- OrdList = lists:reverse(List),
- finalize_fun(OrdList, Exports, Opts)
- end,
- {T2Compile,_} = erlang:statistics(runtime),
- ?when_option(verbose, Opts,
- ?debug_msg("Compiled ~p in ~.2f s\n",
- [Mod,(T2Compile-T1Compile)/1000])),
- case proplists:get_bool(to_rtl, Opts) of
- true ->
- {ok, CompiledCode};
- false ->
- Closures =
- [MFA || {MFA, Icode} <- List,
- hipe_icode:icode_is_closure(Icode)],
- {T1,_} = erlang:statistics(runtime),
- ?when_option(verbose, Opts, ?debug_msg("Assembling ~w",[Mod])),
- try assemble(CompiledCode, Closures, Exports, Opts) of
- Bin ->
- {T2,_} = erlang:statistics(runtime),
- ?when_option(verbose, Opts,
- ?debug_untagged_msg(" in ~.2f s\n",
- [(T2-T1)/1000])),
- {module,Mod} = maybe_load(Mod, Bin, WholeModule, Opts),
- TargetArch = get(hipe_target_arch),
- {ok, {TargetArch,Bin}}
- catch
- error:Error:StackTrace ->
- {error,Error,StackTrace}
- end
- end.
-
-finalize_fun(MfaIcodeList, Exports, Opts) ->
- case proplists:get_value(concurrent_comp, Opts) of
- FalseVal when (FalseVal =:= undefined) orelse (FalseVal =:= false) ->
- NoServers = #comp_servers{pp_server = none, range = none, type = none},
- [finalize_fun_sequential(MFAIcode, Opts, NoServers)
- || {_MFA, _Icode} = MFAIcode <- MfaIcodeList];
- TrueVal when (TrueVal =:= true) orelse (TrueVal =:= debug) ->
- finalize_fun_concurrent(MfaIcodeList, Exports, Opts)
- end.
-
-finalize_fun_concurrent(MfaIcodeList, Exports, Opts) ->
- Self = self(),
- case MfaIcodeList of
- [{{M,_,_},_}|_] ->
- CallGraph = hipe_icode_callgraph:construct_callgraph(MfaIcodeList),
- Exported = [{M, F, A} || {F, A} <- Exports],
- Closures = [MFA || {MFA, Icode} <- MfaIcodeList,
- hipe_icode:icode_is_closure(Icode)],
- %% In principle, a function could both be exported and used as a
- %% closure so make sure to add it only once in Escaping below
- Escaping = ordsets:from_list(Exported ++ Closures),
- NonEscaping = [MFA || {{_M, F, A} = MFA, Icode} <- MfaIcodeList,
- not lists:member({F, A}, Exports),
- not hipe_icode:icode_is_closure(Icode)],
- TypeServerFun =
- fun() ->
- hipe_icode_coordinator:coordinate(CallGraph, Escaping,
- NonEscaping, hipe_icode_type)
- end,
- TypeServer = spawn_link(TypeServerFun),
- PPServerFun =
- fun() ->
- pp_server_start(Opts)
- end,
- PPServer = spawn_link(PPServerFun),
- RangeServerFun =
- fun() ->
- hipe_icode_coordinator:coordinate(CallGraph, Escaping,
- NonEscaping, hipe_icode_range)
- end,
- RangeServer = spawn_link(RangeServerFun),
- Servers = #comp_servers{pp_server = PPServer,
- range = RangeServer,
- type = TypeServer},
- CompFuns =
- [fun() ->
- set_architecture(Opts),
- pre_init(Opts),
- init(Opts),
- Self ! finalize_fun_sequential(IcodeFun, Opts, Servers)
- end || IcodeFun <- MfaIcodeList],
- lists:foreach(fun (F) -> spawn_link(F) end, CompFuns),
- Final = [receive Res when element(1, Res) =:= MFA -> Res end
- || {MFA, _} <- MfaIcodeList],
- lists:foreach(fun (Pid) -> stop_and_wait(Pid) end,
- [PPServer, TypeServer, RangeServer]),
- Final;
- [] ->
- []
- end.
-
-stop_and_wait(Pid) ->
- Pid ! {stop, self()},
- receive
- _ -> ok
- end.
-
-finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
- {T1, _} = erlang:statistics(runtime),
- ?when_option(verbose, Opts, ?debug_msg("Compiling ~w~n", [MFA])),
- try hipe_main:compile_icode(MFA, Icode, Opts, Servers) of
- {native, _Platform, {unprofiled, Code}} ->
- {T2, _} = erlang:statistics(runtime),
- ?when_option(verbose, Opts,
- ?debug_msg("Compiled ~w in ~.2f s\n", [MFA,(T2-T1)/1000])),
- {MFA, Code};
- {rtl, LinearRtl} ->
- {MFA, LinearRtl};
- {llvm_binary, Binary} ->
- {MFA, Binary}
- catch
- error:Error:StackTrace ->
- ?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
- print_crash_message(MFA, Error, StackTrace),
- exit(Error)
- end.
-
-print_crash_message(What, Error, StackTrace) ->
- StackFun = fun(_,_,_) -> false end,
- FormatFun = fun (Term, _) -> io_lib:format("~p", [Term]) end,
- StackTraceS = erl_error:format_stacktrace(1, StackTrace,
- StackFun, FormatFun),
- WhatS = case What of
- {M,F,A} -> io_lib:format("~w:~w/~w", [M,F,A]);
- Mod -> io_lib:format("~w", [Mod])
- end,
- ?error_msg("INTERNAL ERROR~n"
- "while compiling ~s~n"
- "crash reason: ~p~n"
- "~s~n",
- [WhatS, Error, StackTraceS]).
-
-pp_server_start(Opts) ->
- set_architecture(Opts),
- garbage_collect(),
- pp_server().
-
-pp_server() ->
- receive
- {print, Fun} ->
- Fun(), pp_server();
- {stop, Pid} ->
- Pid ! {done, self()};
- _ ->
- pp_server()
- end.
-
-icode_multret(List, Mod, Opts, Exports) ->
- case proplists:get_bool(icode_multret, Opts) of
- true ->
- hipe_icode_mulret:mult_ret(List, Mod, Opts, Exports);
- false ->
- List
- end.
-
-maybe_load(Mod, Bin, WholeModule, Opts) ->
- case proplists:get_bool(load, Opts) of
- false ->
- {module, Mod};
- true ->
- ?when_option(verbose, Opts, ?debug_msg("Loading/linking\n", [])),
- do_load(Mod, Bin, WholeModule)
- end.
-
-do_load(Mod, Bin, BeamBinOrPath) when is_binary(BeamBinOrPath);
- is_list(BeamBinOrPath) ->
- HostArch = get(hipe_host_arch),
- TargetArch = get(hipe_target_arch),
- %% Make sure we can do the load.
- if HostArch =/= TargetArch ->
- ?EXIT({host_and_target_arch_differ, HostArch, TargetArch});
- true -> ok
- end,
- case code:is_sticky(Mod) of
- true ->
- %% We unpack and repack the Beam binary as a workaround to
- %% ensure that it is not compressed.
- {ok, _, Chunks} = beam_lib:all_chunks(BeamBinOrPath),
- {ok, Beam} = beam_lib:build_module(Chunks),
- %% Don't purge or register sticky mods; just load native.
- code:load_native_sticky(Mod, Bin, Beam);
- false ->
- %% Normal loading of a whole module
- ChunkName = hipe_unified_loader:chunk_name(HostArch),
- {ok, _, Chunks0} = beam_lib:all_chunks(BeamBinOrPath),
- Chunks = [{ChunkName, Bin}|lists:keydelete(ChunkName, 1, Chunks0)],
- {ok, BeamPlusNative} = beam_lib:build_module(Chunks),
- code:load_binary(Mod, code:which(Mod), BeamPlusNative)
- end.
-
-assemble(CompiledCode, Closures, Exports, Options) ->
- case proplists:get_bool(to_llvm, Options) of
- false ->
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
- powerpc ->
- hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
- ppc64 ->
- hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
- arm ->
- hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
- x86 ->
- hipe_x86_assemble:assemble(CompiledCode, Closures, Exports, Options);
- amd64 ->
- hipe_amd64_assemble:assemble(CompiledCode, Closures, Exports, Options);
- Arch ->
- ?EXIT({executing_on_an_unsupported_architecture, Arch})
- end;
- true ->
- %% Merge already compiled code (per MFA) to a single binary.
- hipe_llvm_merge:finalize(CompiledCode, Closures, Exports)
- end.
-
-%% --------------------------------------------------------------------
-
-%% Initialise host and target architectures. Target defaults to host,
-%% but can be overridden by passing an option {target, Target}.
-
-set_architecture(Options) ->
- HostArch = erlang:system_info(hipe_architecture),
- put(hipe_host_arch, HostArch),
- put(hipe_target_arch, proplists:get_value(target, Options, HostArch)),
- ok.
-
-%% This sets up some globally accessed stuff that are needed by the
-%% compiler process before it even gets the full list of options.
-%% Therefore, this expands the current set of options for local use.
-
-pre_init(Opts) ->
- Options = expand_options(Opts, get(hipe_target_arch)),
- %% Initialise some counters used for measurements and benchmarking. If
- %% the option 'measure_regalloc' is given the compilation will return
- %% a keylist with the counter values.
- put(hipe_time,
- case proplists:get_value(time, Options, false) of
- true -> [hipe, hipe_main];
- OptTime -> OptTime
- end),
- lists:foreach(fun (T) -> ?set_hipe_timer_val(T, 0) end, hipe_timers()),
- lists:foreach(fun (Counter) ->
- case Counter of
- {CounterName, InitVal} -> put(CounterName, InitVal);
- CounterName -> put(CounterName, 0)
- end
- end,
- proplists:get_value(counters, Options, [])),
- put(hipe_debug, proplists:get_bool(debug, Options)),
- put(hipe_inline_fp, proplists:get_bool(inline_fp, Options)),
- ok.
-
-%% Prepare the compiler process by setting up variables which are
-%% accessed globally. Options have been fully expanded at ths point.
-
-init(_Options) ->
- put(callersavetime, 0),
- put(totalspill, {0,0}),
- put(spilledtemps, 0),
- put(pre_ra_instrs, 0),
- put(post_ra_instrs, 0),
- put(pre_ra_temps, 0),
- put(post_ra_temps, 0),
- put(noregs, 0),
- put(bbs, 0),
- ok.
-
-%% --------------------------------------------------------------------
-
-post(Res, Icode, Options) ->
- TimerVals =
- case proplists:get_value(timers, Options) of
- Timers when is_list(Timers) ->
- [{Timer, ?get_hipe_timer_val(Timer)} || Timer <- Timers];
- _ -> []
- end,
- CounterVals =
- case proplists:get_value(counters, Options) of
- Counters when is_list(Counters) ->
- [case Counter of
- {CounterName, _InitVal} -> {CounterName, get(CounterName)};
- CounterName -> {CounterName, get(CounterName)}
- end
- || Counter <- Counters];
- _ -> []
- end,
- Measures =
- case proplists:get_bool(measure_regalloc, Options) of
- true ->
- get(); % return whole process dictionary list (simplest way...)
- false -> []
- end,
- Info = TimerVals ++ CounterVals ++ Measures,
- case proplists:get_bool(get_called_modules, Options) of
- true ->
- CalledMods = hipe_icode_callgraph:get_called_modules(Icode),
- case Info of
- [] ->
- {Res, {called_modules, CalledMods}};
- _ ->
- {Res, {info, Info}, {called_modules, CalledMods}}
- end;
- false ->
- case Info of
- [] ->
- Res;
- _ ->
- {Res, {info, Info}}
- end
- end.
-
-%% --------------------------------------------------------------------
-
-%% @doc Returns the current HiPE version as a string().
--spec version() -> nonempty_string().
-
-version() ->
- ?VERSION_STRING().
-
-%% @doc Returns checksum identifying the target runtime system.
--spec erts_checksum() -> integer().
-
-erts_checksum() ->
- ?HIPE_ERTS_CHECKSUM.
-
-%% --------------------------------------------------------------------
-%% D O C U M E N T A T I O N - H E L P
-%% --------------------------------------------------------------------
-
-%% @doc Prints on-line documentation to the standard output.
--spec help() -> 'ok'.
-
-help() ->
- M =
- "The HiPE Compiler (Version " ++ ?VERSION_STRING() ++ ")\n" ++
- "\n" ++
- " The normal way to native-compile Erlang code using HiPE is to\n" ++
- " include `native' in the Erlang compiler options, as in:\n" ++
- " 1> c(my_module, [native]).\n" ++
- " Options to the HiPE compiler must then be passed as follows:\n" ++
- " 1> c(my_module, [native,{hipe,Options}]).\n" ++
- " Use `help_options()' for details.\n" ++
- "\n" ++
- " Utility functions:\n" ++
- " help()\n" ++
- " Prints this message.\n" ++
- " help_options()\n" ++
- " Prints a description of options recognized by the\n" ++
- " HiPE compiler.\n" ++
- " help_option(Option)\n" ++
- " Prints a description of that option.\n" ++
- " help_debug_options()\n" ++
- " Prints a description of debug options.\n" ++
- " version() ->\n" ++
- " Returns the HiPE version as a string'.\n" ++
- " erts_checksum() ->\n" ++
- " Returns a checksum identifying the target runtime system.\n" ++
- "\n" ++
- " For HiPE developers only:\n" ++
- " Use `help_hiper()' for information about HiPE's low-level interface\n",
- io:put_chars(M),
- ok.
-
--spec help_hiper() -> 'ok'.
-
-help_hiper() ->
- M =
- " This interface is supposed to be used by HiPE-developers only!\n" ++
- " Note that all options are specific to the HiPE compiler.\n" ++
- " c(Name,Options)\n" ++
- " Compiles the module or function Name and loads it\n" ++
- " to memory. Name is an atom or a tuple {M,F,A}.\n" ++
- " c(Name)\n" ++
- " As above, but using only default options.\n" ++
- " f(File,Options)\n" ++
- " As c(Name,File,Options), but taking the module name\n" ++
- " from File.\n" ++
- " f(File)\n" ++
- " As above, but using only default options.\n" ++
- " compile(Name,Options)\n" ++
- " Compiles the module or function Name to a binary.\n" ++
- " By default, this does not load to memory.\n" ++
- " compile(Name)\n" ++
- " As above, but using only default options.\n" ++
- " file(File,Options)\n" ++
- " As compile(Name,File,Options), but taking the\n" ++
- " module name from File.\n" ++
- " file(File)\n" ++
- " As above, but using only default options.\n" ++
- " load(Module)\n" ++
- " Loads the named module into memory.\n",
- io:put_chars(M),
- ok.
-
-%% TODO: it should be possible to specify the target somehow when asking
-%% for available options. Right now, you only see host machine options.
-
-%% @doc Prints documentation about options to the standard output.
--spec help_options() -> 'ok'.
-
-help_options() ->
- HostArch = erlang:system_info(hipe_architecture),
- O0 = expand_options([o0] ++ ?COMPILE_DEFAULTS, HostArch),
- O1 = expand_options([o1] ++ ?COMPILE_DEFAULTS, HostArch),
- O2 = expand_options([o2] ++ ?COMPILE_DEFAULTS, HostArch),
- O3 = expand_options([o3] ++ ?COMPILE_DEFAULTS, HostArch),
- io:format("HiPE Compiler Options\n" ++
- " Boolean-valued options generally have corresponding " ++
- "aliases `no_...',\n" ++
- " and can also be specified as `{Option, true}' " ++
- "or `{Option, false}.\n\n" ++
- " General boolean options:\n" ++
- " ~p.\n\n" ++
- " Non-boolean options:\n" ++
- " o#, where 0 =< # =< 3:\n" ++
- " Select optimization level (the default is 2).\n\n" ++
- " Further options can be found below; " ++
- "use `hipe:help_option(Name)' for details.\n\n" ++
- " Aliases:\n" ++
- " pp_all = ~p,\n" ++
- " pp_sparc = pp_native,\n" ++
- " pp_x86 = pp_native,\n" ++
- " pp_amd64 = pp_native,\n" ++
- " pp_ppc = pp_native,\n" ++
- " o0 = ~p,\n" ++
- " o1 = ~p ++ o0,\n" ++
- " o2 = ~p ++ o1,\n" ++
- " o3 = ~p ++ o2.\n",
- [ordsets:from_list([verbose, debug, time, load, pp_beam,
- pp_icode, pp_rtl, pp_native, pp_asm,
- timeout]),
- expand_options([pp_all], HostArch),
- O0 -- [o0],
- (O1 -- O0) -- [o1],
- (O2 -- O1) -- [o2],
- (O3 -- O2) -- [o3]]),
- ok.
-
-%% Documentation of the individual options.
-%% If you add an option, please add help-text here.
-
--spec option_text(atom()) -> string().
-
-option_text('O') ->
- "Specify optimization level. Used as o1, o2, o3.\n" ++
- " At the moment levels 0 - 3 are implemented.\n" ++
- " Aliases: 'O1', 'O2', O3'.";
-option_text(caller_save_spill_restore) ->
- "Activates caller save register spills and restores";
-option_text(debug) ->
- "Outputs internal debugging information during compilation";
-option_text(icode_call_elim) ->
- "Performs call elimination of BIFs that are side-effect free\n" ++
- "only on some argument types";
-option_text(icode_range) ->
- "Performs integer range analysis on the Icode level";
-option_text(icode_ssa_check) ->
- "Checks whether Icode is on SSA form or not";
-option_text(icode_ssa_copy_prop) ->
- "Performs copy propagation on Icode SSA";
-option_text(icode_ssa_const_prop) ->
- "Performs sparse conditional constant propagation on Icode SSA";
-option_text(icode_ssa_struct_reuse) ->
- "Factors out common tuple and list constructions on Icode SSA";
-option_text(icode_type) ->
- "Performs type analysis on the Icode level\n" ++
- "and then simplifies the code based on the results of this analysis";
-option_text(load) ->
- "Automatically load the produced native code into memory";
-option_text(peephole) ->
- "Enables peephole optimizations";
-option_text(pmatch) ->
- "Enables pattern matching compilation when compiling from Core;\n" ++
- "has no effect when compiling from BEAM bytecode";
-option_text(pp_asm) ->
- "Displays assembly listing with addresses and bytecode\n" ++
- "Currently available for x86 only";
-option_text(pp_beam) ->
- "Display the input BEAM code";
-option_text(pp_icode) ->
- "Display the intermediate HiPE-ICode";
-option_text(pp_rtl) ->
- "Display the intermediate HiPE-RTL code";
-option_text(pp_rtl_lcm) ->
- "Display the intermediate HiPE-RTL lazy code motion sets";
-option_text(pp_rtl_ssapre) ->
- "Display the intermediate HiPE-RTL A-SSAPRE sets";
-option_text(pp_native) ->
- "Display the generated (back-end specific) native code";
-option_text(regalloc) ->
- "Select register allocation algorithm. Used as {regalloc, METHOD}.\n" ++
- " Currently available methods:\n" ++
- " naive - spills everything (for debugging and testing)\n" ++
- " linear_scan - fast; not so good if few registers available\n" ++
- " graph_color - slow, but gives OK performance\n" ++
- " coalescing - slower, tries hard to use registers\n" ++
- " optimistic - another variant of a coalescing allocator";
-option_text(remove_comments) ->
- "Strip comments from intermediate code";
-option_text(ra_range_split) ->
- "Split live ranges of temporaries live over call instructions\n"
- "before performing register allocation.\n"
- "Heuristically tries to move stack accesses to the cold path of function.\n"
- "This range splitter is more sophisticated than 'ra_restore_reuse', but has\n"
- "a significantly larger impact on compile time.\n"
- "Should only be used with move coalescing register allocators.";
-option_text(ra_restore_reuse) ->
- "Split live ranges of temporaries such that straight-line\n"
- "code will not need to contain multiple restores from the same stack\n"
- "location.\n"
- "Should only be used with move coalescing register allocators.";
-option_text(rtl_ssa) ->
- "Perform SSA conversion on the RTL level -- default starting at O2";
-option_text(rtl_ssa_const_prop) ->
- "Performs sparse conditional constant propagation on RTL SSA";
-option_text(rtl_lcm) ->
- "Perform Lazy Code Motion on RTL";
-option_text(rtl_ssapre) ->
- "Perform A-SSAPRE on RTL";
-option_text(time) ->
- "Reports the compilation times for the different stages\n" ++
- "of the compiler.\n" ++
- " {time, Module} reports timings for the module Module.\n" ++
- " {time, [M1, M2, M3]} reports timings for the specified modules.\n" ++
- " {time, all} reports timings all modules.\n" ++
- " time reports timings for the main module.\n";
-option_text(timeout) ->
- "Specify compilation time limit in ms. Used as {timeout, LIMIT}.\n" ++
- " The limit must be a non-negative integer or the atom 'infinity'.\n" ++
- " The current default limit is 15 minutes (900000 ms).";
-option_text(use_indexing) ->
- "Use indexing for multiple-choice branch selection";
-option_text(use_callgraph) ->
- "Compile the functions in a module according to a reversed topological\n" ++
- "sorted order to gain more information when using a persistent lookup\n" ++
- "table for storing intra-modular type information";
-option_text(verbose) ->
- "Output information about what is being done";
-option_text(Opt) when is_atom(Opt) ->
- "".
-
-%% @doc Prints documentation about a specific option to the standard output.
--spec help_option(comp_option()) -> 'ok'.
-
-help_option(Opt) ->
- HostArch = erlang:system_info(hipe_architecture),
- case expand_options([Opt], HostArch) of
- [Opt] ->
- Name = if is_atom(Opt) -> Opt;
- tuple_size(Opt) =:= 2 -> element(1, Opt)
- end,
- case option_text(Name) of
- "" ->
- case lists:member(Name, opt_keys()) of
- true ->
- io:format("~w - Sorry, this option is not documented yet.\n",
- [Name]);
- _ ->
- io:format("Unknown option ~p.\n", [Name])
- end;
- Txt ->
- io:fwrite("~w - ~s\n", [Name, Txt])
- end;
- Opts ->
- io:fwrite("This is an alias for: ~p.\n", [Opts])
- end,
- ok.
-
-%% @doc Prints documentation about debugging options to the standard
-%% output.
--spec help_debug_options() -> 'ok'.
-
-help_debug_options() ->
- io:format("HiPE compiler debug options:\n" ++
- " Might require that some modules have been compiled " ++
- "with the debug flag.\n" ++
- " rtl_show_translation - Prints each step in the\n" ++
- " translation from Icode to RTL\n",
- []),
- ok.
-
-hipe_timers() ->
- [time_ra].
-
-%% ____________________________________________________________________
-%%
-%% Option expansion
-
-%% These are currently in use, but not documented:
-%%
-%% count_instrs:
-%% icode_type:
-%% icode_range:
-%% {ls_order, Order}:
-%% {regalloc, Algorithm}:
-%% remove_comments
-%% timeregalloc:
-%% timers
-%% use_indexing
-
-%% Valid option keys. (Don't list aliases or negations - the check is
-%% done after the options have been expanded to normal form.)
-
-opt_keys() ->
- [
- binary_opt,
- bitlevel_binaries,
- caller_save_spill_restore,
- concurrent_comp,
- core,
- core_transform,
- counters,
- count_instrs,
- count_spills,
- count_temps,
- debug,
- get_called_modules,
- split_arith,
- split_arith_unsafe,
- icode_call_elim,
- icode_inline_bifs,
- icode_ssa_check,
- icode_ssa_copy_prop,
- icode_ssa_const_prop,
- icode_ssa_struct_reuse,
- icode_type,
- icode_range,
- icode_multret,
- inline_fp,
- ls_order,
- load,
- measure_regalloc,
- peephole,
- pmatch,
- pp_asm,
- pp_beam,
- pp_icode,
- pp_icode_ssa,
- pp_icode_split_arith,
- pp_opt_icode,
- pp_range_icode,
- pp_typed_icode,
- pp_icode_liveness,
- pp_native,
- pp_rtl,
- pp_rtl_liveness,
- pp_rtl_ssa,
- pp_rtl_lcm,
- pp_rtl_ssapre,
- pp_rtl_linear,
- ra_partitioned,
- ra_prespill,
- ra_range_split,
- ra_restore_reuse,
- range_split_min_gain,
- range_split_mode1_fudge,
- range_split_weight_power,
- range_split_weights,
- regalloc,
- remove_comments,
- rtl_ssa,
- rtl_ssa_const_prop,
- rtl_lcm,
- rtl_ssapre,
- rtl_show_translation,
- spillmin_color,
- target,
- time,
- timeout,
- timeregalloc,
- timers,
- to_rtl,
- to_llvm, % Use the LLVM backend for compilation.
- llvm_save_temps, % Save the LLVM intermediate files in the current
- % directory; useful for debugging.
- llvm_llc, % Specify llc optimization-level: o1, o2, o3, undefined.
- llvm_opt, % Specify opt optimization-level: o1, o2, o3, undefined.
- use_indexing,
- use_inline_atom_search,
- use_callgraph,
- use_clusters,
- use_jumptable,
- verbose,
- verify_gcsafe,
- %% verbose_spills,
- x87].
-
-%% Definitions:
-
-o0_opts(_TargetArch) ->
- [concurrent_comp, {regalloc,linear_scan}].
-
-o1_opts(TargetArch) ->
- Common = [inline_fp, pmatch, peephole, ra_prespill, ra_partitioned,
- icode_ssa_const_prop, icode_ssa_copy_prop, icode_inline_bifs,
- rtl_ssa, rtl_ssa_const_prop, rtl_ssapre,
- spillmin_color, use_indexing, remove_comments,
- binary_opt, {regalloc,coalescing}, ra_restore_reuse
- | o0_opts(TargetArch)],
- case TargetArch of
- ultrasparc ->
- Common;
- powerpc ->
- Common;
- ppc64 ->
- Common;
- arm ->
- Common -- [inline_fp]; % Pointless optimising for absent hardware
- x86 ->
- [x87 | Common]; % XXX: Temporary until x86 has sse2
- amd64 ->
- Common;
- Arch ->
- ?EXIT({executing_on_an_unsupported_architecture,Arch})
- end.
-
-o2_opts(TargetArch) ->
- Common = [icode_type, icode_call_elim, % icode_ssa_struct_reuse,
- ra_range_split, range_split_weights, % XXX: Having defaults here is ugly
- rtl_lcm | (o1_opts(TargetArch) -- [rtl_ssapre, ra_restore_reuse])],
- case TargetArch of
- T when T =:= amd64 orelse T =:= ppc64 -> % 64-bit targets
- [icode_range | Common];
- _ -> % T \in [arm, powerpc, ultrasparc, x86]
- Common % [rtl_ssapre | Common];
- end.
-
-o3_opts(TargetArch) ->
- %% no point checking for target architecture since this is checked in 'o1'
- [icode_range | o2_opts(TargetArch)].
-
-%% Note that in general, the normal form for options should be positive.
-%% This is a good programming convention, so that tests in the code say
-%% "if 'x' ..." instead of "if not 'no_x' ...".
-
-opt_negations() ->
- [{no_binary_opt, binary_opt},
- {no_bitlevel_binaries, bitlevel_binaries},
- {no_core, core},
- {no_debug, debug},
- {no_get_called_modules, get_called_modules},
- {no_split_arith, split_arith},
- {no_concurrent_comp, concurrent_comp},
- {no_icode_inline_bifs, icode_inline_bifs},
- {no_icode_range, icode_range},
- {no_icode_split_arith, icode_split_arith},
- {no_icode_call_elim, icode_call_elim},
- {no_icode_ssa_check, icode_ssa_check},
- {no_icode_ssa_copy_prop, icode_ssa_copy_prop},
- {no_icode_ssa_const_prop, icode_ssa_const_prop},
- {no_icode_ssa_struct_reuse, icode_ssa_struct_reuse},
- {no_icode_type, icode_type},
- {no_inline_fp, inline_fp},
- {no_load, load},
- {no_peephole, peephole},
- {no_pmatch, pmatch},
- {no_pp_beam, pp_beam},
- {no_pp_icode, pp_icode},
- {no_pp_icode_ssa, pp_icode_ssa},
- {no_pp_opt_icode, pp_opt_icode},
- {no_pp_typed_icode, pp_typed_icode},
- {no_pp_rtl, pp_rtl},
- {no_pp_native, pp_native},
- {no_pp_rtl_lcm, pp_rtl_lcm},
- {no_pp_rtl_ssapre, pp_rtl_ssapre},
- {no_ra_partitioned, ra_partitioned},
- {no_ra_prespill, ra_prespill},
- {no_ra_range_split, ra_range_split},
- {no_ra_restore_reuse, ra_restore_reuse},
- {no_range_split_weights, range_split_weights},
- {no_remove_comments, remove_comments},
- {no_rtl_ssa, rtl_ssa},
- {no_rtl_ssa_const_prop, rtl_ssa_const_prop},
- {no_rtl_lcm, rtl_lcm},
- {no_rtl_ssapre, rtl_ssapre},
- {no_rtl_show_translation, rtl_show_translation},
- {no_time, time},
- {no_use_callgraph, use_callgraph},
- {no_use_clusters, use_clusters},
- {no_use_inline_atom_search, use_inline_atom_search},
- {no_use_indexing, use_indexing},
- {no_verify_gcsafe, verify_gcsafe}].
-
-%% Don't use negative forms in right-hand sides of aliases and expansions!
-%% We only expand negations once, before the other expansions are done.
-
-opt_aliases() ->
- [{'O0', o0},
- {'O1', o1},
- {'O2', o2},
- {'O3', o3},
- {pp_sparc, pp_native},
- {pp_x86, pp_native},
- {pp_amd64, pp_native},
- {pp_ppc, pp_native}].
-
-opt_basic_expansions() ->
- [{pp_all, [pp_beam, pp_icode, pp_rtl, pp_native]}].
-
-opt_expansions(TargetArch) ->
- [{o0, o0_opts(TargetArch)},
- {o1, o1_opts(TargetArch)},
- {o2, o2_opts(TargetArch)},
- {o3, o3_opts(TargetArch)},
- {to_llvm, llvm_opts(o3, TargetArch)},
- {{to_llvm, o0}, llvm_opts(o0, TargetArch)},
- {{to_llvm, o1}, llvm_opts(o1, TargetArch)},
- {{to_llvm, o2}, llvm_opts(o2, TargetArch)},
- {{to_llvm, o3}, llvm_opts(o3, TargetArch)},
- {x87, [x87, inline_fp]},
- {inline_fp, case TargetArch of %% XXX: Temporary until x86 has sse2
- x86 -> [x87, inline_fp];
- _ -> [inline_fp] end}].
-
-llvm_opts(O, TargetArch) ->
- Base = [to_llvm, {llvm_opt, O}, {llvm_llc, O}],
- case TargetArch of
- %% A llvm bug present in 3.4 through (at least) 3.8 miscompiles x86
- %% functions that have floats are spilled to stack by clobbering the process
- %% pointer (ebp) trying to realign the stack pointer.
- x86 -> [no_inline_fp | Base];
- _ -> Base
- end.
-
-%% This expands "basic" options, which may be tested early and cannot be
-%% in conflict with options found in the source code.
-
--spec expand_basic_options(comp_options()) -> comp_options().
-
-expand_basic_options(Opts) ->
- proplists:normalize(Opts, [{negations, opt_negations()},
- {aliases, opt_aliases()},
- {expand, opt_basic_expansions()}]).
-
--spec expand_kt2(comp_options()) -> comp_options().
-
-expand_kt2(Opts) ->
- proplists:normalize(Opts, [{expand, [{kt2_type,
- [{use_callgraph, fixpoint}, core,
- {core_transform, cerl_typean}]}]}]).
-
-%% Note that the given
-%% list should contain the total set of options, since things like 'o2'
-%% are expanded here. Basic expansions are processed here also, since
-%% this function is called from the help functions.
-
--spec expand_options(comp_options(), hipe_architecture()) -> comp_options().
-
-expand_options(Opts0, TargetArch) ->
- Opts1 = proplists:normalize(Opts0, [{aliases, opt_aliases()}]),
- Opts = normalise_opt_options(Opts1),
- proplists:normalize(Opts, [{negations, opt_negations()},
- {expand, opt_basic_expansions()},
- {expand, opt_expansions(TargetArch)},
- {negations, opt_negations()}]).
-
-normalise_opt_options([o0|Opts]) -> [o0] ++ (Opts -- [o0, o1, o2, o3]);
-normalise_opt_options([o1|Opts]) -> [o1] ++ (Opts -- [o0, o1, o2, o3]);
-normalise_opt_options([o2|Opts]) -> [o2] ++ (Opts -- [o0, o1, o2, o3]);
-normalise_opt_options([o3|Opts]) -> [o3] ++ (Opts -- [o0, o1, o2, o3]);
-normalise_opt_options([O|Opts]) -> [O|normalise_opt_options(Opts)];
-normalise_opt_options([]) -> [].
-
--spec check_options(comp_options()) -> 'ok'.
-
-check_options(Opts) ->
- Keys = ordsets:from_list(opt_keys()),
- Used = ordsets:from_list(proplists:get_keys(Opts)),
- case ordsets:subtract(Used, Keys) of
- [] ->
- ok;
- L ->
- ?WARNING_MSG("Unknown options: ~p.\n", [L]),
- ok
- end.
-
--spec erllvm_is_supported() -> boolean().
-erllvm_is_supported() ->
- %% XXX: The test should really check the _target_ architecture,
- %% (hipe_target_arch), but there's no guarantee it's set.
- Arch = erlang:system_info(hipe_architecture),
- lists:member(Arch, [amd64, x86]) andalso llvm_version_is_OK().
-
--spec llvm_version_is_OK() -> boolean().
-llvm_version_is_OK() ->
- get_llvm_version() >= {3,9}.
-
--type llvm_version() :: {Major :: integer(), Minor :: integer()}.
-
--spec get_llvm_version() -> llvm_version() | {0, 0}.
-get_llvm_version() ->
- OptStr = os:cmd("opt -version"),
- SubStr = "LLVM version ", N = length(SubStr),
- case string:find(OptStr, SubStr) of
- nomatch -> % No opt available
- {0, 0};
- S ->
- case string:lexemes(string:slice(S, N), ".") of
- [MajorS, MinorS | _] ->
- case {string:to_integer(MajorS), string:to_integer(MinorS)} of
- {{Major, ""}, {Minor, _}}
- when is_integer(Major), is_integer(Minor) ->
- {Major, Minor};
- _ -> {0, 0}
- end;
- _ -> {0, 0} %XXX: Assumes no revision numbers in versioning
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src
deleted file mode 100644
index b9accf0054..0000000000
--- a/lib/hipe/main/hipe.hrl.src
+++ /dev/null
@@ -1,319 +0,0 @@
-%% -*- mode: erlang; erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Filename : hipe.hrl (automatically generated by hipe.hrl.src)
-%% Purpose : Defines some useful macros for debugging and error
-%% reporting.
-%%
-%% History : * 2000-11-03 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%%
-%% Defines:
-%% msg/2 - Works like io:format but prepends
-%% ?MSGTAG to the message.
-%% If LOGGING is defined then error_logger is used,
-%% or rather its substitute in code_server.
-%% untagged_msg/2 - Like msg/2 but without the tag.
-%% WARNING_MSG/2 - Prints a tagged warning.
-%% error_msg/2 - Logs a tagged error.
-%% debug_msg/2 - Prints a tagged msg if DEBUG is defined.
-%% IF_DEBUG(A,B) - Executes A if DEBUG is defined B otherwise.
-%% IF_DEBUG(Lvl,A,B) - Executes A if DEBUG is defined to a value >= Lvl
-%% otherwise B is executed.
-%% EXIT - Exits with added module and line info.
-%% ASSERT - Exits if the expresion does not evaluate to true.
-%% VERBOSE_ASSSERT - A message is printed even when an asertion is true.
-%% TIME_STMNT(Stmnt, String, FreeVar)
-%% - Times the statemnet Stmnt if TIMING is on.
-%% The execution time is bound to FreeVar.
-%% String is printed after the execution
-%% followed by the execution time in seconds and
-%% a newline.
-%%
-%% Flags:
-%% DEBUG - Turns on debugging. (Can be defined to a integer
-%% value to determine the level of debugging)
-%% HIPE_LOGGING - Turn on logging of messages with erl_logger.
-%% DO_ASSERT - Turn on assertions.
-%% TIMING - Turn on timing.
-%% HIPE_INSTRUMENT_COMPILER - Turn on instrumentation of the compiler.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--define(VERSION_STRING(),"%VSN%").
--define(MSGTAG, "<HiPE (v " ++ ?VERSION_STRING() ++ ")> ").
-
-%%
-%% Define the message macros with or without logging,
-%% depending on the value of the HIPE_LOGGING flag.
-%%
-
--ifdef(HIPE_LOGGING).
--define(msg(Msg, Args),
- code_server:info_msg(?MSGTAG ++ Msg, Args)).
--define(untagged_msg(Msg, Args),
- code_server:info_msg(Msg, Args)).
--define(untagged_error_msg(Msg, Args),
- code_server:error_msg(Msg, Args)).
--else.
--define(msg(Msg, Args),
- io:format(?MSGTAG ++ Msg, Args)).
--define(untagged_msg(Msg, Args),
- io:format(Msg, Args)).
--define(untagged_error_msg(Msg, Args),
- io:format(Msg, Args)).
--endif.
-
-%%
-%% Define error and warning messages.
-%%
--define(error_msg(Msg, Args),
- ?untagged_error_msg(?MSGTAG ++
- "Error: [~s:~w]: " ++ Msg,
- [?MODULE,?LINE|Args])).
--define(WARNING_MSG(Msg, Args),
- ?msg("Warning: [~s:~w]: " ++ Msg, [?MODULE,?LINE|Args])).
-
-%%
-%% Define the macros that are dependent on the debug flag.
-%%
-
--ifdef(DEBUG).
--define(debug_msg(Msg,Data), ?msg(Msg,Data)).
--define(debug_untagged_msg(Msg,Data), ?untagged_msg(Msg,Data)).
--define(IF_DEBUG(DebugAction,NoDebugAction), DebugAction).
--define(IF_DEBUG_LEVEL(Level,DebugAction,NoDebugAction),
- if (Level =< ?DEBUG) -> DebugAction; true -> NoDebugAction end).
--else.
--define(debug_msg(Msg,Data), no_debug).
--define(debug_untagged_msg(Msg,Data), no_debug).
--define(IF_DEBUG(DebugAction,NoDebugAction), NoDebugAction).
--define(IF_DEBUG_LEVEL(Level,DebugAction,NoDebugAction), NoDebugAction).
--endif.
-
-%%
-%% Define the exit macro
-%%
--define(EXIT(Reason),
- ?msg("EXITED with reason ~w @~w:~w\n", [Reason,?MODULE,?LINE]),
- erlang:error({?MODULE,?LINE,Reason})).
-
-%%
-%% Assertions.
-%%
--ifdef(DO_ASSERT).
--define(VERBOSE_ASSERT(X),
- case X of
- true ->
- io:format("Assertion ok ~w ~w\n",[?MODULE,?LINE]),
- true;
- __ASSVAL_R ->
- io:format("Assertion failed ~w ~w: ~p\n",
- [?MODULE,?LINE, __ASSVAL_R]),
- ?EXIT(assertion_failed)
- end).
--define(ASSERT(X),
- case X of
- true -> true;
- _ -> ?EXIT(assertion_failed)
- end).
--else.
--define(ASSERT(X),true).
--define(VERBOSE_ASSERT(X),true).
--endif.
-
-
-%% Use this to display info, save stuff and so on.
-%% Vars cannot be exported from __Action
--define(when_option(__Opt,__Opts,__Action),
- case proplists:get_bool(__Opt,__Opts) of
- true -> __Action;
- false -> ok
- end).
-
-%% Timing macros
-
--ifdef(TIMING).
--define(TIME_STMNT(STMNT,Msg,Timer),
- Timer = hipe_timing:start_timer(),
- STMNT,
- ?untagged_msg(Msg ++ "~.2f s\n",[hipe_timing:stop_timer(Timer)/1000])).
--else.
--define(TIME_STMNT(STMNT,Msg,Timer), STMNT).
--endif.
-
--define(start_timer(Text), hipe_timing:start(Text, ?MODULE)).
--define(stop_timer(Text), hipe_timing:stop(Text, ?MODULE)).
--define(start_hipe_timer(Timer), hipe_timing:start_hipe_timer(Timer)).
--define(stop_hipe_timer(Timer), hipe_timing:stop_hipe_timer(Timer)).
--define(get_hipe_timer_val(Timer), get(Timer)).
--define(set_hipe_timer_val(Timer, Val), put(Timer, Val)).
--define(option_time(Stmnt, Text, Options),
- begin
- ?when_option(time, Options, ?start_timer(Text)),
- fun(R) ->
- ?when_option(time, Options, ?stop_timer(Text)),
- R
- end(Stmnt)
- end).
-
--define(option_start_time(Text, Options),
- ?when_option(time, Options, ?start_timer(Text))).
-
--define(option_stop_time(Text, Options),
- ?when_option(time, Options, ?stop_timer(Text))).
-
--define(opt_start_timer(Text),
- hipe_timing:start_optional_timer(Text, ?MODULE)).
--define(opt_stop_timer(Text),
- hipe_timing:stop_optional_timer(Text, ?MODULE)).
-
-%%
-%% Turn on instrumentation of the compiler.
-%%
--ifdef(HIPE_INSTRUMENT_COMPILER).
-
--define(count_pre_ra_instructions(Options, NoInstrs),
- ?when_option(count_instrs, Options,
- put(pre_ra_instrs,
- get(pre_ra_instrs) + NoInstrs))).
--define(count_post_ra_instructions(Options, NoInstrs),
- ?when_option(count_instrs, Options,
- put(post_ra_instrs,
- get(post_ra_instrs) + NoInstrs))).
-
--define(start_time_regalloc(Options),
- ?when_option(timeregalloc, Options,
- put(regalloctime1, erlang:statistics(runtime)))).
--define(stop_time_regalloc(Options),
- ?when_option(timeregalloc, Options,
- put(regalloctime,
- get(regalloctime) +
- (element(1,erlang:statistics(runtime))
- -element(1,get(regalloctime1)))))).
--define(start_time_caller_saves(Options),
- ?when_option(timeregalloc, Options,
- put(callersavetime1,erlang:statistics(runtime)))).
--define(stop_time_caller_saves(Options),
- ?when_option(timeregalloc, Options,
- put(callersavetime,
- get(callersavetime) +
- (element(1,erlang:statistics(runtime))
- -element(1,get(callersavetime1)))))).
-
--define(count_pre_ra_temps(Options, NoTemps),
- ?when_option(count_temps, Options,
- put(pre_ra_temps,
- get(pre_ra_temps) + NoTemps))).
--define(count_post_ra_temps(Options, NoTemps),
- ?when_option(count_temps, Options,
- put(post_ra_temps,
- get(post_ra_temps) + NoTemps))).
-
--define(inc_counter(Counter, Val),
- case get(Counter) of
- undefined -> true;
- _ -> put(Counter, Val + get(Counter))
- end).
-
--define(cons_counter(Counter, Val),
- case get(Counter) of
- undefined -> true;
- _ -> put(Counter, [Val|get(Counter)])
- end).
-
--define(update_counter(Counter, Val, Op),
- case get(Counter) of
- undefined -> true;
- _ -> put(Counter, get(Counter) Op Val)
- end).
-
--define(start_ra_instrumentation(Options, NoInstrs, NoTemps),
- begin
- ?count_pre_ra_instructions(Options, NoInstrs),
- ?count_pre_ra_temps(Options, NoTemps),
- case get(counter_mem_temps) of
- undefined -> true;
- _ -> put(counter_mfa_mem_temps,[])
- end,
- ?start_time_regalloc(Options)
- end).
--define(stop_ra_instrumentation(Options, NoInstrs, NoTemps),
- begin
- ?stop_time_regalloc(Options),
- ?count_post_ra_instructions(Options, NoInstrs),
- ?cons_counter(counter_mem_temps, get(counter_mfa_mem_temps)),
- ?cons_counter(ra_all_iterations_counter, get(ra_iteration_counter)),
- put(ra_iteration_counter, 0),
- ?count_post_ra_temps(Options, NoTemps)
- end).
-
--define(add_spills(Options, NoSpills),
- ?when_option(count_spills, Options,
- put(spilledtemps, get(spilledtemps) + NoSpills))).
-
--define(optional_start_timer(Timer, Options),
- case lists:member(Timer, proplists:get_value(timers, Options++[{timers,[]}])) of
- true -> ?start_hipe_timer(Timer);
- false -> true
- end).
--define(optional_stop_timer(Timer, Options),
- case lists:member(Timer, proplists:get_value(timers, Options++[{timers,[]}])) of
- true -> ?stop_hipe_timer(Timer);
- false -> true
- end).
-
--else. %% HIPE_INSTRUMENT_COMPILER
-
--define(count_pre_ra_instructions(Options, NoInstrs), no_instrumentation).
--define(count_post_ra_instructions(Options, NoInstrs),no_instrumentation).
--define(start_time_regalloc(Options), no_instrumentation).
--define(stop_time_regalloc(Options), no_instrumentation).
--define(start_time_caller_saves(Options), no_instrumentation).
--define(stop_time_caller_saves(Options), no_instrumentation).
--define(count_pre_ra_temps(Options, NoTemps), no_instrumentation).
--define(count_post_ra_temps(Options, NoTemps), no_instrumentation).
--define(start_ra_instrumentation(Options, NoInstrs, NoTemps),no_instrumentation).
--define(stop_ra_instrumentation(Options, NoInstrs, NoTemps),no_instrumentation).
--define(add_spills(Options, NoSpills), no_instrumentation).
--define(optional_start_timer(Options, Timer), no_instrumentation).
--define(optional_stop_timer(Options, Timer), no_instrumentation).
--define(inc_counter(Counter, Val), no_instrumentation).
--define(update_counter(Counter, Val, Op), no_instrumentation).
--define(cons_counter(Counter, Val), no_instrumentation).
-
--endif. %% HIPE_INSTRUMENT_COMPILER
-
-%%----------------------------------------------------------------------------
-%% Records defined in the hipe module used in other parts of the compiler
-%%----------------------------------------------------------------------------
-
--type mpid() :: 'none' | pid().
--record(comp_servers, {pp_server :: mpid(), range :: mpid(), type :: mpid()}).
-
-%%----------------------------------------------------------------------------
-%% Basic types of the 'hipe' application used in other parts of the system
-%%----------------------------------------------------------------------------
-
--type comp_option() :: atom() | {atom(), atom()}.
--type comp_options() :: [comp_option()].
-
--type hipe_architecture() ::
- 'amd64' | 'arm' | 'powerpc' | 'ppc64' | 'ultrasparc' | 'x86'.
-
--type hipe_map() :: [{non_neg_integer(),
- 'unknown' | {'reg' | 'fp_reg' | 'spill',
- non_neg_integer()}}].
--type hipe_temp_map() :: tuple().
--type hipe_spill_map() :: [{non_neg_integer(), {'spill', non_neg_integer()}}].
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
deleted file mode 100644
index bfd23be389..0000000000
--- a/lib/hipe/main/hipe_main.erl
+++ /dev/null
@@ -1,592 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% @doc This is the HiPE compiler's main "loop".
-%%
-%% <h3>Purpose</h3>
-%%
-%% <p> This module provides code which compiles a single Erlang
-%% function, represented as linear ICode all the way down to a linear
-%% native code representation (which depends on the 'hipe_target_arch'
-%% global variable). </p>
-%%
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=====================================================================
-
--module(hipe_main).
--compile([{nowarn_deprecated_function, [{erlang,phash,2}]}]).
--export([compile_icode/4]).
-
-%%=====================================================================
-
--ifndef(DEBUG).
--define(DEBUG,1).
--endif.
-
--define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.
-
--include("hipe.hrl").
--include("../icode/hipe_icode.hrl").
-%%-include("../rtl/hipe_rtl.hrl").
-
-%%=====================================================================
-
--type comp_icode_ret() :: {'native',hipe_architecture(),{'unprofiled',_}}
- | {'rtl',tuple()} | {'llvm_binary',term()}.
-
-%%=====================================================================
-
-%% @spec compile_icode(MFA::mfa(),
-%% LinearIcode::icode(),
-%% CompilerOptions::comp_options(),
-%% CompServers::#comp_servers()) ->
-%% {native,Platform,{unprofiled,NativeCode}} | {rtl,RTLCode}
-%%
-%% @doc Compiles the Icode (in linear form) of a single MFA down to
-%% native code for the platform of the target architecture.
-%% CompilerOptions influence the steps of this compilation process.
-%%
-%% <p> In particular, the compiler option '<code>to_rtl</code>' stops
-%% compilation after translation to RTL (in which case RTL code is
-%% generated). The compiler options must have already been expanded
-%% (cf. `<a href="hipe.html">hipe:expand_options</a>'). </p>
-
--spec compile_icode(mfa(), icode(), comp_options(), #comp_servers{}) ->
- comp_icode_ret().
-
-compile_icode(MFA, LinearIcode, Options, Servers) ->
- compile_icode(MFA, LinearIcode, Options, Servers, get(hipe_debug)).
-
-%%--------------------------------------------------------------------
-%%
-%% The following constraints apply to the passes on Icode:
-%%
-%% 1. The no_comment pass must be done on linear form;
-%%
-%% 2. linear_to_cfg, which turns linear form into a CFG, must be
-%% performed before any of the passes on CFG form;
-%%
-%% 3. handle_exceptions must be performed before icode_ssa;
-%%
-%% 4. split_arith should be performed after icode_ssa for
-%% effectiveness reasons (and perhaps to work at all);
-%%
-%% 5. remove_trivial_bbs should be performed last to tidy up the CFG.
-%%
-%%---------------------------------------------------------------------
-
-compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) ->
- %% Set up gensym with the right ranges for this function.
- {LMin,LMax} = hipe_icode:icode_label_range(LinearIcode0),
- hipe_gensym:set_label_range(icode, LMin, LMax+1),
- {VMin,VMax} = hipe_icode:icode_var_range(LinearIcode0),
- hipe_gensym:set_var_range(icode, VMin, VMax+1),
- %%hipe_icode_pp:pp(LinearIcode0),
- ?opt_start_timer("Icode"),
- LinearIcode1 = icode_no_comment(LinearIcode0, Options),
- IcodeCfg0 = icode_linear_to_cfg(LinearIcode1, Options),
- %% hipe_icode_cfg:pp(IcodeCfg0),
- IcodeCfg1 = icode_handle_exceptions(IcodeCfg0, MFA, Options),
- IcodeCfg3 = icode_inline_bifs(IcodeCfg1, Options),
- pp(IcodeCfg3, MFA, icode, pp_icode, Options, Servers),
- IcodeCfg4 = icode_ssa(IcodeCfg3, MFA, Options, Servers),
- IcodeCfg5 = icode_split_arith(IcodeCfg4, MFA, Options),
- pp(IcodeCfg5, MFA, icode, pp_icode_split_arith, Options, Servers),
- IcodeCfg6 = icode_heap_test(IcodeCfg5, Options),
- IcodeCfg7 = icode_remove_trivial_bbs(IcodeCfg6, Options),
- pp(IcodeCfg7, MFA, icode, pp_opt_icode, Options, Servers),
- pp(IcodeCfg7, MFA, icode_liveness, pp_icode_liveness, Options, Servers),
- FinalIcode = hipe_icode_cfg:cfg_to_linear(IcodeCfg7),
- ?opt_stop_timer("Icode"),
- {LinearRTL, Roots} = ?option_time(icode_to_rtl(MFA, FinalIcode, Options, Servers),
- "RTL", Options),
- case proplists:get_bool(to_rtl, Options) of
- false ->
- case proplists:get_bool(to_llvm, Options) of
- false ->
- rtl_to_native(MFA, LinearRTL, Options, DebugState);
- true ->
- %% The LLVM backend returns binary code, unlike the rest of the HiPE
- %% backends which return native assembly.
- rtl_to_llvm_to_binary(MFA, LinearRTL, Roots, Options, DebugState)
- end;
- true ->
- put(hipe_debug, DebugState),
- {rtl, LinearRTL}
- end.
-
-%%----------------------------------------------------------------
-%%
-%% Icode passes
-%%
-%%----------------------------------------------------------------
-
-icode_no_comment(LinearIcode, Options) ->
- case proplists:get_bool(remove_comments, Options) of
- true ->
- ?option_time(hipe_icode:strip_comments(LinearIcode),
- "Icode remove comments", Options);
- _ ->
- LinearIcode
- end.
-
-icode_linear_to_cfg(LinearIcode, Options) ->
- ?option_time(hipe_icode_cfg:linear_to_cfg(LinearIcode),
- "transform linear Icode to CFG", Options).
-
-icode_ssa_binary_pass(IcodeSSA, Options) ->
- case proplists:get_bool(binary_opt, Options) of
- true ->
- ?option_time(hipe_icode_bincomp:cfg(IcodeSSA),
- "Icode binary pass", Options);
- false ->
- IcodeSSA
- end.
-
-icode_handle_exceptions(IcodeCfg, MFA, Options) ->
- debug("Icode fix catches: ~w~n", [MFA], Options),
- ?option_time(hipe_icode_exceptions:fix_catches(IcodeCfg),
- "Icode fix catches", Options).
-
-icode_inline_bifs(IcodeCfg, Options) ->
- case proplists:get_bool(icode_inline_bifs, Options) of
- true ->
- ?option_time(hipe_icode_inline_bifs:cfg(IcodeCfg),
- "Icode inline bifs", Options);
- false ->
- IcodeCfg
- end.
-
-%%---------------------------------------------------------------------
-
-icode_split_arith(IcodeCfg, MFA, Options) ->
- case proplists:get_bool(split_arith, Options) orelse
- proplists:get_bool(split_arith_unsafe, Options) of
- true ->
- ?option_time(hipe_icode_split_arith:cfg(IcodeCfg, MFA, Options),
- "Icode split arith", Options);
- false ->
- IcodeCfg
- end.
-
-icode_heap_test(IcodeCfg, Options) ->
- ?option_time(hipe_icode_heap_test:cfg(IcodeCfg),
- "Icode heap_test", Options).
-
-icode_remove_trivial_bbs(IcodeCfg, Options) ->
- ?option_time(hipe_icode_cfg:remove_trivial_bbs(IcodeCfg),
- "Icode trivial BB removal", Options).
-
-pp(Cfg, MFA, Level, PrintOption, Options, Servers) ->
- perform_io(pp_fun(Cfg, MFA, get_pp_module(Level),
- proplists:get_value(PrintOption, Options)),
- Servers#comp_servers.pp_server).
-
-pp_fun(Cfg, MFA, PP, PrintOptionValue) ->
- case PrintOptionValue of
- true ->
- fun() -> PP:pp(Cfg) end;
- {only, Lst} when is_list(Lst) ->
- case lists:member(MFA, Lst) of
- true ->
- fun() -> PP:pp(Cfg) end;
- false ->
- no_fun
- end;
- {only, MFA} ->
- fun() -> PP:pp(Cfg) end;
- {file, FileName} ->
- fun() ->
- {ok, File} = file:open(FileName, [write,append]),
- PP:pp(File, Cfg),
- file:close(File)
- end;
- _ ->
- no_fun
- end.
-
-get_pp_module(icode) -> hipe_icode_cfg;
-get_pp_module(rtl) -> hipe_rtl_cfg;
-get_pp_module(rtl_linear) -> hipe_rtl;
-get_pp_module(icode_liveness) -> hipe_icode_liveness;
-get_pp_module(rtl_liveness) -> hipe_rtl_liveness.
-
-perform_io(no_fun, _) -> ok;
-perform_io(Fun, PPServer) when is_pid(PPServer) ->
- PPServer ! {print, Fun},
- ok;
-perform_io(Fun, none) ->
- Fun(),
- ok.
-
-
-%%--------------------------------------------------------------------
-%%
-%% Icode passes on SSA form. The following constraints are applicable:
-%%
-%% 1. ssa_convert must be first and ssa_unconvert last
-%%
-%% 2. ssa_dead_code must be run after the other passes
-%%
-%% 3. The present order was chosen to maximize effectiveness as
-%% ssa_const_prop might make ssa_type_info more effective
-%%
-%% 4. ssa_check could be put in between all passes to make sure that
-%% they preserve SSA-ness
-%%
-%%---------------------------------------------------------------------
-
-icode_ssa(IcodeCfg0, MFA, Options, Servers) ->
- ?opt_start_timer("Icode SSA passes"),
- IcodeSSA0 = icode_ssa_convert(IcodeCfg0, Options),
- pp(IcodeSSA0, MFA, icode, pp_icode_ssa, Options, Servers),
- IcodeSSA1 = icode_ssa_const_prop(IcodeSSA0, Options),
- IcodeSSA2 = icode_ssa_dead_code_elimination(IcodeSSA1, Options),
- IcodeSSA3 = icode_ssa_copy_prop(IcodeSSA2, Options),
- IcodeSSA3a = icode_ssa_binary_pass(IcodeSSA3, Options),
- IcodeSSA4 = icode_ssa_type(IcodeSSA3a, MFA, Options, Servers),
- IcodeSSA5 = icode_ssa_dead_code_elimination(IcodeSSA4, Options),
- IcodeSSA6 = icode_ssa_struct_reuse(IcodeSSA5, Options),
- icode_ssa_check(IcodeSSA6, Options), %% just for sanity
- pp(IcodeSSA6, MFA, icode, pp_icode_ssa, Options, Servers),
- IcodeCfg = icode_ssa_unconvert(IcodeSSA6, Options),
- ?opt_stop_timer("Icode SSA passes"),
- IcodeCfg.
-
-icode_ssa_type(IcodeSSA, MFA, Options, Servers) ->
- case proplists:get_value(icode_type, Options) of
- false -> IcodeSSA;
- undefined -> IcodeSSA;
- true ->
- AnnIcode1 = icode_ssa_type_info(IcodeSSA, MFA, Options, Servers),
- pp(AnnIcode1, MFA, icode, pp_typed_icode, Options, Servers),
- AnnIcode2 =
- case proplists:get_bool(inline_fp, Options) of
- true -> hipe_icode_fp:cfg(AnnIcode1);
- false -> AnnIcode1
- end,
- AnnIcode3 = icode_range_analysis(AnnIcode2, MFA, Options, Servers),
- AnnIcode4 = icode_eliminate_safe_calls(AnnIcode3, Options),
- pp(AnnIcode4, MFA, icode, pp_range_icode, Options, Servers),
- hipe_icode_type:unannotate_cfg(AnnIcode4)
- end.
-
-icode_ssa_convert(IcodeCfg, Options) ->
- ?option_time(hipe_icode_ssa:convert(IcodeCfg),
- "Icode SSA conversion", Options).
-
-icode_ssa_const_prop(IcodeSSA, Options) ->
- case proplists:get_bool(icode_ssa_const_prop, Options) of
- true ->
- Tmp = ?option_time(hipe_icode_ssa_const_prop:propagate(IcodeSSA),
- "Icode SSA sparse conditional constant propagation", Options),
- ?option_time(hipe_icode_ssa:remove_dead_code(Tmp),
- "Icode SSA dead code elimination pass 1", Options);
- false ->
- IcodeSSA
- end.
-
-icode_ssa_copy_prop(IcodeSSA, Options) ->
- case proplists:get_bool(icode_ssa_copy_prop, Options) of
- true ->
- ?option_time(hipe_icode_ssa_copy_prop:cfg(IcodeSSA),
- "Icode SSA copy propagation", Options);
- false ->
- IcodeSSA
- end.
-
-icode_ssa_struct_reuse(IcodeSSA, Options) ->
- case proplists:get_value(icode_ssa_struct_reuse, Options) of
- true ->
- ?option_time(hipe_icode_ssa_struct_reuse:struct_reuse(IcodeSSA),
- "Icode SSA structure reuse", Options);
- _ ->
- IcodeSSA
- end.
-
-icode_ssa_type_info(IcodeSSA, MFA, Options, Servers) ->
- ?option_time(hipe_icode_type:cfg(IcodeSSA, MFA, Options, Servers),
- io_lib:format("Icode SSA type info for ~p", [MFA]), Options).
-
-icode_range_analysis(IcodeSSA, MFA, Options, Servers) ->
- case proplists:get_bool(icode_range, Options) of
- true ->
- ?option_time(hipe_icode_range:cfg(IcodeSSA, MFA, Options, Servers),
- "Icode SSA integer range analysis", Options);
- false ->
- IcodeSSA
- end.
-
-icode_eliminate_safe_calls(IcodeSSA, Options) ->
- case proplists:get_bool(icode_call_elim, Options) of
- true ->
- ?option_time(hipe_icode_call_elim:cfg(IcodeSSA),
- "Icode SSA safe call elimination", Options);
- false ->
- IcodeSSA
- end.
-
-icode_ssa_dead_code_elimination(IcodeSSA, Options) ->
- IcodeSSA1 = ?option_time(hipe_icode_ssa:remove_dead_code(IcodeSSA),
- "Icode SSA dead code elimination pass 2",
- Options),
- hipe_icode_cfg:remove_unreachable_code(IcodeSSA1).
-
-icode_ssa_check(IcodeSSA, Options) ->
- ?when_option(icode_ssa_check, Options,
- ?option_time(hipe_icode_ssa:check(IcodeSSA),
- "Icode check for SSA-ness", Options)).
-
-icode_ssa_unconvert(IcodeSSA, Options) ->
- ?option_time(hipe_icode_ssa:unconvert(IcodeSSA),
- "Icode SSA unconversion", Options).
-
-
-%%=====================================================================
-%%
-%% @spec icode_to_rtl(MFA::mfa(), Icode, options()) -> Linear_RTL_code
-%% @end
-%%=====================================================================
-
-%%---------------------------------------------------------------------
-%%
-%% The passes on RTL are as follows:
-%%
-%% 1. The translation to RTL, in particular the way exceptions are
-%% currently handled in RTL, introduces some unreachable code.
-%% Therefore, unreachable code is removed early on followed by a
-%% pass that removes trivial basic blocks so as to have smaller
-%% code to play with.
-%%
-%% 2. Code is then converted to SSA so as to perform as many
-%% optimizations as possible in this pass.
-%% Currently, the following optimizations are performed on SSA:
-%% - sparse conditional constant propagation (controlled by an option)
-%% - dead code elimination
-%% - detection of available exceptions
-%% - partial redundancy elimination (controlled by an option)
-%% Finally, code is converted back to non-SSA form.
-%%
-%% 3. rtl_symbolic expands some symbolic instructions.
-%%
-%% 4. rtl_lcm performs a lazy code motion on RTL.
-%%
-%%----------------------------------------------------------------------
-
-icode_to_rtl(MFA, Icode, Options, Servers) ->
- debug("ICODE -> RTL: ~w, ~w~n", [MFA, hash(Icode)], Options),
- LinearRTL = translate_to_rtl(Icode, Options),
- pp(LinearRTL, MFA, rtl_linear, pp_rtl_linear, Options, Servers),
- RtlCfg = initialize_rtl_cfg(LinearRTL, Options),
- %% hipe_rtl_cfg:pp(RtlCfg),
- RtlCfg0 = hipe_rtl_cfg:remove_unreachable_code(RtlCfg),
- RtlCfg1 = hipe_rtl_cfg:remove_trivial_bbs(RtlCfg0),
- %% hipe_rtl_cfg:pp(RtlCfg1),
- RtlCfg2 = rtl_ssa(RtlCfg1, Options),
- RtlCfg3 = rtl_symbolic(RtlCfg2, Options),
- %% hipe_rtl_cfg:pp(RtlCfg3),
- pp(RtlCfg3, MFA, rtl_liveness, pp_rtl_liveness, Options, Servers),
- RtlCfg4 = rtl_lcm(RtlCfg3, Options),
- %% LLVM: A liveness analysis on RTL must be performed in order to find the GC
- %% roots and explicitly mark them (in RTL) when they go out of scope (only
- %% when the LLVM backend is used).
- {RtlCfg5, Roots} =
- case proplists:get_bool(to_llvm, Options) of
- false ->
- {RtlCfg4, []};
- true ->
- hipe_llvm_liveness:analyze(RtlCfg4)
- end,
- pp(RtlCfg5, MFA, rtl, pp_rtl, Options, Servers),
- case proplists:get_bool(no_verify_gcsafe, Options) of
- true -> ok;
- false ->
- ok = hipe_rtl_verify_gcsafe:check(RtlCfg5)
- end,
- LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg5),
- LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
- %% hipe_rtl:pp(standard_io, LinearRTL2),
- {LinearRTL2, Roots}.
-
-translate_to_rtl(Icode, Options) ->
- %% GC tests should have been added in the conversion to Icode.
- ?option_time(hipe_icode2rtl:translate(Icode, Options),
- "translate", Options).
-
-initialize_rtl_cfg(LinearRTL, Options) ->
- ?option_time(hipe_rtl_cfg:init(LinearRTL), "to cfg", Options).
-
-rtl_symbolic(RtlCfg, Options) ->
- ?option_time(hipe_rtl_symbolic:expand(RtlCfg),
- "Expansion of symbolic instructions", Options).
-
-%%----------------------------------------------------------------------
-%%
-%% RTL passes on SSA form. The following constraints are applicable:
-%%
-%% 1. ssa_convert must be first and ssa_unconvert last.
-%%
-%% 2. dead_code_elimination should be performed after conditional
-%% constant propagation in order to cleanup dead code that might
-%% be created by that pass.
-%%
-%% 3. avail_expr ... (PER ADD THIS)
-%%
-%% 4. rtl_ssapre performs A-SSAPRE and has to be done after all other
-%% optimizations.
-%%
-%% 5. ssa_check could be put in between all passes to make sure that
-%% they preserve SSA-ness.
-%%
-%%----------------------------------------------------------------------
-
-rtl_ssa(RtlCfg0, Options) ->
- case proplists:get_bool(rtl_ssa, Options) of
- true ->
- ?opt_start_timer("RTL SSA passes"),
- RtlSSA0 = rtl_ssa_convert(RtlCfg0, Options),
- RtlSSA1 = rtl_ssa_const_prop(RtlSSA0, Options),
- %% RtlSSA1a = rtl_ssa_copy_prop(RtlSSA1, Options),
- RtlSSA2 = rtl_ssa_dead_code_elimination(RtlSSA1, Options),
- RtlSSA3 = rtl_ssa_avail_expr(RtlSSA2, Options),
- RtlSSA4 = rtl_ssapre(RtlSSA3, Options),
- %% rtl_ssa_check(RtlSSA4, Options), %% just for sanity
- RtlCfg = rtl_ssa_unconvert(RtlSSA4, Options),
- case proplists:get_bool(pp_rtl_ssa, Options) of
- true ->
- io:format("%%------------- After SSA un-conversion -----------\n"),
- hipe_rtl_cfg:pp(RtlCfg);
- false ->
- ok
- end,
- ?opt_stop_timer("RTL SSA passes"),
- RtlCfg;
- false ->
- RtlCfg0
- end.
-
-rtl_ssa_convert(RtlCfg, Options) ->
- case proplists:get_bool(pp_rtl_ssa, Options) of
- true ->
- io:format("%%------------- Before SSA conversion --------------\n"),
- hipe_rtl_cfg:pp(RtlCfg),
- io:format("%%------------- After SSA conversion --------------\n"),
- RtlCfgSSA = hipe_rtl_ssa:convert(RtlCfg),
- hipe_rtl_cfg:pp(RtlCfgSSA),
- io:format("%%------------- SSA check warnings below -----------\n"),
- hipe_rtl_ssa:check(RtlCfgSSA),
- RtlCfgSSA;
- false ->
- ?option_time(hipe_rtl_ssa:convert(RtlCfg),
- "RTL SSA conversion", Options)
- end.
-
-rtl_ssa_const_prop(RtlCfgSSA, Options) ->
- case proplists:get_bool(rtl_ssa_const_prop, Options) of
- true ->
- ?option_time(hipe_rtl_ssa_const_prop:propagate(RtlCfgSSA),
- "RTL SSA sparse conditional constant propagation", Options);
- false ->
- RtlCfgSSA
- end.
-
-rtl_ssa_dead_code_elimination(RtlCfgSSA, Options) ->
- ?option_time(hipe_rtl_ssa:remove_dead_code(RtlCfgSSA),
- "RTL SSA dead code elimination", Options).
-
-rtl_ssa_avail_expr(RtlCfgSSA, Options) ->
- ?option_time(hipe_rtl_ssa_avail_expr:cfg(RtlCfgSSA),
- "RTL SSA heap optimizations", Options).
-
-%%---------------------------------------------------------------------
-
-rtl_ssapre(RtlCfg, Options) ->
- case proplists:get_bool(rtl_ssapre, Options) of
- true ->
- ?opt_start_timer("Partial Redundancy Elimination (A-SSAPRE)"),
- NewRtlCfg = hipe_rtl_ssapre:rtl_ssapre(RtlCfg, Options),
- ?opt_stop_timer("Partial Redundancy Elimination (A-SSAPRE)"),
- NewRtlCfg;
- false ->
- RtlCfg
- end.
-
-%%---------------------------------------------------------------------
-
-rtl_ssa_unconvert(RtlCfgSSA, Options) ->
- ?option_time(hipe_rtl_ssa:unconvert(RtlCfgSSA),
- "RTL SSA un-convert", Options).
-
-%%---------------------------------------------------------------------
-
-rtl_lcm(RtlCfg, Options) ->
- case proplists:get_bool(rtl_lcm, Options) of
- true ->
- ?opt_start_timer("RTL lazy code motion"),
- %% ?option_time(hipe_rtl_lcm:rtl_lcm(RtlCfg, Options),
- %% "RTL lazy code motion", Options);
- RtlCfg1 = hipe_rtl_lcm:rtl_lcm(RtlCfg, Options),
- ?opt_stop_timer("RTL lazy code motion"),
- RtlCfg1;
- false ->
- RtlCfg
- end.
-
-%%=====================================================================
-%% Translation to native code takes place in the corresponding back-end
-%%=====================================================================
-
-rtl_to_native(MFA, LinearRTL, Options, DebugState) ->
- ?opt_start_timer("Native code"),
- LinearNativeCode =
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_sparc_main:rtl_to_sparc(MFA, LinearRTL, Options);
- powerpc ->
- hipe_ppc_main:rtl_to_ppc(MFA, LinearRTL, Options);
- ppc64 ->
- hipe_ppc_main:rtl_to_ppc(MFA, LinearRTL, Options);
- arm ->
- hipe_arm_main:rtl_to_arm(MFA, LinearRTL, Options);
- x86 ->
- hipe_x86_main:rtl_to_x86(MFA, LinearRTL, Options);
- amd64 ->
- hipe_amd64_main:rtl_to_amd64(MFA, LinearRTL, Options)
- end,
- ?opt_stop_timer("Native code"),
- put(hipe_debug, DebugState),
- LinearNativeCode.
-
-%% Translate Linear RTL to binary code using LLVM.
-rtl_to_llvm_to_binary(MFA, LinearRTL, Roots, Options, DebugState) ->
- ?opt_start_timer("LLVM native code"),
- %% BinaryCode is a tuple, as defined in llvm/hipe_llvm_main module, which
- %% contains the binary code together with info needed by the loader, e.g.
- %% ConstTab, Refs, LabelMap, etc.
- BinaryCode = hipe_llvm_main:rtl_to_native(MFA, LinearRTL, Roots, Options),
- ?opt_stop_timer("LLVM native code"),
- put(hipe_debug, DebugState),
- {llvm_binary, BinaryCode}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Debugging stuff ...
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-debug(Text, Args, Options) ->
- ?when_option(debug, Options, ?msg(Text,Args)).
-
-hash(X) ->
- erlang:phash(X, 16#7f3f5f1).
diff --git a/lib/hipe/misc/Makefile b/lib/hipe/misc/Makefile
deleted file mode 100644
index e5033e444b..0000000000
--- a/lib/hipe/misc/Makefile
+++ /dev/null
@@ -1,117 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-ifdef HIPE_ENABLED
-HIPE_MODULES = hipe_data_pp hipe_pack_constants hipe_sdi hipe_segment_trees
-else
-HIPE_MODULES =
-endif
-MODULES = hipe_consttab hipe_gensym $(HIPE_MODULES)
-
-HRL_FILES= hipe_sdi.hrl
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars +warn_missing_spec +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/misc"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/misc"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-distclean: clean
-realclean: clean
-
-$(EBIN)/hipe_consttab.beam: hipe_consttab.hrl
-$(EBIN)/hipe_data_pp.beam: hipe_consttab.hrl
-$(EBIN)/hipe_pack_constants.beam: hipe_consttab.hrl ../../kernel/src/hipe_ext_format.hrl
-$(EBIN)/hipe_sdi.beam: hipe_sdi.hrl
diff --git a/lib/hipe/misc/hipe_consttab.erl b/lib/hipe/misc/hipe_consttab.erl
deleted file mode 100644
index 741bdb2094..0000000000
--- a/lib/hipe/misc/hipe_consttab.erl
+++ /dev/null
@@ -1,502 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% @doc
-%% CONSTTAB - maps labels to constants.
-%% <p>
-%% <strong> Note:</strong> 'constant' is a misnomer throughout this code.
-%% </p>
-%% <p>
-%% There are two different types of constants that can be stored:
-%% <ul>
-%% <li>Erlang terms</li>
-%% <li>Blocks of binary data</li>
-%% </ul>
-%% </p>
-%% <p>
-%% Erlang terms are just what you would expect, you can store any
-%% Erlang term in the constant table.
-%% The term is assumed to be loaded to the place in memory denoted by the
-%% label returned by the insertion function.
-%% </p>
-%% <p>
-%% Blocks of binary data comes in some different shapes, you can
-%% either insert a block of integers (of byte, word (4 bytes), or
-%% word (8 bytes) size) or a list of references to code.
-%% These references will then be threated as word sized addresses
-%% and can be used for jumptables.
-%% The list of references can have an optional ordering, so that
-%% you can create a jumptable that will be sorted on the load-time
-%% representation of e.g. atoms.
-%% </p>
-%% @type ctdata() = #ctdata{}. See {@link mk_ctdata/4}.
-%% @type ct_type() = term | block | sorted_block | ref
-%% @type data() = term() | [term()] | [byte()] | internal().
-%% This type is dependent on ct_type
-%% <ul>
-%% <li> If ct_type() = term -- data() = term() </li>
-%% <li> If ct_type() = block -- data() = [byte()] </li>
-%% <li> If ct_type() = sorted_block -- data() = [term()] </li>
-%% <li> If ct_type() = ref -- data() = internal() </li>
-%% </ul>
-%% @type ct_alignment().
-%% Alignment is always a power of two equal to the number of bytes
-%% in the machine word.
-%% @end
-%% @type byte(). <code>B</code> is an integer between 0 and 255.
-%% @type hipe_consttab().
-%% An abstract datatype for storing data.
-%% @end
-%% Internal note:
-%% A hipe_consttab is a tuple {Data, ReferedLabels, NextConstLabel}
-%% @type hipe_constlbl().
-%% An abstract datatype for referring to data.
-%% @type element_type() = byte | word
-%% @type block() = [integer() | label_ref()]
-%% @type label_ref() = {label, Label::code_label()}
-%% @type code_label() = hipe_sparc:label_name() | hipe_x86:label_name()
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--module(hipe_consttab).
-
--export([new/0, % new() -> ConstTab
- insert_term/2, % insert_term(ConstTab, Term) -> {NewTab, Lbl}
- %% insert_fun/2, % insert_term(ConstTab, Fun) -> {NewTab, Lbl}
- %% insert_word/2, % insert_word(ConstTab, Value) -> {NewTab, Lbl}
- insert_sorted_block/2, % insert_word(ConstTab, ValueList) ->
- % {NewTab, Lbl}
- insert_sorted_block/4,
- insert_block/3,
- insert_binary_const/3,
- %% insert_global_word/2,
- %% insert_global_block/4,
- %% update_word/3, % update_word(ConstTab, Value) -> {NewTab, Lbl}
- %% update_block/5,
- %% update_global_word/3,
- %% update_global_block/5,
- lookup/2, % lookup(Key, ConstTab) -> [Term|Block]
- labels/1, % labels(ConstTab) -> LabelList
- referred_labels/1, % referred_labels(ConstTab) -> LabelList
- update_referred_labels/2,
- decompose/1,
- size_of/1,
- const_type/1,
- const_align/1,
- const_exported/1,
- const_data/1,
- const_size/1
- %% block_size/1 % size of a block in bytes
- ]).
-
-%%-----------------------------------------------------------------------------
-
--include("hipe_consttab.hrl").
-
--type code_label() :: term(). % XXX: FIXME
--type label_ref() :: {'label', code_label()}.
--type block() :: [hipe_constlbl() | label_ref()].
-
--type element_type() :: 'byte' | 'word'.
-
--type sort_order() :: term(). % XXX: FIXME
-
-%%-----------------------------------------------------------------------------
-
-%% @doc Create a new constant table.
--spec new() -> hipe_consttab().
-new() -> {tree_empty(), [], 0}.
-
-
-%% @spec insert_term(ConstTab::hipe_consttab(), Term::term()) -> {NewTab, Lbl}
-%% NewTab = hipe_consttab()
-%% Lbl = hipe_constlbl()
-%% @doc Inserts an erlang term into the const table if the term was not
-%% present before, otherwise do nothing.
--spec insert_term(hipe_consttab(), term()) -> {hipe_consttab(),hipe_constlbl()}.
-insert_term(ConstTab, Term) ->
- case lookup_const(ConstTab, term, word_size(), false, Term) of
- {value, Label} ->
- {ConstTab, Label};
- none ->
- insert_const(ConstTab, term, word_size(), false, Term)
- end.
-
-
-%% %% @spec insert_fun(ConstTab::hipe_consttab(), Term::term()) -> {NewTab, Lbl}
-%% %% NewTab = hipe_consttab()
-%% %% Lbl = hipe_constlbl()
-%% %% @doc Inserts a Fun into the const table.
-%% %% Don't ask me what this is for...
-%% -spec insert_fun(hipe_consttab(), term()) -> {hipe_consttab(), hipe_constlbl()}.
-%% insert_fun(ConstTab, Fun) ->
-%% insert_const(ConstTab, term, word_size(), false, Fun).
-
-
-%% @spec (ConstTab::hipe_consttab(), TermList::[term()]) -> {NewTab, Lbl}
-%% NewTab = hipe_consttab()
-%% Lbl = hipe_constlbl()
-%% @doc Inserts a list of terms into the const table.
--spec insert_sorted_block(hipe_consttab(), [term()]) -> {hipe_consttab(), hipe_constlbl()}.
-insert_sorted_block(CTab, TermList) ->
- insert_const(CTab, sorted_block, word_size(), false, TermList).
-
-%% %% @spec (ConstTab::hipe_consttab(), InitVal::integer()) -> {NewTab, Lbl}
-%% %% NewTab = hipe_consttab()
-%% %% Lbl = hipe_constlbl()
-%% %% @doc Inserts a word into the const table.
-%% %% Shorthand for inserting a word.
-%% insert_word(ConstTab, InitVal) ->
-%% insert_block(ConstTab, word, [InitVal]).
-
-%% %% @spec (ConstTab::hipe_consttab(), InitVal::integer()) -> {NewTab, Lbl}
-%% %% NewTab = hipe_consttab()
-%% %% Lbl = hipe_constlbl()
-%% %% @doc Inserts a word into the const table.
-%% %% This constant should be exported from the function...
-%% %% <strong>Note</strong> Global constants are
-%% %% not supported in current version of HiPE.
-%% insert_global_word(ConstTab, InitVal) ->
-%% insert_global_block(ConstTab, word_size(), word, [InitVal]).
-
-
-%% @spec (ConstTab::hipe_consttab(),
-%% ElementType::element_type(),
-%% InitList::block()) -> {hipe_consttab(), hipe_constlbl()}
-%% @doc Inserts a block into the const table.
-%% The block can consist of references to labels in the code.
-%% This is used for jump tables. These references should be tracked
-%% and the corresponding BBs should not be considered dead.
--spec insert_block(hipe_consttab(), element_type(), block()) ->
- {hipe_consttab(), hipe_constlbl()}.
-insert_block({ConstTab, RefToLabels, NextLabel}, ElementType, InitList) ->
- ReferredLabels = get_labels(InitList, []),
- NewRefTo = ReferredLabels ++ RefToLabels,
- {NewTa, Id} = insert_const({ConstTab, NewRefTo, NextLabel},
- block, size_of(ElementType), false,
- {ElementType,InitList}),
- {insert_backrefs(NewTa, Id, ReferredLabels), Id}.
-
-%% @doc Inserts a binary constant literal into the const table.
--spec insert_binary_const(hipe_consttab(), ct_alignment(), binary()) ->
- {hipe_consttab(), hipe_constlbl()}.
-insert_binary_const(ConstTab, Alignment, Binary)
- when (Alignment =:= 4 orelse Alignment =:= 8 orelse Alignment =:= 16
- orelse Alignment =:= 32), is_binary(Binary),
- size(Binary) rem Alignment =:= 0 ->
- insert_const(ConstTab, block, Alignment, false,
- {byte, binary_to_list(Binary)}).
-
-
-%% @spec (ConstTab::hipe_consttab(), ElementType::element_type(),
-%% InitList::block(), SortOrder) -> {hipe_consttab(), hipe_constlbl()}
-%% @doc Inserts a block into the const table.
-%% The block can consist of references to labels in the code.
-%% This is used for jump tables. These references should be tracked
-%% and the corresponding BBs should not be considered dead.
-%% At load-time the block will be sorted according to SortOrder.
-%% This is used to make jump tables on atom indices.
--spec insert_sorted_block(hipe_consttab(), element_type(), block(), sort_order()) ->
- {hipe_consttab(), hipe_constlbl()}.
-insert_sorted_block({ConstTab, RefToLabels, NextLabel},
- ElementType, InitList, SortOrder) ->
- ReferredLabels = get_labels(InitList, []),
- NewRefTo = ReferredLabels ++ RefToLabels,
- {NewTa, Id} = insert_const({ConstTab, NewRefTo, NextLabel},
- block, word_size(), false,
- {ElementType, InitList, SortOrder}),
- {insert_backrefs(NewTa, Id, ReferredLabels), Id}.
-
-insert_backrefs(Tbl, From, ToLabels) ->
- lists:foldl(fun(To, Tab) ->
- insert_ref(Tab, From, To)
- end, Tbl, ToLabels).
-
-insert_ref({Table, RefToLabels, NextLblNr}, From, To) ->
- Ref = {To, ref},
- case tree_lookup(Ref, Table) of
- none ->
- {tree_insert(Ref, [From], Table), RefToLabels, NextLblNr};
- {value, RefList} ->
- {tree_update(Ref, [From|RefList], Table), RefToLabels, NextLblNr}
- end.
-
-find_refs(To, {Table,_,_}) ->
- %% returns 'none' or {value, V}
- tree_lookup({To, ref}, Table).
-
-delete_ref(To, {ConstTab, RefToLabels, NextLabel}) ->
- {tree_delete({To, ref}, ConstTab), RefToLabels, NextLabel}.
-
-%% TODO: handle refs to labels.
-%% insert_global_block(ConstTab, Align, ElementType, InitList) ->
-%% ByteList = decompose(size_of(ElementType), InitList),
-%% insert_const(ConstTab, block, Align, true, {byte,ByteList}).
-
-get_labels([{label, L}|Rest], Acc) ->
- get_labels(Rest, [L|Acc]);
-get_labels([I|Rest], Acc) when is_integer(I) ->
- get_labels(Rest, Acc);
-get_labels([], Acc) ->
- Acc.
-
-%% @spec size_of(element_type()) -> pos_integer()
-%% @doc Returns the size in bytes of an element_type.
--spec size_of(element_type()) -> pos_integer().
-size_of(byte) -> 1;
-size_of(word) -> word_size().
-
-%% @spec decompose({element_type(), block()}) -> [byte()]
-%% @doc Turns a block into a list of bytes.
-%% <strong>Note:</strong> Be careful with the byte order here.
--spec decompose({element_type(), block()}) -> [byte()].
-decompose({ElementType, Data}) ->
- decompose(size_of(ElementType), Data).
-
-decompose(_Bytes, []) ->
- [];
-decompose(Bytes, [X|Xs]) ->
- number_to_bytes(Bytes, X, decompose(Bytes, Xs)).
-
-number_to_bytes(0, X, Bytes) when is_integer(X) ->
- Bytes;
-number_to_bytes(N, X, Bytes) ->
- Byte = X band 255,
- number_to_bytes(N-1, X bsr 8, [Byte|Bytes]).
-
-%% @spec block_size({element_type(), block()}) -> non_neg_integer()
-%% @doc Returns the size in bytes of a block.
-block_size({ElementType, Block}) ->
- length(Block) * size_of(ElementType);
-block_size({ElementType, Block, _SortOrder}) ->
- length(Block) * size_of(ElementType).
-
-
-%%--------------------
-%% ctdata and friends
-%%--------------------
-
--type ct_type() :: 'block' | 'ref' | 'sorted_block' | 'term'.
-
--record(ctdata, {type :: ct_type(),
- alignment :: ct_alignment(),
- exported :: boolean(),
- data :: term()}).
--type ctdata() :: #ctdata{}.
-
--spec mk_ctdata(Type::ct_type(), Alignment::ct_alignment(),
- Exported::boolean(), Data::term()) -> ctdata().
-mk_ctdata(Type, Alignment, Exported, Data) ->
- #ctdata{type = Type, alignment = Alignment, exported = Exported, data = Data}.
-
--spec const_type(ctdata()) -> ct_type().
-const_type(#ctdata{type = Type}) -> Type.
-
--spec const_align(ctdata()) -> ct_alignment().
-const_align(#ctdata{alignment = Alignment}) -> Alignment.
-
--spec const_exported(ctdata()) -> boolean().
-const_exported(#ctdata{exported = Exported}) -> Exported.
-
--spec const_data(ctdata()) -> term().
-const_data(#ctdata{data = Data}) -> Data.
-
--spec update_const_data(ctdata(), {_,[_]} | {_,[_],_}) -> ctdata().
-update_const_data(CTData, Data) ->
- CTData#ctdata{data = Data}.
-
-%% @doc Returns the size in bytes.
--spec const_size(ctdata()) -> non_neg_integer().
-const_size(Constant) ->
- case const_type(Constant) of
- %% term: you can't and shouldn't ask for its size
- block -> block_size(const_data(Constant));
- sorted_block -> length(const_data(Constant)) * word_size()
- end.
-
--spec word_size() -> ct_alignment().
-word_size() ->
- hipe_rtl_arch:word_size().
-
-
-%%--------------------
-%% Update a label
-%%--------------------
-
-
-%% TODO: Remove RefsTOfrom overwitten labels...
-%% update_word(ConstTab, Label, InitVal) ->
-%% update_block(ConstTab, Label, word_size(), word, [InitVal]).
-%%
-%% update_global_word(ConstTab, Label, InitVal) ->
-%% update_global_block(ConstTab, Label, word_size(), word, [InitVal]).
-
-%%
-%% Update info for an existing label
-%%
-%% Returns NewTable
-%%
-%%
-%% update_block(ConstTab, Label, Align, ElementType, InitList) ->
-%% ByteList = decompose(size_of(ElementType), InitList),
-%% update_const(ConstTab, Label, block, Align, false, {ElementType,ByteList}).
-
-update_block_labels(ConstTab, DataLbl, OldLbl, NewLbl) ->
- Const = lookup(DataLbl, ConstTab),
- Old = {label, OldLbl},
- case const_data(Const) of
- {Type, Data} ->
- NewData = update_data(Data, Old, NewLbl),
- update(ConstTab, DataLbl, update_const_data(Const, {Type,NewData}));
- {Type, Data, Order} ->
- NewData = update_data(Data, Old, NewLbl),
- update(ConstTab, DataLbl, update_const_data(Const, {Type,NewData,Order}))
- end.
-
-update_data(Data, Old, New) ->
- [if Lbl =:= Old -> {label, New}; true -> Lbl end || Lbl <- Data].
-
-%% update_global_block(ConstTab, Label, Align, ElementType, InitList) ->
-%% ByteList = decompose(size_of(ElementType), InitList),
-%% update_const(ConstTab, Label, block, Align, true, ByteList).
-
-%%
-%% Insert a constant in the table, returns {NewTable, Label}.
-%%
-
-insert_const({Table, RefToLabels, NextLblNr}, Type, Alignment, Exported, Data) ->
- Const = mk_ctdata(Type, Alignment, Exported, Data),
- {{tree_insert(NextLblNr, Const, Table), RefToLabels, NextLblNr+1},
- NextLblNr}.
-
-%% %% Update information for a label, returns NewTable.
-%% %% (Removes old info.)
-%%
-%% update_const({Table, RefToLabels, NextLblNr}, Label, Type, Alignment, Exported, Data) ->
-%% Const = mk_ctdata(Type, Alignment, Exported, Data),
-%% {tree_update(Label, Const, Table), RefToLabels, NextLblNr}.
-
-update({Table, RefToLabels, NextLblNr}, Label, NewConst) ->
- {tree_update(Label, NewConst, Table), RefToLabels, NextLblNr}.
-
-%% @spec lookup(hipe_constlbl(), hipe_consttab()) -> ctdata()
-%% @doc Lookup a label.
--spec lookup(hipe_constlbl(), hipe_consttab()) -> ctdata().
-lookup(Lbl, {Table, _RefToLabels, _NextLblNr}) ->
- tree_get(Lbl, Table).
-
-%% Find out if a constant term is present in the constant table.
-lookup_const({Table, _RefToLabels, _NextLblNr},
- Type, Alignment, Exported, Data) ->
- Const = mk_ctdata(Type, Alignment, Exported, Data),
- tree_lookup_key_for_value(Const, Table).
-
-%% @doc Return the labels bound in a table.
--spec labels(hipe_consttab()) -> [hipe_constlbl() | {hipe_constlbl(), 'ref'}].
-labels({Table, _RefToLabels, _NextLblNr}) ->
- tree_keys(Table).
-
-%% @spec referred_labels(hipe_consttab()) -> [hipe_constlbl()]
-%% @doc Return the referred labels bound in a table.
--spec referred_labels(hipe_consttab()) -> [hipe_constlbl()].
-referred_labels({_Table, RefToLabels, _NextLblNr}) ->
- RefToLabels.
-
-
-%%
-%% Change label names in constant blocks (jump_tables).
-%%
--spec update_referred_labels(hipe_consttab(),
- [{hipe_constlbl(), hipe_constlbl()}]) ->
- hipe_consttab().
-update_referred_labels(Table, LabelMap) ->
- %% io:format("LabelMap: ~w\nTb:~w\n", [LabelMap, Table]),
- {Tb, Refs, Next} =
- lists:foldl(
- fun({OldLbl, NewLbl}, Tbl) ->
- case find_refs(OldLbl, Tbl) of
- none ->
- Tbl;
- {value, DataLbls} ->
- %% A label may be referred several times.
- UniqueLbls = ordsets:from_list(DataLbls),
- lists:foldl(fun(DataLbl, AccTbl) ->
- insert_ref(
- delete_ref(OldLbl,
- update_block_labels(AccTbl, DataLbl, OldLbl, NewLbl)),
- DataLbl, NewLbl)
- end,
- Tbl,
- UniqueLbls)
- end
- end,
- Table,
- LabelMap),
- NewRefs = [case lists:keyfind(Lbl, 1, LabelMap) of
- {_, New} -> New;
- false -> Lbl
- end || Lbl <- Refs],
- %% io:format("NewTb:~w\n", [{Tb, NewRefs, Next}]),
- {Tb, NewRefs, Next}.
-
-
-%%-----------------------------------------------------------------------------
-%% primitives for constants
-%%-----------------------------------------------------------------------------
-
-%% Since using `gb_trees' is not safe because of term ordering, we use
-%% the `dict' module instead since it matches with =:= on the keys.
-
-tree_keys(T) ->
- dict:fetch_keys(T).
-
--spec tree_to_list(dict:dict()) -> [{_, _}].
-tree_to_list(T) ->
- dict:to_list(T).
-
-tree_get(Key, T) ->
- dict:fetch(Key, T).
-
-tree_update(Key, Val, T) ->
- dict:store(Key, Val, T).
-
-tree_insert(Key, Val, T) ->
- dict:store(Key, Val, T).
-
-tree_delete(Key, T) ->
- dict:erase(Key, T).
-
-tree_lookup(Key, T) ->
- case dict:find(Key, T) of
- {ok, Val} ->
- {value, Val};
- error ->
- none
- end.
-
--spec tree_empty() -> dict:dict().
-tree_empty() ->
- dict:new().
-
--spec tree_lookup_key_for_value(ctdata(), dict:dict()) -> 'none' | {'value', _}.
-tree_lookup_key_for_value(Val, T) ->
- tree_lookup_key_for_value_1(tree_to_list(T), Val).
-
--spec tree_lookup_key_for_value_1([{_,_}], ctdata()) -> 'none' | {'value', _}.
-tree_lookup_key_for_value_1([{Key, Val}|_], Val) ->
- {value, Key};
-tree_lookup_key_for_value_1([_|Left], Val) ->
- tree_lookup_key_for_value_1(Left, Val);
-tree_lookup_key_for_value_1([], _Val) ->
- none.
diff --git a/lib/hipe/misc/hipe_consttab.hrl b/lib/hipe/misc/hipe_consttab.hrl
deleted file mode 100644
index 4d2d357a0b..0000000000
--- a/lib/hipe/misc/hipe_consttab.hrl
+++ /dev/null
@@ -1,22 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-----------------------------------------------------------------------------
-
--type ct_alignment() :: 4 | 8 | 16 | 32.
-
--type hipe_constlbl() :: non_neg_integer().
--type hipe_consttab() :: {dict:dict(), [hipe_constlbl()], hipe_constlbl()}.
-
-%%-----------------------------------------------------------------------------
diff --git a/lib/hipe/misc/hipe_data_pp.erl b/lib/hipe/misc/hipe_data_pp.erl
deleted file mode 100644
index 2c737b6d78..0000000000
--- a/lib/hipe/misc/hipe_data_pp.erl
+++ /dev/null
@@ -1,152 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Module : hipe_data_pp
-%% Purpose :
-%% Notes :
-%% History : * 2001-02-25 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_data_pp).
--export([pp/4]).
-
-%%-----------------------------------------------------------------------------
-
--include("hipe_consttab.hrl").
-
--type hipe_code_type() :: 'icode' | 'rtl' | 'arm' | 'ppc' | 'sparc' | 'x86'.
-
-%%-----------------------------------------------------------------------------
-%%
-%% Pretty print
-
--spec pp(io:device(), hipe_consttab(), hipe_code_type(), string()) -> 'ok'.
-
-pp(Dev, Table, CodeType, Pre) ->
- Ls = hipe_consttab:labels(Table),
- lists:foreach(fun ({{_, ref}, _}) -> ok;
- ({L, E}) -> pp_element(Dev, L, E, CodeType, Pre)
- end,
- [{L, hipe_consttab:lookup(L, Table)} || L <- Ls]).
-
-pp_element(Dev, Name, Element, CodeType, Prefix) ->
- %% Alignment
- case hipe_consttab:const_align(Element) of
- 4 -> ok; %% Wordalignment is assumed
- Alignment ->
- io:format(Dev, " .align~w\n", [Alignment])
- end,
- %% Local or exported?
- Exported = hipe_consttab:const_exported(Element),
- case CodeType of
- rtl ->
- case Exported of
- true ->
- io:format(Dev, "DL~w: ", [Name]);
- false ->
- io:format(Dev, ".DL~w: ", [Name])
- end;
- _ ->
- io:format(Dev, "~w ", [Name])
- end,
- %% Type and data...
- case hipe_consttab:const_type(Element) of
- term ->
- io:format(Dev, "~w\n", [hipe_consttab:const_data(Element)]);
- sorted_block ->
- Data = hipe_consttab:const_data(Element),
- pp_block(Dev, {word, lists:sort(Data)}, CodeType, Prefix);
- block ->
- pp_block(Dev, hipe_consttab:const_data(Element), CodeType, Prefix)
- end.
-
-pp_block(Dev, {word, Data, SortOrder}, CodeType, Prefix) ->
- case CodeType of
- rtl ->
- io:format(Dev, "\n",[]);
- _ ->
- ok
- end,
- pp_wordlist(Dev, Data, CodeType, Prefix),
- case CodeType of
- rtl ->
- io:format(Dev, ";; Sorted by ~w\n",[SortOrder]);
- _ ->
- ok
- end;
-pp_block(Dev, {word, Data}, CodeType, Prefix) ->
- case CodeType of
- rtl ->
- io:format(Dev, ".word\n",[]);
- _ ->
- ok
- end,
- pp_wordlist(Dev, Data, CodeType, Prefix);
-pp_block(Dev, {byte, Data}, CodeType, _Prefix) ->
- case CodeType of
- rtl ->
- io:format(Dev, ".byte\n ",[]);
- _ ->
- ok
- end,
- pp_bytelist(Dev, Data, CodeType),
- case CodeType of
- rtl ->
- io:format(Dev, " ;; ~s\n ", [Data]);
- _ -> ok
- end.
-
-pp_wordlist(Dev, [{label, L}|Rest], CodeType, Prefix) ->
- case CodeType of
- rtl ->
- io:format(Dev, " &L~w\n", [L]);
- _ ->
- io:format(Dev, " <~w>\n", [L])
- end,
- pp_wordlist(Dev, Rest, CodeType, Prefix);
-pp_wordlist(Dev, [D|Rest], CodeType, Prefix) ->
- case CodeType of
- rtl ->
- io:format(Dev, " ~w\n", [D]);
- _ ->
- io:format(Dev, " ~w\n", [D])
- end,
- pp_wordlist(Dev, Rest, CodeType, Prefix);
-pp_wordlist(_Dev, [], _CodeType, _Prefix) ->
- ok.
-
-pp_bytelist(Dev, [D], CodeType) ->
- case CodeType of
- rtl ->
- io:format(Dev, "~w\n", [D]);
- _ ->
- io:format(Dev, "~w\n", [D])
- end,
- ok;
-pp_bytelist(Dev, [D|Rest], CodeType) ->
- case CodeType of
- rtl ->
- io:format(Dev, "~w,", [D]);
- _ ->
- io:format(Dev, "~w,", [D])
- end,
- pp_bytelist(Dev, Rest, CodeType);
-pp_bytelist(Dev, [], _CodeType) ->
- io:format(Dev, "\n", []).
diff --git a/lib/hipe/misc/hipe_gensym.erl b/lib/hipe/misc/hipe_gensym.erl
deleted file mode 100644
index 548071fd8f..0000000000
--- a/lib/hipe/misc/hipe_gensym.erl
+++ /dev/null
@@ -1,237 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%=======================================================================
-%% File : hipe_gensym.erl
-%% Author : Eric Johansson and Kostis Sagonas
-%% Description : Generates unique symbols and fresh integer counts.
-%%=======================================================================
-%% Notes: Written while we were in Montreal, Canada for PPDP-2000 as an
-%% exercise in Principles and Practice of Declarative Programming!
-%%=======================================================================
-
--module(hipe_gensym).
-
--export([%% init/0, new_var/0, new_label/0,
- %% update_lblrange/1, update_vrange/1, var_range/0, label_range/0,
- set_var/1, get_var/0, get_next_var/0,
- set_label/1, get_label/0, get_next_label/0]).
--export([init/1, new_var/1, new_label/1,
- update_vrange/2, update_lblrange/2, var_range/1, label_range/1,
- set_var_range/3, set_label_range/3,
- set_var/2, get_var/1, get_next_var/1,
- set_label/2, get_label/1, get_next_label/1]).
-
-%%-----------------------------------------------------------------------
-%% Types of allowable entities to set global variables for
-%%-----------------------------------------------------------------------
-
--type gvarname() :: 'icode' | 'rtl' | 'arm' | 'ppc' | 'sparc' | 'x86' | 'llvm'.
-
-%%-----------------------------------------------------------------------
-
-%% init() ->
-%% put(var_count, 0),
-%% put(label_count, 0),
-%% put(var_min, 0),
-%% put(var_max, 0),
-%% put(lbl_min, 1),
-%% put(lbl_max, 1),
-%% ok.
-
--spec init(gvarname()) -> 'ok'.
-
-init(What) ->
- put({What,var_count}, 0),
- put({What,label_count}, 0),
- put({What,var_min}, 0),
- put({What,var_max}, 0),
- put({What,lbl_min}, 1),
- put({What,lbl_max}, 1),
- ok.
-
-%% new_var() ->
-%% V = get(var_count),
-%% put(var_count, V+1),
-%% V.
-
--spec new_var(gvarname()) -> non_neg_integer().
-
-new_var(What) ->
- T = {What, var_count},
- V = get(T),
- put(T, V+1),
- V.
-
-%% new_label() ->
-%% L = get(label_count),
-%% put(label_count, L+1),
-%% L.
-
--spec new_label(gvarname()) -> non_neg_integer().
-
-new_label(What) ->
- T = {What, label_count},
- L = get(T),
- put(T, L+1),
- L.
-
-%% update_vrange(V) ->
-%% Vmax = get(var_max),
-%% Vmin = get(var_min),
-%% put(var_min, erlang:min(V, Vmin)),
-%% put(var_max, erlang:max(V, Vmax)),
-%% ok.
-
--spec update_vrange(gvarname(), non_neg_integer()) -> 'ok'.
-update_vrange(What, V) ->
- Tmin = {What, var_min},
- Tmax = {What, var_max},
- Vmax = get(Tmax),
- Vmin = get(Tmin),
- put(Tmin, erlang:min(V, Vmin)),
- put(Tmax, erlang:max(V, Vmax)),
- ok.
-
-%% update_lblrange(L) ->
-%% Lmax = get(lbl_max),
-%% Lmin = get(lbl_min),
-%% put(lbl_min, erlang:min(L, Lmin)),
-%% put(lbl_max, erlang:max(L, Lmax)),
-%% ok.
-
--spec update_lblrange(gvarname(), non_neg_integer()) -> 'ok'.
-
-update_lblrange(What, L) ->
- Tmin = {What, lbl_min},
- Tmax = {What, lbl_max},
- Lmax = get(Tmax),
- Lmin = get(Tmin),
- put(Tmin, erlang:min(L, Lmin)),
- put(Tmax, erlang:max(L, Lmax)),
- ok.
-
-%% var_range() ->
-%% {get(var_min), get(var_max)}.
-
--spec var_range(gvarname()) -> {non_neg_integer(), non_neg_integer()}.
-
-var_range(What) ->
- {get({What,var_min}), get({What,var_max})}.
-
--spec set_var_range(gvarname(), non_neg_integer(), non_neg_integer()) -> 'ok'.
-
-set_var_range(What, Min, Max) ->
- put({What,var_min}, Min),
- put({What,var_max}, Max),
- ok.
-
-%% label_range() ->
-%% {get(lbl_min), get(lbl_max)}.
-
--spec label_range(gvarname()) -> {non_neg_integer(), non_neg_integer()}.
-
-label_range(What) ->
- {get({What,lbl_min}), get({What,lbl_max})}.
-
--spec set_label_range(gvarname(), non_neg_integer(), non_neg_integer()) -> 'ok'.
-
-set_label_range(What, Min, Max) ->
- put({What,lbl_min}, Min),
- put({What,lbl_max}, Max),
- ok.
-
-%%-----------------------------------------------------------------------
-%% Variable counter
-%%-----------------------------------------------------------------------
-
--spec set_var(non_neg_integer()) -> 'ok'.
-
-set_var(X) ->
- put(var_max, X),
- ok.
-
--spec set_var(gvarname(), non_neg_integer()) -> 'ok'.
-
-set_var(What, X) ->
- put({What,var_max}, X),
- ok.
-
--spec get_var() -> non_neg_integer().
-
-get_var() ->
- get(var_max).
-
--spec get_var(gvarname()) -> non_neg_integer().
-
-get_var(What) ->
- get({What,var_max}).
-
--spec get_next_var() -> non_neg_integer().
-
-get_next_var() ->
- C = get(var_max),
- put(var_max, C+1),
- C+1.
-
--spec get_next_var(gvarname()) -> non_neg_integer().
-
-get_next_var(What) ->
- T = {What, var_max},
- C = get(T),
- put(T, C+1),
- C+1.
-
-%%-----------------------------------------------------------------------
-%% Label counter
-%%-----------------------------------------------------------------------
-
--spec set_label(non_neg_integer()) -> 'ok'.
-
-set_label(X) ->
- put(lbl_max, X),
- ok.
-
--spec set_label(gvarname(), non_neg_integer()) -> 'ok'.
-
-set_label(What, X) ->
- put({What,lbl_max}, X),
- ok.
-
--spec get_label() -> non_neg_integer().
-
-get_label() ->
- get(lbl_max).
-
--spec get_label(gvarname()) -> non_neg_integer().
-
-get_label(What) ->
- get({What,lbl_max}).
-
--spec get_next_label() -> non_neg_integer().
-
-get_next_label() ->
- C = get(lbl_max),
- put(lbl_max, C+1),
- C+1.
-
--spec get_next_label(gvarname()) -> non_neg_integer().
-
-get_next_label(What) ->
- T = {What, lbl_max},
- C = get(T),
- put(T, C+1),
- C+1.
-
-%%-----------------------------------------------------------------------
diff --git a/lib/hipe/misc/hipe_pack_constants.erl b/lib/hipe/misc/hipe_pack_constants.erl
deleted file mode 100644
index 6736d1f503..0000000000
--- a/lib/hipe/misc/hipe_pack_constants.erl
+++ /dev/null
@@ -1,278 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_pack_constants).
--export([pack_constants/1, slim_refs/1, slim_constmap/1,
- find_const/2, mk_data_relocs/2, slim_sorted_exportmap/3]).
-
--include("hipe_consttab.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../main/hipe.hrl"). % Needed for the EXIT macro in find_const/2.
-
-%%-----------------------------------------------------------------------------
-
--type const_num() :: non_neg_integer().
--type raw_data() :: binary() | number() | list() | tuple().
-
--type addr() :: non_neg_integer().
--type ref_p() :: {DataPos :: hipe_constlbl(), CodeOffset :: addr()}.
--type ref() :: ref_p() | {'sorted', Base :: addr(), [ref_p()]}.
-
--type mfa_refs() :: {mfa(), [ref()]}.
-
-%% XXX: these types may not belong here: FIX!
--type fa() :: {atom(), arity()}.
--type export_map() :: [{addr(), module(), atom(), arity()}].
-
--record(pcm_entry, {mfa :: mfa(),
- label :: hipe_constlbl(),
- const_num :: const_num(),
- start :: addr(),
- type :: 0 | 1 | 2,
- raw_data :: raw_data()}).
--type pcm_entry() :: #pcm_entry{}.
-
--type label_map() :: gb_trees:tree({mfa(), hipe_constlbl()}, addr()).
-
-%% Some of the following types may possibly need to be exported
--type data_relocs() :: [ref()].
--type packed_const_map() :: [pcm_entry()].
--type mfa_refs_map() :: [mfa_refs()].
--type slim_export_map() :: [addr() | module() | atom() | arity() | boolean()].
-
-%%-----------------------------------------------------------------------------
-
--spec pack_constants([{mfa(),[_],hipe_consttab()}]) ->
- {ct_alignment(), non_neg_integer(), packed_const_map(), mfa_refs_map()}.
-
-pack_constants(Data) ->
- pack_constants(Data, 0, 1, 0, [], []). % 1 = byte alignment
-
-pack_constants([{MFA,_,ConstTab}|Rest], Size, Align, ConstNo, Acc, Refs) ->
- Labels = hipe_consttab:labels(ConstTab),
- %% RefToLabels = hipe_consttab:referred_labels(ConstTab),
- {NewSize, NewAlign, Map, NewConstNo, RefToLabels} =
- pack_labels(Labels, MFA, ConstTab, Size, Align, ConstNo, Acc, []),
- NewRefs =
- case RefToLabels of
- [] -> Refs;
- _ -> [{MFA,RefToLabels}|Refs]
- end,
- pack_constants(Rest, NewSize, NewAlign, NewConstNo, Map, NewRefs);
-pack_constants([], Size, Align, _, Acc, Refs) ->
- {Align, Size, Acc, Refs}.
-
-%%
-%% pack_labels converts a ConstTab to a packed ConstMap, which
-%% maps {MFA,Label} pairs to information about individual constants,
-%% including their ConstNo and start offset in the constants pool.
-%%
-pack_labels([{_Label,ref}|Labels],MFA,ConstTab,Size,Align,ConstNo,Acc, Refs) ->
- pack_labels(Labels, MFA, ConstTab, Size, Align, ConstNo, Acc, Refs);
-pack_labels([Label|Labels],MFA,ConstTab,AccSize,OldAlign,ConstNo, Acc, Refs) ->
- Const = hipe_consttab:lookup(Label, ConstTab),
- Align = hipe_consttab:const_align(Const),
- NewAlign = erlang:max(Align, OldAlign),
- Start =
- case AccSize rem Align of
- 0 -> AccSize;
- N -> AccSize + (Align - N)
- end,
- %% io:format("Const ~w\n", [Const]),
- RawType = hipe_consttab:const_type(Const),
- Type = ?CONST_TYPE2EXT(RawType),
- RawData = hipe_consttab:const_data(Const),
- case RawType of
- term ->
- %% If the constant term is already in the constant map we want
- %% to use the same constant number so that, in the end, the
- %% constant term is not duplicated.
- case lists:keyfind(RawData, 7, Acc) of
- false ->
- NewInfo = #pcm_entry{mfa=MFA, label=Label, const_num=ConstNo,
- start=0, type=Type, raw_data=RawData},
- pack_labels(Labels, MFA, ConstTab, AccSize, OldAlign, ConstNo+1,
- [NewInfo|Acc], Refs);
- #pcm_entry{const_num=OtherConstNo, type=Type, raw_data=RawData} ->
- NewInfo = #pcm_entry{mfa=MFA, label=Label, const_num=OtherConstNo,
- start=0, type=Type, raw_data=RawData},
- pack_labels(Labels, MFA, ConstTab, AccSize, OldAlign, ConstNo,
- [NewInfo|Acc], Refs);
- _ ->
- NewInfo = #pcm_entry{mfa=MFA, label=Label, const_num=ConstNo,
- start=0, type=Type, raw_data=RawData},
- pack_labels(Labels, MFA, ConstTab, AccSize, OldAlign, ConstNo+1,
- [NewInfo|Acc], Refs)
- end;
- sorted_block ->
- Need = hipe_consttab:const_size(Const),
- NewInfo = #pcm_entry{mfa=MFA, label=Label, const_num=ConstNo,
- start=Start, type=Type, raw_data=RawData},
- pack_labels(Labels, MFA, ConstTab, Start+Need, NewAlign, ConstNo+1,
- [NewInfo|Acc], Refs);
- block ->
- Need = hipe_consttab:const_size(Const),
- {Data, NewRefs} =
- case RawData of
- {ElementType, ElementData} ->
- decompose_block(ElementType, ElementData, Start);
- {ElementType, ElementData, SortOrder} ->
- {TblData, TblRefs} = get_sorted_refs(ElementData, SortOrder),
- {hipe_consttab:decompose({ElementType, TblData}),
- [{sorted,Start,TblRefs}]}
- end,
- NewInfo = #pcm_entry{mfa=MFA, label=Label, const_num=ConstNo,
- start=Start, type=Type, raw_data=Data},
- pack_labels(Labels, MFA, ConstTab, Start+Need, NewAlign, ConstNo+1,
- [NewInfo|Acc], NewRefs++Refs)
- end;
-pack_labels([], _, _, Size, Align, ConstNo, Acc, Refs) ->
- {Size, Align, Acc, ConstNo, Refs}.
-
-decompose_block(ElementType, Data, Addr) ->
- ElementSize = hipe_consttab:size_of(ElementType),
- {NewData, Refs} = get_refs(Data, Addr, ElementSize),
- {hipe_consttab:decompose({ElementType, NewData}), Refs}.
-
-get_refs([{label,L}|Rest], Pos, ElementSize) ->
- {NewData, Refs} = get_refs(Rest, Pos+ElementSize, ElementSize),
- {[0|NewData], [{L,Pos}|Refs]};
-get_refs([D|Rest], Pos, ElementSize) ->
- {NewData, Refs} = get_refs(Rest, Pos+ElementSize, ElementSize),
- {[D|NewData], Refs};
-get_refs([], _, _) ->
- {[],[]}.
-
-get_sorted_refs([{label,L}|Rest], [Ordering|Os]) ->
- {NewData, Refs} = get_sorted_refs(Rest, Os),
- {[0|NewData], [{L,Ordering}|Refs]};
-get_sorted_refs([D|Rest], [_Ordering|Os]) ->
- {NewData, Refs} = get_sorted_refs(Rest, Os),
- {[D|NewData], Refs};
-get_sorted_refs([], []) ->
- {[], []}.
-
--type ref_type() :: 0..4.
-
--spec slim_refs([{ref_type(),non_neg_integer(),term()}]) ->
- [{ref_type(), [{term(), [non_neg_integer()]}]}].
-slim_refs([]) -> [];
-slim_refs(Refs) ->
- [Ref|Rest] = lists:keysort(1, Refs),
- compact_ref_types(Rest, element(1, Ref), [Ref], []).
-
-compact_ref_types([Ref|Refs], Type, AccofType, Acc) ->
- case element(1, Ref) of
- Type ->
- compact_ref_types(Refs, Type, [Ref|AccofType], Acc);
- NewType ->
- compact_ref_types(Refs, NewType, [Ref],
- [{Type,lists:sort(compact_dests(AccofType))}|Acc])
- end;
-compact_ref_types([], Type, AccofType ,Acc) ->
- [{Type,lists:sort(compact_dests(AccofType))}|Acc].
-
-
-%% compact_dests([]) -> []; % clause is redundant
-compact_dests(Refs) ->
- [Ref|Rest] = lists:keysort(3, Refs),
- compact_dests(Rest, element(3,Ref), [element(2,Ref)], []).
-
-compact_dests([Ref|Refs], Dest, AccofDest, Acc) ->
- case element(3, Ref) of
- Dest ->
- compact_dests(Refs, Dest, [element(2,Ref)|AccofDest], Acc);
- NewDest ->
- compact_dests(Refs, NewDest, [element(2,Ref)], [{Dest,AccofDest}|Acc])
- end;
-compact_dests([], Dest, AccofDest, Acc) ->
- [{Dest,AccofDest}|Acc].
-
-%%
-%% slim_constmap/1 takes a packed ConstMap, as produced by pack_labels
-%% called from hipe_pack_constants:pack_constants/2, and converts it
-%% to the slimmed and flattened format ConstMap which is put in object
-%% files.
-%%
--spec slim_constmap(packed_const_map()) -> [raw_data()].
-slim_constmap(Map) ->
- slim_constmap(Map, gb_sets:new(), []).
-
-slim_constmap([#pcm_entry{const_num = ConstNo, start = Offset,
- type = Type, raw_data = Term}|Rest], Inserted, Acc) ->
- case gb_sets:is_member(ConstNo, Inserted) of
- true ->
- slim_constmap(Rest, Inserted, Acc);
- false ->
- NewInserted = gb_sets:insert(ConstNo, Inserted),
- slim_constmap(Rest, NewInserted, [ConstNo, Offset, Type, Term|Acc])
- end;
-slim_constmap([], _Inserted, Acc) -> Acc.
-
-%%
-%% Lookup a constant in a ConstMap.
-%%
--spec find_const({mfa(), hipe_constlbl()}, packed_const_map()) -> const_num().
-
-find_const({MFA, Label}, [E = #pcm_entry{mfa = MFA, label = Label}|_]) ->
- E#pcm_entry.const_num;
-find_const(N, [_|R]) ->
- find_const(N, R);
-find_const(C, []) ->
- ?EXIT({constant_not_found, C}).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%
-%% Functions to build and handle Refs, ExportMap and LabelMap.
-%% Note: Moved here because they are used by all backends in
-%% hipe_{arm,sparc,ppc,x86}_assemble.erl
-%% XXX: Is this the right place for them?
-%%
-
--spec mk_data_relocs(mfa_refs_map(), label_map()) -> data_relocs().
-
-mk_data_relocs(RefsFromConsts, LabelMap) ->
- lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
-
-mk_data_relocs([{MFA, Labels} | Rest], LabelMap, Acc) ->
- Map = [case Label of
- {L,Pos} ->
- Offset = find({MFA,L}, LabelMap),
- {Pos,Offset};
- {sorted,Base,OrderedLabels} ->
- {sorted, Base, [begin
- Offset = find({MFA,L}, LabelMap),
- {Order, Offset}
- end
- || {L,Order} <- OrderedLabels]}
- end
- || Label <- Labels],
- %% msg("Map: ~w Map\n", [Map]),
- mk_data_relocs(Rest, LabelMap, [Map,Acc]);
-mk_data_relocs([], _, Acc) -> Acc.
-
-find({MFA,L}, LabelMap) ->
- gb_trees:get({MFA,L}, LabelMap).
-
--spec slim_sorted_exportmap(export_map(), [mfa()], [fa()]) -> slim_export_map().
-
-slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
- IsClosure = lists:member({M,F,A}, Closures),
- IsExported = is_exported(F, A, Exports),
- [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
-slim_sorted_exportmap([], _, _) -> [].
-
-is_exported(F, A, Exports) ->
- lists:member({F,A}, Exports).
diff --git a/lib/hipe/misc/hipe_sdi.erl b/lib/hipe/misc/hipe_sdi.erl
deleted file mode 100644
index 9a60382686..0000000000
--- a/lib/hipe/misc/hipe_sdi.erl
+++ /dev/null
@@ -1,393 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%======================================================================
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% An implementation of the algorithm described in:
-%%% "Assembling Code for Machines with Span-Dependent Instructions",
-%%% Thomas G. Szymanski, CACM 21(4), April 1978, pp. 300--308.
-%%%
-%%% Copyright (C) 2000, 2004, 2007 Mikael Pettersson
-
--module(hipe_sdi).
--export([pass1_init/0,
- pass1_add_label/3,
- pass1_add_sdi/4,
- pass2/1]).
-
--include("hipe_sdi.hrl").
-
-%%------------------------------------------------------------------------
-
--type hipe_array() :: integer(). % declare this in hipe.hrl or builtin?
--type hipe_vector(E) :: {} | {E} | {E, E} | {E, E, E} | tuple().
-
--type label() :: non_neg_integer().
--type address() :: non_neg_integer().
-
--type parents() :: {hipe_vector(_ :: integer()), hipe_segment_trees:tree()}.
-
-%%------------------------------------------------------------------------
-
--record(label_data, {address :: address(),
- prevSdi :: integer()}).
-
--record(pre_sdi_data, {address :: address(),
- label :: label(),
- si :: #sdi_info{}}).
-
--record(pass1, {prevSdi :: integer(),
- preS = [] :: [#pre_sdi_data{}],
- labelMap = gb_trees:empty() :: gb_trees:tree()}).
-
--record(sdi_data, {address :: address(),
- label_address :: address(),
- prevSdi :: integer(), %% -1 is the first previous
- si :: #sdi_info{}}).
-
-%%------------------------------------------------------------------------
-
-%%% "During the first pass we assign addresses to instructions
-%%% and build a symbol table of labels and their addresses
-%%% according to the minimum address assignment. We do this by
-%%% treating each sdi as having its shorter length. We also
-%%% number the sdi's [sic] from 1 to n in order of occurrence
-%%% and record in the symbol table entry for each label the
-%%% number of sdi's [sic] preceding it in the program.
-%%% Simultaneously with pass 1 we build a set
-%%% S = {(i,a,l,c) | 1 <= i <= n, a is the minimum address of
-%%% the ith sdi, l and c, are the label and constant
-%%% components of the operand of the ith sdi respectively}."
-%%%
-%%% Implementation notes:
-%%% - We number the SDIs from 0 to n-1, not from 1 to n.
-%%% - SDIs target only labels, so the constant offsets are omitted.
-%%% - The set S is represented by a vector S[0..n-1] such that if
-%%% (i,a,l) is in the set, then S[i] = (a,l).
-%%% - The symbol table maps a label to its minimum address and the
-%%% number of the last SDI preceding it (-1 if none).
-%%% - To allow this module to make architecture-specific decisions
-%%% without using callbacks or making it architecture-specific,
-%%% the elements in the set S include a fourth component, SdiInfo,
-%%% supplied by the caller of this module.
-%%% - At the end of the first pass we finalise the preliminary SDIs
-%%% by replacing their symbolic target labels with the corresponding
-%%% data from the symbol table. This avoids repeated O(logn) time
-%%% lookup costs for the labels.
-
--spec pass1_init() -> #pass1{}.
-pass1_init() ->
- #pass1{prevSdi = -1}.
-
--spec pass1_add_label(#pass1{}, non_neg_integer(), label()) -> #pass1{}.
-pass1_add_label(Pass1, Address, Label) ->
- #pass1{prevSdi=PrevSdi, labelMap=LabelMap} = Pass1,
- LabelData = #label_data{address=Address, prevSdi=PrevSdi},
- LabelMap2 = gb_trees:insert(Label, LabelData, LabelMap),
- Pass1#pass1{labelMap=LabelMap2}.
-
--spec pass1_add_sdi(#pass1{}, non_neg_integer(), label(), #sdi_info{}) ->
- #pass1{}.
-pass1_add_sdi(Pass1, Address, Label, SdiInfo) ->
- #pass1{prevSdi=PrevSdi, preS=PreS} = Pass1,
- PreSdiData = #pre_sdi_data{address=Address, label=Label, si=SdiInfo},
- Pass1#pass1{prevSdi=PrevSdi+1, preS=[PreSdiData|PreS]}.
-
--spec pass1_finalise(#pass1{}) -> {non_neg_integer(),tuple(),gb_trees:tree()}.
-pass1_finalise(#pass1{prevSdi=PrevSdi, preS=PreS, labelMap=LabelMap}) ->
- {PrevSdi+1, pass1_finalise_preS(PreS, LabelMap, []), LabelMap}.
-
--spec pass1_finalise_preS([#pre_sdi_data{}], gb_trees:tree(), [#sdi_data{}]) ->
- tuple().
-pass1_finalise_preS([], _LabelMap, S) -> vector_from_list(S);
-pass1_finalise_preS([PreSdiData|PreS], LabelMap, S) ->
- #pre_sdi_data{address=Address, label=Label, si=SdiInfo} = PreSdiData,
- LabelData = gb_trees:get(Label, LabelMap),
- #label_data{address=LabelAddress, prevSdi=PrevSdi} = LabelData,
- SdiData = #sdi_data{address=Address, label_address=LabelAddress,
- prevSdi=PrevSdi, si=SdiInfo},
- pass1_finalise_preS(PreS, LabelMap, [SdiData|S]).
-
-%%% Pass2.
-
--spec pass2(#pass1{}) -> {gb_trees:tree(), non_neg_integer()}.
-pass2(Pass1) ->
- {N,SDIS,LabelMap} = pass1_finalise(Pass1),
- LONG = mk_long(N),
- SPAN = mk_span(N, SDIS),
- PARENTS = mk_parents(N, SDIS),
- update_long(N, SDIS, SPAN, PARENTS, LONG),
- {INCREMENT,CodeSizeIncr} = mk_increment(N, LONG),
- {adjust_label_map(LabelMap, INCREMENT), CodeSizeIncr}.
-
-%%% "Between passes 1 and 2 we will construct an integer table
-%%% LONG[1:n] such that LONG[i] is nonzero if and only if the
-%%% ith sdi must be given a long form translation. Initially
-%%% LONG[i] is zero for all i."
-%%%
-%%% Implementation notes:
-%%% - LONG is an integer array indexed from 0 to N-1.
-
--spec mk_long(non_neg_integer()) -> hipe_array().
-mk_long(N) ->
- mk_array_of_zeros(N).
-
-%%% "At the heart of our algorithm is a graphical representation
-%%% of the interdependencies of the sdi's [sic] of the program.
-%%% For each sdi we construct a node containing the empty span
-%%% of that instruction. Nodes of this graph will be referred to
-%%% by the number of the sdi to which they correspond. Directed
-%%% arcs are now added to the graph so that i->j is an arc if
-%%% and only if the span of the ith sdi depends on the size of
-%%% the jth sdi, that is, the jth sdi lies between the ith sdi
-%%% and the label occurring in its operand. It is easy to see
-%%% that the graph we have just described can be constructed from
-%%% the information present in the set S and the symbol table.
-%%%
-%%% The significance if this graph is that sizes can be assigned
-%%% to the sdi's [sic] of the program so that the span of the ith
-%%% sdi is equal to the number appearing in node i if and only if
-%%% all the children of i can be given short translations."
-%%%
-%%% Implementation notes:
-%%% - The nodes are represented by an integer array SPAN[0..n-1]
-%%% such that SPAN[i] contains the current span of sdi i.
-%%% - Since the graph is traversed from child to parent nodes in
-%%% Step 3, the edges are represented by a vector PARENTS[0..n-1]
-%%% such that PARENTS[j] = { i | i is a parent of j }.
-%%% - An explicit PARENTS graph would have size O(n^2). Instead, we
-%%% observe that (i is a parent of j) iff (j \in range(i)), where
-%%% range(i) is a constant function. We can thus precompute all the
-%%% ranges i and insert them into a data structure built for such
-%%% queries. In this case, we use a segment tree.
-
--spec mk_span(non_neg_integer(), tuple()) -> hipe_array().
-mk_span(N, SDIS) ->
- initSPAN(0, N, SDIS, mk_array_of_zeros(N)).
-
--spec initSPAN(non_neg_integer(), non_neg_integer(),
- tuple(), hipe_array()) -> hipe_array().
-initSPAN(SdiNr, N, SDIS, SPAN) ->
- if SdiNr >= N -> SPAN;
- true ->
- SdiData = vector_sub(SDIS, SdiNr),
- #sdi_data{address=SdiAddress, label_address=LabelAddress} = SdiData,
- SdiSpan = LabelAddress - SdiAddress,
- array_update(SPAN, SdiNr, SdiSpan),
- initSPAN(SdiNr+1, N, SDIS, SPAN)
- end.
-
--spec mk_parents(non_neg_integer(), tuple()) -> parents().
-mk_parents(N, SDIS) ->
- PrevSDIS = vector_from_list(select_prev_sdis(N-1, SDIS, [])),
- Ranges = parents_generate_ranges(N-1, PrevSDIS, []),
- {PrevSDIS, hipe_segment_trees:build(Ranges)}.
-
-select_prev_sdis(-1, _SDIS, Acc) -> Acc;
-select_prev_sdis(SdiNr, SDIS, Acc) ->
- #sdi_data{prevSdi=PrevSdi} = vector_sub(SDIS, SdiNr),
- select_prev_sdis(SdiNr-1, SDIS, [PrevSdi|Acc]).
-
-parents_generate_ranges(-1, _PrevSDIS, Acc) -> Acc;
-parents_generate_ranges(SdiNr, PrevSDIS, Acc) ->
- %% inclusive
- {LO,HI} = parents_generate_range(SdiNr, PrevSDIS),
- parents_generate_ranges(SdiNr-1, PrevSDIS, [{LO,HI}|Acc]).
-
--compile({inline, parents_generate_range/2}).
-parents_generate_range(SdiNr, PrevSDIS) ->
- PrevSdi = vector_sub(PrevSDIS, SdiNr),
- if SdiNr =< PrevSdi -> {SdiNr+1, PrevSdi}; % forwards
- true -> {PrevSdi+1, SdiNr-1} % backwards
- end.
-
-%%% "After the structure is built we process it as follows.
-%%% For any node i whose listed span exceeds the architectural
-%%% limit for a short form instruction, the LONG[i] equal to
-%%% the difference between the long and short forms of the ith
-%%% sdi. Increment the span of each parent of i by LONG[i] if
-%%% the parent precedes the child in the program. Otherwise,
-%%% decrement the span of the parent by LONG[i]. Finally, remove
-%%% node i from the graph. Clearly this process must terminate.
-%%% Any nodes left in the final graph correspond to sdi's [sic]
-%%% which can be translated in the short form."
-%%%
-%%% Implementation notes:
-%%% - We use a simple worklist algorithm, operating on a set
-%%% of SDIs known to require long form.
-%%% - A node is removed from the graph by setting its span to zero.
-%%% - The result is the updated LONG array. Afterwards, S, SPAN,
-%%% and PARENTS are no longer useful.
-
--spec update_long(non_neg_integer(), tuple(), hipe_array(),
- parents(),hipe_array()) -> 'ok'.
-update_long(N, SDIS, SPAN, PARENTS, LONG) ->
- WKL = initWKL(N-1, SDIS, SPAN, []),
- processWKL(WKL, SDIS, SPAN, PARENTS, LONG).
-
--spec initWKL(integer(), tuple(),
- hipe_array(), [non_neg_integer()]) -> [non_neg_integer()].
-initWKL(SdiNr, SDIS, SPAN, WKL) ->
- if SdiNr < 0 -> WKL;
- true ->
- SdiSpan = array_sub(SPAN, SdiNr),
- WKL2 = updateWKL(SdiNr, SDIS, SdiSpan, WKL),
- initWKL(SdiNr-1, SDIS, SPAN, WKL2)
- end.
-
--spec processWKL([non_neg_integer()], tuple(), hipe_array(),
- parents(), hipe_array()) -> 'ok'.
-processWKL([], _SDIS, _SPAN, _PARENTS, _LONG) -> ok;
-processWKL([Child|WKL], SDIS, SPAN, PARENTS0, LONG) ->
- {WKL2, PARENTS} =
- case array_sub(SPAN, Child) of
- 0 -> {WKL, PARENTS0}; % removed
- _ ->
- SdiData = vector_sub(SDIS, Child),
- Incr = sdiLongIncr(SdiData),
- array_update(LONG, Child, Incr),
- array_update(SPAN, Child, 0), % remove child
- PARENTS1 = deleteParent(PARENTS0, Child),
- PS = parentsOfChild(PARENTS1, Child),
- {updateParents(PS, Child, Incr, SDIS, SPAN, WKL), PARENTS1}
- end,
- processWKL(WKL2, SDIS, SPAN, PARENTS, LONG).
-
--spec parentsOfChild(parents(), non_neg_integer()) -> [non_neg_integer()].
-parentsOfChild({_PrevSDIS, SegTree}, Child) ->
- hipe_segment_trees:intersect(Child, SegTree).
-
--spec deleteParent(parents(), non_neg_integer()) -> parents().
-deleteParent({PrevSDIS, SegTree0}, Parent) ->
- {LO,HI} = parents_generate_range(Parent, PrevSDIS),
- SegTree = hipe_segment_trees:delete(Parent, LO, HI, SegTree0),
- {PrevSDIS, SegTree}.
-
--spec updateParents([non_neg_integer()], non_neg_integer(),
- byte(), tuple(), hipe_array(),
- [non_neg_integer()]) -> [non_neg_integer()].
-updateParents([], _Child, _Incr, _SDIS, _SPAN, WKL) -> WKL;
-updateParents([P|PS], Child, Incr, SDIS, SPAN, WKL) ->
- WKL2 = updateParent(P, Child, Incr, SDIS, SPAN, WKL),
- updateParents(PS, Child, Incr, SDIS, SPAN, WKL2).
-
--spec updateParent(non_neg_integer(), non_neg_integer(),
- byte(), tuple(), hipe_array(),
- [non_neg_integer()]) -> [non_neg_integer()].
-updateParent(Parent, Child, Incr, SDIS, SPAN, WKL) ->
- case array_sub(SPAN, Parent) of
- 0 -> WKL; % removed
- OldSpan ->
- NewSpan =
- if Parent < Child -> OldSpan + Incr;
- true -> OldSpan - Incr
- end,
- array_update(SPAN, Parent, NewSpan),
- updateWKL(Parent, SDIS, NewSpan, WKL)
- end.
-
--spec updateWKL(non_neg_integer(), tuple(),
- integer(), [non_neg_integer()]) -> [non_neg_integer()].
-updateWKL(SdiNr, SDIS, SdiSpan, WKL) ->
- case sdiSpanIsShort(vector_sub(SDIS, SdiNr), SdiSpan) of
- true -> WKL;
- false -> [SdiNr|WKL]
- end.
-
--compile({inline, sdiSpanIsShort/2}). %% Only called once
--spec sdiSpanIsShort(#sdi_data{}, integer()) -> boolean().
-sdiSpanIsShort(#sdi_data{si = #sdi_info{lb = LB, ub = UB}}, SdiSpan) ->
- SdiSpan >= LB andalso SdiSpan =< UB.
-
--compile({inline, sdiLongIncr/1}). %% Only called once
--spec sdiLongIncr(#sdi_data{}) -> byte().
-sdiLongIncr(#sdi_data{si = #sdi_info{incr = Incr}}) -> Incr.
-
-%%% "Now construct a table INCREMENT[0:n] by defining
-%%% INCREMENT[0] = 0 and INCREMENT[i] = INCREMENT[i-1]+LONG[i]
-%%% for 1 <= i <= n. INCREMENT[i] represents the total increase
-%%% in size of the first i sdi's [sic] in the program."
-%%%
-%%% Implementation notes:
-%%% - INCREMENT is an integer vector indexed from 0 to n-1.
-%%% INCREMENT[i] = SUM(0 <= j <= i)(LONG[j]), for 0 <= i < n.
-%%% - Due to the lack of an SML-like Array.extract operation,
-%%% INCREMENT is an array, not an immutable vector.
-
--spec mk_increment(non_neg_integer(), hipe_array()) ->
- {hipe_array(), non_neg_integer()}.
-mk_increment(N, LONG) ->
- initINCR(0, 0, N, LONG, mk_array_of_zeros(N)).
-
--spec initINCR(non_neg_integer(), non_neg_integer(), non_neg_integer(),
- hipe_array(), hipe_array()) -> {hipe_array(), non_neg_integer()}.
-initINCR(SdiNr, PrevIncr, N, LONG, INCREMENT) ->
- if SdiNr >= N -> {INCREMENT, PrevIncr};
- true ->
- SdiIncr = PrevIncr + array_sub(LONG, SdiNr),
- array_update(INCREMENT, SdiNr, SdiIncr),
- initINCR(SdiNr+1, SdiIncr, N, LONG, INCREMENT)
- end.
-
-%%% "At this point we can adjust the addresses of each label L
-%%% in the symbol table. If L is preceded by i sdi's [sic] in
-%%% the program, then add INCREMENT[i] to the value of L in the
-%%% symbol table."
-%%%
-%%% Implementation notes:
-%%% - Due to the 0..n-1 SDI numbering, a label L with address
-%%% a and previous sdi i is remapped to a+incr(i), where
-%%% incr(i) = if i < 0 then 0 else INCREMENT[i].
-
--spec adjust_label_map(gb_trees:tree(), hipe_array()) -> gb_trees:tree().
-adjust_label_map(LabelMap, INCREMENT) ->
- applyIncr(gb_trees:to_list(LabelMap), INCREMENT, gb_trees:empty()).
-
--type label_pair() :: {label(), #label_data{}}.
-
--spec applyIncr([label_pair()], hipe_array(), gb_trees:tree()) ->
- gb_trees:tree().
-applyIncr([], _INCREMENT, LabelMap) -> LabelMap;
-applyIncr([{Label,LabelData}|List], INCREMENT, LabelMap) ->
- #label_data{address=Address, prevSdi=PrevSdi} = LabelData,
- Incr =
- if PrevSdi < 0 -> 0;
- true -> array_sub(INCREMENT, PrevSdi)
- end,
- applyIncr(List, INCREMENT, gb_trees:insert(Label, Address+Incr, LabelMap)).
-
-%%% ADT for immutable vectors, indexed from 0 to N-1.
-%%% Currently implemented as tuples.
-%%% Used for the 'SDIS' and 'PARENTS' vectors.
-
--spec vector_from_list([E]) -> hipe_vector(E).
-vector_from_list(Values) -> list_to_tuple(Values).
-
--compile({inline, vector_sub/2}).
--spec vector_sub(hipe_vector(E), non_neg_integer()) -> V when V :: E.
-vector_sub(Vec, I) -> element(I+1, Vec).
-
-%%% ADT for mutable integer arrays, indexed from 0 to N-1.
-%%% Currently implemented as HiPE arrays.
-%%% Used for the 'LONG', 'SPAN', and 'INCREMENT' arrays.
-
--spec mk_array_of_zeros(non_neg_integer()) -> hipe_array().
-mk_array_of_zeros(N) -> hipe_bifs:array(N, 0).
-
--compile({inline, array_update/3}).
--spec array_update(hipe_array(), non_neg_integer(), integer()) -> hipe_array().
-array_update(A, I, V) -> hipe_bifs:array_update(A, I, V).
-
--compile({inline, array_sub/2}).
--spec array_sub(hipe_array(), non_neg_integer()) -> integer().
-array_sub(A, I) -> hipe_bifs:array_sub(A, I).
diff --git a/lib/hipe/misc/hipe_sdi.hrl b/lib/hipe/misc/hipe_sdi.hrl
deleted file mode 100644
index def697549c..0000000000
--- a/lib/hipe/misc/hipe_sdi.hrl
+++ /dev/null
@@ -1,18 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--record(sdi_info,
- {lb :: integer(), % span lower bound for short form
- ub :: integer(), % span upper bound for short form
- incr :: byte()}). % instruction size increase for long form
diff --git a/lib/hipe/misc/hipe_segment_trees.erl b/lib/hipe/misc/hipe_segment_trees.erl
deleted file mode 100644
index 3d6a7487ec..0000000000
--- a/lib/hipe/misc/hipe_segment_trees.erl
+++ /dev/null
@@ -1,174 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Segment trees, with a delete operation.
-%%%
-%%% Keys are the (0-based) indices into the list passed to build/1.
-%%%
-%%% Range bounds are inclusive.
-%%%
-
--module(hipe_segment_trees).
-
--export([build/1, intersect/2, delete/4]).
-
--record(segment_tree, {
- lo :: integer(),
- hi :: integer(),
- root :: tnode()
- }).
-
-%% X =< Mid belongs in Left
--define(NODE(Left, Right, Mid, Segments), {Left, Right, Mid, Segments}).
-
--define(POINT_LEAF(Val), Val).
--define(RANGE_LEAF(Lo, Hi), {Lo, Hi}).
-
--type segments() :: [non_neg_integer()].
--type leaf() :: segments().
--type tnode() :: ?NODE(tnode(), tnode(), integer(), segments()) | leaf().
-
--opaque tree() :: #segment_tree{} | nil.
--export_type([tree/0]).
-
-%% @doc Builds a segment tree of the given intervals.
--spec build([{integer(), integer()}]) -> tree().
-build(ListOfIntervals) ->
- case
- lists:usort(
- lists:append(
- [[Lo, Hi] || {Lo, Hi} <- ListOfIntervals, Lo =< Hi]))
- of
- [] -> nil;
- Endpoints ->
- Tree0 = empty_tree_from_endpoints(Endpoints),
- [Lo|_] = Endpoints,
- Hi = lists:last(Endpoints),
- Tree1 = insert_intervals(0, ListOfIntervals, Lo, Hi, Tree0),
- Tree = squash_empty_subtrees(Tree1),
- #segment_tree{lo=Lo, hi=Hi, root=Tree}
- end.
-
-empty_tree_from_endpoints(Endpoints) ->
- Leaves = leaves(Endpoints),
- {T, [], _, _} = balanced_bst(Leaves, length(Leaves)),
- T.
-
-leaves([Endpoint]) -> [?POINT_LEAF(Endpoint)];
-leaves([A | [B|_] = Tail]) ->
- %% We omit the range leaf if it's empty
- case A<B-1 of
- true -> [?POINT_LEAF(A),?RANGE_LEAF(A+1,B-1) | leaves(Tail)];
- false -> [?POINT_LEAF(A) | leaves(Tail)]
- end.
-
-balanced_bst(L, S) when S > 1 ->
- Sm = S, %% - 1
- S2 = Sm div 2,
- S1 = Sm - S2,
- {Left, L1, LeftLo, LeftHi} = balanced_bst(L, S1),
- {Right, L2, _, RightHi} = balanced_bst(L1, S2),
- T = ?NODE(Left, Right, LeftHi, []),
- {T, L2, LeftLo, RightHi};
-balanced_bst([?RANGE_LEAF(Lo, Hi) | L], 1) ->
- {[], L, Lo, Hi};
-balanced_bst([?POINT_LEAF(Val) | L], 1) ->
- {[], L, Val, Val}.
-
-insert_intervals(_Ix, [], _Lo, _Hi, Tree) -> Tree;
-insert_intervals(Ix, [Int|Ints], Lo, Hi, Tree) ->
- insert_intervals(Ix + 1, Ints, Lo, Hi,
- insert_interval(Ix, Int, Lo, Hi, Tree)).
-
-insert_interval(_, {Lo, Hi}, _, _, Node) when Lo > Hi -> Node;
-insert_interval(I, Int={Lo,Hi}, NLo, NHi,
- ?NODE(Left0, Right0, Mid, Segments)) ->
- if Lo =< NLo, NHi =< Hi ->
- ?NODE(Left0, Right0, Mid, [I|Segments]);
- true ->
- Left = case intervals_intersect(Lo, Hi, NLo, Mid) of
- true -> insert_interval(I, Int, NLo, Mid, Left0);
- false -> Left0
- end,
- Right = case intervals_intersect(Lo, Hi, Mid+1, NHi) of
- true -> insert_interval(I, Int, Mid+1, NHi, Right0);
- false -> Right0
- end,
- ?NODE(Left, Right, Mid, Segments)
- end;
-insert_interval(I, {_Lo,_Hi}, _NLo, _NHi, Leaf) -> [I|Leaf].
-
-intervals_intersect(ALo, AHi, BLo, BHi) ->
- (ALo =< AHi) andalso (BLo =< BHi) %% both nonempty
- andalso nonempty_intervals_intersect(ALo, AHi, BLo, BHi).
-
-%% Purely optional optimisation
-squash_empty_subtrees(?NODE(Left0, Right0, Mid, Segs)) ->
- build_squash_node(squash_empty_subtrees(Left0),
- squash_empty_subtrees(Right0),
- Mid, Segs);
-squash_empty_subtrees(Leaf) -> Leaf.
-
-build_squash_node([], [], _, Segs) -> Segs;
-build_squash_node(Left, Right, Mid, Segs) ->
- ?NODE(Left, Right, Mid, Segs).
-
-%% @doc Returns the indices of the intervals in the tree that contains Point.
--spec intersect(integer(), tree()) -> [non_neg_integer()].
-intersect(Point, nil) when is_integer(Point) -> [];
-intersect(Point, #segment_tree{lo=Lo, hi=Hi, root=Root})
- when is_integer(Point) ->
- case Lo =< Point andalso Point =< Hi of
- false -> [];
- true -> intersect_1(Point, Root, [])
- end.
-
-intersect_1(Point, ?NODE(Left, Right, Mid, Segs), Acc0) ->
- Child = if Point =< Mid -> Left; true -> Right end,
- intersect_1(Point, Child, Segs ++ Acc0);
-intersect_1(_, LeafSegs, Acc) -> LeafSegs ++ Acc.
-
-%% @doc Deletes the interval {Lo, Hi}, which had index Index in the list passed
-%% to build/1.
--spec delete(non_neg_integer(), integer(), integer(), tree()) -> tree().
-delete(_, _, _, nil) -> nil;
-delete(_, Lo, Hi, Tree) when Lo > Hi -> Tree;
-delete(_, Lo, Hi, Tree = #segment_tree{lo=TLo, hi=THi})
- when Hi < TLo; Lo > THi -> Tree;
-delete(Index, Lo, Hi, Tree = #segment_tree{lo=TLo, hi=THi, root=Root0})
- when is_integer(Lo), is_integer(Hi) ->
- Root = delete_1(Index, Lo, Hi, TLo, THi, Root0),
- Tree#segment_tree{root=Root}.
-
-delete_1(I, Lo, Hi, NLo, NHi, ?NODE(Left0, Right0, Mid, Segments)) ->
- if Lo =< NLo, NHi =< Hi ->
- ?NODE(Left0, Right0, Mid, delete_2(Segments, I));
- true ->
- Left = case nonempty_intervals_intersect(Lo, Hi, NLo, Mid) of
- true -> delete_1(I, Lo, Hi, NLo, Mid, Left0);
- false -> Left0
- end,
- Right = case nonempty_intervals_intersect(Lo, Hi, Mid+1, NHi) of
- true -> delete_1(I, Lo, Hi, Mid+1, NHi, Right0);
- false -> Right0
- end,
- %% We could do build_squash_node here, is it worth it?
- ?NODE(Left, Right, Mid, Segments)
- end;
-delete_1(I, _Lo, _Hi, _NLo, _NHi, Leaf) -> delete_2(Leaf, I).
-
-delete_2([I|Segs], I) -> Segs;
-delete_2([S|Segs], I) -> [S|delete_2(Segs,I)].
-
--compile({inline,nonempty_intervals_intersect/4}).
-nonempty_intervals_intersect(ALo, AHi, BLo, BHi) ->
- (BLo =< AHi) andalso (ALo =< BHi).
diff --git a/lib/hipe/native.mk b/lib/hipe/native.mk
deleted file mode 100644
index 738e78e556..0000000000
--- a/lib/hipe/native.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-ifeq ($(NATIVE_LIBS_ENABLED),yes)
-ifndef SECONDARY_BOOTSTRAP
-ERL_COMPILE_FLAGS += +native
-else
-EBIN = ../boot_ebin
-endif
-endif
diff --git a/lib/hipe/opt/Makefile b/lib/hipe/opt/Makefile
deleted file mode 100644
index 5a729d04ae..0000000000
--- a/lib/hipe/opt/Makefile
+++ /dev/null
@@ -1,109 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = hipe_spillmin hipe_spillmin_color hipe_spillmin_scan \
- hipe_bb_weights
-
-HRL_FILES=
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars +warn_missing_spec # +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-$(EBIN)/hipe_spillmin.beam: ../main/hipe.hrl ../flow/cfg.hrl
-$(EBIN)/hipe_spillmin_color.beam: ../main/hipe.hrl ../flow/cfg.hrl
-$(EBIN)/hipe_spillmin_scan.beam: ../main/hipe.hrl ../flow/cfg.hrl
diff --git a/lib/hipe/opt/hipe_bb_weights.erl b/lib/hipe/opt/hipe_bb_weights.erl
deleted file mode 100644
index 8ef113b94c..0000000000
--- a/lib/hipe/opt/hipe_bb_weights.erl
+++ /dev/null
@@ -1,449 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% BASIC BLOCK WEIGHTING
-%%
-%% Computes basic block weights by using branch probabilities as weights in a
-%% linear equation system, that is then solved using Gauss-Jordan Elimination.
-%%
-%% The equation system representation is intentionally sparse, since most blocks
-%% have at most two successors.
--module(hipe_bb_weights).
--export([compute/3, compute_fast/3, weight/2, call_exn_pred/0]).
--export_type([bb_weights/0]).
-
--compile(inline).
-
-%%-define(DO_ASSERT,1).
-%%-define(DEBUG,1).
--include("../main/hipe.hrl").
-
-%% If the equation system is large, it might take too long to solve it exactly.
-%% Thus, if there are more than ?HEUR_MAX_SOLVE labels, we use the iterative
-%% approximation.
--define(HEUR_MAX_SOLVE, 10000).
-
--opaque bb_weights() :: #{label() => float()}.
-
--type cfg() :: any().
--type target_module() :: module().
--type target_context() :: any().
--type target() :: {target_module(), target_context()}.
-
--type label() :: integer().
--type var() :: label().
--type assignment() :: {var(), float()}.
--type eq_assoc() :: [{var(), key()}].
--type solution() :: [assignment()].
-
-%% Constant. Predicted probability of a call resulting in an exception.
--spec call_exn_pred() -> float().
-call_exn_pred() -> 0.01.
-
--spec compute(cfg(), target_module(), target_context()) -> bb_weights().
-compute(CFG, TgtMod, TgtCtx) ->
- Target = {TgtMod, TgtCtx},
- Labels = labels(CFG, Target),
- if length(Labels) > ?HEUR_MAX_SOLVE ->
- ?debug_msg("~w: Too many labels (~w), approximating.~n",
- [?MODULE, length(Labels)]),
- compute_fast(CFG, TgtMod, TgtCtx);
- true ->
- {EqSys, EqAssoc} = build_eq_system(CFG, Labels, Target),
- case solve(EqSys, EqAssoc) of
- {ok, Solution} ->
- maps:from_list(Solution)
- end
- end.
-
--spec build_eq_system(cfg(), [label()], target()) -> {eq_system(), eq_assoc()}.
-build_eq_system(CFG, Labels, Target) ->
- StartLb = hipe_gen_cfg:start_label(CFG),
- EQS0 = eqs_new(),
- {EQS1, Assoc} = build_eq_system(Labels, CFG, Target, [], EQS0),
- {StartLb, StartKey} = lists:keyfind(StartLb, 1, Assoc),
- StartRow0 = eqs_get(StartKey, EQS1),
- StartRow = row_set_const(-1.0, StartRow0), % -1.0 since StartLb coef is -1.0
- EQS = eqs_put(StartKey, StartRow, EQS1),
- {EQS, Assoc}.
-
-build_eq_system([], _CFG, _Target, Map, EQS) -> {EQS, lists:reverse(Map)};
-build_eq_system([L|Ls], CFG, Target, Map, EQS0) ->
- PredProb = pred_prob(L, CFG, Target),
- {Key, EQS} = eqs_insert(row_new([{L, -1.0}|PredProb], 0.0), EQS0),
- build_eq_system(Ls, CFG, Target, [{L, Key}|Map], EQS).
-
-pred_prob(L, CFG, Target) ->
- [begin
- BB = bb(CFG, Pred, Target),
- Ps = branch_preds(hipe_bb:last(BB), Target),
- ?ASSERT(length(lists:ukeysort(1, Ps))
- =:= length(hipe_gen_cfg:succ(CFG, Pred))),
- case lists:keyfind(L, 1, Ps) of
- {L, Prob} when is_float(Prob) -> {Pred, Prob}
- end
- end || Pred <- hipe_gen_cfg:pred(CFG, L)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec triangelise(eq_system(), eq_assoc()) -> {eq_system(), eq_assoc()}.
-triangelise(EQS, VKs) ->
- triangelise_1(mk_triix(EQS, VKs), []).
-
-triangelise_1(TIX0, Acc) ->
- case triix_is_empty(TIX0) of
- true -> {triix_eqs(TIX0), lists:reverse(Acc)};
- false ->
- {V,Key,TIX1} = triix_pop_smallest(TIX0),
- Row0 = triix_get(Key, TIX1),
- case row_get(V, Row0) of
- Coef when Coef > -0.0001, Coef < 0.0001 ->
- throw(error);
- _ ->
- Row = row_normalise(V, Row0),
- TIX2 = triix_put(Key, Row, TIX1),
- TIX = eliminate_triix(V, Key, Row, TIX2),
- triangelise_1(TIX, [{V,Key}|Acc])
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Triangelisation maintains its own index, outside of eqs. This index is
-%% essentially a BST (used as a heap) of all equations by size, with {Key,Var}
-%% as the values and only containing a subset of all the keys in the whole
-%% equation system. The key operation is triix_pop_smallest/1, which pops a
-%% {Key,Var} from the heap corresponding to one of the smallest equations. This
-%% is critical in order to prevent the equations from growing during
-%% triangelisation, which would make the algorithm O(n^2) in the common case.
--type tri_eq_system() :: {eq_system(),
- gb_trees:tree(non_neg_integer(),
- gb_trees:tree(key(), var()))}.
-
-triix_eqs({EQS, _}) -> EQS.
-triix_get(Key, {EQS, _}) -> eqs_get(Key, EQS).
-triix_is_empty({_, Tree}) -> gb_trees:is_empty(Tree).
-triix_lookup(V, {EQS, _}) -> eqs_lookup(V, EQS).
-
-mk_triix(EQS, VKs) ->
- {EQS,
- lists:foldl(fun({V,Key}, Tree) ->
- Size = row_size(eqs_get(Key, EQS)),
- sitree_insert(Size, Key, V, Tree)
- end, gb_trees:empty(), VKs)}.
-
-sitree_insert(Size, Key, V, SiTree) ->
- SubTree1 =
- case gb_trees:lookup(Size, SiTree) of
- none -> gb_trees:empty();
- {value, SubTree0} -> SubTree0
- end,
- SubTree = gb_trees:insert(Key, V, SubTree1),
- gb_trees:enter(Size, SubTree, SiTree).
-
-sitree_update_subtree(Size, SubTree, SiTree) ->
- case gb_trees:is_empty(SubTree) of
- true -> gb_trees:delete(Size, SiTree);
- false -> gb_trees:update(Size, SubTree, SiTree)
- end.
-
-triix_put(Key, Row, {EQS, Tree0}) ->
- OldSize = row_size(eqs_get(Key, EQS)),
- case row_size(Row) of
- OldSize -> {eqs_put(Key, Row, EQS), Tree0};
- Size ->
- Tree =
- case gb_trees:lookup(OldSize, Tree0) of
- none -> Tree0;
- {value, SubTree0} ->
- case gb_trees:lookup(Key, SubTree0) of
- none -> Tree0;
- {value, V} ->
- SubTree = gb_trees:delete(Key, SubTree0),
- Tree1 = sitree_update_subtree(OldSize, SubTree, Tree0),
- sitree_insert(Size, Key, V, Tree1)
- end
- end,
- {eqs_put(Key, Row, EQS), Tree}
- end.
-
-triix_pop_smallest({EQS, Tree}) ->
- {Size, SubTree0} = gb_trees:smallest(Tree),
- {Key, V, SubTree} = gb_trees:take_smallest(SubTree0),
- {V, Key, {EQS, sitree_update_subtree(Size, SubTree, Tree)}}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-row_normalise(Var, Row) ->
- %% Normalise v's coef to 1.0
- %% row_set_coef ensures the coef is exactly 1.0 (no rounding errors)
- row_set_coef(Var, 1.0, row_scale(Row, 1.0/row_get(Var, Row))).
-
-%% Precondition: Row must be normalised; i.e. Vars coef must be 1.0 (mod
-%% rounding errors)
--spec eliminate(var(), key(), row(), eq_system()) -> eq_system().
-eliminate(Var, Key, Row, TIX0) ->
- eliminate_abstr(Var, Key, Row, TIX0,
- fun eqs_get/2, fun eqs_lookup/2, fun eqs_put/3).
-
--spec eliminate_triix(var(), key(), row(), tri_eq_system()) -> tri_eq_system().
-eliminate_triix(Var, Key, Row, TIX0) ->
- eliminate_abstr(Var, Key, Row, TIX0,
- fun triix_get/2, fun triix_lookup/2, fun triix_put/3).
-
-%% The same function implemented for two data types, eqs and triix.
--compile({inline, eliminate_abstr/7}).
--spec eliminate_abstr(var(), key(), row(), ADT, fun((key(), ADT) -> row()),
- fun((var(), ADT) -> [key()]),
- fun((key(), row(), ADT) -> ADT)) -> ADT.
-eliminate_abstr(Var, Key, Row, ADT0, GetFun, LookupFun, PutFun) ->
- ?ASSERT(1.0 =:= row_get(Var, Row)),
- ADT =
- lists:foldl(fun(RK, ADT1) when RK =:= Key -> ADT1;
- (RK, ADT1) ->
- R = GetFun(RK, ADT1),
- PutFun(RK, row_addmul(R, Row, -row_get(Var, R)), ADT1)
- end, ADT0, LookupFun(Var, ADT0)),
- [Key] = LookupFun(Var, ADT),
- ADT.
-
--spec solve(eq_system(), eq_assoc()) -> error | {ok, solution()}.
-solve(EQS0, EqAssoc0) ->
- try triangelise(EQS0, EqAssoc0)
- of {EQS1, EqAssoc} ->
- {ok, solve_1(EqAssoc, maps:from_list(EqAssoc), EQS1, [])}
- catch error -> error
- end.
-
-solve_1([], _VarEqs, _EQS, Acc) -> Acc;
-solve_1([{V,K}|Ps], VarEqs, EQS0, Acc0) ->
- Row0 = eqs_get(K, EQS0),
- VarsToKill = [Var || {Var, _} <- row_coefs(Row0), Var =/= V],
- Row1 = kill_vars(VarsToKill, VarEqs, EQS0, Row0),
- [{V,_}] = row_coefs(Row1), % assertion
- Row = row_normalise(V, Row1),
- [{V,1.0}] = row_coefs(Row), % assertion
- EQS = eliminate(V, K, Row, EQS0),
- [K] = eqs_lookup(V, EQS),
- solve_1(Ps, VarEqs, eqs_remove(K, EQS), [{V, row_const(Row)}|Acc0]).
-
-kill_vars([], _VarEqs, _EQS, Row) -> Row;
-kill_vars([V|Vs], VarEqs, EQS, Row0) ->
- VRow0 = eqs_get(maps:get(V, VarEqs), EQS),
- VRow = row_normalise(V, VRow0),
- ?ASSERT(1.0 =:= row_get(V, VRow)),
- Row = row_addmul(Row0, VRow, -row_get(V, Row0)),
- ?ASSERT(0.0 =:= row_get(V, Row)), % V has been killed
- kill_vars(Vs, VarEqs, EQS, Row).
-
--spec weight(label(), bb_weights()) -> float().
-weight(Lbl, Weights) ->
- maps:get(Lbl, Weights).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Row datatype
-%% Invariant: No 0.0 coefficiets!
--spec row_empty() -> row().
-row_empty() -> {orddict:new(), 0.0}.
-
--spec row_new([{var(), float()}], float()) -> row().
-row_new(Coefs, Const) when is_float(Const) ->
- row_ensure_invar({row_squash_multiples(lists:keysort(1, Coefs)), Const}).
-
-row_squash_multiples([{K, C1},{K, C2}|Ps]) ->
- row_squash_multiples([{K,C1+C2}|Ps]);
-row_squash_multiples([P|Ps]) -> [P|row_squash_multiples(Ps)];
-row_squash_multiples([]) -> [].
-
-row_ensure_invar({Coef, Const}) ->
- {orddict:filter(fun(_, 0.0) -> false; (_, F) when is_float(F) -> true end,
- Coef), Const}.
-
-row_const({_, Const}) -> Const.
-row_coefs({Coefs, _}) -> orddict:to_list(Coefs).
-row_size({Coefs, _}) -> orddict:size(Coefs).
-
-row_get(Var, {Coefs, _}) ->
- case lists:keyfind(Var, 1, Coefs) of
- false -> 0.0;
- {_, Coef} -> Coef
- end.
-
-row_set_coef(Var, 0.0, {Coefs, Const}) ->
- {orddict:erase(Var, Coefs), Const};
-row_set_coef(Var, Coef, {Coefs, Const}) ->
- {orddict:store(Var, Coef, Coefs), Const}.
-
-row_set_const(Const, {Coefs, _}) -> {Coefs, Const}.
-
-%% Lhs + Rhs*Factor
--spec row_addmul(row(), row(), float()) -> row().
-row_addmul({LhsCoefs, LhsConst}, {RhsCoefs, RhsConst}, Factor)
- when is_float(Factor) ->
- Coefs = row_addmul_coefs(LhsCoefs, RhsCoefs, Factor),
- Const = LhsConst + RhsConst * Factor,
- {Coefs, Const}.
-
-row_addmul_coefs(Ls, [], Factor) when is_float(Factor) -> Ls;
-row_addmul_coefs([], Rs, Factor) when is_float(Factor) ->
- row_scale_coefs(Rs, Factor);
-row_addmul_coefs([L={LV, _}|Ls], Rs=[{RV,_}|_], Factor)
- when LV < RV, is_float(Factor) ->
- [L|row_addmul_coefs(Ls, Rs, Factor)];
-row_addmul_coefs(Ls=[{LV, _}|_], [{RV, RC}|Rs], Factor)
- when LV > RV, is_float(RC), is_float(Factor) ->
- [{RV, RC*Factor}|row_addmul_coefs(Ls, Rs, Factor)];
-row_addmul_coefs([{V, LC}|Ls], [{V, RC}|Rs], Factor)
- when is_float(LC), is_float(RC), is_float(Factor) ->
- case LC + RC * Factor of
- 0.0 -> row_addmul_coefs(Ls, Rs, Factor);
- C -> [{V,C}|row_addmul_coefs(Ls, Rs, Factor)]
- end.
-
-row_scale(_, 0.0) -> row_empty();
-row_scale({RowCoefs, RowConst}, Factor) when is_float(Factor) ->
- {row_scale_coefs(RowCoefs, Factor), RowConst * Factor}.
-
-row_scale_coefs([{V,C}|Cs], Factor) when is_float(Factor), is_float(C) ->
- [{V,C*Factor}|row_scale_coefs(Cs, Factor)];
-row_scale_coefs([], Factor) when is_float(Factor) ->
- [].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Equation system ADT
-%%
-%% Stores a linear equation system, allowing for efficient updates and efficient
-%% queries for all equations mentioning a variable.
-%%
-%% It is sort of like a "database" table of {Primary, Terms, Const} indexed both
-%% on Primary as well as the vars (map keys) in Terms.
--type row() :: {Terms :: orddict:orddict(var(), float()),
- Const :: float()}.
--type key() :: non_neg_integer().
--type rev_index() :: #{var() => ordsets:ordset(key())}.
--record(eq_system, {
- rows = #{} :: #{key() => row()},
- revidx = revidx_empty() :: rev_index(),
- next_key = 0 :: key()
- }).
--type eq_system() :: #eq_system{}.
-
-eqs_new() -> #eq_system{}.
-
--spec eqs_insert(row(), eq_system()) -> {key(), eq_system()}.
-eqs_insert(Row, EQS=#eq_system{next_key=NextKey0}) ->
- Key = NextKey0,
- NextKey = NextKey0 + 1,
- {Key, eqs_insert(Key, Row, EQS#eq_system{next_key=NextKey})}.
-
-eqs_insert(Key, Row, EQS=#eq_system{rows=Rows, revidx=RevIdx0}) ->
- RevIdx = revidx_add(Key, Row, RevIdx0),
- EQS#eq_system{rows=Rows#{Key => Row}, revidx=RevIdx}.
-
-eqs_put(Key, Row, EQS0) ->
- eqs_insert(Key, Row, eqs_remove(Key, EQS0)).
-
-eqs_remove(Key, EQS=#eq_system{rows=Rows, revidx=RevIdx0}) ->
- OldRow = maps:get(Key, Rows),
- RevIdx = revidx_remove(Key, OldRow, RevIdx0),
- EQS#eq_system{rows = maps:remove(Key, Rows), revidx=RevIdx}.
-
--spec eqs_get(key(), eq_system()) -> row().
-eqs_get(Key, #eq_system{rows=Rows}) -> maps:get(Key, Rows).
-
-%% Keys of all equations containing a nonzero coefficient for Var
--spec eqs_lookup(var(), eq_system()) -> ordsets:ordset(key()).
-eqs_lookup(Var, #eq_system{revidx=RevIdx}) -> maps:get(Var, RevIdx).
-
-%% eqs_rows(#eq_system{rows=Rows}) -> maps:to_list(Rows).
-
-%% eqs_print(EQS) ->
-%% lists:foreach(fun({_, Row}) ->
-%% row_print(Row)
-%% end, lists:sort(eqs_rows(EQS))).
-
-%% row_print(Row) ->
-%% CoefStrs = [io_lib:format("~wl~w", [Coef, Var])
-%% || {Var, Coef} <- row_coefs(Row)],
-%% CoefStr = lists:join(" + ", CoefStrs),
-%% io:format("~w = ~s~n", [row_const(Row), CoefStr]).
-
-revidx_empty() -> #{}.
-
--spec revidx_add(key(), row(), rev_index()) -> rev_index().
-revidx_add(Key, Row, RevIdx0) ->
- orddict:fold(fun(Var, _Coef, RevIdx1) ->
- ?ASSERT(_Coef /= 0.0),
- RevIdx1#{Var => ordsets:add_element(
- Key, maps:get(Var, RevIdx1, ordsets:new()))}
- end, RevIdx0, row_coefs(Row)).
-
--spec revidx_remove(key(), row(), rev_index()) -> rev_index().
-revidx_remove(Key, {Coefs, _}, RevIdx0) ->
- orddict:fold(fun(Var, _Coef, RevIdx1) ->
- case RevIdx1 of
- #{Var := Keys0} ->
- case ordsets:del_element(Key, Keys0) of
- [] -> maps:remove(Var, RevIdx1);
- Keys -> RevIdx1#{Var := Keys}
- end
- end
- end, RevIdx0, Coefs).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(FAST_ITERATIONS, 5).
-
-%% @doc Computes a rough approximation of BB weights. The approximation is
-%% particularly poor (converges slowly) for recursive functions and loops.
--spec compute_fast(cfg(), target_module(), target_context()) -> bb_weights().
-compute_fast(CFG, TgtMod, TgtCtx) ->
- Target = {TgtMod, TgtCtx},
- StartLb = hipe_gen_cfg:start_label(CFG),
- RPO = reverse_postorder(CFG, Target),
- PredProbs = [{L, pred_prob(L, CFG, Target)} || L <- RPO, L =/= StartLb],
- Probs0 = (maps:from_list([{L, 0.0} || L <- RPO]))#{StartLb := 1.0},
- fast_iterate(?FAST_ITERATIONS, PredProbs, Probs0).
-
-fast_iterate(0, _Pred, Probs) -> Probs;
-fast_iterate(Iters, Pred, Probs0) ->
- fast_iterate(Iters-1, Pred,
- fast_one(Pred, Probs0)).
-
-fast_one([{L, Pred}|Ls], Probs0) ->
- Weight = fast_sum(Pred, Probs0, 0.0),
- Probs = Probs0#{L => Weight},
- fast_one(Ls, Probs);
-fast_one([], Probs) ->
- Probs.
-
-fast_sum([{P,EWt}|Pred], Probs, Acc) when is_float(EWt), is_float(Acc) ->
- case Probs of
- #{P := PWt} when is_float(PWt) ->
- fast_sum(Pred, Probs, Acc + PWt * EWt)
- end;
-fast_sum([], _Probs, Acc) when is_float(Acc) ->
- Acc.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Target module interface functions
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(TGT_IFACE_0(N), N( {M,C}) -> M:N( C)).
--define(TGT_IFACE_1(N), N(A1, {M,C}) -> M:N(A1, C)).
--define(TGT_IFACE_2(N), N(A1,A2, {M,C}) -> M:N(A1,A2, C)).
--define(TGT_IFACE_3(N), N(A1,A2,A3,{M,C}) -> M:N(A1,A2,A3,C)).
-
-?TGT_IFACE_2(bb).
-?TGT_IFACE_1(branch_preds).
-?TGT_IFACE_1(labels).
-?TGT_IFACE_1(reverse_postorder).
diff --git a/lib/hipe/opt/hipe_spillmin.erl b/lib/hipe/opt/hipe_spillmin.erl
deleted file mode 100644
index b28a6bfd13..0000000000
--- a/lib/hipe/opt/hipe_spillmin.erl
+++ /dev/null
@@ -1,118 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ==========================================================================
-%% Module : hipe_spillmin
-%% Purpose : Driver module for minimizing the number of stack slots used
-%% by a function. This is done using an algorithm for register
-%% allocation. The implementation is target-independent and
-%% requires a target-specific interface module as argument.
-%% ==========================================================================
-%% Exported functions (short description):
-%%
-%% stackalloc(CFG, StackSlots, SpillIndex, Options, TgtMod, TgtCtx,
-%% TempMap) ->
-%% {Coloring, NumberOfSpills}
-%% Takes a CFG and the TempMap from register allocation and returns
-%% a coloring of stack slots.
-%% StackSlots should be a list of used stack slots, usually empty at
-%% first call to function.
-%% SpillIndex is the the first position we will spill to, usually 0.
-%% TempMap is the TempMap from the register allocation
-%%
-%% The Coloring will be in the form of the "allocation datastructure"
-%% described below, that is, a list of tuples on the form
-%% {Name, {spill, SpillIndex}}
-%% The NumberOfSpills is either 0 indicating no spill or the
-%% SpillIndex of the last spilled register.
-%%
-%% mapmerge(Map, SpillMap) -> NewMap
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_spillmin).
--export([stackalloc/7, stackalloc/8, mapmerge/2]).
-
-%%-define(DEBUG, 1).
--define(HIPE_INSTRUMENT_COMPILER, true).
-
-%%---------------------------------------------------------------------------
-
--include("../main/hipe.hrl").
--include("../flow/cfg.hrl").
-
--type target_context() :: any().
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% stackalloc(CFG, StackSlots, SpillIndex, Options, Target, TempMap)
-%% Calculates an allocation of stack slots using either a linear scan
-%% or a graph coloring allocation algorithm.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--spec stackalloc(#cfg{}, [_], non_neg_integer(),
- comp_options(), module(), target_context(), hipe_temp_map()) ->
- {hipe_spill_map(), non_neg_integer()}.
-
-stackalloc(CFG, StackSlots, SpillIndex, Options, TgtMod, TgtCtx, TempMap) ->
- Liveness = TgtMod:analyze(CFG,TgtCtx),
- stackalloc(CFG, Liveness, StackSlots, SpillIndex, Options, TgtMod, TgtCtx, TempMap).
-
--spec stackalloc(#cfg{}, _, [_], non_neg_integer(),
- comp_options(), module(), target_context(), hipe_temp_map()) ->
- {hipe_spill_map(), non_neg_integer()}.
-
-stackalloc(CFG, Liveness, StackSlots, SpillIndex, Options, TgtMod, TgtCtx,
- TempMap) ->
- case proplists:get_bool(spillmin_color, Options) of
- false ->
- ?option_time(hipe_spillmin_scan:stackalloc(
- CFG, Liveness, StackSlots, SpillIndex, Options, TgtMod,
- TgtCtx, TempMap),
- "Spill minimize, linear scan", Options);
- true ->
- ?option_time(hipe_spillmin_color:stackalloc(
- CFG, Liveness, StackSlots, SpillIndex, Options, TgtMod,
- TgtCtx, TempMap),
- "Spill minimize, graph coloring", Options)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% mapmerge(Map, SpillMap)
-%%
-%% stackalloc/6 will only return the subset of the tempmap that contains
-%% the spilled temporaries. This function is used to merge the old
-%% complete tempmap with the new spill information.
-%% Map is the old map (a list of [{R0, C1}, {R1, C2}, ...]).
-%% SpillMap is the new "spill" map.
-%% !! Warning, the function does not work with the maps in another order !!
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% Combines the map with allocated spills with a map from the register
-%% allocator
-
--spec mapmerge(hipe_map(), hipe_spill_map()) -> hipe_map().
-
-mapmerge(TempMap, SpillMap) ->
- mapmerge(TempMap, SpillMap, []).
-
-mapmerge([], _, Ack) ->
- lists:reverse(Ack);
-mapmerge([{T1, _}|T1s], [{T2, C}|T2s], Ack) when T1 =:= T2 ->
- mapmerge(T1s, T2s, [{T1, C}|Ack]);
-mapmerge([{_, unknown}|T1s], T2s, Ack) ->
- mapmerge(T1s, T2s, Ack);
-mapmerge([T1|T1s], T2s, Ack) ->
- mapmerge(T1s, T2s, [T1|Ack]).
diff --git a/lib/hipe/opt/hipe_spillmin_color.erl b/lib/hipe/opt/hipe_spillmin_color.erl
deleted file mode 100644
index f87d9a5b61..0000000000
--- a/lib/hipe/opt/hipe_spillmin_color.erl
+++ /dev/null
@@ -1,583 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ===========================================================================
-%%@doc
-%% GRAPH COLORING STACK SLOT SPILL MINIMIZER
-%%
-%% A simple pessimistic graph coloring stack slot spill minimizer
-%%
-%% - build interference graph
-%% - estimate number of stack slots needed
-%% - simplify graph (push on stack, abort and retry with more stack slots if spill)
-%% - select colors
-%%
-%% Emits a coloring: a list of {TempName,Location}
-%% where Location is {spill,M}.
-%% {spill,M} denotes the Mth spilled node
-%%
-%% This version uses ETS tables
-%%
-%% Deficiencies:
-%% - pessimistic coloring
-%%
-
--module(hipe_spillmin_color).
-
--export([stackalloc/8]).
-
-%%-ifndef(DO_ASSERT).
-%%-define(DO_ASSERT, true).
-%%-endif.
-
-%%-ifndef(DEBUG).
-%%-define(DEBUG,0).
-%%-endif.
-
-%%---------------------------------------------------------------------------
-
--include("../main/hipe.hrl").
--include("../flow/cfg.hrl").
-
-%% Define these as 'ok' or 'report(X,Y)' depending on how much output you want.
--define(report0(X,Y), ?IF_DEBUG_LEVEL(0,?msg(X, Y),ok)).
--define(report(X,Y), ?IF_DEBUG_LEVEL(1,?msg(X, Y),ok)).
--define(report2(X,Y), ?IF_DEBUG_LEVEL(2,?msg(X, Y),ok)).
--define(report3(X,Y), ?IF_DEBUG_LEVEL(3,?msg(X, Y),ok)).
-
-%% Emits a coloring: a list of {TempName,Location}
-%% where Location is {spill,M}.
-%% {spill,M} denotes the Mth spilled node
-
--type target_context() :: any().
-
--spec stackalloc(#cfg{}, _, [_], non_neg_integer(),
- comp_options(), module(), target_context(), hipe_temp_map()) ->
- {hipe_spill_map(), non_neg_integer()}.
-
-stackalloc(CFG, Live, _StackSlots, SpillIndex, _Options, TargetMod,
- TargetContext, TempMap) ->
- Target = {TargetMod, TargetContext},
- ?report2("building IG~n", []),
- {IG, NumNodes} = build_ig(CFG, Live, Target, TempMap),
- {Cols, MaxColors} =
- color_heuristic(IG, 0, NumNodes, NumNodes, NumNodes, Target, 1),
- SortedCols = lists:sort(Cols),
- {remap_temp_map(SortedCols, TempMap, SpillIndex), SpillIndex+MaxColors}.
-
-%% Rounds a floating point value upwards
-ceiling(X) ->
- T = trunc(X),
- case (X - T) of
- Neg when Neg < 0.0 -> T;
- Pos when Pos > 0.0 -> T + 1;
- _ -> T
- end.
-
-%% Emits a coloring: an unsorted list of {Temp,Location}
-%% where Location is {spill,M}.
-%% {spill,M} denotes the Mth spilled node
-%%
-%% Notes:
-%% - Arguments:
-%% IG: The interference graph
-%% Min: The lower bound, the minimal number of colors tried.
-%% Max: The upper bound, the maximal number of colors tried.
-%% Safe: The number of colors that are guaranteed to work. This is
-%% needed, because we reuse information from color() about how
-%% many colors it used at the last try, but this is not guaranteed to
-%% be a feasible solution because color might work differently using
-%% more colors although it has successfully colored the graph with
-%% fewer colors previously. Example: color(666) colors with 23 colors,
-%% but color(23) fails.
-%% We use Safe inefficently, because we run color 1 additional
-%% time with the same argument if Safe is needed.
-%% MaxNodes: The number of nodes in IG.
-%% Target: Target specific information.
-%% MaxDepth: The maximum recursion depth.
-color_heuristic(IG, Min, Max, Safe, MaxNodes, Target, MaxDepth) ->
- case MaxDepth of
- 0 ->
- case color(IG, ordsets:from_list(init_stackslots(Max)),
- MaxNodes, Target) of
- not_easily_colorable ->
- color(IG, ordsets:from_list(init_stackslots(Safe)),
- MaxNodes, Target);
- Else ->
- Else
- end;
- _ ->
- %% This can be increased from 2, and by this the heuristic can be
- %% exited earlier, but the same can be achieved by decreasing the
- %% recursion depth. This should not be decreased below 2.
- case (Max - Min) < 2 of
- true ->
- case color(IG, ordsets:from_list(init_stackslots(Max)),
- MaxNodes, Target) of
- not_easily_colorable ->
- color(IG, ordsets:from_list(init_stackslots(Safe)),
- MaxNodes, Target);
- Else ->
- Else
- end;
- false ->
- NumSlots = ceiling((Max - Min)/2) + Min,
- case color(IG, ordsets:from_list(init_stackslots(NumSlots)),
- MaxNodes, Target) of
- not_easily_colorable ->
- color_heuristic(IG, NumSlots, Max,
- Safe, MaxNodes, Target, MaxDepth - 1);
- {_TmpCols, TmpMaxColors} ->
- color_heuristic(IG, Min, TmpMaxColors,
- NumSlots, MaxNodes, Target, MaxDepth - 1)
- end
- end
- end.
-
-%% Returns a new temp map with the spilled temporaries mapped to stack slots,
-%% located after SpillIndex, according to Cols.
-remap_temp_map(Cols, TempMap, SpillIndex) ->
- remap_temp_map0(Cols, hipe_temp_map:to_substlist(TempMap), SpillIndex).
-
-remap_temp_map0([], _TempMap, _SpillIndex) ->
- [];
-remap_temp_map0([{_M, {spill, N}}|Xs], [{TempNr, {spill,_}}|Ys], SpillIndex) ->
- [{TempNr, {spill, SpillIndex + N-1}}|remap_temp_map0(Xs, Ys, SpillIndex)];
-remap_temp_map0(Cols, [_Y|Ys], SpillIndex) ->
- remap_temp_map0(Cols, Ys, SpillIndex).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** BUILD THE INTERFERENCE GRAPH ***
-%%
-%% Returns {Interference_graph, Number_Of_Nodes}
-%%
-
-build_ig(CFG, Live, Target, TempMap) ->
- TempMapping = map_spilled_temporaries(TempMap),
- TempMappingTable = setup_ets(TempMapping),
- NumSpilled = length(TempMapping),
- IG = build_ig_bbs(labels(CFG, Target), CFG, Live, empty_ig(NumSpilled),
- Target, TempMap, TempMappingTable),
- ets:delete(TempMappingTable),
- {normalize_ig(IG), NumSpilled}.
-
-%% Creates an ETS table consisting of the keys given in List, with the values
-%% being an integer which is the position of the key in List.
-%% [1,5,7] -> {1,0} {5,1} {7,2}
-%% etc.
-setup_ets(List) ->
- setup_ets0(List, ets:new(tempMappingTable, []), 0).
-
-setup_ets0([], Table, _N) ->
- Table;
-setup_ets0([X|Xs], Table, N) ->
- ets:insert(Table, {X, N}),
- setup_ets0(Xs, Table, N+1).
-
-build_ig_bbs([], _CFG, _Live, IG, _Target, _TempMap, _TempMapping) ->
- IG;
-build_ig_bbs([L|Ls], CFG, Live, IG, Target, TempMap, TempMapping) ->
- Xs = bb(CFG, L, Target),
- LiveOut = [X || X <- liveout(Live, L, Target),
- hipe_temp_map:is_spilled(X, TempMap)],
- LiveOutList = ordsets:to_list(LiveOut),
- LiveOutListMapped = list_map(LiveOutList, TempMapping, []),
- LiveOutSetMapped = ordsets:from_list(LiveOutListMapped),
- {_, NewIG} =
- build_ig_bb(Xs, LiveOutSetMapped, IG, Target, TempMap, TempMapping),
- build_ig_bbs(Ls, CFG, Live, NewIG, Target, TempMap, TempMapping).
-
-build_ig_bb([], LiveOut, IG, _Target, _TempMap, _TempMapping) ->
- {LiveOut, IG};
-build_ig_bb([X|Xs], LiveOut, IG, Target, TempMap, TempMapping) ->
- {Live,NewIG} =
- build_ig_bb(Xs, LiveOut, IG, Target, TempMap, TempMapping),
- build_ig_instr(X, Live, NewIG, Target, TempMap, TempMapping).
-
-build_ig_instr(X, Live0, IG0, Target, TempMap, TempMapping) ->
- {Def, Use} = def_use(X, Target, TempMap),
- ?report3("Live ~w\n~w : Def: ~w Use ~w\n",[Live0, X, Def,Use]),
- DefListMapped = list_map(Def, TempMapping, []),
- UseListMapped = list_map(Use, TempMapping, []),
- DefSetMapped = ordsets:from_list(DefListMapped),
- UseSetMapped = ordsets:from_list(UseListMapped),
- {Live1, IG1} =
- analyze_move(X, Live0, IG0, Target, DefSetMapped, UseSetMapped),
- IG = interference_arcs(DefListMapped, ordsets:to_list(Live1), IG1),
- Live = ordsets:union(UseSetMapped, ordsets:subtract(Live1, DefSetMapped)),
- {Live, IG}.
-
-analyze_move(X, Live0, IG0, Target, DefSetMapped, UseSetMapped) ->
- case {is_spill_move(X, Target), DefSetMapped, UseSetMapped} of
- {true, [Dst], [Src]} ->
- {ordsets:del_element(Src, Live0), add_move(Src, Dst, IG0)};
- {_, _, _} ->
- {Live0, IG0}
- end.
-
-%% Given a list of Keys and an ets-table returns a list of the elements
-%% in Mapping corresponding to the Keys and appends Acc to this list.
-list_map([], _Mapping, Acc) ->
- Acc;
-list_map([X|Xs], Mapping, Acc) ->
- {_Key, Val} = hd(ets:lookup(Mapping, X)),
- list_map(Xs, Mapping, [Val | Acc]).
-
-%% Returns an ordered list of spilled temporaries in TempMap
-map_spilled_temporaries(TempMap) ->
- map_spilled_temporaries0(hipe_temp_map:to_substlist(TempMap)).
-
-map_spilled_temporaries0([]) ->
- [];
-map_spilled_temporaries0([{N, {spill, _}}|Xs]) ->
- [N | map_spilled_temporaries0(Xs)];
-map_spilled_temporaries0([_X|Xs]) ->
- map_spilled_temporaries0(Xs).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-interference_arcs([], _Live, IG) ->
- IG;
-interference_arcs([X|Xs], Live, IG) ->
- interference_arcs(Xs, Live, i_arcs(X, Live, IG)).
-
-i_arcs(_X, [], IG) ->
- IG;
-i_arcs(X, [Y|Ys], IG) ->
- i_arcs(X, Ys, add_edge(X, Y, IG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** COLORING ***
-%%
-%% Coloring is done straightforwardly:
-%% - find the low-degree nodes, put them in low
-%% - while low non-empty:
-%% * remove x from low
-%% * push x on stack
-%% * decrement degree of neighbors of x
-%% * for each neighbor y of low degree, put y on low
-%% - when low empty:
-%% - if graph empty, return stack
-%% - otherwise
-%% throw an exception (the caller should retry with more stack slots)
-
-color(IG, StackSlots, NumNodes, Target) ->
- ?report("simplification of IG~n", []),
- K = ordsets:size(StackSlots),
- Nodes = list_ig(IG),
- Low = low_degree_nodes(Nodes, K),
- ?report(" starting with low degree nodes ~p~n", [Low]),
- EmptyStk = [],
- case simplify(Low, NumNodes, IG, K, EmptyStk, Target) of
- non_simplifiable -> not_easily_colorable;
- Stk ->
- ?report(" selecting colors~n", []),
- select(Stk, IG, StackSlots, NumNodes)
- end.
-
-%%%%%%%%%%%%%%%%%%%%
-%%
-%% Simplification: push all easily colored nodes on a stack;
-%% when the list of easy nodes becomes empty, see if graph is
-%% empty as well. If it is not, throw an exception and abort.
-%% If it is empty, return the stack.
-%%
-%% Notes:
-%% - Arguments:
-%% Low: low-degree nodes (ready to color)
-%% NumNodes: number of remaining nodes in graph
-%% IG: interference graph
-%% K: number of colors
-%% Stk: stack of already simplified nodes
-%% Target: Machine to compile for
-
-simplify(Low, NumNodes, IG, K, Stk, Target) ->
- Vis = none_visited(NumNodes),
- simplify_ig(Low, NumNodes, IG, K, Stk, Vis, Target).
-
-simplify_ig([], 0, _IG, _K, Stk, _Vis, _Target) ->
- Stk;
-simplify_ig([], N, _IG, _K, _Stk, _Vis, _Target) when N > 0 ->
- ?report3("N: ~w Stk: ~w N+Stk ~w\n", [N,length(Stk),N+length(Stk)]),
- non_simplifiable;
-simplify_ig([X|Xs], N, IG, K, Stk, Vis, Target) ->
- ?report3("N: ~w Stk: ~w N+Stk ~w\n", [N,length(Stk),N+length(Stk)]),
- case is_visited(X, Vis) of
- true ->
- ?report(" node ~p already visited~n", [X]),
- simplify_ig(Xs, N, IG, K, Stk, Vis, Target);
- false ->
- ?report("Stack ~w\n", [Stk]),
- {NewLow, NewIG} = decrement_neighbors(X, Xs, IG, Vis, K),
- ?report(" node ~w pushed\n(~w now ready)~n", [X, NewLow]),
- NewStk = push_colored(X, Stk),
- simplify_ig(NewLow, N-1, NewIG, K, NewStk, visit(X, Vis), Target)
- end.
-
-decrement_neighbors(X, Xs, IG, Vis, K) ->
- Ns = unvisited_neighbors(X, Vis, IG),
- ?report(" node ~p has neighbors ~w\n(unvisited ~p)~n",
- [X, neighbors(X, IG), Ns]),
- decrement_each(Ns, Xs, IG, Vis, K).
-
-%% For each node, decrement its degree and check if it is now
-%% a low-degree node. In that case, add it to the 'low list'.
-decrement_each([], Low, IG, _Vis, _K) ->
- {Low, IG};
-decrement_each([N|Ns], OldLow, IG, Vis, K) ->
- {Low, CurrIG} = Res = decrement_each(Ns, OldLow, IG, Vis, K),
- case is_visited(N, Vis) of
- true ->
- Res;
- false ->
- {D, NewIG} = decrement_degree(N, CurrIG),
- if
- D =:= K-1 ->
- {[N|Low], NewIG};
- true ->
- {Low, NewIG}
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%
-%%
-%% Returns a list of {Name,Location}, where Location is {spill,M}
-%%
-%% Note: we use pessimistic coloring here.
-%% - we could use optimistic coloring: for spilled node, check if there is
-%% an unused color among the neighbors and choose that.
-
-select(Stk, IG, PhysRegs, NumNodes) ->
- select_colors(Stk, IG, none_colored(NumNodes), PhysRegs).
-
-select_colors([], _IG, _Cols, _PhysRegs) ->
- ?report("all nodes colored~n", []),
- {[], 0};
-select_colors([{X,colorable}|Xs], IG, Cols, PhysRegs) ->
- ?report("color of ~p\n", [X]),
- {Slot,NewCols} = select_color(X, IG, Cols, PhysRegs),
- ?report("~p~n", [Slot]),
- {Tail, MaxColor} = select_colors(Xs, IG, NewCols, PhysRegs),
- NewMaxColor = erlang:max(Slot, MaxColor),
- %% Since we are dealing with spills we label all our temporaries accordingly.
- {[{X,{spill,Slot}} | Tail], NewMaxColor}.
-
-select_color(X, IG, Cols, PhysRegs) ->
- UsedColors = get_colors(neighbors(X, IG), Cols),
- Preferences = get_colors(move_connected(X, IG), Cols),
- Reg = select_unused_color(UsedColors, Preferences, PhysRegs),
- {Reg, set_color(X, Reg, Cols)}.
-
-%%%%%%%%%%%%%%%%%%%%
-
-get_colors([], _Cols) -> [];
-get_colors([X|Xs], Cols) ->
- case color_of(X, Cols) of
- uncolored ->
- get_colors(Xs, Cols);
- {color, R} ->
- [R|get_colors(Xs, Cols)]
- end.
-
-select_unused_color(UsedColors, Preferences, PhysRegs) ->
- Summary = ordsets:from_list(UsedColors),
- case ordsets:subtract(ordsets:from_list(Preferences), Summary) of
- [PreferredColor|_] -> PreferredColor;
- _ ->
- AvailRegs = ordsets:to_list(ordsets:subtract(PhysRegs, Summary)),
- hd(AvailRegs)
- end.
-
-push_colored(X, Stk) ->
- [{X, colorable} | Stk].
-
-low_degree_nodes([], _K) -> [];
-low_degree_nodes([{N,Info}|Xs], K) ->
- ?report0("node ~p has degree ~p: ~w~n", [N, degree(Info), neighbors(Info)]),
- Deg = degree(Info),
- if
- Deg < K ->
- [N|low_degree_nodes(Xs, K)];
- true ->
- low_degree_nodes(Xs, K)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-unvisited_neighbors(X, Vis, IG) ->
- ordsets:from_list(unvisited(neighbors(X, IG), Vis)).
-
-unvisited([], _Vis) -> [];
-unvisited([X|Xs], Vis) ->
- case is_visited(X, Vis) of
- true ->
- unvisited(Xs, Vis);
- false ->
- [X|unvisited(Xs, Vis)]
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** ABSTRACT DATATYPES ***
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%
-%% The stack slot datatype
-%%
-
-init_stackslots(NumSlots) ->
- init_stackslots(NumSlots, []).
-
-init_stackslots(0, Acc) ->
- Acc;
-init_stackslots(NumSlots, Acc) ->
- init_stackslots(NumSlots - 1, [NumSlots|Acc]).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The ig datatype:
-%%
-%% Note: if we know the number of temps used, we can use a VECTOR
-%% instead, which will speed up things.
-%%
-%% Note: later on, we may wish to add 'move-related' support.
-
--record(ig_info, {
- neighbors = [] :: [_],
- degree = 0 :: non_neg_integer(),
- move_connected = [] :: [_]
- }).
-
-empty_ig(NumNodes) ->
- hipe_vectors:new(NumNodes, #ig_info{}).
-
-degree(Info) ->
- Info#ig_info.degree.
-
-neighbors(Info) ->
- Info#ig_info.neighbors.
-
-move_connected(Info) ->
- Info#ig_info.move_connected.
-
-add_edge(X, X, IG) -> IG;
-add_edge(X, Y, IG) ->
- add_arc(X, Y, add_arc(Y, X, IG)).
-
-add_move(X, X, IG) -> IG;
-add_move(X, Y, IG) ->
- add_move_arc(X, Y, add_move_arc(Y, X, IG)).
-
-add_arc(X, Y, IG) ->
- Info = hipe_vectors:get(IG, X),
- Old = neighbors(Info),
- New = Info#ig_info{neighbors = [Y|Old]},
- hipe_vectors:set(IG,X,New).
-
-add_move_arc(X, Y, IG) ->
- Info = hipe_vectors:get(IG, X),
- Old = move_connected(Info),
- New = Info#ig_info{move_connected = [Y|Old]},
- hipe_vectors:set(IG,X,New).
-
-normalize_ig(IG) ->
- Size = hipe_vectors:size(IG),
- normalize_ig(Size-1, IG).
-
-normalize_ig(-1, IG) ->
- IG;
-normalize_ig(I, IG) ->
- Info = hipe_vectors:get(IG, I),
- N = ordsets:from_list(neighbors(Info)),
- M = ordsets:subtract(ordsets:from_list(move_connected(Info)), N),
- NewInfo = Info#ig_info{neighbors = N, degree = length(N), move_connected = M},
- NewIG = hipe_vectors:set(IG, I, NewInfo),
- normalize_ig(I-1, NewIG).
-
-neighbors(X, IG) ->
- Info = hipe_vectors:get(IG, X),
- Info#ig_info.neighbors.
-
-move_connected(X, IG) ->
- Info = hipe_vectors:get(IG, X),
- Info#ig_info.move_connected.
-
-decrement_degree(X, IG) ->
- Info = hipe_vectors:get(IG, X),
- Degree = degree(Info),
- NewDegree = Degree-1,
- NewInfo = Info#ig_info{degree = NewDegree},
- {NewDegree, hipe_vectors:set(IG, X, NewInfo)}.
-
-list_ig(IG) ->
- hipe_vectors:list(IG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The coloring datatype:
-
-none_colored(NumNodes) ->
- hipe_vectors:new(NumNodes, uncolored).
-
-color_of(X, Cols) ->
- hipe_vectors:get(Cols, X).
-
-set_color(X, R, Cols) ->
- hipe_vectors:set(Cols, X, {color, R}).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Note: there might be a slight gain in separating the two versions
-%% of visit/2 and visited/2. (So that {var,X} selects X and calls
-%% the integer version.
-
-none_visited(NumNodes) ->
- hipe_vectors:new(NumNodes, false).
-
-visit(X, Vis) ->
- hipe_vectors:set(Vis, X, true).
-
-is_visited(X, Vis) ->
- hipe_vectors:get(Vis, X).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** INTERFACES TO OTHER MODULES ***
-%%
-
-labels(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:labels(CFG, TgtCtx).
-
-liveout(CFG, L, Target={TgtMod,TgtCtx}) ->
- ordsets:from_list(reg_names(TgtMod:liveout(CFG, L, TgtCtx), Target)).
-
-bb(CFG, L, {TgtMod,TgtCtx}) ->
- hipe_bb:code(TgtMod:bb(CFG, L, TgtCtx)).
-
-def_use(X, Target={TgtMod,TgtCtx}, TempMap) ->
- Defines = [Y || Y <- reg_names(TgtMod:defines(X,TgtCtx), Target),
- hipe_temp_map:is_spilled(Y, TempMap)],
- Uses = [Z || Z <- reg_names(TgtMod:uses(X,TgtCtx), Target),
- hipe_temp_map:is_spilled(Z, TempMap)],
- {Defines, Uses}.
-
-reg_names(Regs, {TgtMod,TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
-is_spill_move(Instr, {TgtMod,TgtCtx}) ->
- TgtMod:is_spill_move(Instr, TgtCtx).
diff --git a/lib/hipe/opt/hipe_spillmin_scan.erl b/lib/hipe/opt/hipe_spillmin_scan.erl
deleted file mode 100644
index 484b05b790..0000000000
--- a/lib/hipe/opt/hipe_spillmin_scan.erl
+++ /dev/null
@@ -1,558 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ===========================================================================
-%% Copyright (c) 2002 by Niklas Andersson, Andreas Lundin, and Erik Johansson.
-%% ===========================================================================
-%% Module : hipe_spillmin_scan
-%% Purpose : Optimizes the number of stack slots used by using a
-%% "linear-scan algorithm" to allocate stack slots.
-%% Notes : * This is a simplified implementation of
-%% "Linear Scan Register Allocation" by
-%% Massimiliano Poletto & Vivek Sarkar described in
-%% ACM TOPLAS Vol 21, No 5, September 1999.
-%%
-%% * This implementation is target-independent and
-%% requires a target specific interface module
-%% as argument.
-%%
-%% * Based on the hipe_ls_regalloc module by Erik Johansson
-%%
-%% History : * 2002-04-01, NA & AL: Created
-%% * 2002-10-08, Happi: Cleanup and speedup
-%% ============================================================================
-%% Exported functions (short description):
-%% stackalloc(CFG, StackSlots, SpillIndex, Options, Target, TempMap) ->
-%% {Coloring, NumberOfSpills}
-%% Takes a CFG and the TempMap from register allocation and returns
-%% a coloring of stack slots.
-%% StackSlots should be a list of used stack slots, usually empty at
-%% first call to function.
-%% SpillIndex is the the first position we will spill to, usually 0.
-%% TempMap is the TempMap from the register allocation
-%%
-%% The Coloring will be in the form of the "allocation datastructure"
-%% described below, that is, a list of tuples on the form
-%% {Name, {spill, SpillIndex}}
-%% The NumberOfSpills is either 0 indicating no spill or the
-%% SpillIndex of the last spilled register.
-%%
-%% mapmerge
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_spillmin_scan).
-
--export([stackalloc/8]).
-
-%%-define(DEBUG, 1).
--define(HIPE_INSTRUMENT_COMPILER, true).
-
-%%----------------------------------------------------------------------------
-
--include("../main/hipe.hrl").
--include("../flow/cfg.hrl").
-
--type target_context() :: any().
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% stackalloc(CFG, StackSlots, SpillIndex, Options, Target, TempMap)
-%% Calculates an allocation of stack slots using a linear_scan algorithm.
-%% There are three steps in the algorithm:
-%% 1. Calculate live-ranges for all spilled temporaries.
-%% 2. Calculate live-intervals for each temporary.
-%% The live interval consists of a start position and a end position
-%% these are the first definition and last use of the temporary
-%% given as instruction numbers in a breadth-first traversal of the
-%% control-flow-graph.
-%% 3. Do a linear scan allocation over the live intervals.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--spec stackalloc(#cfg{}, _, [_], non_neg_integer(),
- comp_options(), module(), target_context(), hipe_temp_map()) ->
- {hipe_spill_map(), non_neg_integer()}.
-
-stackalloc(CFG, Liveness, StackSlots, SpillIndex, Options, TargetMod,
- TargetContext, TempMap) ->
- Target = {TargetMod, TargetContext},
- ?debug_msg("LinearScan: ~w\n", [erlang:statistics(runtime)]),
- USIntervals = calculate_intervals(CFG, Liveness, Options,
- Target, TempMap),
- %% ?debug_msg("intervals (done) ~w\n", [erlang:statistics(runtime)]),
- Intervals = sort_on_start(USIntervals),
- ?debug_msg("sort intervals (done) ~w\n", [erlang:statistics(runtime)]),
- ?debug_msg("Intervals ~w\n", [Intervals]),
- ?debug_msg("No intervals: ~w\n", [length(Intervals)]),
- ?debug_msg("count intervals (done) ~w\n", [erlang:statistics(runtime)]),
- Allocation = allocate(Intervals, StackSlots, SpillIndex, Target),
- ?debug_msg("allocation (done) ~w\n", [erlang:statistics(runtime)]),
- Allocation.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Step 2: Calculate live-intervals for each temporary. %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% calculate_intervals(CFG, Liveness, Options, Target, TempMap)
-%% CFG: The Control-Flow Graph.
-%% Liveness: A map of live-in and live-out sets for each Basic-Block.
-%% TempMap: The TempMap from the register allocation
-%%
-%% This function will only consider the intervals of the temporaries
-%% that have been spilled during register allocation, and will ignore
-%% all other.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-calculate_intervals(CFG, Liveness, _Options, Target, TempMap) ->
- Interval = empty_interval(number_of_temporaries(CFG, Target)),
- Worklist = reverse_postorder(CFG, Target),
- intervals(Worklist, Interval, 1, CFG, Liveness, Target, TempMap).
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% intervals(WorkList, Intervals, InstructionNr,
-%% CFG, Liveness, Target, TempMap)
-%% WorkList: List of BB-names to handle.
-%% Intervals: Intervals seen so far (sorted on register names).
-%% InstructionNr: The number of examined instructions.
-%% CFG: The Control-Flow Graph.
-%% Liveness: A map of live-in and live-out sets for each Basic-Block.
-%% Target: The backend for which we generate native code.
-%% TempMap: The TempMap from the register allocation
-%%
-%% This function will only consider the intervals of the temporaries
-%% that have been spilled during register allocation, and will ignore
-%% all other.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-intervals([L|ToDO], Intervals, InstructionNr, CFG, Liveness, Target,
- TempMap) ->
- ?debug_msg("Block ~w\n", [L]),
- %% Add all variables that are live at the entry of this block
- %% to the interval data structure.
-
- %% Only consider spilled temporaries in LiveIn
- LiveIn = [X || X <- livein(Liveness, L, Target),
- hipe_temp_map:is_spilled(X, TempMap)],
- Intervals2 = add_def_point(LiveIn, InstructionNr, Intervals),
-
- %% Only consider spilled temporaries in LiveOut
- LiveOut = [X2 || X2 <- liveout(Liveness, L, Target),
- hipe_temp_map:is_spilled(X2, TempMap)],
- ?debug_msg("In ~w -> Out ~w\n", [LiveIn, LiveOut]),
-
- %% Traverse this block instruction by instruction and add all
- %% uses and defines to the intervals.
- Code = hipe_bb:code(bb(CFG, L, Target)),
- {Intervals3, NewINr} = traverse_block(Code, InstructionNr+1,
- Intervals2, Target, TempMap),
-
- %% Add end points for the temporaries that are in the live-out set.
- Intervals4 = add_use_point(LiveOut, NewINr+1, Intervals3),
-
- intervals(ToDO, Intervals4, NewINr+1, CFG, Liveness, Target, TempMap);
-intervals([], Intervals, _, _, _, _, _) ->
- %% Return the calculated intervals
- interval_to_list(Intervals).
- %% Intervals.
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% traverse_block(Code, InstructionNo, Intervals, Unchanged)
-%% Examine each instruction in the Code:
-%% For each temporary T used or defined by instruction number N:
-%% extend the interval of T to include N.
-%% TempMap: The TempMap from the register allocation
-%%
-%% This function will only consider the the instruction that have temporaries
-%% that have been spilled during register allocation, and will ignore
-%% all other.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-
-traverse_block([Instruction|Is], InstrNo, Intervals, Target, TempMap) ->
- %% Get used temps.
- %% Only consider spilled temporaries in the Use set.
- UsesSet = [X || X <- uses(Instruction, Target),
- hipe_temp_map:is_spilled(X, TempMap)],
- %% Get defined temps.
- %% Only consider spilled temporaries in the Def set.
- DefsSet = [X2 || X2 <- defines(Instruction, Target),
- hipe_temp_map:is_spilled(X2, TempMap)],
- %% Only consider those temps that starts or ends their lifetime
- %% within the basic block (that is remove all Unchanged temps).
- Intervals1 = add_def_point( DefsSet, InstrNo, Intervals),
- %% Extend the intervals for these temporaries to include InstrNo.
- Intervals2 = add_use_point(UsesSet, InstrNo, Intervals1),
- %% Handle the next instruction.
- traverse_block(Is, InstrNo+1, Intervals2, Target, TempMap);
-traverse_block([], InstrNo, Intervals, _, _) ->
- %% Return the new intervals and the number of the next instruction.
- {Intervals,InstrNo}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Step 3. Do a linear scan allocation over the live intervals. %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% allocate(Intervals, PhysicalRegisters, Target)
-%%
-%% This function performs the linear scan algorithm.
-%% Intervals contains the start and stop position of each spilled temporary,
-%% sorted on increasing startpositions
-%% StackSlots is a list of available Stack slots to use. If they run out a
-%% new stack slot is allocated from an (in theory) infinite domain.
-%%
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-allocate(Intervals, StackSlots, SpillIndex, Target) ->
- AllocatedSlots = empty_allocation(),
- allocate(Intervals, StackSlots, [], AllocatedSlots, SpillIndex, Target).
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% allocate(Intervals, Free, Active, Allocated, SpillIndex, Target)
-%% Iterates on each temporary interval.
-%% Intervals: The list of temporary intervals.
-%% Free: Currently available stack slots.
-%% Active: Currently used stack slots (sorted on increasing
-%% interval enpoints)
-%% Allocated: The mapping of register names to spill positions.
-%% SpillIndex: The number of spilled registers.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-allocate([TempInt|TIS], Free, Active, Alloc, SpillIndex, Target) ->
- %% Remove from the active list those temporaries whose interval
- %% ends before the start of the current interval.
- {NewActive, NewFree} =
- expire_old_intervals(Active, startpoint(TempInt), Free, Target),
- %% Get the name of the temp in the current interval.
- Temp = reg(TempInt),
- case NewFree of
- [] ->
- %% There are no free spill slots, so we allocate a new one
- NewSpillIndex = SpillIndex+1,
- NewAlloc = spillalloc(Temp, SpillIndex, Alloc),
- NewActive2 = add_active(endpoint(TempInt), SpillIndex, NewActive),
- allocate(TIS, NewFree, NewActive2, NewAlloc, NewSpillIndex, Target);
- [FreeSpillslot | Spillslots] ->
- %% The spill slot FreeSpillSlot is available, let's use it.
- allocate(TIS, Spillslots,
- add_active(endpoint(TempInt), FreeSpillslot, NewActive),
- spillalloc(Temp, FreeSpillslot, Alloc),
- SpillIndex, Target)
- end;
-allocate([], _, _, Alloc, SpillIndex, _) ->
- %% No more register intervals to handle;
- %% return the result sorted on regnames.
- {lists:sort(Alloc), SpillIndex}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% expire_old_intervals(ActiveTemps, CurrentPos, FreeRegisters)
-%% Remove all temporaries that have live-ranges that ends before the
-%% current position from the active list and put them into the free
-%% list instead.
-%%
-%% ---------------------------------------------------------------------
-expire_old_intervals([Act|Acts] = AllActives, CurrentPos, Free, Target) ->
- %% Does the live-range of the first active register end before
- %% the current position?
-
- %% We expand multimove before regalloc, ignore the next 2 lines.
- %% %% We don't free registers that end at the current position,
- %% %% since a multimove can decide to do the moves in another order...
- case active_endpoint(Act) =< CurrentPos of
- true -> %% Yes -> Then we can free that register.
- Spillslot = active_spillslot(Act),
- %% Add the spillslot to the free pool.
- NewFree = [Spillslot|Free],
- %% Here we could try appending the register to get a more
- %% widespread use of registers.
- %% Free ++ [active_spillslot(Act)]);
- expire_old_intervals(Acts, CurrentPos, NewFree, Target);
- false ->
- %% No -> Then we cannot free any more temporaries.
- %% (Since they are sorted on endpoints...)
- {AllActives, Free}
- end;
-expire_old_intervals([], _, Free, _) ->
- {[], Free}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% D A T A S T R U C T U R E S %%
-%% & %%
-%% A U X I L I A R Y F U N C T I O N S %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The "allocation datastructure"
-%%
-%% This is an order list of register names paired with their allocations.
-%% {Name, Allocation}
-%% Since we are only dealing with spills, the allocation will look like:
-%% {spill, SpillIndex}
-%%
-%% ---------------------------------------------------------------------
-
-empty_allocation() -> [].
-
-spillalloc(Name, N, Allocation) -> [{Name,{spill,N}}|Allocation].
-
-%% spillalloc(Name,N,[{Name,_}|A]) ->
-%% ?debug_msg("Spilled ~w\n",[Name]),
-%% [{Name,{spill,N}}|A];
-%% spillalloc(Name,N,[{Name2,Binding}|Bindings]) when Name > Name2 ->
-%% [{Name2,Binding}|spillalloc(Name,N,Bindings)];
-%% spillalloc(Name,N,Bindings) ->
-%% [{Name,{spill,N}}|Bindings].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The active datastructure.
-%% Keeps tracks of currently active (allocated) spill slots.
-%% It is sorted on end points in the intervals
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-add_active(Endpoint, SpillSlot, [A1={P1,_}|Active]) when P1 < Endpoint ->
- [A1|add_active(Endpoint, SpillSlot, Active)];
-add_active(Endpoint, SpillSlot, Active) ->
- [{Endpoint, SpillSlot}|Active].
-
-active_spillslot({_,SpillSlot}) ->
- SpillSlot.
-
-active_endpoint({EndPoint,_}) ->
- EndPoint.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The Interval data structure.
-%%
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-
-%% mk_interval(Name, Start, End) ->
-%% {Name, Start, End}.
-
-endpoint({_R,_S,Endpoint}) ->
- Endpoint.
-
-startpoint({_R,Startpoint,_E}) ->
- Startpoint.
-
-reg({RegName,_S,_E}) ->
- RegName.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The Intervals data structure.
-
-sort_on_start(I) ->
- lists:keysort(2, I).
-
--ifdef(gb_intervals).
-empty_interval(_) ->
- gb_trees:empty().
-
-interval_to_list(Intervals) ->
- lists:flatten(
- lists:map(
- fun({T, I}) when is_list(I) ->
- lists:map(
- fun ({none, End}) ->
- {T,End,End};
- ({Beg, none}) ->
- {T,Beg, Beg}
- end,
- I);
- ({T,{B,E}}) -> {T, B, E}
- end,
- gb_trees:to_list(Intervals))).
-
-add_use_point([Temp|Temps], Pos, Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case gb_trees:lookup(Temp, Intervals) of
- %% This temp has an old interval...
- {value, Value} ->
- %% ... extend it.
- extend_interval(Pos, Value);
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos}
- end,
- %% Add or update the extended interval.
- Intervals2 = gb_trees:enter(Temp, NewInterval, Intervals),
- %% Add the rest of the temporaries.
- add_use_point(Temps, Pos, Intervals2);
-add_use_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-add_def_point([Temp|Temps], Pos, Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case gb_trees:lookup(Temp, Intervals) of
- %% This temp has an old interval...
- {value, Value} ->
- %% ... extend it.
- extend_interval(Pos, Value);
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos}
- end,
- %% Add or update the extended interval.
- Intervals2 = gb_trees:enter(Temp, NewInterval, Intervals),
- %% Add the rest of the temporaries.
- add_def_point(Temps, Pos, Intervals2);
-add_def_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-extend_interval(Pos, {Beginning, End}) ->
- %% If this position occurs before the beginning of the interval,
- %% then extend the beginning to this position.
- NewBeginning = erlang:min(Pos, Beginning),
- %% If this position occurs after the end of the interval, then
- %% extend the end to this position.
- NewEnd = erlang:max(Pos, End),
- {NewBeginning, NewEnd}.
-
-extend_def_interval(Pos, {Beginning, End}) ->
- %% If this position occurs before the beginning of the interval,
- %% then extend the beginning to this position.
- NewBeginning = erlang:min(Pos, Beginning),
- %% If this position occurs after the end of the interval, then
- %% extend the end to this position.
- NewEnd = erlang:max(Pos, End),
- {NewBeginning, NewEnd};
-extend_def_interval(Pos, [{Beginning, none}|More]) ->
- [{Pos,none}, {Beginning, none}|More];
-extend_def_interval(Pos, Intervals) ->
- {Pos, Pos}.
-
--else. %% ifdef gb_intervals
-
-empty_interval(N) ->
- hipe_vectors:new(N, none).
-
-interval_to_list(Intervals) ->
- add_indices(hipe_vectors:vector_to_list(Intervals), 0).
-
-add_indices([{B, E}|Xs], N) ->
- [{N, B, E}|add_indices(Xs, N+1)];
-add_indices([List|Xs], N) when is_list(List) ->
- flatten(List, N, Xs);
-add_indices([none|Xs], N) ->
- add_indices(Xs, N+1);
-add_indices([], _N) -> [].
-
-flatten([{none, End}|Rest], N, More) ->
- [{N,End,End} | flatten(Rest, N, More)];
-flatten([{Beg, none}|Rest], N ,More) ->
- [{N,Beg,Beg} | flatten(Rest, N, More)];
-flatten([], N, More) ->
- add_indices(More, N+1).
-
-add_use_point([Temp|Temps], Pos, Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case hipe_vectors:get(Intervals, Temp) of
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos};
- %% This temp has an old interval...
- Value ->
- %% ... extend it.
- extend_interval(Pos, Value)
- end,
- %% Add or update the extended interval.
- Intervals2 = hipe_vectors:set(Intervals, Temp, NewInterval),
- %% Add the rest of the temporaries.
- add_use_point(Temps, Pos, Intervals2);
-add_use_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-add_def_point([Temp|Temps], Pos, Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case hipe_vectors:get(Intervals, Temp) of
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos};
- %% This temp has an old interval...
- Value ->
- %% ... extend it.
- extend_interval(Pos, Value)
- end,
- %% Add or update the extended interval.
- Intervals2 = hipe_vectors:set(Intervals, Temp, NewInterval),
- %% Add the rest of the temporaries.
- add_def_point(Temps, Pos, Intervals2);
-add_def_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-extend_interval(Pos, {Beginning, End})
- when is_integer(Beginning), is_integer(End) ->
- %% If this position occurs before the beginning of the interval,
- %% then extend the beginning to this position.
- NewBeginning = erlang:min(Pos, Beginning),
- %% If this position occurs after the end of the interval, then
- %% extend the end to this position.
- NewEnd = erlang:max(Pos, End),
- {NewBeginning, NewEnd}.
-
--endif. %% gb_intervals
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to external functions.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bb(CFG, L, {TgtMod,TgtCtx}) ->
- TgtMod:bb(CFG, L, TgtCtx).
-
-livein(Liveness, L, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:livein(Liveness, L, TgtCtx), Target).
-
-liveout(Liveness, L, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:liveout(Liveness, L, TgtCtx), Target).
-
-number_of_temporaries(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:number_of_temporaries(CFG, TgtCtx).
-
-uses(I, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:uses(I,TgtCtx), Target).
-
-defines(I, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:defines(I,TgtCtx), Target).
-
-regnames(Regs, {TgtMod,TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
-reverse_postorder(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:reverse_postorder(CFG, TgtCtx).
diff --git a/lib/hipe/ppc/Makefile b/lib/hipe/ppc/Makefile
deleted file mode 100644
index 1ca1d51846..0000000000
--- a/lib/hipe/ppc/Makefile
+++ /dev/null
@@ -1,128 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-# Please keep this list sorted.
-MODULES=hipe_ppc \
- hipe_ppc_assemble \
- hipe_ppc_cfg \
- hipe_ppc_defuse \
- hipe_ppc_encode \
- hipe_ppc_finalise \
- hipe_ppc_frame \
- hipe_ppc_liveness_all \
- hipe_ppc_liveness_fpr \
- hipe_ppc_liveness_gpr \
- hipe_ppc_main \
- hipe_ppc_pp \
- hipe_ppc_ra \
- hipe_ppc_ra_finalise \
- hipe_ppc_ra_ls \
- hipe_ppc_ra_naive \
- hipe_ppc_ra_postconditions \
- hipe_ppc_ra_postconditions_fp \
- hipe_ppc_registers \
- hipe_ppc_subst \
- hipe_rtl_to_ppc
-
-HRL_FILES=hipe_ppc.hrl
-ERL_FILES=$(MODULES:%=%.erl)
-TARGET_FILES=$(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-# Please keep this list sorted.
-$(EBIN)/hipe_ppc_assemble.beam: ../main/hipe.hrl ../../kernel/src/hipe_ext_format.hrl ../rtl/hipe_literals.hrl ../misc/hipe_sdi.hrl
-$(EBIN)/hipe_ppc_cfg.beam: ../flow/cfg.hrl ../flow/cfg.inc
-$(EBIN)/hipe_ppc_frame.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_ppc_liveness_all.beam: ../flow/liveness.inc
-$(EBIN)/hipe_ppc_liveness_fpr.beam: ../flow/liveness.inc
-$(EBIN)/hipe_ppc_liveness_gpr.beam: ../flow/liveness.inc
-$(EBIN)/hipe_ppc_registers.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_rtl_to_ppc.beam: ../rtl/hipe_rtl.hrl
-
-$(TARGET_FILES): hipe_ppc.hrl ../misc/hipe_consttab.hrl
diff --git a/lib/hipe/ppc/hipe_ppc.erl b/lib/hipe/ppc/hipe_ppc.erl
deleted file mode 100644
index 63ecd0a0b8..0000000000
--- a/lib/hipe/ppc/hipe_ppc.erl
+++ /dev/null
@@ -1,522 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc).
--export([
- mk_temp/2,
- mk_new_temp/1,
- mk_new_nonallocatable_temp/1,
- is_temp/1,
- temp_reg/1,
- temp_type/1,
- temp_is_allocatable/1,
- temp_is_precoloured/1,
-
- mk_simm16/1,
- mk_uimm16/1,
-
- mk_mfa/3,
-
- mk_prim/1,
- is_prim/1,
- prim_prim/1,
-
- mk_sdesc/4,
-
- mk_alu/4,
-
- mk_b_fun/2,
-
- mk_b_label/1,
-
- mk_bc/3,
-
- mk_bctr/1,
-
- mk_bctrl/1,
-
- mk_bl/3,
-
- mk_blr/0,
-
- mk_cmp/3,
- cmpop_word/0,
- cmpiop_word/0,
- cmplop_word/0,
- cmpliop_word/0,
-
- mk_comment/1,
-
- mk_label/1,
- is_label/1,
- label_label/1,
-
- mk_li/2,
- mk_li/3,
- mk_addi/4,
-
- mk_load/4,
- mk_loadx/4,
- mk_load/6,
- ldop_to_ldxop/1,
- ldop_word/0,
- ldop_wordx/0,
-
- mk_mfspr/2,
-
- mk_mtcr/1,
-
- mk_mtspr/2,
-
- mk_pseudo_bc/4,
- negate_bcond/1,
-
- mk_pseudo_call/4,
- pseudo_call_contlab/1,
- pseudo_call_func/1,
- pseudo_call_sdesc/1,
- pseudo_call_linkage/1,
-
- mk_pseudo_call_prepare/1,
- pseudo_call_prepare_nrstkargs/1,
-
- mk_pseudo_li/2,
-
- mk_pseudo_move/2,
- is_pseudo_move/1,
- pseudo_move_dst/1,
- pseudo_move_src/1,
-
- mk_pseudo_spill_move/3,
- is_pseudo_spill_move/1,
-
- mk_pseudo_tailcall/4,
- pseudo_tailcall_func/1,
- pseudo_tailcall_stkargs/1,
- pseudo_tailcall_linkage/1,
-
- mk_pseudo_tailcall_prepare/0,
-
- mk_store/4,
- mk_storex/4,
- mk_store/6,
- stop_to_stxop/1,
- stop_word/0,
- stop_wordx/0,
-
- mk_unary/3,
-
- mk_lfd/3,
- mk_lfdx/3,
- mk_fload/4,
-
- %% mk_stfd/3,
- mk_stfdx/3,
- mk_fstore/4,
-
- mk_fp_binary/4,
-
- mk_fp_unary/3,
-
- mk_pseudo_fmove/2,
- is_pseudo_fmove/1,
- pseudo_fmove_dst/1,
- pseudo_fmove_src/1,
-
- mk_pseudo_spill_fmove/3,
- is_pseudo_spill_fmove/1,
-
- mk_defun/8,
- defun_mfa/1,
- defun_formals/1,
- defun_is_closure/1,
- defun_is_leaf/1,
- defun_code/1,
- defun_data/1,
- defun_var_range/1]).
-
--include("hipe_ppc.hrl").
-
-mk_temp(Reg, Type, Allocatable) ->
- #ppc_temp{reg=Reg, type=Type, allocatable=Allocatable}.
-mk_temp(Reg, Type) -> mk_temp(Reg, Type, true).
-mk_new_temp(Type, Allocatable) ->
- mk_temp(hipe_gensym:get_next_var(ppc), Type, Allocatable).
-mk_new_temp(Type) -> mk_new_temp(Type, true).
-mk_new_nonallocatable_temp(Type) -> mk_new_temp(Type, false).
-is_temp(X) -> case X of #ppc_temp{} -> true; _ -> false end.
-temp_reg(#ppc_temp{reg=Reg}) -> Reg.
-temp_type(#ppc_temp{type=Type}) -> Type.
-temp_is_allocatable(#ppc_temp{allocatable=A}) -> A.
-temp_is_precoloured(#ppc_temp{reg=Reg,type=Type}) ->
- case Type of
- 'double' -> hipe_ppc_registers:is_precoloured_fpr(Reg);
- _ -> hipe_ppc_registers:is_precoloured_gpr(Reg)
- end.
-
-mk_simm16(Value) when Value >= -(1 bsl 15), Value < (1 bsl 15) ->
- #ppc_simm16{value=Value}.
-mk_uimm16(Value) when Value >= 0, Value < (1 bsl 16) ->
- #ppc_uimm16{value=Value}.
-
-mk_mfa(M, F, A) -> #ppc_mfa{m=M, f=F, a=A}.
-
-mk_prim(Prim) -> #ppc_prim{prim=Prim}.
-is_prim(X) -> case X of #ppc_prim{} -> true; _ -> false end.
-prim_prim(#ppc_prim{prim=Prim}) -> Prim.
-
-mk_sdesc(ExnLab, FSize, Arity, Live) ->
- #ppc_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}.
-
-mk_alu(AluOp, Dst, Src1, Src2) ->
- #alu{aluop=AluOp, dst=Dst, src1=Src1, src2=Src2}.
-
-mk_b_fun(Fun, Linkage) -> #b_fun{'fun'=Fun, linkage=Linkage}.
-
-mk_b_label(Label) -> #b_label{label=Label}.
-
-mk_bc(BCond, Label, Pred) -> #bc{bcond=BCond, label=Label, pred=Pred}.
-
-mk_bctr(Labels) -> #bctr{labels=Labels}.
-
-mk_bctrl(SDesc) -> #bctrl{sdesc=SDesc}.
-
-mk_bl(Fun, SDesc, Linkage) -> #bl{'fun'=Fun, sdesc=SDesc, linkage=Linkage}.
-
-mk_blr() -> #blr{}.
-
-mk_cmp(CmpOp, Src1, Src2) -> #cmp{cmpop=CmpOp, src1=Src1, src2=Src2}.
-
-cmpop_word() ->
- case get(hipe_target_arch) of
- powerpc -> 'cmp';
- ppc64 -> 'cmpd'
- end.
-
-cmpiop_word() ->
- case get(hipe_target_arch) of
- powerpc -> 'cmpi';
- ppc64 -> 'cmpdi'
- end.
-
-cmplop_word() ->
- case get(hipe_target_arch) of
- powerpc -> 'cmpl';
- ppc64 -> 'cmpld'
- end.
-
-cmpliop_word() ->
- case get(hipe_target_arch) of
- powerpc -> 'cmpli';
- ppc64 -> 'cmpldi'
- end.
-
-
-mk_comment(Term) -> #comment{term=Term}.
-
-mk_label(Label) -> #label{label=Label}.
-is_label(I) -> case I of #label{} -> true; _ -> false end.
-label_label(#label{label=Label}) -> Label.
-
-%%% Load an integer constant into a register.
-mk_li(Dst, Value) -> mk_li(Dst, Value, []).
-
-mk_li(Dst, Value, Tail) -> % Dst can be R0
- R0 = mk_temp(0, 'untagged'),
- %% Check if immediate can fit in the 32 bits, this is obviously a
- %% sufficient check for PPC32
- if Value >= -16#80000000,
- Value =< 16#7FFFFFFF ->
- mk_li32(Dst, R0, Value, Tail);
- true ->
- Highest = case (Value bsr 48) of % Value@highest
- TopBitSet when TopBitSet >= (1 bsl 15) ->
- TopBitSet - (1 bsl 16); % encoder needs it to be negative
- FitsSimm16 -> FitsSimm16
- end,
- Higher = (Value bsr 32) band 16#FFFF, % Value@higher
- High = (Value bsr 16) band 16#FFFF, % Value@h
- Low = Value band 16#FFFF, % Value@l
- LdLo =
- case Low of
- 0 -> Tail;
- _ -> [mk_alu('ori', Dst, Dst, mk_uimm16(Low)) | Tail]
- end,
- Ld32bits =
- case High of
- 0 -> LdLo;
- _ -> [mk_alu('oris', Dst, Dst, mk_uimm16(High)) | LdLo]
- end,
- [mk_alu('addis', Dst, R0, mk_simm16(Highest)),
- mk_alu('ori', Dst, Dst, mk_uimm16(Higher)),
- mk_alu('sldi', Dst, Dst, mk_uimm16(32)) |
- Ld32bits]
- end.
-
-mk_li32(Dst, R0, Value, Tail) ->
- case at_ha(Value) of
- 0 ->
- %% Value[31:16] are the sign-extension of Value[15].
- %% Use a single addi to load and sign-extend 16 bits.
- [mk_alu('addi', Dst, R0, mk_simm16(at_l(Value))) | Tail];
- _ ->
- %% Use addis to load the high 16 bits, followed by an
- %% optional ori to load non sign-extended low 16 bits.
- High = simm16sext((Value bsr 16) band 16#FFFF),
- [mk_alu('addis', Dst, R0, mk_simm16(High)) |
- case (Value band 16#FFFF) of
- 0 -> Tail;
- Low -> [mk_alu('ori', Dst, Dst, mk_uimm16(Low)) | Tail]
- end]
- end.
-
-mk_addi(Dst, R0, Value, Tail) ->
- Low = at_l(Value),
- High = at_ha(Value),
- case High of
- 0 ->
- [mk_alu('addi', Dst, R0, mk_simm16(Low)) |
- Tail];
- _ ->
- case Low of
- 0 ->
- [mk_alu('addis', Dst, R0, mk_simm16(High)) |
- Tail];
- _ ->
- [mk_alu('addi', Dst, R0, mk_simm16(Low)),
- mk_alu('addis', Dst, Dst, mk_simm16(High)) |
- Tail]
- end
- end.
-
-at_l(Value) ->
- simm16sext(Value band 16#FFFF).
-
-at_ha(Value) ->
- simm16sext(((Value + 16#8000) bsr 16) band 16#FFFF).
-
-simm16sext(Value) ->
- if Value >= 32768 -> (-1 bsl 16) bor Value;
- true -> Value
- end.
-
-mk_load(LDop, Dst, Disp, Base) ->
- #load{ldop=LDop, dst=Dst, disp=Disp, base=Base}.
-
-mk_loadx(LdxOp, Dst, Base1, Base2) ->
- #loadx{ldxop=LdxOp, dst=Dst, base1=Base1, base2=Base2}.
-
-mk_load(LdOp, Dst, Offset, Base, Scratch, Rest) when is_integer(Offset) ->
- RequireAlignment =
- case LdOp of
- 'ld' -> true;
- 'ldx' -> true;
- _ -> false
- end,
- if Offset >= -32768, Offset =< 32767,
- not RequireAlignment orelse Offset band 3 =:= 0 ->
- [mk_load(LdOp, Dst, Offset, Base) | Rest];
- true ->
- LdxOp = ldop_to_ldxop(LdOp),
- Index =
- begin
- DstReg = temp_reg(Dst),
- BaseReg = temp_reg(Base),
- if DstReg =/= BaseReg -> Dst;
- true -> mk_scratch(Scratch)
- end
- end,
- mk_li(Index, Offset,
- [mk_loadx(LdxOp, Dst, Base, Index) | Rest])
- end.
-
-ldop_to_ldxop(LdOp) ->
- case LdOp of
- 'lbz' -> 'lbzx';
- 'lha' -> 'lhax';
- 'lhz' -> 'lhzx';
- 'lwa' -> 'lwax';
- 'lwz' -> 'lwzx';
- 'ld' -> 'ldx'
- end.
-
-ldop_word() ->
- case get(hipe_target_arch) of
- powerpc -> 'lwz';
- ppc64 -> 'ld'
- end.
-
-ldop_wordx() ->
- case get(hipe_target_arch) of
- powerpc -> 'lwzx';
- ppc64 -> 'ldx'
- end.
-
-mk_scratch(Scratch) ->
- case Scratch of
- 0 -> mk_temp(0, 'untagged');
- 'new' -> mk_new_temp('untagged')
- end.
-
-mk_mfspr(Dst, Spr) -> #mfspr{dst=Dst, spr=Spr}.
-
-mk_mtcr(Src) -> #mtcr{src=Src}.
-
-mk_mtspr(Spr, Src) -> #mtspr{spr=Spr, src=Src}.
-
-mk_pseudo_bc(BCond, TrueLab, FalseLab, Pred) ->
- if Pred >= 0.5 ->
- mk_pseudo_bc_simple(negate_bcond(BCond), FalseLab,
- TrueLab, 1.0-Pred);
- true ->
- mk_pseudo_bc_simple(BCond, TrueLab, FalseLab, Pred)
- end.
-
-mk_pseudo_bc_simple(BCond, TrueLab, FalseLab, Pred) when Pred =< 0.5 ->
- #pseudo_bc{bcond=BCond, true_label=TrueLab,
- false_label=FalseLab, pred=Pred}.
-
-negate_bcond(BCond) ->
- case BCond of
- 'lt' -> 'ge';
- 'ge' -> 'lt';
- 'gt' -> 'le';
- 'le' -> 'gt';
- 'eq' -> 'ne';
- 'ne' -> 'eq';
- 'so' -> 'ns';
- 'ns' -> 'so'
- end.
-
-mk_pseudo_call(FunC, SDesc, ContLab, Linkage) ->
- #pseudo_call{func=FunC, sdesc=SDesc, contlab=ContLab, linkage=Linkage}.
-pseudo_call_func(#pseudo_call{func=FunC}) -> FunC.
-pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc.
-pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab.
-pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage.
-
-mk_pseudo_call_prepare(NrStkArgs) ->
- #pseudo_call_prepare{nrstkargs=NrStkArgs}.
-pseudo_call_prepare_nrstkargs(#pseudo_call_prepare{nrstkargs=NrStkArgs}) ->
- NrStkArgs.
-
-mk_pseudo_li(Dst, Imm) -> #pseudo_li{dst=Dst, imm=Imm}.
-
-mk_pseudo_move(Dst, Src) -> #pseudo_move{dst=Dst, src=Src}.
-is_pseudo_move(I) -> case I of #pseudo_move{} -> true; _ -> false end.
-pseudo_move_dst(#pseudo_move{dst=Dst}) -> Dst.
-pseudo_move_src(#pseudo_move{src=Src}) -> Src.
-
-mk_pseudo_spill_move(Dst, Temp, Src) ->
- #pseudo_spill_move{dst=Dst, temp=Temp, src=Src}.
-is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move).
-
-mk_pseudo_tailcall(FunC, Arity, StkArgs, Linkage) ->
- #pseudo_tailcall{func=FunC, arity=Arity, stkargs=StkArgs, linkage=Linkage}.
-pseudo_tailcall_func(#pseudo_tailcall{func=FunC}) -> FunC.
-pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs.
-pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage.
-
-mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}.
-
-mk_store(STop, Src, Disp, Base) ->
- #store{stop=STop, src=Src, disp=Disp, base=Base}.
-
-mk_storex(StxOp, Src, Base1, Base2) ->
- #storex{stxop=StxOp, src=Src, base1=Base1, base2=Base2}.
-
-mk_store(StOp, Src, Offset, Base, Scratch, Rest)when is_integer(Offset) ->
- RequireAlignment =
- case StOp of
- 'std' -> true;
- 'stdx' -> true;
- _ -> false
- end,
- if Offset >= -32768, Offset =< 32767,
- not RequireAlignment orelse Offset band 3 =:= 0 ->
- [mk_store(StOp, Src, Offset, Base) | Rest];
- true ->
- StxOp = stop_to_stxop(StOp),
- Index = mk_scratch(Scratch),
- mk_li(Index, Offset,
- [mk_storex(StxOp, Src, Base, Index) | Rest])
- end.
-
-stop_to_stxop(StOp) ->
- case StOp of
- 'stb' -> 'stbx';
- 'sth' -> 'sthx';
- 'stw' -> 'stwx';
- 'std' -> 'stdx'
- end.
-
-stop_word() ->
- case get(hipe_target_arch) of
- powerpc -> 'stw';
- ppc64 -> 'std'
- end.
-
-stop_wordx() ->
- case get(hipe_target_arch) of
- powerpc -> 'stwx';
- ppc64 -> 'stdx'
- end.
-
-mk_unary(UnOp, Dst, Src) -> #unary{unop=UnOp, dst=Dst, src=Src}.
-
-mk_lfd(Dst, Disp, Base) -> #lfd{dst=Dst, disp=Disp, base=Base}.
-mk_lfdx(Dst, Base1, Base2) -> #lfdx{dst=Dst, base1=Base1, base2=Base2}.
-mk_fload(Dst, Offset, Base, Scratch) when is_integer(Offset) ->
- if Offset >= -32768, Offset =< 32767 ->
- [mk_lfd(Dst, Offset, Base)];
- true ->
- Index = mk_scratch(Scratch),
- mk_li(Index, Offset, [mk_lfdx(Dst, Base, Index)])
- end.
-
-mk_stfd(Src, Disp, Base) -> #stfd{src=Src, disp=Disp, base=Base}.
-mk_stfdx(Src, Base1, Base2) -> #stfdx{src=Src, base1=Base1, base2=Base2}.
-mk_fstore(Src, Offset, Base, Scratch) when is_integer(Offset) ->
- if Offset >= -32768, Offset =< 32767 ->
- [mk_stfd(Src, Offset, Base)];
- true ->
- Index = mk_scratch(Scratch),
- mk_li(Index, Offset, [mk_stfdx(Src, Base, Index)])
- end.
-
-mk_fp_binary(FpBinOp, Dst, Src1, Src2) ->
- #fp_binary{fp_binop=FpBinOp, dst=Dst, src1=Src1, src2=Src2}.
-
-mk_fp_unary(FpUnOp, Dst, Src) -> #fp_unary{fp_unop=FpUnOp, dst=Dst, src=Src}.
-
-mk_pseudo_fmove(Dst, Src) -> #pseudo_fmove{dst=Dst, src=Src}.
-is_pseudo_fmove(I) -> case I of #pseudo_fmove{} -> true; _ -> false end.
-pseudo_fmove_dst(#pseudo_fmove{dst=Dst}) -> Dst.
-pseudo_fmove_src(#pseudo_fmove{src=Src}) -> Src.
-
-mk_pseudo_spill_fmove(Dst, Temp, Src) ->
- #pseudo_spill_fmove{dst=Dst, temp=Temp, src=Src}.
-is_pseudo_spill_fmove(I) -> is_record(I, pseudo_spill_fmove).
-
-mk_defun(MFA, Formals, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) ->
- #defun{mfa=MFA, formals=Formals, code=Code, data=Data,
- isclosure=IsClosure, isleaf=IsLeaf,
- var_range=VarRange, label_range=LabelRange}.
-defun_mfa(#defun{mfa=MFA}) -> MFA.
-defun_formals(#defun{formals=Formals}) -> Formals.
-defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure.
-defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf.
-defun_code(#defun{code=Code}) -> Code.
-defun_data(#defun{data=Data}) -> Data.
-defun_var_range(#defun{var_range=VarRange}) -> VarRange.
diff --git a/lib/hipe/ppc/hipe_ppc.hrl b/lib/hipe/ppc/hipe_ppc.hrl
deleted file mode 100644
index 3eef8be487..0000000000
--- a/lib/hipe/ppc/hipe_ppc.hrl
+++ /dev/null
@@ -1,113 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-
-%%%--------------------------------------------------------------------
-%%% Basic Values:
-%%%
-%%% temp ::= {ppc_temp, reg, type, allocatable}
-%%% reg ::= <token from hipe_ppc_registers>
-%%% type ::= tagged | untagged
-%%% allocatable ::= true | false
-%%%
-%%% sdesc ::= {ppc_sdesc, exnlab, fsize, arity, live}
-%%% exnlab ::= [] | label
-%%% fsize ::= int32 (frame size in words)
-%%% live ::= <tuple of int32> (word offsets)
-%%% arity ::= uint8
-%%%
-%%% mfa ::= {ppc_mfa, atom, atom, arity}
-%%% prim ::= {ppc_prim, atom}
-
--record(ppc_mfa, {m::atom(), f::atom(), a::arity()}).
--record(ppc_prim, {prim}).
--record(ppc_sdesc, {exnlab, fsize, arity::arity(), live}).
--record(ppc_simm16, {value}).
--record(ppc_temp, {reg, type, allocatable}).
--record(ppc_uimm16, {value}).
-
-%%% Instruction Operands:
-%%%
-%%% aluop ::= add | add. | addi | addic. | addis | addo. | subf | subf. | subfo.
-%%% | and | and. | andi. | or | or. | ori | xor | xor. | xori
-%%% | slw | slw. | slwi | slwi. | srw | srw. | srwi | srwi.
-%%% | sraw | sraw. | srawi | srawi. | mulli | mullw | mullw. | mullwo.
-%%% bcond ::= eq | ne | gt | ge | lt | le | so | ns
-%%% cmpop ::= cmp | cmpi | cmpl | cmpli
-%%% ldop ::= lbz | lha | lhz | lwz
-%%% ldxop ::= lbzx | lhax | lhzx | lwzx | lhbrx | lwbrx
-%%% stop ::= stb | stw (HW has sth, but we don't use it)
-%%% stxop ::= stbx | stwx (HW has sthx/sthbrx/stwbrx, but we don't use them)
-%%% unop ::= extsb | extsh | {rlwinm,SH,MB,ME} | {rlwinm.,SH,MB,ME}
-%%%
-%%% immediate ::= int32 | atom | {label, label_type}
-%%% label_type ::= constant | closure | c_const
-%%%
-%%% dst ::= temp
-%%% src ::= temp
-%%% | simm16 | uimm16 (only in alu.src2, cmp.src2)
-%%% base ::= temp
-%%% disp ::= sint16 (untagged simm16)
-%%%
-%%% fun ::= mfa | prim
-%%% func ::= mfa | prim | 'ctr'
-%%%
-%%% spr ::= ctr | lr | xer
-
-%%% Instructions:
-
--record(alu, {aluop, dst, src1, src2}).
--record(b_fun, {'fun', linkage}). % known tailcall
--record(b_label, {label}). % local jump, unconditional
--record(bc, {bcond, label, pred}). % local jump, conditional
--record(bctr, {labels}). % computed tailcall or switch
--record(bctrl, {sdesc}). % computed recursive call
--record(bl, {'fun', sdesc, linkage}). % known recursive call
--record(blr, {}). % unconditional bclr (return)
--record(cmp, {cmpop, src1, src2}).
--record(comment, {term}).
--record(label, {label}).
--record(load, {ldop, dst, disp, base}). % non-indexed, non-update form
--record(loadx, {ldxop, dst, base1, base2}). % indexed, non-update form
--record(mfspr, {dst, spr}). % for reading LR and XER
--record(mtcr, {src}). % for copying XER[CA] to CR0[EQ] via a temp
--record(mtspr, {spr, src}). % for writing LR, CTR, and XER
--record(pseudo_bc, {bcond, true_label, false_label, pred}).
--record(pseudo_call, {func, sdesc, contlab, linkage}).
--record(pseudo_call_prepare, {nrstkargs}).
--record(pseudo_li, {dst, imm}).
--record(pseudo_move, {dst, src}).
--record(pseudo_spill_move, {dst, temp, src}).
--record(pseudo_tailcall, {func, arity, stkargs, linkage}).
--record(pseudo_tailcall_prepare, {}).
--record(store, {stop, src, disp, base}). % non-indexed, non-update form
--record(storex, {stxop, src, base1, base2}).% indexed, non-update form
--record(unary, {unop, dst, src}).
--record(lfd, {dst, disp, base}).
--record(lfdx, {dst, base1, base2}).
--record(stfd, {src, disp, base}).
--record(stfdx, {src, base1, base2}).
--record(fp_binary, {fp_binop, dst, src1, src2}).
--record(fp_unary, {fp_unop, dst, src}).
--record(pseudo_fmove, {dst, src}).
--record(pseudo_spill_fmove, {dst, temp, src}).
-
-%%% Function definitions.
-
--include("../misc/hipe_consttab.hrl").
-
--record(defun, {mfa :: mfa(), formals, code,
- data :: hipe_consttab(),
- isclosure :: boolean(),
- isleaf :: boolean(),
- var_range, label_range}).
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
deleted file mode 100644
index b0f57e5582..0000000000
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ /dev/null
@@ -1,609 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_assemble).
--export([assemble/4]).
-
--include("../main/hipe.hrl"). % for VERSION_STRING, when_option
--include("hipe_ppc.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../rtl/hipe_literals.hrl").
--include("../misc/hipe_sdi.hrl").
--undef(ASSERT).
--define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).
-
-assemble(CompiledCode, Closures, Exports, Options) ->
- print("****************** Assembling *******************\n", [], Options),
- %%
- Code = [{MFA,
- hipe_ppc:defun_code(Defun),
- hipe_ppc:defun_data(Defun)}
- || {MFA, Defun} <- CompiledCode],
- %%
- {ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code),
- %%
- {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =
- encode(translate(Code, ConstMap), Options),
- print("Total num bytes=~w\n", [CodeSize], Options),
- %%
- SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
- SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
- ConstAlign, ConstSize,
- SC,
- DataRelocs, % nee LM, LabelMap
- SSE,
- CodeSize,CodeBinary,SlimRefs,
- 0,[] % ColdCodeSize, SlimColdRefs
- ]),
- %%
- Bin.
-
-%%%
-%%% Assembly Pass 1.
-%%% Process initial {MFA,Code,Data} list.
-%%% Translate each MFA's body, choosing operand & instruction kinds.
-%%%
-%%% Assembly Pass 2.
-%%% Perform short/long form optimisation for jumps.
-%%%
-%%% Result is {MFA,NewCode,CodeSize,LabelMap} list.
-%%%
-
-translate(Code, ConstMap) ->
- translate_mfas(Code, ConstMap, []).
-
-translate_mfas([{MFA,Insns,_Data}|Code], ConstMap, NewCode) ->
- {NewInsns,CodeSize,LabelMap} =
- translate_insns(Insns, MFA, ConstMap, hipe_sdi:pass1_init(), 0, []),
- translate_mfas(Code, ConstMap, [{MFA,NewInsns,CodeSize,LabelMap}|NewCode]);
-translate_mfas([], _ConstMap, NewCode) ->
- lists:reverse(NewCode).
-
-translate_insns([I|Insns], MFA, ConstMap, SdiPass1, Address, NewInsns) ->
- NewIs = translate_insn(I, MFA, ConstMap),
- add_insns(NewIs, Insns, MFA, ConstMap, SdiPass1, Address, NewInsns);
-translate_insns([], _MFA, _ConstMap, SdiPass1, Address, NewInsns) ->
- {LabelMap,CodeSizeIncr} = hipe_sdi:pass2(SdiPass1),
- {lists:reverse(NewInsns), Address+CodeSizeIncr, LabelMap}.
-
-add_insns([I|Is], Insns, MFA, ConstMap, SdiPass1, Address, NewInsns) ->
- NewSdiPass1 =
- case I of
- {'.label',L,_} ->
- hipe_sdi:pass1_add_label(SdiPass1, Address, L);
- {bc_sdi,{_,{label,L},_},_} ->
- SdiInfo = #sdi_info{incr=(8-4),lb=-16#2000*4,ub=16#1FFF*4},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo);
- _ ->
- SdiPass1
- end,
- Address1 = Address + insn_size(I),
- add_insns(Is, Insns, MFA, ConstMap, NewSdiPass1, Address1, [I|NewInsns]);
-add_insns([], Insns, MFA, ConstMap, SdiPass1, Address, NewInsns) ->
- translate_insns(Insns, MFA, ConstMap, SdiPass1, Address, NewInsns).
-
-insn_size(I) ->
- case I of
- {'.label',_,_} -> 0;
- {'.reloc',_,_} -> 0;
- _ -> 4 % bc_sdi included in this case
- end.
-
-translate_insn(I, MFA, ConstMap) -> % -> [{Op,Opnd,OrigI}]
- case I of
- #alu{} -> do_alu(I);
- #b_fun{} -> do_b_fun(I);
- #b_label{} -> do_b_label(I);
- #bc{} -> do_bc(I);
- #bctr{} -> do_bctr(I);
- #bctrl{} -> do_bctrl(I);
- #bl{} -> do_bl(I);
- #blr{} -> do_blr(I);
- #comment{} -> [];
- #cmp{} -> do_cmp(I);
- #label{} -> do_label(I);
- #load{} -> do_load(I);
- #loadx{} -> do_loadx(I);
- #mfspr{} -> do_mfspr(I);
- #mtcr{} -> do_mtcr(I);
- #mtspr{} -> do_mtspr(I);
- %% pseudo_bc: eliminated before assembly
- %% pseudo_call: eliminated before assembly
- %% pseudo_call_prepare: eliminated before assembly
- #pseudo_li{} -> do_pseudo_li(I, MFA, ConstMap);
- %% pseudo_move: eliminated before assembly
- %% pseudo_tailcall: eliminated before assembly
- %% pseudo_tailcall_prepare: eliminated before assembly
- #store{} -> do_store(I);
- #storex{} -> do_storex(I);
- #unary{} -> do_unary(I);
- #lfd{} -> do_lfd(I);
- #stfd{} -> do_stfd(I);
- #fp_binary{} -> do_fp_binary(I);
- #fp_unary{} -> do_fp_unary(I);
- _ -> exit({?MODULE,translate_insn,I})
- end.
-
-do_alu(I) ->
- #alu{aluop=AluOp,dst=Dst,src1=Src1,src2=Src2} = I,
- NewDst = do_reg(Dst),
- NewSrc1 = do_reg(Src1),
- NewSrc2 = do_reg_or_imm(Src2),
- {NewI,NewOpnds} =
- case AluOp of
- 'slwi' -> {'rlwinm', do_slwi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'slwi.' -> {'rlwinm.', do_slwi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'srwi' -> {'rlwinm', do_srwi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'srwi.' -> {'rlwinm.', do_srwi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'srawi' -> {'srawi', {NewDst,NewSrc1,do_srawi_src2(NewSrc2)}};
- 'srawi.' -> {'srawi.', {NewDst,NewSrc1,do_srawi_src2(NewSrc2)}};
- %ppc64 extension
- 'sldi' -> {'rldicr', do_sldi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'sldi.' -> {'rldicr.', do_sldi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'srdi' -> {'rldicl', do_srdi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'srdi.' -> {'rldicl.', do_srdi_opnds(NewDst, NewSrc1, NewSrc2)};
- 'sradi' -> {'sradi', {NewDst,NewSrc1,do_sradi_src2(NewSrc2)}};
- 'sradi.' -> {'sradi.', {NewDst,NewSrc1,do_sradi_src2(NewSrc2)}};
- _ -> {AluOp, {NewDst,NewSrc1,NewSrc2}}
- end,
- [{NewI, NewOpnds, I}].
-
-do_slwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
- {Dst, Src1, {sh,N}, {mb,0}, {me,31-N}}.
-
-do_srwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
- %% SH should be 0 (not 32) when N is 0
- {Dst, Src1, {sh,(32-N) band 31}, {mb,N}, {me,31}}.
-
-do_srawi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 32 -> {sh,N}.
-
-%% ppc64 extension
-do_sldi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
- {Dst, Src1, {sh6,N}, {me6,63-N}}.
-
-do_srdi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
- %% SH should be 0 (not 64) when N is 0
- {Dst, Src1, {sh6,(64-N) band 63}, {mb6,N}}.
-
-do_sradi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 64 -> {sh6,N}.
-
-do_b_fun(I) ->
- #b_fun{'fun'=Fun,linkage=Linkage} = I,
- [{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},
- {b, {{li,0}}, I}].
-
-do_b_label(I) ->
- #b_label{label=Label} = I,
- [{b, do_label_ref(Label), I}].
-
-do_bc(I) ->
- #bc{bcond=BCond,label=Label,pred=Pred} = I,
- [{bc_sdi, {{bcond,BCond},do_label_ref(Label),{pred,Pred}}, I}].
-
-do_bctr(I) ->
- [{bcctr, {{bo,2#10100},{bi,0}}, I}].
-
-do_bctrl(I) ->
- #bctrl{sdesc=SDesc} = I,
- [{bcctrl, {{bo,2#10100},{bi,0}}, I},
- {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}}].
-
-do_bl(I) ->
- #bl{'fun'=Fun,sdesc=SDesc,linkage=Linkage} = I,
- [{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},
- {bl, {{li,0}}, I},
- {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}}].
-
-do_blr(I) ->
- [{bclr, {{bo,2#10100},{bi,0}}, I}].
-
-do_cmp(I) ->
- #cmp{cmpop=CmpOp,src1=Src1,src2=Src2} = I,
- NewSrc1 = do_reg(Src1),
- NewSrc2 = do_reg_or_imm(Src2),
- {RealOp,L} =
- case CmpOp of
- 'cmpd' -> {'cmp',1};
- 'cmpdi' -> {'cmpi',1};
- 'cmpld' -> {'cmpl',1};
- 'cmpldi' -> {'cmpli',1};
- 'cmp' -> {CmpOp,0};
- 'cmpi' -> {CmpOp,0};
- 'cmpl' -> {CmpOp,0};
- 'cmpli' -> {CmpOp,0}
- end,
- [{RealOp, {{crf,0},L,NewSrc1,NewSrc2}, I}].
-
-do_label(I) ->
- #label{label=Label} = I,
- [{'.label', Label, I}].
-
-do_load(I) ->
- #load{ldop=LdOp,dst=Dst,disp=Disp,base=Base} = I,
- NewDst = do_reg(Dst),
- NewDisp =
- case LdOp of
- 'ld' -> do_disp_ds(Disp);
- 'ldu' -> do_disp_ds(Disp);
- 'lwa' -> do_disp_ds(Disp);
- _ -> do_disp(Disp)
- end,
- NewBase = do_reg(Base),
- [{LdOp, {NewDst,NewDisp,NewBase}, I}].
-
-do_loadx(I) ->
- #loadx{ldxop=LdxOp,dst=Dst,base1=Base1,base2=Base2} = I,
- NewDst = do_reg(Dst),
- NewBase1 = do_reg(Base1),
- NewBase2 = do_reg(Base2),
- [{LdxOp, {NewDst,NewBase1,NewBase2}, I}].
-
-do_mfspr(I) ->
- #mfspr{dst=Dst,spr=SPR} = I,
- NewDst = do_reg(Dst),
- NewSPR = do_spr(SPR),
- [{mfspr, {NewDst,NewSPR}, I}].
-
-do_mtcr(I) ->
- #mtcr{src=Src} = I,
- NewSrc = do_reg(Src),
- [{mtcrf, {{crm,16#80},NewSrc}, I}].
-
-do_mtspr(I) ->
- #mtspr{spr=SPR,src=Src} = I,
- NewSPR = do_spr(SPR),
- NewSrc = do_reg(Src),
- [{mtspr, {NewSPR,NewSrc}, I}].
-
-do_pseudo_li(I, MFA, ConstMap) ->
- #pseudo_li{dst=Dst,imm=Imm} = I,
- RelocData =
- case Imm of
- Atom when is_atom(Atom) ->
- {load_atom, Atom};
-%%% {mfa,MFAorPrim,Linkage} ->
-%%% Tag =
-%%% case Linkage of
-%%% remote -> remote_function;
-%%% not_remote -> local_function
-%%% end,
-%%% {load_address, {Tag,untag_mfa_or_prim(MFAorPrim)}};
- {Label,constant} ->
- ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
- {load_address, {constant,ConstNo}};
- {Label,closure} ->
- {load_address, {closure,Label}};
- {Label,c_const} ->
- {load_address, {c_const,Label}}
- end,
- NewDst = do_reg(Dst),
- Simm0 = {simm,0},
- Uimm0 = {uimm,0},
- case get(hipe_target_arch) of
- powerpc ->
- [{'.reloc', RelocData, #comment{term=reloc}},
- {addi, {NewDst,{r,0},Simm0}, I},
- {addis, {NewDst,NewDst,Simm0}, I}];
- ppc64 ->
- [{'.reloc', RelocData, #comment{term=reloc}},
- {addis, {NewDst,{r,0},Simm0}, I}, % @highest
- {ori, {NewDst,NewDst,Uimm0}, I}, % @higher
- {rldicr, {NewDst,NewDst,{sh6,32},{me6,31}}, I},
- {oris, {NewDst,NewDst,Uimm0}, I}, % @h
- {ori, {NewDst,NewDst,Uimm0}, I}] % @l
- end.
-
-do_store(I) ->
- #store{stop=StOp,src=Src,disp=Disp,base=Base} = I,
- NewSrc = do_reg(Src),
- NewDisp =
- case StOp of
- 'std' -> do_disp_ds(Disp);
- 'stdu' -> do_disp_ds(Disp);
- _ -> do_disp(Disp)
- end,
- NewBase = do_reg(Base),
- [{StOp, {NewSrc,NewDisp,NewBase}, I}].
-
-do_storex(I) ->
- #storex{stxop=StxOp,src=Src,base1=Base1,base2=Base2} = I,
- NewSrc = do_reg(Src),
- NewBase1 = do_reg(Base1),
- NewBase2 = do_reg(Base2),
- [{StxOp, {NewSrc,NewBase1,NewBase2}, I}].
-
-do_unary(I) ->
- #unary{unop=UnOp,dst=Dst,src=Src} = I,
- NewDst = do_reg(Dst),
- NewSrc = do_reg(Src),
- {NewI,NewOpnds} =
- case UnOp of
- {RLWINM,SH,MB,ME} -> {RLWINM, {NewDst,NewSrc,{sh,SH},{mb,MB},{me,ME}}};
- _ -> {UnOp, {NewDst,NewSrc}}
- end,
- [{NewI, NewOpnds, I}].
-
-do_lfd(I) ->
- #lfd{dst=Dst,disp=Disp,base=Base} = I,
- NewDst = do_fpreg(Dst),
- NewDisp = do_disp(Disp),
- NewBase = do_reg(Base),
- [{lfd, {NewDst,NewDisp,NewBase}, I}].
-
-do_stfd(I) ->
- #stfd{src=Src,disp=Disp,base=Base} = I,
- NewSrc = do_fpreg(Src),
- NewDisp = do_disp(Disp),
- NewBase = do_reg(Base),
- [{stfd, {NewSrc,NewDisp,NewBase}, I}].
-
-do_fp_binary(I) ->
- #fp_binary{fp_binop=FpBinOp,dst=Dst,src1=Src1,src2=Src2} = I,
- NewDst = do_fpreg(Dst),
- NewSrc1 = do_fpreg(Src1),
- NewSrc2 = do_fpreg(Src2),
- [{FpBinOp, {NewDst,NewSrc1,NewSrc2}, I}].
-
-do_fp_unary(I) ->
- #fp_unary{fp_unop=FpUnOp,dst=Dst,src=Src} = I,
- NewDst = do_fpreg(Dst),
- NewSrc = do_fpreg(Src),
- [{FpUnOp, {NewDst,NewSrc}, I}].
-
-do_fpreg(#ppc_temp{reg=Reg,type='double'}) when is_integer(Reg), 0 =< Reg, Reg < 32 ->
- {fr,Reg}.
-
-do_reg(#ppc_temp{reg=Reg,type=Type})
- when is_integer(Reg), 0 =< Reg, Reg < 32, Type =/= 'double' ->
- {r,Reg}.
-
-do_label_ref(Label) when is_integer(Label) ->
- {label,Label}. % symbolic, since offset is not yet computable
-
-do_reg_or_imm(Src) ->
- case Src of
- #ppc_temp{} ->
- do_reg(Src);
- #ppc_simm16{value=Value} when is_integer(Value), -32768 =< Value, Value =< 32767 ->
- {simm, Value band 16#ffff};
- #ppc_uimm16{value=Value} when is_integer(Value), 0 =< Value, Value =< 65535 ->
- {uimm, Value}
- end.
-
-do_disp(Disp) when is_integer(Disp), -32768 =< Disp, Disp =< 32767 ->
- {d, Disp band 16#ffff}.
-
-do_disp_ds(Disp) when is_integer(Disp),
- -32768 =< Disp, Disp =< 32767, Disp band 3 =:= 0 ->
- {ds, (Disp band 16#ffff) bsr 2}.
-
-do_spr(SPR) ->
- SPR_NR =
- case SPR of
- 'xer' -> 1;
- 'lr' -> 8;
- 'ctr' -> 9
- end,
- {spr,SPR_NR}.
-
-%%%
-%%% Assembly Pass 3.
-%%% Process final {MFA,Code,CodeSize,LabelMap} list from pass 2.
-%%% Translate to a single binary code segment.
-%%% Collect relocation patches.
-%%% Build ExportMap (MFA-to-address mapping).
-%%% Combine LabelMaps to a single one (for mk_data_relocs/2 compatibility).
-%%% Return {CombinedCodeSize,BinaryCode,Relocs,CombinedLabelMap,ExportMap}.
-%%%
-
-encode(Code, Options) ->
- CodeSize = compute_code_size(Code, 0),
- ExportMap = build_export_map(Code, 0, []),
- {AccCode,Relocs} = encode_mfas(Code, 0, [], [], Options),
- CodeBinary = list_to_binary(lists:reverse(AccCode)),
- ?ASSERT(CodeSize =:= byte_size(CodeBinary)),
- CombinedLabelMap = combine_label_maps(Code, 0, gb_trees:empty()),
- {CodeSize,CodeBinary,Relocs,CombinedLabelMap,ExportMap}.
-
-compute_code_size([{_MFA,_Insns,CodeSize,_LabelMap}|Code], Size) ->
- compute_code_size(Code, Size+CodeSize);
-compute_code_size([], Size) -> Size.
-
-build_export_map([{{M,F,A},_Insns,CodeSize,_LabelMap}|Code], Address, ExportMap) ->
- build_export_map(Code, Address+CodeSize, [{Address,M,F,A}|ExportMap]);
-build_export_map([], _Address, ExportMap) -> ExportMap.
-
-combine_label_maps([{MFA,_Insns,CodeSize,LabelMap}|Code], Address, CLM) ->
- NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
- combine_label_maps(Code, Address+CodeSize, NewCLM);
-combine_label_maps([], _Address, CLM) -> CLM.
-
-merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
- NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
- merge_label_map(Rest, MFA, Address, NewCLM);
-merge_label_map([], _MFA, _Address, CLM) -> CLM.
-
-encode_mfas([{MFA,Insns,CodeSize,LabelMap}|Code], Address, AccCode, Relocs, Options) ->
- print("Generating code for: ~w\n", [MFA], Options),
- print("Offset | Opcode | Instruction\n", [], Options),
- {Address1,Relocs1,AccCode1} =
- encode_insns(Insns, Address, Address, LabelMap, Relocs, AccCode, Options),
- ExpectedAddress = Address + CodeSize,
- ?ASSERT(Address1 =:= ExpectedAddress),
- print("Finished.\n", [], Options),
- encode_mfas(Code, Address1, AccCode1, Relocs1, Options);
-encode_mfas([], _Address, AccCode, Relocs, _Options) ->
- {AccCode,Relocs}.
-
-encode_insns([I|Insns], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case I of
- {'.label',L,_} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ?ASSERT(Address =:= LabelAddress), % sanity check
- print_insn(Address, [], I, Options),
- encode_insns(Insns, Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- {'.reloc',Data,_} ->
- Reloc = encode_reloc(Data, Address, FunAddress, LabelMap),
- encode_insns(Insns, Address, FunAddress, LabelMap, [Reloc|Relocs], AccCode, Options);
- {bc_sdi,_,_} ->
- encode_insns(fix_bc_sdi(I, Insns, Address, FunAddress, LabelMap),
- Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- _ ->
- {Op,Arg,_} = fix_jumps(I, Address, FunAddress, LabelMap),
- Word = hipe_ppc_encode:insn_encode(Op, Arg),
- print_insn(Address, Word, I, Options),
- Segment = <<Word:32/integer-big>>,
- NewAccCode = [Segment|AccCode],
- encode_insns(Insns, Address+4, FunAddress, LabelMap, Relocs, NewAccCode, Options)
- end;
-encode_insns([], Address, _FunAddress, _LabelMap, Relocs, AccCode, _Options) ->
- {Address,Relocs,AccCode}.
-
-encode_reloc(Data, Address, FunAddress, LabelMap) ->
- case Data of
- {b_fun,MFAorPrim,Linkage} ->
- %% b and bl are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case Linkage of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- {PatchTypeExt, Address, untag_mfa_or_prim(MFAorPrim)};
- {load_atom,Atom} ->
- {?LOAD_ATOM, Address, Atom};
- {load_address,X} ->
- {?LOAD_ADDRESS, Address, X};
- {sdesc,SDesc} ->
- #ppc_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live} = SDesc,
- ExnRA =
- case ExnLab of
- [] -> []; % don't cons up a new one
- ExnLab -> gb_trees:get(ExnLab, LabelMap) + FunAddress
- end,
- {?SDESC, Address,
- ?STACK_DESC(ExnRA, FSize, Arity, Live)}
- end.
-
-untag_mfa_or_prim(#ppc_mfa{m=M,f=F,a=A}) -> {M,F,A};
-untag_mfa_or_prim(#ppc_prim{prim=Prim}) -> Prim.
-
-fix_bc_sdi(I, Insns, InsnAddress, FunAddress, LabelMap) ->
- {bc_sdi,Opnds,OrigI} = I,
- {{bcond,BCond},Label,{pred,Pred}} = Opnds,
- {label,L} = Label,
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- BD = (LabelAddress - InsnAddress) div 4,
- if BD >= -(16#2000), BD =< 16#1FFF ->
- [{bc, Opnds, OrigI} | Insns];
- true ->
- NewBCond = hipe_ppc:negate_bcond(BCond),
- NewPred = 1.0 - Pred,
- [{bc,
- {{bcond,NewBCond},'.+8',{pred,NewPred}},
- #bc{bcond=NewBCond,label='.+8',pred=NewPred}}, %% pp will be ugly
- {b, Label, #b_label{label=L}} |
- Insns]
- end.
-
-fix_jumps(I, InsnAddress, FunAddress, LabelMap) ->
- case I of
- {b, {label,L}, OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- LI = (LabelAddress - InsnAddress) div 4,
- %% ensure LI fits in a 24 bit sign-extended field
- ?ASSERT(LI =< 16#7FFFFF),
- ?ASSERT(LI >= -(16#800000)),
- {b, {{li,LI band 16#FFFFFF}}, OrigI};
- {bc, {{bcond,BCond},Target,{pred,Pred}}, OrigI} ->
- LabelAddress =
- case Target of
- {label,L} -> gb_trees:get(L, LabelMap) + FunAddress;
- '.+8' -> InsnAddress + 8
- end,
- BD = (LabelAddress - InsnAddress) div 4,
- %% ensure BD fits in a 14 bit sign-extended field
- ?ASSERT(BD =< 16#1FFF),
- ?ASSERT(BD >= -(16#2000)),
- {BO1,BI} = split_bcond(BCond),
- BO = mk_bo(BO1, Pred, BD),
- {bc, {{bo,BO},{bi,BI},{bd,BD band 16#3FFF}}, OrigI};
- _ -> I
- end.
-
-split_bcond(BCond) -> % {BO[1], BI for CR0}
- case BCond of
- 'lt' -> {1, 2#0000};
- 'ge' -> {0, 2#0000}; % not lt
- 'gt' -> {1, 2#0001};
- 'le' -> {0, 2#0001}; % not gt
- 'eq' -> {1, 2#0010};
- 'ne' -> {0, 2#0010}; % not eq
- 'so' -> {1, 2#0011};
- 'ns' -> {0, 2#0011} % not so
- end.
-
-mk_bo(BO1, Pred, BD) ->
- (BO1 bsl 3) bor 2#00100 bor mk_y(Pred, BD).
-
-mk_y(Pred, BD) ->
- if Pred < 0.5 -> % not taken
- if BD < 0 -> 1; true -> 0 end;
- true -> % taken
- if BD < 0 -> 0; true -> 1 end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%
-%%% Assembly listing support (pp_asm option).
-%%%
-
-print(String, Arglist, Options) ->
- ?when_option(pp_asm, Options, io:format(String, Arglist)).
-
-print_insn(Address, Word, I, Options) ->
- ?when_option(pp_asm, Options, print_insn_2(Address, Word, I)).
-
-print_insn_2(Address, Word, {_,_,OrigI}) ->
- io:format("~8.16.0b | ", [Address]),
- print_code_list(word_to_bytes(Word), 0),
- hipe_ppc_pp:pp_insn(OrigI).
-
-word_to_bytes(W) ->
- case W of
- [] -> []; % label or other pseudo instruction
- _ -> [(W bsr 24) band 16#FF, (W bsr 16) band 16#FF,
- (W bsr 8) band 16#FF, W band 16#FF]
- end.
-
-print_code_list([Byte|Rest], Len) ->
- print_byte(Byte),
- print_code_list(Rest, Len+1);
-print_code_list([], Len) ->
- fill_spaces(8-(Len*2)),
- io:format(" | ").
-
-print_byte(Byte) ->
- io:format("~2.16.0b", [Byte band 16#FF]).
-
-fill_spaces(N) when N > 0 ->
- io:format(" "),
- fill_spaces(N-1);
-fill_spaces(0) ->
- [].
diff --git a/lib/hipe/ppc/hipe_ppc_cfg.erl b/lib/hipe/ppc/hipe_ppc_cfg.erl
deleted file mode 100644
index d44d38f38d..0000000000
--- a/lib/hipe/ppc/hipe_ppc_cfg.erl
+++ /dev/null
@@ -1,152 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_cfg).
-
--export([init/1,
- labels/1, start_label/1,
- succ/2,
- map_bbs/2, fold_bbs/3,
- bb/2, bb_add/3]).
--export([postorder/1]).
--export([linearise/1, params/1, reverse_postorder/1]).
--export([redirect_jmp/3, arity/1]).
--export([branch_preds/1]).
-
-%%% these tell cfg.inc what to define (ugly as hell)
--define(BREADTH_ORDER,true).
--define(PARAMS_NEEDED,true).
--define(START_LABEL_UPDATE_NEEDED,true).
--define(MAP_FOLD_NEEDED,true).
-
--include("hipe_ppc.hrl").
--include("../flow/cfg.hrl").
--include("../flow/cfg.inc").
-
-init(Defun) ->
- Code = hipe_ppc:defun_code(Defun),
- StartLab = hipe_ppc:label_label(hd(Code)),
- Data = hipe_ppc:defun_data(Defun),
- IsClosure = hipe_ppc:defun_is_closure(Defun),
- Name = hipe_ppc:defun_mfa(Defun),
- IsLeaf = hipe_ppc:defun_is_leaf(Defun),
- Formals = hipe_ppc:defun_formals(Defun),
- CFG0 = mk_empty_cfg(Name, StartLab, Data, IsClosure, IsLeaf, Formals),
- take_bbs(Code, CFG0).
-
-is_branch(I) ->
- case I of
- #b_fun{} -> true;
- #b_label{} -> true;
- %% not bc
- #bctr{} -> true;
- %% not bctrl
- %% not bl
- #blr{} -> true;
- #pseudo_bc{} -> true;
- #pseudo_call{} -> true;
- #pseudo_tailcall{} -> true;
- _ -> false
- end.
-
-branch_successors(Branch) ->
- case Branch of
- #b_fun{} -> [];
- #b_label{label=Label} -> [Label];
- #bctr{labels=Labels} -> Labels;
- #blr{} -> [];
- #pseudo_bc{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
- #pseudo_call{contlab=ContLab, sdesc=#ppc_sdesc{exnlab=ExnLab}} ->
- case ExnLab of
- [] -> [ContLab];
- _ -> [ContLab,ExnLab]
- end;
- #pseudo_tailcall{} -> []
- end.
-
-branch_preds(Branch) ->
- case Branch of
- #bctr{labels=Labels} ->
- Prob = 1.0/length(Labels),
- [{L, Prob} || L <- Labels];
- #pseudo_bc{true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
- [{FalseLab, 1.0-Pred}, {TrueLab, Pred}];
- #pseudo_call{contlab=ContLab, sdesc=#ppc_sdesc{exnlab=[]}} ->
- %% A function can still cause an exception, even if we won't catch it
- [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}];
- #pseudo_call{contlab=ContLab, sdesc=#ppc_sdesc{exnlab=ExnLab}} ->
- CallExnPred = hipe_bb_weights:call_exn_pred(),
- [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}];
- _ ->
- case branch_successors(Branch) of
- [] -> [];
- [Single] -> [{Single, 1.0}]
- end
- end.
-
--ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
-fails_to(_Instr) -> [].
--endif.
-
-redirect_jmp(I, Old, New) ->
- case I of
- #b_label{label=Label} ->
- if Old =:= Label -> I#b_label{label=New};
- true -> I
- end;
- #pseudo_bc{true_label=TrueLab, false_label=FalseLab} ->
- I1 = if Old =:= TrueLab -> I#pseudo_bc{true_label=New};
- true -> I
- end,
- if Old =:= FalseLab -> I1#pseudo_bc{false_label=New};
- true -> I1
- end;
- #pseudo_call{sdesc=SDesc0, contlab=ContLab0} ->
- SDesc = case SDesc0 of
- #ppc_sdesc{exnlab=Old} -> SDesc0#ppc_sdesc{exnlab=New};
- #ppc_sdesc{exnlab=_} -> SDesc0
- end,
- ContLab = if Old =:= ContLab0 -> New;
- true -> ContLab0
- end,
- I#pseudo_call{sdesc=SDesc, contlab=ContLab}
- end.
-
-mk_goto(Label) ->
- hipe_ppc:mk_b_label(Label).
-
-is_label(I) ->
- hipe_ppc:is_label(I).
-
-label_name(Label) ->
- hipe_ppc:label_label(Label).
-
-mk_label(Name) ->
- hipe_ppc:mk_label(Name).
-
-linearise(CFG) -> % -> defun, not insn list
- MFA = function(CFG),
- Formals = params(CFG),
- Code = linearize_cfg(CFG),
- Data = data(CFG),
- VarRange = hipe_gensym:var_range(ppc),
- LabelRange = hipe_gensym:label_range(ppc),
- IsClosure = is_closure(CFG),
- IsLeaf = is_leaf(CFG),
- hipe_ppc:mk_defun(MFA, Formals, IsClosure, IsLeaf,
- Code, Data, VarRange, LabelRange).
-
-arity(CFG) ->
- {_M, _F, A} = function(CFG),
- A.
diff --git a/lib/hipe/ppc/hipe_ppc_defuse.erl b/lib/hipe/ppc/hipe_ppc_defuse.erl
deleted file mode 100644
index d8a864f7d5..0000000000
--- a/lib/hipe/ppc/hipe_ppc_defuse.erl
+++ /dev/null
@@ -1,150 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_defuse).
--export([insn_def_all/1, insn_use_all/1]).
--export([insn_def_gpr/1, insn_use_gpr/1]).
--export([insn_defs_all_gpr/1, insn_defs_all_fpr/1]).
--export([insn_def_fpr/1, insn_use_fpr/1]).
--include("hipe_ppc.hrl").
-
-%%%
-%%% Defs and uses for both general-purpose and floating-point registers.
-%%% This is needed for the frame module, alas.
-%%%
-insn_def_all(I) ->
- addtemps(insn_def_fpr(I), insn_def_gpr(I)).
-
-insn_use_all(I) ->
- addtemps(insn_use_fpr(I), insn_use_gpr(I)).
-
-%%%
-%%% Defs and uses for general-purpose (integer) registers only.
-%%%
-insn_def_gpr(I) ->
- case I of
- #alu{dst=Dst} -> [Dst];
- #load{dst=Dst} -> [Dst];
- #loadx{dst=Dst} -> [Dst];
- #mfspr{dst=Dst} -> [Dst];
- #pseudo_call{} -> call_clobbered_gpr();
- #pseudo_li{dst=Dst} -> [Dst];
- #pseudo_move{dst=Dst} -> [Dst];
- #pseudo_spill_move{dst=Dst,temp=Temp} -> [Dst, Temp];
- #pseudo_tailcall_prepare{} -> tailcall_clobbered_gpr();
- #unary{dst=Dst} -> [Dst];
- _ -> []
- end.
-
-insn_defs_all_gpr(#pseudo_call{}) -> true;
-insn_defs_all_gpr(_) -> false.
-
-call_clobbered_gpr() ->
- [hipe_ppc:mk_temp(R, T)
- || {R,T} <- hipe_ppc_registers:call_clobbered() ++ all_fp_pseudos()].
-
-all_fp_pseudos() -> []. % XXX: for now
-
-tailcall_clobbered_gpr() ->
- [hipe_ppc:mk_temp(R, T)
- || {R,T} <- hipe_ppc_registers:tailcall_clobbered() ++ all_fp_pseudos()].
-
-insn_use_gpr(I) ->
- case I of
- #alu{src1=Src1,src2=Src2} -> addsrc(Src2, [Src1]);
- #blr{} ->
- [hipe_ppc:mk_temp(hipe_ppc_registers:return_value(), 'tagged')];
- #cmp{src1=Src1,src2=Src2} -> addsrc(Src2, [Src1]);
- #load{base=Base} -> [Base];
- #loadx{base1=Base1,base2=Base2} -> addtemp(Base1, [Base2]);
- #mtcr{src=Src} -> [Src];
- #mtspr{src=Src} -> [Src];
- #pseudo_call{sdesc=#ppc_sdesc{arity=Arity}} -> arity_use_gpr(Arity);
- #pseudo_move{src=Src} -> [Src];
- #pseudo_spill_move{src=Src} -> [Src];
- #pseudo_tailcall{arity=Arity,stkargs=StkArgs} ->
- addsrcs(StkArgs, addtemps(tailcall_clobbered_gpr(), arity_use_gpr(Arity)));
- #store{src=Src,base=Base} -> addtemp(Src, [Base]);
- #storex{src=Src,base1=Base1,base2=Base2} ->
- addtemp(Src, addtemp(Base1, [Base2]));
- #unary{src=Src} -> [Src];
- #lfd{base=Base} -> [Base];
- #lfdx{base1=Base1,base2=Base2} -> addtemp(Base1, [Base2]);
- #stfd{base=Base} -> [Base];
- #stfdx{base1=Base1,base2=Base2} -> addtemp(Base1, [Base2]);
- _ -> []
- end.
-
-arity_use_gpr(Arity) ->
- [hipe_ppc:mk_temp(R, 'tagged')
- || R <- hipe_ppc_registers:args(Arity)].
-
-addsrcs([Arg|Args], Set) ->
- addsrcs(Args, addsrc(Arg, Set));
-addsrcs([], Set) ->
- Set.
-
-addsrc(Src, Set) ->
- case Src of
- #ppc_temp{} -> addtemp(Src, Set);
- _ -> Set
- end.
-
-%%%
-%%% Defs and uses for floating-point registers only.
-%%%
-insn_def_fpr(I) ->
- case I of
- #pseudo_call{} -> call_clobbered_fpr();
- #lfd{dst=Dst} -> [Dst];
- #lfdx{dst=Dst} -> [Dst];
- #fp_binary{dst=Dst} -> [Dst];
- #fp_unary{dst=Dst} -> [Dst];
- #pseudo_fmove{dst=Dst} -> [Dst];
- #pseudo_spill_fmove{dst=Dst,temp=Temp} -> [Dst, Temp];
- _ -> []
- end.
-
-insn_defs_all_fpr(#pseudo_call{}) -> true;
-insn_defs_all_fpr(_) -> false.
-
-call_clobbered_fpr() ->
- [hipe_ppc:mk_temp(R, 'double') || R <- hipe_ppc_registers:allocatable_fpr()].
-
-insn_use_fpr(I) ->
- case I of
- #stfd{src=Src} -> [Src];
- #stfdx{src=Src} -> [Src];
- #fp_binary{src1=Src1,src2=Src2} -> addtemp(Src1, [Src2]);
- #fp_unary{src=Src} -> [Src];
- #pseudo_fmove{src=Src} -> [Src];
- #pseudo_spill_fmove{src=Src} -> [Src];
- _ -> []
- end.
-
-%%%
-%%% Auxiliary operations on sets of temps
-%%% These sets are small. No point using gb_trees, right?
-%%%
-
-addtemps([Arg|Args], Set) ->
- addtemps(Args, addtemp(Arg, Set));
-addtemps([], Set) ->
- Set.
-
-addtemp(Temp, Set) ->
- case lists:member(Temp, Set) of
- false -> [Temp|Set];
- _ -> Set
- end.
diff --git a/lib/hipe/ppc/hipe_ppc_encode.erl b/lib/hipe/ppc/hipe_ppc_encode.erl
deleted file mode 100644
index 1d0ce4f510..0000000000
--- a/lib/hipe/ppc/hipe_ppc_encode.erl
+++ /dev/null
@@ -1,1553 +0,0 @@
-%%% -*- erlang-indent-level: 4 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Encode symbolic PowerPC instructions to binary form.
-%%% Copyright (C) 2003-2005, 2009 Mikael Pettersson
-%%%
-%%% Notes:
-%%% - PowerPC manuals use reversed bit numbering. In a 32-bit word,
-%%% the most significant bit has number 0, and the least significant
-%%% bit has number 31.
-%%% - PowerPC manuals list opcodes in decimal, not hex.
-%%% - This module does not support AltiVec instructions.
-%%%
-%%% Instruction Operands:
-%%%
-%%% {li,LI} long branch offset/address (24 bits, signed)
-%%% {bo,BO} branch control operand (5 bits, restricted)
-%%% {bi,BI} branch CR field and bits operand (5 bits)
-%%% {bd,BD} branch offset (14 bits, signed)
-%%% {to,TO} trap condition (5 bits)
-%%% {nb,NB} number of bytes to copy (5 bits)
-%%% {sh,SH} shift count (5 bits)
-%%% {mb,MB} mask begin bit number (5 bits)
-%%% {mb6,MB6} mask begin bit number (6 bits) (64-bit)
-%%% {me,ME} mask end bit number (5 bits)
-%%% {me6,ME6} mask end bit number (6 bits) (64-bit)
-%%% {sr,SR} segment register (4 bits)
-%%% {crimm,IMM} FPSCR CR image (4 bits)
-%%% {simm,SIMM} immediate operand (16 bits, signed)
-%%% {uimm,UIMM} immediate operand (16 bits, unsigned)
-%%% {d,Disp} load/store byte displacement (16 bits, signed)
-%%% {ds,DS} load/store word displacement (14 bits, signed) (64-bit)
-%%% {r,R} integer register (5 bits)
-%%% {fr,FR} floating-point register (5 bits)
-%%% {crf,CRF} CR field number (3 bits)
-%%% {crb,CRB} CR bit number (5 bits)
-%%% {tbr,TBR} TBR number (10 bits, 268 or 269)
-%%% {spr,SPR} SPR number (10 bits)
-%%% {crm,CRM} CR fields set (8 bits)
-%%% {fm,FM} FPSCR fields set (8 bits)
-
--module(hipe_ppc_encode).
-
--export([insn_encode/2]).
-
-%-define(TESTING,1).
--ifdef(TESTING).
--export([dotest/0, dotest/1]).
--endif.
-
--define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).
-
--define(BF(LB,RB,V), bf(LB,RB,V)).
-
-bf(LeftBit, RightBit, Value) ->
- ?ASSERT(LeftBit >= 0),
- ?ASSERT(LeftBit =< RightBit),
- ?ASSERT(RightBit < 32),
- ?ASSERT(Value >= 0),
- ?ASSERT(Value < (1 bsl ((RightBit - LeftBit) + 1))),
- Value bsl (31 - RightBit).
-
--define(BIT(Pos,Val), ?BF(Pos,Pos,Val)).
--define(BITS(N,Val), ?BF(32-N,31,Val)).
-
-%%% I-Form Instructions
-%%% b, ba, bl, bla
-
-b_AA_LK({{li,LI}}, AA, LK) ->
- ?BF(0,5,10#18) bor ?BF(6,29,LI) bor ?BIT(30,AA) bor ?BIT(31,LK).
-
-%%% B-Form Instructions
-%%% bc, bca, bcl, bcla
-
-bc_AA_LK({{bo,BO}, {bi,BI}, {bd,BD}}, AA, LK) ->
- ?BF(0,5,10#16) bor ?BF(6,10,BO) bor ?BF(11,15,BI) bor ?BF(16,29,BD) bor ?BIT(30,AA) bor ?BIT(31,LK).
-
-%%% SC-Form Instructions
-%%% sc
-
-sc({}) ->
- ?BF(0,5,10#17) bor ?BIT(30,1).
-
-%%% D-Form Instructions
-%%% addi, addic, addic., addis, mulli, subfic
-%%% andi., andis., ori, oris, xori, xoris
-%%% lbz, lbzu, lha, lhau, lhz, lhzu, lwz, lwzu, lfd, lfdu, lfs, lfsu, lmw
-%%% stb, stbu, sth, sthu, stw, stwu, stfd, stfdu, stfs, stfsu, stmw
-%%% cmpi, cmpli, twi
-%%% tdi (64-bit)
-
-d_form(OPCD, D, A, IMM) ->
- ?BF(0,5,OPCD) bor ?BF(6,10,D) bor ?BF(11,15,A) bor ?BF(16,31,IMM).
-
-d_form_D_A_SIMM(OPCD, {{r,D}, {r,A}, {simm,SIMM}}) ->
- d_form(OPCD, D, A, SIMM).
-
-addi(Opnds) -> d_form_D_A_SIMM(10#14, Opnds).
-addic(Opnds) -> d_form_D_A_SIMM(10#12, Opnds).
-addic_dot(Opnds) -> d_form_D_A_SIMM(10#13, Opnds).
-addis(Opnds) -> d_form_D_A_SIMM(10#15, Opnds).
-mulli(Opnds) -> d_form_D_A_SIMM(10#07, Opnds).
-subfic(Opnds) -> d_form_D_A_SIMM(10#08, Opnds).
-
-d_form_S_A_UIMM(OPCD, {{r,A}, {r,S}, {uimm,UIMM}}) ->
- d_form(OPCD, S, A, UIMM).
-
-andi_dot(Opnds) -> d_form_S_A_UIMM(10#28, Opnds).
-andis_dot(Opnds) -> d_form_S_A_UIMM(10#29, Opnds).
-ori(Opnds) -> d_form_S_A_UIMM(10#24, Opnds).
-oris(Opnds) -> d_form_S_A_UIMM(10#25, Opnds).
-xori(Opnds) -> d_form_S_A_UIMM(10#26, Opnds).
-xoris(Opnds) -> d_form_S_A_UIMM(10#27, Opnds).
-
-d_form_D_A_d_simple(OPCD, {{r,D}, {d,Disp}, {r,A}}) ->
- d_form(OPCD, D, A, Disp).
-
-d_form_D_A_d_update(OPCD, {{r,D}, {d,Disp}, {r,A}}) ->
- ?ASSERT(A =/= 0),
- ?ASSERT(A =/= D),
- d_form(OPCD, D, A, Disp).
-
-lbz(Opnds) -> d_form_D_A_d_simple(10#34, Opnds).
-lbzu(Opnds) -> d_form_D_A_d_update(10#35, Opnds).
-lha(Opnds) -> d_form_D_A_d_simple(10#42, Opnds).
-lhau(Opnds) -> d_form_D_A_d_update(10#43, Opnds).
-lhz(Opnds) -> d_form_D_A_d_simple(10#40, Opnds).
-lhzu(Opnds) -> d_form_D_A_d_update(10#41, Opnds).
-lwz(Opnds) -> d_form_D_A_d_simple(10#32, Opnds).
-lwzu(Opnds) -> d_form_D_A_d_update(10#33, Opnds).
-
-d_form_frD_A_d_simple(OPCD, {{fr,D}, {d,Disp}, {r,A}}) ->
- d_form(OPCD, D, A, Disp).
-
-d_form_frD_A_d_update(OPCD, {{fr,D}, {d,Disp}, {r,A}}) ->
- ?ASSERT(A =/= 0),
- d_form(OPCD, D, A, Disp).
-
-lfd(Opnds) -> d_form_frD_A_d_simple(10#50, Opnds).
-lfdu(Opnds) -> d_form_frD_A_d_update(10#51, Opnds).
-lfs(Opnds) -> d_form_frD_A_d_simple(10#48, Opnds).
-lfsu(Opnds) -> d_form_frD_A_d_update(10#49, Opnds).
-
-lmw({{r,D}, {d,Disp}, {r,A}}) ->
- ?ASSERT(A < D),
- d_form(10#46, D, A, Disp).
-
-d_form_S_A_d_simple(OPCD, {{r,S}, {d,Disp}, {r,A}}) ->
- d_form(OPCD, S, A, Disp).
-
-d_form_S_A_d_update(OPCD, {{r,S}, {d,Disp}, {r,A}}) ->
- ?ASSERT(A =/= 0),
- d_form(OPCD, S, A, Disp).
-
-stb(Opnds) -> d_form_S_A_d_simple(10#38, Opnds).
-stbu(Opnds) -> d_form_S_A_d_update(10#39, Opnds).
-sth(Opnds) -> d_form_S_A_d_simple(10#44, Opnds).
-sthu(Opnds) -> d_form_S_A_d_update(10#45, Opnds).
-stmw(Opnds) -> d_form_S_A_d_simple(10#47, Opnds).
-stw(Opnds) -> d_form_S_A_d_simple(10#36, Opnds).
-stwu(Opnds) -> d_form_S_A_d_update(10#37, Opnds).
-
-d_form_frS_A_d_simple(OPCD, {{fr,S}, {d,Disp}, {r,A}}) ->
- d_form(OPCD, S, A, Disp).
-
-d_form_frS_A_d_update(OPCD, {{fr,S}, {d,Disp}, {r,A}}) ->
- ?ASSERT(A =/= 0),
- d_form(OPCD, S, A, Disp).
-
-stfd(Opnds) -> d_form_frS_A_d_simple(10#54, Opnds).
-stfdu(Opnds) -> d_form_frS_A_d_update(10#55, Opnds).
-stfs(Opnds) -> d_form_frS_A_d_simple(10#52, Opnds).
-stfsu(Opnds) -> d_form_frS_A_d_update(10#53, Opnds).
-
-cmpi({{crf,CRFD}, L, {r,A}, {simm,SIMM}}) ->
- %% ?ASSERT(L == 0), % L must be zero in 32-bit code
- d_form(10#11, (CRFD bsl 2) bor L, A, SIMM).
-
-cmpli({{crf,CRFD}, L, {r,A}, {uimm,UIMM}}) ->
- %% ?ASSERT(L == 0), % L must be zero in 32-bit code
- d_form(10#10, (CRFD bsl 2) bor L, A, UIMM).
-
-d_form_OPCD_TO_A_SIMM(OPCD, {{to,TO}, {r,A}, {simm,SIMM}}) ->
- d_form(OPCD, TO, A, SIMM).
-
-tdi(Opnds) -> d_form_OPCD_TO_A_SIMM(10#02, Opnds). % 64-bit
-twi(Opnds) -> d_form_OPCD_TO_A_SIMM(10#03, Opnds).
-
-%%% DS-Form Instructions
-%%% ld, ldu, lwa, std, stdu (64-bit)
-
-ds_form(OPCD, D, A, DS, XO) ->
- ?BF(0,5,OPCD) bor ?BF(6,10,D) bor ?BF(11,15,A) bor ?BF(16,29,DS) bor ?BF(30,31,XO).
-
-ds_form_D_A_DS_XO_simple(OPCD, {{r,D}, {ds,DS}, {r,A}}, XO) ->
- ds_form(OPCD, D, A, DS, XO).
-
-ds_form_D_A_DS_XO_update(OPCD, {{r,D}, {ds,DS}, {r,A}}, XO) ->
- ?ASSERT(A =/= 0),
- ?ASSERT(A =/= D),
- ds_form(OPCD, D, A, DS, XO).
-
-ld(Opnds) -> ds_form_D_A_DS_XO_simple(10#58, Opnds, 10#0). % 64-bit
-ldu(Opnds) -> ds_form_D_A_DS_XO_update(10#58, Opnds, 10#1). % 64-bit
-lwa(Opnds) -> ds_form_D_A_DS_XO_simple(10#58, Opnds, 10#2). % 64-bit
-std(Opnds) -> ds_form_D_A_DS_XO_simple(10#62, Opnds, 10#0). % 64-bit
-stdu(Opnds) -> ds_form_D_A_DS_XO_update(10#62, Opnds, 10#1). % 64-bit
-
-%%% X-Form Instructions
-%%% ecixw, lbzux, lbzx, lhaux, lhax, lhbrx, lhzux, lhzx, lwarx, lwbrx, lwzux, lwzx, lswx
-%%% lwaux, lwax (64-bit)
-%%% lfdux, lfdx, lfsux, lfsx
-%%% lswi
-%%% fabs, fctiw, fctiwz, fmr, fnabs, fneg, frsp
-%%% fcfid, fctid, fctidz (64-bit)
-%%% mfsrin
-%%% mffs
-%%% mfcr, mfmsr
-%%% mfsr
-%%% and, andc, eqv, nand, nor, or, orc, slw, sraw, srw, xor
-%%% sld, srad, srd (64-bit)
-%%% stwcx.
-%%% stdcx. (64-bit)
-%%% ecowx, stbx, stbux, sthbrx, sthx, sthux, stswx, stwbrx, stwx, stwux
-%%% stdux, stdx (64-bit)
-%%% stfdx, stfdux, stfiwx, stfsx, stfsux
-%%% stswi
-%%% cntlzw, extsb, extsh
-%%% cntlzd, extsw (64-bit)
-%%% mtmsr
-%%% mtmsrd (64-bit)
-%%% mtsr, mtsrin
-%%% mtsrd, mtsrdin (64-bit)
-%%% srawi
-%%% sradi (64-bit)
-%%% cmp, cmpl
-%%% fcmpo, fcmpu
-%%% mcrfs
-%%% mcrxr (obsolete)
-%%% mtfsfi
-%%% tw
-%%% td (64-bit)
-%%% mtfsb0, mtfsb1
-%%% dcba, dcbf, dcbi, dcbst, dcbt, dcbtst, dcbz, icbi
-%%% tlbie
-%%% eieio, sync, tlbia, tlbsync
-
-x_form(OPCD, D, A, B, XO, Rc) ->
- ?BF(0,5,OPCD) bor ?BF(6,10,D) bor ?BF(11,15,A) bor ?BF(16,20,B) bor ?BF(21,30,XO) bor ?BIT(31,Rc).
-
-x_form_D_A_B_XO_simple({{r,D}, {r,A}, {r,B}}, XO) ->
- x_form(10#31, D, A, B, XO, 0).
-
-x_form_D_A_B_XO_update({{r,D}, {r,A}, {r,B}}, XO) ->
- ?ASSERT(A =/= 0),
- ?ASSERT(A =/= D),
- x_form(10#31, D, A, B, XO, 0).
-
-eciwx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#310). % optional
-lbzux(Opnds) -> x_form_D_A_B_XO_update(Opnds, 10#119).
-lbzx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#87).
-ldarx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#84). % 64-bit
-ldux(Opnds) -> x_form_D_A_B_XO_update(Opnds, 10#53). % 64-bit
-ldx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#21). % 64-bit
-lhaux(Opnds) -> x_form_D_A_B_XO_update(Opnds, 10#375).
-lhax(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#343).
-lhbrx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#790).
-lhzux(Opnds) -> x_form_D_A_B_XO_update(Opnds, 10#311).
-lhzx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#279).
-lswx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#533). % XXX: incomplete checks
-lwarx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#20).
-lwaux(Opnds) -> x_form_D_A_B_XO_update(Opnds, 10#373). % 64-bit
-lwax(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#341). % 64-bit
-lwbrx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#534).
-lwzux(Opnds) -> x_form_D_A_B_XO_update(Opnds, 10#55).
-lwzx(Opnds) -> x_form_D_A_B_XO_simple(Opnds, 10#23).
-
-x_form_frD_A_B_XO_simple({{fr,D}, {r,A}, {r,B}}, XO) ->
- x_form(10#31, D, A, B, XO, 0).
-
-x_form_frD_A_B_XO_update({{fr,D}, {r,A}, {r,B}}, XO) ->
- ?ASSERT(A =/= 0),
- x_form(10#31, D, A, B, XO, 0).
-
-lfdux(Opnds) -> x_form_frD_A_B_XO_update(Opnds, 10#631).
-lfdx(Opnds) -> x_form_frD_A_B_XO_simple(Opnds, 10#599).
-lfsux(Opnds) -> x_form_frD_A_B_XO_update(Opnds, 10#567).
-lfsx(Opnds) -> x_form_frD_A_B_XO_simple(Opnds, 10#535).
-
-lswi({{r,D}, {r,A}, {nb,NB}}) -> % XXX: incomplete checks
- x_form(10#31, D, A, NB, 10#597, 0).
-
-x_form_D_B_XO_Rc({{fr,D}, {fr,B}}, XO, Rc) ->
- x_form(10#63, D, 0, B, XO, Rc).
-
-fabs_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#264, Rc).
-fcfid_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#846, Rc). % 64-bit
-fctid_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#814, Rc). % 64-bit
-fctidz_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#815, Rc). % 64-bit
-fctiw_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#14, Rc).
-fctiwz_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#15, Rc).
-fmr_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#72, Rc).
-fnabs_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#136, Rc).
-fneg_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#40, Rc).
-frsp_Rc(Opnds, Rc) -> x_form_D_B_XO_Rc(Opnds, 10#12, Rc).
-
-mfsrin({{r,D}, {r,B}}) -> % supervisor
- x_form(10#31, D, 0, B, 10#659, 0).
-
-mffs_Rc({{fr,D}}, Rc) ->
- x_form(10#63, D, 0, 0, 10#583, Rc).
-
-x_form_D_XO({{r,D}}, XO) ->
- x_form(10#31, D, 0, 0, XO, 0).
-
-mfcr(Opnds) -> x_form_D_XO(Opnds, 10#19).
-mfmsr(Opnds) -> x_form_D_XO(Opnds, 10#83). % supervisor
-
-mfsr({{r,D}, {sr,SR}}) -> % supervisor
- x_form(10#31, D, ?BITS(4,SR), 0, 10#595, 0).
-
-x_form_S_A_B_XO_Rc({{r,A}, {r,S}, {r,B}}, XO, Rc) ->
- x_form(10#31, S, A, B, XO, Rc).
-
-and_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#28, Rc).
-andc_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#60, Rc).
-eqv_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#284, Rc).
-nand_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#476, Rc).
-nor_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#124, Rc).
-or_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#444, Rc).
-orc_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#412, Rc).
-sld_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#27, Rc). % 64-bit
-slw_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#24, Rc).
-srad_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#794, Rc). % 64-bit
-sraw_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#792, Rc).
-srd_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#539, Rc). % 64-bit
-srw_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#536, Rc).
-xor_Rc(Opnds, Rc) -> x_form_S_A_B_XO_Rc(Opnds, 10#316, Rc).
-
-xform_S_A_B_XO_1({{r,S}, {r,A}, {r,B}}, XO) ->
- x_form(10#31, S, A, B, XO, 1).
-
-stdcx_dot(Opnds) -> xform_S_A_B_XO_1(Opnds, 10#214). % 64-bit
-stwcx_dot(Opnds) -> xform_S_A_B_XO_1(Opnds, 10#150).
-
-x_form_S_A_B_XO_simple({{r,S}, {r,A}, {r,B}}, XO) ->
- x_form(10#31, S, A, B, XO, 0).
-
-x_form_S_A_B_XO_update({{r,S}, {r,A}, {r,B}}, XO) ->
- ?ASSERT(A =/= 0),
- x_form(10#31, S, A, B, XO, 0).
-
-ecowx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#438). % optional
-stbx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#215).
-stbux(Opnds) -> x_form_S_A_B_XO_update(Opnds, 10#247).
-sthbrx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#918).
-stdx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#149). % 64-bit
-stdux(Opnds) -> x_form_S_A_B_XO_update(Opnds, 10#181). % 64-bit
-sthx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#407).
-sthux(Opnds) -> x_form_S_A_B_XO_update(Opnds, 10#439).
-stswx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#661).
-stwbrx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#662).
-stwx(Opnds) -> x_form_S_A_B_XO_simple(Opnds, 10#151).
-stwux(Opnds) -> x_form_S_A_B_XO_update(Opnds, 10#183).
-
-x_form_frS_A_B_XO_simple({{fr,S}, {r,A}, {r,B}}, XO) ->
- x_form(10#31, S, A, B, XO, 0).
-
-x_form_frS_A_B_XO_update({{fr,S}, {r,A}, {r,B}}, XO) ->
- ?ASSERT(A =/= 0),
- x_form(10#31, S, A, B, XO, 0).
-
-stfdx(Opnds) -> x_form_frS_A_B_XO_simple(Opnds, 10#727).
-stfdux(Opnds) -> x_form_frS_A_B_XO_update(Opnds, 10#759).
-stfiwx(Opnds) -> x_form_frS_A_B_XO_simple(Opnds, 10#983). % optional
-stfsx(Opnds) -> x_form_frS_A_B_XO_simple(Opnds, 10#663).
-stfsux(Opnds) -> x_form_frS_A_B_XO_update(Opnds, 10#695).
-
-stswi({{r,S}, {r,A}, {nb,NB}}) ->
- x_form(10#31, S, A, NB, 10#725, 0).
-
-x_form_S_A_XO_Rc({{r,A}, {r,S}}, XO, Rc) ->
- x_form(10#31, S, A, 0, XO, Rc).
-
-cntlzd_Rc(Opnds, Rc) -> x_form_S_A_XO_Rc(Opnds, 10#58, Rc). % 64-bit
-cntlzw_Rc(Opnds, Rc) -> x_form_S_A_XO_Rc(Opnds, 10#26, Rc).
-extsb_Rc(Opnds, Rc) -> x_form_S_A_XO_Rc(Opnds, 10#954, Rc).
-extsh_Rc(Opnds, Rc) -> x_form_S_A_XO_Rc(Opnds, 10#922, Rc).
-extsw_Rc(Opnds, Rc) -> x_form_S_A_XO_Rc(Opnds, 10#986, Rc). % 64-bit
-
-mtmsr({{r,S}}) -> % supervisor
- x_form(10#31, S, 0, 0, 10#146, 0).
-
-mtmsrd({{r,S}}) -> % supervisor, 64-bit
- x_form(10#31, S, 0, 0, 10#178, 0).
-
-mtsr({{sr,SR}, {r,S}}) -> % supervisor
- x_form(10#31, S, ?BITS(4,SR), 0, 10#210, 0).
-
-mtsrd({{sr,SR}, {r,S}}) -> % supervisor, 64-bit
- x_form(10#31, S, ?BITS(4,SR), 0, 10#82, 0).
-
-mtsrdin({{r,S}, {r,B}}) -> % supervisor, 64-bit
- x_form(10#31, S, 0, B, 10#114, 0).
-
-mtsrin({{r,S}, {r,B}}) -> % supervisor, 32-bit
- x_form(10#31, S, 0, B, 10#242, 0).
-
-slbia({}) -> % supervisor, 64-bit
- x_form(10#31, 0, 0, 0, 10#498, 0).
-
-slbie({{r,B}}) -> % supervisor, 64-bit
- x_form(10#31, 0, 0, B, 10#434, 0).
-
-srawi_Rc({{r,A}, {r,S}, {sh,SH}}, Rc) ->
- x_form(10#31, S, A, SH, 10#824, Rc).
-
-x_form_crfD_L_A_B_XO({{crf,CRFD}, L, {r,A}, {r,B}}, XO) ->
- %% ?ASSERT(L == 0), % L should be zero in 32-bit code
- x_form(10#31, (CRFD bsl 2) bor L, A, B, XO, 0).
-
-cmp(Opnds) -> x_form_crfD_L_A_B_XO(Opnds, 0).
-cmpl(Opnds) -> x_form_crfD_L_A_B_XO(Opnds, 10#32).
-
-x_form_crfD_A_B_XO({{crf,CRFD}, {fr,A}, {fr,B}}, XO) ->
- x_form(10#63, CRFD bsl 2, A, B, XO, 0).
-
-fcmpo(Opnds) -> x_form_crfD_A_B_XO(Opnds, 10#32).
-fcmpu(Opnds) -> x_form_crfD_A_B_XO(Opnds, 0).
-
-mcrfs({{crf,CRFD}, {crf,CRFS}}) ->
- x_form(10#63, CRFD bsl 2, CRFS bsl 2, 0, 10#64, 0).
-
-%% mcrxr({{crf,CRFD}}) ->
-%% x_form(10#31, CRFD bsl 2, 0, 0, 10#512, 0).
-
-mtfsfi_Rc({{crf,CRFD}, {crimm,IMM}}, Rc) ->
- x_form(10#63, CRFD bsl 2, 0, IMM bsl 1, 10#134, Rc).
-
-x_form_TO_A_B_XO({{to,TO}, {r,A}, {r,B}}, XO) ->
- x_form(10#31, TO, A, B, XO, 0).
-
-td(Opnds) -> x_form_TO_A_B_XO(Opnds, 10#68). % 64-bit
-tw(Opnds) -> x_form_TO_A_B_XO(Opnds, 10#4).
-
-x_form_crbD_XO_Rc({{crb,CRBD}}, XO, Rc) ->
- x_form(10#63, CRBD, 0, 0, XO, Rc).
-
-mtfsb0_Rc(Opnds, Rc) -> x_form_crbD_XO_Rc(Opnds, 10#70, Rc).
-mtfsb1_Rc(Opnds, Rc) -> x_form_crbD_XO_Rc(Opnds, 10#38, Rc).
-
-x_form_A_B_XO({{r,A}, {r,B}}, XO) ->
- x_form(10#31, 0, A, B, XO, 0).
-
-dcba(Opnds) -> x_form_A_B_XO(Opnds, 10#758). % optional
-dcbf(Opnds) -> x_form_A_B_XO(Opnds, 10#86).
-dcbi(Opnds) -> x_form_A_B_XO(Opnds, 10#470). % supervisor
-dcbst(Opnds) -> x_form_A_B_XO(Opnds, 10#54).
-dcbt(Opnds) -> x_form_A_B_XO(Opnds, 10#278).
-dcbtst(Opnds) -> x_form_A_B_XO(Opnds, 10#246).
-dcbz(Opnds) -> x_form_A_B_XO(Opnds, 10#1014).
-icbi(Opnds) -> x_form_A_B_XO(Opnds, 10#982).
-
-x_form_B_XO({{r,B}}, XO) ->
- x_form(10#31, 0, 0, B, XO, 0).
-
-tlbie(Opnds) -> x_form_B_XO(Opnds, 10#306). % supervisor, optional
-tlbld(Opnds) -> x_form_B_XO(Opnds, 10#978). % supervisor, optional
-tlbli(Opnds) -> x_form_B_XO(Opnds, 10#1010). % supervisor, optional
-
-x_form_XO({}, XO) ->
- x_form(10#31, 0, 0, 0, XO, 0).
-
-eieio(Opnds) -> x_form_XO(Opnds, 10#854).
-sync(Opnds) -> x_form_XO(Opnds, 10#598).
-tlbia(Opnds) -> x_form_XO(Opnds, 10#370). % supervisor, optional
-tlbsync(Opnds) -> x_form_XO(Opnds, 10#566). % supervisor, optional
-
-%%% XL-Form Instructions
-%%% bcctr, bclr
-%%% crand, crandc, creqv, crnand, crnor, cror, crorc, crxor
-%%% mcrf
-%%% isync, rfi
-%%% rfid (64-bit)
-
-xl_form(A, B, C, XO, LK) ->
- ?BF(0,5,10#19) bor ?BF(6,10,A) bor ?BF(11,15,B) bor ?BF(16,20,C) bor ?BF(21,30,XO) bor ?BIT(31,LK).
-
-xl_form_BO_BI_XO_LK({{bo,BO}, {bi,BI}}, XO, LK) ->
- xl_form(BO, BI, 0, XO, LK).
-
-bcctr_lk(Opnds, LK) -> xl_form_BO_BI_XO_LK(Opnds, 10#528, LK).
-bclr_lk(Opnds, LK) -> xl_form_BO_BI_XO_LK(Opnds, 10#16, LK).
-
-xl_form_crbD_crbA_crbB_XO({{crb,CRBD}, {crb,CRBA}, {crb,CRBB}}, XO) ->
- xl_form(CRBD, CRBA, CRBB, XO, 0).
-
-crand(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#257).
-crandc(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#129).
-creqv(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#289).
-crnand(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#225).
-crnor(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#33).
-cror(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#449).
-crorc(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#417).
-crxor(Opnds) -> xl_form_crbD_crbA_crbB_XO(Opnds, 10#193).
-
-mcrf({{crf,CRFD}, {crf,CRFS}}) ->
- xl_form(CRFD bsl 2, CRFS bsl 2, 0, 0, 0).
-
-xl_form_XO({}, XO) ->
- xl_form(0, 0, 0, XO, 0).
-
-isync(Opnds) -> xl_form_XO(Opnds, 10#150).
-rfi(Opnds) -> xl_form_XO(Opnds, 10#50). % supervisor
-rfid(Opnds) -> xl_form_XO(Opnds, 10#18). % supervisor, 64-bit
-
-%%% XFX-Form Instructions
-%%% mfspr, mtspr, mftb, mtcrf
-
-xfx_form(A, B, XO) ->
- ?BF(0,5,10#31) bor ?BF(6,10,A) bor ?BF(11,20,B) bor ?BF(21,30,XO).
-
-xfx_form_R_SPR_XO(R, SPR, XO) ->
- SPR04 = SPR band 16#1F,
- SPR59 = (SPR bsr 5) band 16#1F,
- xfx_form(R, (SPR04 bsl 5) bor SPR59, XO).
-
-mfspr({{r,D}, {spr,SPR}}) -> xfx_form_R_SPR_XO(D, SPR, 10#339).
-mtspr({{spr,SPR}, {r,S}}) -> xfx_form_R_SPR_XO(S, SPR, 10#467).
-mftb({{r,D}, {tbr,TBR}}) -> xfx_form_R_SPR_XO(D, TBR, 10#371).
-
-mtcrf({{crm,CRM}, {r,S}}) -> xfx_form(S, ?BITS(8,CRM) bsl 1, 10#144).
-
-%%% XFL-Form Instructions
-%%% mtfsf
-
-xfl_form(FM, B, Rc) ->
- ?BF(0,5,10#63) bor ?BF(7,14,FM) bor ?BF(16,20,B) bor ?BF(21,30,10#711) bor ?BIT(31,Rc).
-
-mtfsf_Rc({{fm,FM}, {fr,B}}, Rc) -> xfl_form(FM, B, Rc).
-
-%%% XS-Form Instructions
-%%% sradi (64-bit)
-
-xs_form(S, A, SH1, XO, SH2, Rc) ->
- ?BF(0,5,10#31) bor ?BF(6,10,S) bor ?BF(11,15,A) bor ?BF(16,20,SH1) bor ?BF(21,29,XO) bor ?BIT(30,SH2) bor ?BIT(31,Rc).
-
-sradi_Rc({{r,A}, {r,S}, {sh6,SH6}}, Rc) -> % 64-bit
- xs_form(S, A, sh6_bits0to4(SH6), 10#413, sh6_bit5(SH6), Rc).
-
-%%% XO-Form Instructions
-%%% add, addc, adde, divw, divwu, mullw, subf, subfc, subfe
-%%% divd, divdu, mulld (64-bit)
-%%% mulhw, mulhwu
-%%% mulhd, mulhdu (64-bit)
-%%% addme, addze, neg, subfme, subfze
-
-xo_form(D, A, B, OE, XO, Rc) ->
- ?BF(0,5,10#31) bor ?BF(6,10,D) bor ?BF(11,15,A) bor ?BF(16,20,B) bor ?BIT(21,OE) bor ?BF(22,30,XO) bor ?BIT(31,Rc).
-
-xo_form_D_A_B_OE_XO_Rc({{r,D}, {r,A}, {r,B}}, OE, XO, Rc) ->
- xo_form(D, A, B, OE, XO, Rc).
-
-add_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#266, Rc).
-addc_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#10, Rc).
-adde_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#138, Rc).
-divd_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#489, Rc). % 64-bit
-divdu_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#457, Rc). % 64-bit
-divw_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#491, Rc).
-divwu_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#459, Rc).
-mulld_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#233, Rc). % 64-bit
-mullw_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#235, Rc).
-subf_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#40, Rc).
-subfc_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#8, Rc).
-subfe_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, OE, 10#136, Rc).
-
-mulhd_Rc(Opnds, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, 0, 10#73, Rc). % 64-bit
-mulhdu_Rc(Opnds, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, 0, 10#9, Rc). % 64-bit
-mulhw_Rc(Opnds, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, 0, 10#75, Rc).
-mulhwu_Rc(Opnds, Rc) -> xo_form_D_A_B_OE_XO_Rc(Opnds, 0, 10#11, Rc).
-
-xo_form_D_A_OE_XO_Rc({{r,D}, {r,A}}, OE, XO, Rc) ->
- xo_form(D, A, 0, OE, XO, Rc).
-
-addme_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_OE_XO_Rc(Opnds, OE, 10#234, Rc).
-addze_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_OE_XO_Rc(Opnds, OE, 10#202, Rc).
-neg_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_OE_XO_Rc(Opnds, OE, 10#104, Rc).
-subfme_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_OE_XO_Rc(Opnds, OE, 10#232, Rc).
-subfze_OE_Rc(Opnds, OE, Rc) -> xo_form_D_A_OE_XO_Rc(Opnds, OE, 10#200, Rc).
-
-%%% A-Form Instructions
-%%% fadd, fadds, fdiv, fdivs, fsub, fsubs
-%%% fmadd, fmadds, fmsub, fmsubs, fnmadd, fnmadds, fnmsub, fnmsubs, fsel
-%%% fmul, fmuls
-%%% fres, fsqrte, fsqrt, fsqrts
-
-a_form(OPCD, D, A, B, C, XO, Rc) ->
- ?BF(0,5,OPCD) bor ?BF(6,10,D) bor ?BF(11,15,A) bor ?BF(16,20,B) bor ?BF(21,25,C) bor ?BF(26,30,XO) bor ?BIT(31,Rc).
-
-a_form_D_A_B_XO_Rc(OPCD, {{fr,D}, {fr,A}, {fr,B}}, XO, Rc) ->
- a_form(OPCD, D, A, B, 0, XO, Rc).
-
-fadd_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_XO_Rc(OPCD, Opnds, 10#21, Rc).
-fadd_Rc(Opnds, Rc) -> fadd_OPCD_Rc(10#63, Opnds, Rc).
-fadds_Rc(Opnds, Rc) -> fadd_OPCD_Rc(10#59, Opnds, Rc).
-
-fdiv_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_XO_Rc(OPCD, Opnds, 10#18, Rc).
-fdiv_Rc(Opnds, Rc) -> fdiv_OPCD_Rc(10#63, Opnds, Rc).
-fdivs_Rc(Opnds, Rc) -> fdiv_OPCD_Rc(10#59, Opnds, Rc).
-
-fsub_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_XO_Rc(OPCD, Opnds, 10#20, Rc).
-fsub_Rc(Opnds, Rc) -> fsub_OPCD_Rc(10#63, Opnds, Rc).
-fsubs_Rc(Opnds, Rc) -> fsub_OPCD_Rc(10#59, Opnds, Rc).
-
-a_form_D_A_B_C_XO_Rc(OPCD, {{fr,D}, {fr,A}, {fr,C}, {fr,B}}, XO, Rc) ->
- a_form(OPCD, D, A, B, C, XO, Rc).
-
-fmadd_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_C_XO_Rc(OPCD, Opnds, 10#29, Rc).
-fmadd_Rc(Opnds, Rc) -> fmadd_OPCD_Rc(10#63, Opnds, Rc).
-fmadds_Rc(Opnds, Rc) -> fmadd_OPCD_Rc(10#59, Opnds, Rc).
-
-fmsub_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_C_XO_Rc(OPCD, Opnds, 10#28, Rc).
-fmsub_Rc(Opnds, Rc) -> fmsub_OPCD_Rc(10#63, Opnds, Rc).
-fmsubs_Rc(Opnds, Rc) -> fmsub_OPCD_Rc(10#59, Opnds, Rc).
-
-fnmadd_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_C_XO_Rc(OPCD, Opnds, 10#31, Rc).
-fnmadd_Rc(Opnds, Rc) -> fnmadd_OPCD_Rc(10#63, Opnds, Rc).
-fnmadds_Rc(Opnds, Rc) -> fnmadd_OPCD_Rc(10#59, Opnds, Rc).
-
-fnmsub_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_A_B_C_XO_Rc(OPCD, Opnds, 10#30, Rc).
-fnmsub_Rc(Opnds, Rc) -> fnmsub_OPCD_Rc(10#63, Opnds, Rc).
-fnmsubs_Rc(Opnds, Rc) -> fnmsub_OPCD_Rc(10#59, Opnds, Rc).
-
-fsel_Rc(Opnds, Rc) -> a_form_D_A_B_C_XO_Rc(10#63, Opnds, 10#23, Rc). % optional
-
-fmul_OPCD_Rc(OPCD, {{fr,D}, {fr,A}, {fr,C}}, Rc) ->
- a_form(OPCD, D, A, 0, C, 10#25, Rc).
-
-fmul_Rc(Opnds, Rc) -> fmul_OPCD_Rc(10#63, Opnds, Rc).
-fmuls_Rc(Opnds, Rc) -> fmul_OPCD_Rc(10#59, Opnds, Rc).
-
-a_form_D_B_XO_Rc(OPCD, {{fr,D}, {fr,B}}, XO, Rc) ->
- a_form(OPCD, D, 0, B, 0, XO, Rc).
-
-fres_Rc(Opnds, Rc) -> a_form_D_B_XO_Rc(10#59, Opnds, 10#24, Rc). % optional
-frsqrte_Rc(Opnds, Rc) -> a_form_D_B_XO_Rc(10#63, Opnds, 10#26, Rc). % optional
-
-fsqrt_OPCD_Rc(OPCD, Opnds, Rc) -> a_form_D_B_XO_Rc(OPCD, Opnds, 10#22, Rc). % optional
-fsqrt_Rc(Opnds, Rc) -> fsqrt_OPCD_Rc(10#63, Opnds, Rc). % optional
-fsqrts_Rc(Opnds, Rc) -> fsqrt_OPCD_Rc(10#59, Opnds, Rc). % optional
-
-%%% M-Form Instructions
-%%% rlwimi, rlwinm
-%%% rlwnm
-
-m_form(OPCD, S, A, SH, MB, ME, Rc) ->
- ?BF(0,5,OPCD) bor ?BF(6,10,S) bor ?BF(11,15,A) bor ?BF(16,20,SH) bor ?BF(21,25,MB) bor ?BF(26,30,ME) bor ?BIT(31,Rc).
-
-m_form_S_A_SH_MB_ME_Rc(OPCD, {{r,A}, {r,S}, {sh,SH}, {mb,MB}, {me,ME}}, Rc) ->
- m_form(OPCD, S, A, SH, MB, ME, Rc).
-
-rlwimi_Rc(Opnds, Rc) -> m_form_S_A_SH_MB_ME_Rc(10#20, Opnds, Rc).
-rlwinm_Rc(Opnds, Rc) -> m_form_S_A_SH_MB_ME_Rc(10#21, Opnds, Rc).
-
-rlwnm_Rc({{r,A}, {r,S}, {r,B}, {mb,MB}, {me,ME}}, Rc) ->
- m_form(10#23, S, A, B, MB, ME, Rc).
-
-%%% MD-Form Instructions
-%%% rldic, rldicl, rldicr, rldimi (64-bit)
-
-md_form(S, A, SH1, MB, XO, SH2, Rc) ->
- ?BF(0,5,10#30) bor ?BF(6,10,S) bor ?BF(11,15,A) bor ?BF(16,20,SH1) bor ?BF(21,26,MB) bor ?BF(27,29,XO) bor ?BIT(30,SH2) bor ?BIT(31,Rc).
-
-mb6_reformat(MB6) ->
- ((MB6 band 16#1F) bsl 1) bor ((MB6 bsr 5) band 1).
-
-sh6_bits0to4(SH6) ->
- SH6 band 16#1F.
-
-sh6_bit5(SH6) ->
- (SH6 bsr 5) band 1.
-
-md_form_S_A_SH6_MB6_XO_Rc({{r,A}, {r,S}, {sh6,SH6}, {mb6,MB6}}, XO, Rc) ->
- md_form(S, A, sh6_bits0to4(SH6), mb6_reformat(MB6), XO, sh6_bit5(SH6), Rc).
-
-rldic_Rc(Opnds, Rc) -> md_form_S_A_SH6_MB6_XO_Rc(Opnds, 10#2, Rc). % 64-bit
-rldicl_Rc(Opnds, Rc) -> md_form_S_A_SH6_MB6_XO_Rc(Opnds, 10#0, Rc). % 64-bit
-rldimi_Rc(Opnds, Rc) -> md_form_S_A_SH6_MB6_XO_Rc(Opnds, 10#3, Rc). % 64-bit
-
-rldicr_Rc({{r,A}, {r,S}, {sh6,SH6}, {me6,ME6}}, Rc) -> % 64-bit
- md_form(S, A, sh6_bits0to4(SH6), mb6_reformat(ME6), 10#1, sh6_bit5(SH6), Rc).
-
-%%% MDS-Form Instructions
-%%% rldcl, rldcr (64-bit)
-
-mds_form(S, A, B, MB, XO, Rc) ->
- ?BF(0,5,10#30) bor ?BF(6,10,S) bor ?BF(11,15,A) bor ?BF(16,20,B) bor ?BF(21,26,MB) bor ?BF(27,30,XO) bor ?BIT(31,Rc).
-
-rldcl({{r,A}, {r,S}, {r,B}, {mb6,MB6}}, Rc) -> % 64-bit
- mds_form(S, A, B, mb6_reformat(MB6), 10#8, Rc).
-
-rldcr({{r,A}, {r,S}, {r,B}, {me6,ME6}}, Rc) -> % 64-bit
- mds_form(S, A, B, mb6_reformat(ME6), 10#9, Rc).
-
-%%% main encode dispatch
-
-insn_encode(Op, Opnds) ->
- case Op of
- %% I-Form
- 'b' -> b_AA_LK(Opnds, 0, 0);
- 'ba' -> b_AA_LK(Opnds, 1, 0);
- 'bl' -> b_AA_LK(Opnds, 0, 1);
- 'bla' -> b_AA_LK(Opnds, 1, 1);
- %% B-Form
- 'bc' -> bc_AA_LK(Opnds, 0, 0);
- 'bca' -> bc_AA_LK(Opnds, 1, 0);
- 'bcl' -> bc_AA_LK(Opnds, 0, 1);
- 'bcla' -> bc_AA_LK(Opnds, 1, 1);
- %% SC-Form
- 'sc' -> sc(Opnds);
- %% D-Form
- 'addi' -> addi(Opnds);
- 'addic' -> addic(Opnds);
- 'addic.' -> addic_dot(Opnds);
- 'addis' -> addis(Opnds);
- 'andi.' -> andi_dot(Opnds);
- 'andis.' -> andis_dot(Opnds);
- 'cmpi' -> cmpi(Opnds);
- 'cmpli' -> cmpli(Opnds);
- 'lbz' -> lbz(Opnds);
- 'lbzu' -> lbzu(Opnds);
- 'lfd' -> lfd(Opnds);
- 'lfdu' -> lfdu(Opnds);
- 'lfs' -> lfs(Opnds);
- 'lfsu' -> lfsu(Opnds);
- 'lha' -> lha(Opnds);
- 'lhau' -> lhau(Opnds);
- 'lhz' -> lhz(Opnds);
- 'lhzu' -> lhzu(Opnds);
- 'lmw' -> lmw(Opnds);
- 'lwz' -> lwz(Opnds);
- 'lwzu' -> lwzu(Opnds);
- 'mulli' -> mulli(Opnds);
- 'ori' -> ori(Opnds);
- 'oris' -> oris(Opnds);
- 'stb' -> stb(Opnds);
- 'stbu' -> stbu(Opnds);
- 'stfd' -> stfd(Opnds);
- 'stfdu' -> stfdu(Opnds);
- 'stfs' -> stfs(Opnds);
- 'stfsu' -> stfsu(Opnds);
- 'sth' -> sth(Opnds);
- 'sthu' -> sthu(Opnds);
- 'stmw' -> stmw(Opnds);
- 'stw' -> stw(Opnds);
- 'stwu' -> stwu(Opnds);
- 'subfic' -> subfic(Opnds);
- 'tdi' -> tdi(Opnds);
- 'twi' -> twi(Opnds);
- 'xori' -> xori(Opnds);
- 'xoris' -> xoris(Opnds);
- %% DS-Form
- 'ld' -> ld(Opnds);
- 'ldu' -> ldu(Opnds);
- 'lwa' -> lwa(Opnds);
- 'std' -> std(Opnds);
- 'stdu' -> stdu(Opnds);
- %% X-Form
- 'and' -> and_Rc(Opnds, 0);
- 'and.' -> and_Rc(Opnds, 1);
- 'andc' -> andc_Rc(Opnds, 0);
- 'andc.' -> andc_Rc(Opnds, 1);
- 'cmp' -> cmp(Opnds);
- 'cmpl' -> cmpl(Opnds);
- 'cntlzd' -> cntlzd_Rc(Opnds, 0);
- 'cntlzd.' -> cntlzd_Rc(Opnds, 1);
- 'cntlzw' -> cntlzw_Rc(Opnds, 0);
- 'cntlzw.' -> cntlzw_Rc(Opnds, 1);
- 'dcba' -> dcba(Opnds);
- 'dcbf' -> dcbf(Opnds);
- 'dcbi' -> dcbi(Opnds);
- 'dcbst' -> dcbst(Opnds);
- 'dcbt' -> dcbt(Opnds);
- 'dcbtst' -> dcbtst(Opnds);
- 'dcbz' -> dcbz(Opnds);
- 'eciwx' -> eciwx(Opnds);
- 'ecowx' -> ecowx(Opnds);
- 'eieio' -> eieio(Opnds);
- 'eqv' -> eqv_Rc(Opnds, 0);
- 'eqv.' -> eqv_Rc(Opnds, 1);
- 'extsb' -> extsb_Rc(Opnds, 0);
- 'extsb.' -> extsb_Rc(Opnds, 1);
- 'extsh' -> extsh_Rc(Opnds, 0);
- 'extsh.' -> extsh_Rc(Opnds, 1);
- 'extsw' -> extsw_Rc(Opnds, 0);
- 'extsw.' -> extsw_Rc(Opnds, 1);
- 'fabs' -> fabs_Rc(Opnds, 0);
- 'fabs.' -> fabs_Rc(Opnds, 1);
- 'fcfid' -> fcfid_Rc(Opnds, 0);
- 'fcfid.' -> fcfid_Rc(Opnds, 1);
- 'fcmpo' -> fcmpo(Opnds);
- 'fcmpu' -> fcmpu(Opnds);
- 'fctid' -> fctid_Rc(Opnds, 0);
- 'fctid.' -> fctid_Rc(Opnds, 1);
- 'fctidz' -> fctidz_Rc(Opnds, 0);
- 'fctidz.' -> fctidz_Rc(Opnds, 1);
- 'fctiw' -> fctiw_Rc(Opnds, 0);
- 'fctiw.' -> fctiw_Rc(Opnds, 1);
- 'fctiwz' -> fctiwz_Rc(Opnds, 0);
- 'fctiwz.' -> fctiwz_Rc(Opnds, 1);
- 'fmr' -> fmr_Rc(Opnds, 0);
- 'fmr.' -> fmr_Rc(Opnds, 1);
- 'fnabs' -> fnabs_Rc(Opnds, 0);
- 'fnabs.' -> fnabs_Rc(Opnds, 1);
- 'fneg' -> fneg_Rc(Opnds, 0);
- 'fneg.' -> fneg_Rc(Opnds, 1);
- 'frsp' -> frsp_Rc(Opnds, 0);
- 'frsp.' -> frsp_Rc(Opnds, 1);
- 'icbi' -> icbi(Opnds);
- 'lbzux' -> lbzux(Opnds);
- 'lbzx' -> lbzx(Opnds);
- 'ldarx' -> ldarx(Opnds);
- 'ldux' -> ldux(Opnds);
- 'ldx' -> ldx(Opnds);
- 'lfdux' -> lfdux(Opnds);
- 'lfdx' -> lfdx(Opnds);
- 'lfsux' -> lfsux(Opnds);
- 'lfsx' -> lfsx(Opnds);
- 'lhaux' -> lhaux(Opnds);
- 'lhax' -> lhax(Opnds);
- 'lhbrx' -> lhbrx(Opnds);
- 'lhzux' -> lhzux(Opnds);
- 'lhzx' -> lhzx(Opnds);
- 'lswi' -> lswi(Opnds);
- 'lswx' -> lswx(Opnds);
- 'lwarx' -> lwarx(Opnds);
- 'lwaux' -> lwaux(Opnds);
- 'lwax' -> lwax(Opnds);
- 'lwbrx' -> lwbrx(Opnds);
- 'lwzux' -> lwzux(Opnds);
- 'lwzx' -> lwzx(Opnds);
- 'mcrfs' -> mcrfs(Opnds);
- %% 'mcrxr' -> mcrxr(Opnds);
- 'mfcr' -> mfcr(Opnds);
- 'mffs' -> mffs_Rc(Opnds, 0);
- 'mffs.' -> mffs_Rc(Opnds, 1);
- 'mfmsr' -> mfmsr(Opnds);
- 'mfsr' -> mfsr(Opnds);
- 'mfsrin' -> mfsrin(Opnds);
- 'mtfsb0' -> mtfsb0_Rc(Opnds, 0);
- 'mtfsb0.' -> mtfsb0_Rc(Opnds, 1);
- 'mtfsb1' -> mtfsb1_Rc(Opnds, 0);
- 'mtfsb1.' -> mtfsb1_Rc(Opnds, 1);
- 'mtfsfi' -> mtfsfi_Rc(Opnds, 0);
- 'mtfsfi.' -> mtfsfi_Rc(Opnds, 1);
- 'mtmsr' -> mtmsr(Opnds);
- 'mtmsrd' -> mtmsrd(Opnds);
- 'mtsr' -> mtsr(Opnds);
- 'mtsrd' -> mtsrd(Opnds);
- 'mtsrdin' -> mtsrdin(Opnds);
- 'mtsrin' -> mtsrin(Opnds);
- 'nand' -> nand_Rc(Opnds, 0);
- 'nand.' -> nand_Rc(Opnds, 1);
- 'nor' -> nor_Rc(Opnds, 0);
- 'nor.' -> nor_Rc(Opnds, 1);
- 'or' -> or_Rc(Opnds, 0);
- 'or.' -> or_Rc(Opnds, 1);
- 'orc' -> orc_Rc(Opnds, 0);
- 'orc.' -> orc_Rc(Opnds, 1);
- 'slbia' -> slbia(Opnds);
- 'slbie' -> slbie(Opnds);
- 'sld' -> sld_Rc(Opnds, 0);
- 'sld.' -> sld_Rc(Opnds, 1);
- 'slw' -> slw_Rc(Opnds, 0);
- 'slw.' -> slw_Rc(Opnds, 1);
- 'srad' -> srad_Rc(Opnds, 0);
- 'srad.' -> srad_Rc(Opnds, 1);
- 'sraw' -> sraw_Rc(Opnds, 0);
- 'sraw.' -> sraw_Rc(Opnds, 1);
- 'srawi' -> srawi_Rc(Opnds, 0);
- 'srawi.' -> srawi_Rc(Opnds, 1);
- 'srd' -> srd_Rc(Opnds, 0);
- 'srd.' -> srd_Rc(Opnds, 1);
- 'srw' -> srw_Rc(Opnds, 0);
- 'srw.' -> srw_Rc(Opnds, 1);
- 'stbux' -> stbux(Opnds);
- 'stbx' -> stbx(Opnds);
- 'stdcx.' -> stdcx_dot(Opnds);
- 'stdux' -> stdux(Opnds);
- 'stdx' -> stdx(Opnds);
- 'stfdux' -> stfdux(Opnds);
- 'stfdx' -> stfdx(Opnds);
- 'stfiwx' -> stfiwx(Opnds);
- 'stfsux' -> stfsux(Opnds);
- 'stfsx' -> stfsx(Opnds);
- 'sthbrx' -> sthbrx(Opnds);
- 'sthux' -> sthux(Opnds);
- 'sthx' -> sthx(Opnds);
- 'stswi' -> stswi(Opnds);
- 'stswx' -> stswx(Opnds);
- 'stwbrx' -> stwbrx(Opnds);
- 'stwcx.' -> stwcx_dot(Opnds);
- 'stwux' -> stwux(Opnds);
- 'stwx' -> stwx(Opnds);
- 'sync' -> sync(Opnds);
- 'td' -> td(Opnds);
- 'tlbia' -> tlbia(Opnds); % not implemented in MPC603e or MPC7450
- 'tlbie' -> tlbie(Opnds);
- 'tlbld' -> tlbld(Opnds);
- 'tlbli' -> tlbli(Opnds);
- 'tlbsync' -> tlbsync(Opnds);
- 'tw' -> tw(Opnds);
- 'xor' -> xor_Rc(Opnds, 0);
- 'xor.' -> xor_Rc(Opnds, 1);
- %% XL-Form
- 'bcctr' -> bcctr_lk(Opnds, 0);
- 'bcctrl' -> bcctr_lk(Opnds, 1);
- 'bclr' -> bclr_lk(Opnds, 0);
- 'bclrl' -> bclr_lk(Opnds, 1);
- 'crand' -> crand(Opnds);
- 'crandc' -> crandc(Opnds);
- 'creqv' -> creqv(Opnds);
- 'crnand' -> crnand(Opnds);
- 'crnor' -> crnor(Opnds);
- 'cror' -> cror(Opnds);
- 'crorc' -> crorc(Opnds);
- 'crxor' -> crxor(Opnds);
- 'isync' -> isync(Opnds);
- 'mcrf' -> mcrf(Opnds);
- 'rfi' -> rfi(Opnds);
- 'rfid' -> rfid(Opnds);
- %% XFX-Form
- 'mfspr' -> mfspr(Opnds);
- 'mftb' -> mftb(Opnds);
- 'mtcrf' -> mtcrf(Opnds);
- 'mtspr' -> mtspr(Opnds);
- %% XFL-Form
- 'mtfsf' -> mtfsf_Rc(Opnds, 0);
- 'mtfsf.' -> mtfsf_Rc(Opnds, 1);
- %% XS-Form
- 'sradi' -> sradi_Rc(Opnds, 0);
- 'sradi.' -> sradi_Rc(Opnds, 1);
- %% XO-Form
- 'add' -> add_OE_Rc(Opnds, 0, 0);
- 'add.' -> add_OE_Rc(Opnds, 0, 1);
- 'addo' -> add_OE_Rc(Opnds, 1, 0);
- 'addo.' -> add_OE_Rc(Opnds, 1, 1);
- 'addc' -> addc_OE_Rc(Opnds, 0, 0);
- 'addc.' -> addc_OE_Rc(Opnds, 0, 1);
- 'addco' -> addc_OE_Rc(Opnds, 1, 0);
- 'addco.' -> addc_OE_Rc(Opnds, 1, 1);
- 'adde' -> adde_OE_Rc(Opnds, 0, 0);
- 'adde.' -> adde_OE_Rc(Opnds, 0, 1);
- 'addeo' -> adde_OE_Rc(Opnds, 1, 0);
- 'addeo.' -> adde_OE_Rc(Opnds, 1, 1);
- 'addme' -> addme_OE_Rc(Opnds, 0, 0);
- 'addme.' -> addme_OE_Rc(Opnds, 0, 1);
- 'addmeo' -> addme_OE_Rc(Opnds, 1, 0);
- 'addmeo.' -> addme_OE_Rc(Opnds, 1, 1);
- 'addze' -> addze_OE_Rc(Opnds, 0, 0);
- 'addze.' -> addze_OE_Rc(Opnds, 0, 1);
- 'addzeo' -> addze_OE_Rc(Opnds, 1, 0);
- 'addzeo.' -> addze_OE_Rc(Opnds, 1, 1);
- 'divd' -> divd_OE_Rc(Opnds, 0, 0);
- 'divd.' -> divd_OE_Rc(Opnds, 0, 1);
- 'divdo' -> divd_OE_Rc(Opnds, 1, 0);
- 'divdo.' -> divd_OE_Rc(Opnds, 1, 1);
- 'divdu' -> divdu_OE_Rc(Opnds, 0, 0);
- 'divdu.' -> divdu_OE_Rc(Opnds, 0, 1);
- 'divduo' -> divdu_OE_Rc(Opnds, 1, 0);
- 'divduo.' -> divdu_OE_Rc(Opnds, 1, 1);
- 'divw' -> divw_OE_Rc(Opnds, 0, 0);
- 'divw.' -> divw_OE_Rc(Opnds, 0, 1);
- 'divwo' -> divw_OE_Rc(Opnds, 1, 0);
- 'divwo.' -> divw_OE_Rc(Opnds, 1, 1);
- 'divwu' -> divwu_OE_Rc(Opnds, 0, 0);
- 'divwu.' -> divwu_OE_Rc(Opnds, 0, 1);
- 'divwuo' -> divwu_OE_Rc(Opnds, 1, 0);
- 'divwuo.' -> divwu_OE_Rc(Opnds, 1, 1);
- 'mulhd' -> mulhd_Rc(Opnds, 0);
- 'mulhd.' -> mulhd_Rc(Opnds, 1);
- 'mulhdu' -> mulhdu_Rc(Opnds, 0);
- 'mulhdu.' -> mulhdu_Rc(Opnds, 1);
- 'mulhw' -> mulhw_Rc(Opnds, 0);
- 'mulhw.' -> mulhw_Rc(Opnds, 1);
- 'mulhwu' -> mulhwu_Rc(Opnds, 0);
- 'mulhwu.' -> mulhwu_Rc(Opnds, 1);
- 'mulld' -> mulld_OE_Rc(Opnds, 0, 0);
- 'mulld.' -> mulld_OE_Rc(Opnds, 0, 1);
- 'mulldo' -> mulld_OE_Rc(Opnds, 1, 0);
- 'mulldo.' -> mulld_OE_Rc(Opnds, 1, 1);
- 'mullw' -> mullw_OE_Rc(Opnds, 0, 0);
- 'mullw.' -> mullw_OE_Rc(Opnds, 0, 1);
- 'mullwo' -> mullw_OE_Rc(Opnds, 1, 0);
- 'mullwo.' -> mullw_OE_Rc(Opnds, 1, 1);
- 'neg' -> neg_OE_Rc(Opnds, 0, 0);
- 'neg.' -> neg_OE_Rc(Opnds, 0, 1);
- 'nego' -> neg_OE_Rc(Opnds, 1, 0);
- 'nego.' -> neg_OE_Rc(Opnds, 1, 1);
- 'subf' -> subf_OE_Rc(Opnds, 0, 0);
- 'subf.' -> subf_OE_Rc(Opnds, 0, 1);
- 'subfo' -> subf_OE_Rc(Opnds, 1, 0);
- 'subfo.' -> subf_OE_Rc(Opnds, 1, 1);
- 'subfc' -> subfc_OE_Rc(Opnds, 0, 0);
- 'subfc.' -> subfc_OE_Rc(Opnds, 0, 1);
- 'subfco' -> subfc_OE_Rc(Opnds, 1, 0);
- 'subfco.' -> subfc_OE_Rc(Opnds, 1, 1);
- 'subfe' -> subfe_OE_Rc(Opnds, 0, 0);
- 'subfe.' -> subfe_OE_Rc(Opnds, 0, 1);
- 'subfeo' -> subfe_OE_Rc(Opnds, 1, 0);
- 'subfeo.' -> subfe_OE_Rc(Opnds, 1, 1);
- 'subfme' -> subfme_OE_Rc(Opnds, 0, 0);
- 'subfme.' -> subfme_OE_Rc(Opnds, 0, 1);
- 'subfmeo' -> subfme_OE_Rc(Opnds, 1, 0);
- 'subfmeo.' -> subfme_OE_Rc(Opnds, 1, 1);
- 'subfze' -> subfze_OE_Rc(Opnds, 0, 0);
- 'subfze.' -> subfze_OE_Rc(Opnds, 0, 1);
- 'subfzeo' -> subfze_OE_Rc(Opnds, 1, 0);
- 'subfzeo.' -> subfze_OE_Rc(Opnds, 1, 1);
- %% A-Form
- 'fadd' -> fadd_Rc(Opnds, 0);
- 'fadd.' -> fadd_Rc(Opnds, 1);
- 'fadds' -> fadds_Rc(Opnds, 0);
- 'fadds.' -> fadds_Rc(Opnds, 1);
- 'fdiv' -> fdiv_Rc(Opnds, 0);
- 'fdiv.' -> fdiv_Rc(Opnds, 1);
- 'fdivs' -> fdivs_Rc(Opnds, 0);
- 'fdivs.' -> fdivs_Rc(Opnds, 1);
- 'fmadd' -> fmadd_Rc(Opnds, 0);
- 'fmadd.' -> fmadd_Rc(Opnds, 1);
- 'fmadds' -> fmadds_Rc(Opnds, 0);
- 'fmadds.' -> fmadds_Rc(Opnds, 1);
- 'fmsub' -> fmsub_Rc(Opnds, 0);
- 'fmsub.' -> fmsub_Rc(Opnds, 1);
- 'fmsubs' -> fmsubs_Rc(Opnds, 0);
- 'fmsubs.' -> fmsubs_Rc(Opnds, 1);
- 'fmul' -> fmul_Rc(Opnds, 0);
- 'fmul.' -> fmul_Rc(Opnds, 1);
- 'fmuls' -> fmuls_Rc(Opnds, 0);
- 'fmuls.' -> fmuls_Rc(Opnds, 1);
- 'fnmadd' -> fnmadd_Rc(Opnds, 0);
- 'fnmadd.' -> fnmadd_Rc(Opnds, 1);
- 'fnmadds' -> fnmadds_Rc(Opnds, 0);
- 'fnmadds.' -> fnmadds_Rc(Opnds, 1);
- 'fnmsub' -> fnmsub_Rc(Opnds, 0);
- 'fnmsub.' -> fnmsub_Rc(Opnds, 1);
- 'fnmsubs' -> fnmsubs_Rc(Opnds, 0);
- 'fnmsubs.' -> fnmsubs_Rc(Opnds, 1);
- 'fres' -> fres_Rc(Opnds, 0);
- 'fres.' -> fres_Rc(Opnds, 1);
- 'frsqrte' -> frsqrte_Rc(Opnds, 0);
- 'frsqrte.' -> frsqrte_Rc(Opnds, 1);
- 'fsel' -> fsel_Rc(Opnds, 0);
- 'fsel.' -> fsel_Rc(Opnds, 1);
- 'fsqrt' -> fsqrt_Rc(Opnds, 0); % not implemented in MPC603e or MPC7450
- 'fsqrt.' -> fsqrt_Rc(Opnds, 1); % not implemented in MPC603e or MPC7450
- 'fsqrts' -> fsqrts_Rc(Opnds, 0); % not implemented in MPC603e or MPC7450
- 'fsqrts.' -> fsqrts_Rc(Opnds, 1); % not implemented in MPC603e or MPC7450
- 'fsub' -> fsub_Rc(Opnds, 0);
- 'fsub.' -> fsub_Rc(Opnds, 1);
- 'fsubs' -> fsubs_Rc(Opnds, 0);
- 'fsubs.' -> fsubs_Rc(Opnds, 1);
- %% M-Form
- 'rlwimi' -> rlwimi_Rc(Opnds, 0);
- 'rlwimi.' -> rlwimi_Rc(Opnds, 1);
- 'rlwinm' -> rlwinm_Rc(Opnds, 0);
- 'rlwinm.' -> rlwinm_Rc(Opnds, 1);
- 'rlwnm' -> rlwnm_Rc(Opnds, 0);
- 'rlwnm.' -> rlwnm_Rc(Opnds, 1);
- %% MD-Form
- 'rldic' -> rldic_Rc(Opnds, 0);
- 'rldic.' -> rldic_Rc(Opnds, 1);
- 'rldicl' -> rldicl_Rc(Opnds, 0);
- 'rldicl.' -> rldicl_Rc(Opnds, 1);
- 'rldicr' -> rldicr_Rc(Opnds, 0);
- 'rldicr.' -> rldicr_Rc(Opnds, 1);
- 'rldimi' -> rldimi_Rc(Opnds, 0);
- 'rldimi.' -> rldimi_Rc(Opnds, 1);
- %% MDS-Form
- 'rldcl' -> rldcl(Opnds, 0);
- 'rldcl.' -> rldcl(Opnds, 1);
- 'rldcr' -> rldcr(Opnds, 0);
- 'rldcr.' -> rldcr(Opnds, 1);
- _ -> exit({?MODULE,insn_encode,Op})
- end.
-
-%%% testing interface
-
--ifdef(TESTING).
-
-say(OS, Str) ->
- file:write(OS, Str).
-
-hex_digit(Dig0) ->
- Dig = Dig0 band 16#F,
- if Dig >= 16#A -> $A + (Dig - 16#A);
- true -> $0 + Dig
- end.
-
-say_byte(OS, Byte) ->
- say(OS, [hex_digit(Byte bsr 4)]),
- say(OS, [hex_digit(Byte)]).
-
-say_word(OS, Word) ->
- say(OS, "0x"),
- say_byte(OS, Word bsr 24),
- say_byte(OS, Word bsr 16),
- say_byte(OS, Word bsr 8),
- say_byte(OS, Word).
-
-t(OS, Op, Opnds) ->
- Word = insn_encode(Op, Opnds),
- say(OS, "\t.long "),
- say_word(OS, Word),
- say(OS, "\n").
-
-dotest1(OS) ->
- say(OS, "\t.text\n\t.align 4\n"),
- %%
- R14 = {r,14},
- R10 = {r,10},
- R11 = {r,11},
- F2 = {fr,2},
- F4 = {fr,4},
- F6 = {fr,6},
- F8 = {fr,8},
- DispM3 = {d,16#FFFD},
- DS = {ds,16#FFFD bsr 2},
- SIMM99 = {simm,10#99},
- UIMM4711 = {uimm,10#4711},
- TO_LLE = {to, 2#00110}, % =, <U
- CR7 = {crf,7},
- CR5 = {crf,5},
- CRB_CR0_LT = {crb,0},
- CRB_CR7_SO = {crb,31},
- CRB_CR1_GT = {crb,5},
- CRM192 = {crm,192},
- FM255 = {fm,16#FF}, % all fields
- CRIMM15 = {crimm,16#F},
- TBR268 = {tbr, 10#268}, % TBL
- SPR9 = {spr, 10#9}, % CTR
- SR9 = {sr,9},
- NB7 = {nb,7},
- SH16 = {sh,16},
- SH45 = {sh6,45},
- MB10 = {mb,10},
- MB40 = {mb6,40},
- ME20 = {me,20},
- ME50 = {me6,50},
- LI = {li,16#ffffff},
- BD = {bd,16#3ff},
- BO_NZ_PLUS = {bo,2#01101}, % branch if cond true, predict taken
- BI_CR0_EQ = {bi,2#00010}, % CR0[2], Zero
- %% I-Form
- t(OS,'b',{LI}),
- t(OS,'ba',{LI}),
- t(OS,'bl',{LI}),
- t(OS,'bla',{LI}),
- %% B-Form
- t(OS,'bc',{BO_NZ_PLUS,BI_CR0_EQ,BD}),
- t(OS,'bca',{BO_NZ_PLUS,BI_CR0_EQ,BD}),
- t(OS,'bcl',{BO_NZ_PLUS,BI_CR0_EQ,BD}),
- t(OS,'bcla',{BO_NZ_PLUS,BI_CR0_EQ,BD}),
- %% SC-Form
- t(OS,'sc',{}),
- %% D-Form
- t(OS,'addi',{R14,R10,SIMM99}),
- t(OS,'addic',{R14,R10,SIMM99}),
- t(OS,'addic.',{R14,R10,SIMM99}),
- t(OS,'addis',{R14,R10,SIMM99}),
- t(OS,'andi.',{R14,R10,UIMM4711}),
- t(OS,'andis.',{R14,R10,UIMM4711}),
- t(OS,'cmpi',{CR7,0,R10,SIMM99}),
- t(OS,'cmpi',{CR7,1,R10,SIMM99}),
- t(OS,'cmpli',{CR7,0,R10,UIMM4711}),
- t(OS,'cmpli',{CR7,1,R10,UIMM4711}),
- t(OS,'lbz',{R14,DispM3,R10}),
- t(OS,'lbzu',{R14,DispM3,R10}),
- t(OS,'lfd',{F2,DispM3,R10}),
- t(OS,'lfdu',{F2,DispM3,R10}),
- t(OS,'lfs',{F2,DispM3,R10}),
- t(OS,'lfsu',{F2,DispM3,R10}),
- t(OS,'lha',{R14,DispM3,R10}),
- t(OS,'lhau',{R14,DispM3,R10}),
- t(OS,'lhz',{R14,DispM3,R10}),
- t(OS,'lhzu',{R14,DispM3,R10}),
- t(OS,'lmw',{R14,DispM3,R10}),
- t(OS,'lwz',{R14,DispM3,R10}),
- t(OS,'lwzu',{R14,DispM3,R10}),
- t(OS,'mulli',{R14,R10,SIMM99}),
- t(OS,'ori',{R14,R10,UIMM4711}),
- t(OS,'oris',{R14,R10,UIMM4711}),
- t(OS,'stb',{R14,DispM3,R10}),
- t(OS,'stbu',{R14,DispM3,R10}),
- t(OS,'stfd',{F2,DispM3,R10}),
- t(OS,'stfdu',{F2,DispM3,R10}),
- t(OS,'stfs',{F2,DispM3,R10}),
- t(OS,'stfsu',{F2,DispM3,R10}),
- t(OS,'sth',{R14,DispM3,R10}),
- t(OS,'sthu',{R14,DispM3,R10}),
- t(OS,'stmw',{R14,DispM3,R10}),
- t(OS,'stw',{R14,DispM3,R10}),
- t(OS,'stwu',{R14,DispM3,R10}),
- t(OS,'subfic',{R14,R10,SIMM99}),
- t(OS,'tdi',{TO_LLE,R10,SIMM99}),
- t(OS,'twi',{TO_LLE,R10,SIMM99}),
- t(OS,'xori',{R14,R10,UIMM4711}),
- t(OS,'xoris',{R14,R10,UIMM4711}),
- %% DS-Form
- t(OS,'ld',{R14,DS,R10}),
- t(OS,'ldu',{R14,DS,R10}),
- t(OS,'lwa',{R14,DS,R10}),
- t(OS,'std',{R14,DS,R10}),
- t(OS,'stdu',{R14,DS,R10}),
- %% X-Form
- t(OS,'and',{R14,R10,R11}),
- t(OS,'and.',{R14,R10,R11}),
- t(OS,'andc',{R14,R10,R11}),
- t(OS,'andc.',{R14,R10,R11}),
- t(OS,'cmp',{CR7,0,R10,R11}),
- t(OS,'cmp',{CR7,1,R10,R11}),
- t(OS,'cmpl',{CR7,0,R10,R11}),
- t(OS,'cmpl',{CR7,1,R10,R11}),
- t(OS,'cntlzd',{R14,R10}),
- t(OS,'cntlzd.',{R14,R10}),
- t(OS,'cntlzw',{R14,R10}),
- t(OS,'cntlzw.',{R14,R10}),
- t(OS,'dcba',{R10,R11}),
- t(OS,'dcbf',{R10,R11}),
- t(OS,'dcbi',{R10,R11}),
- t(OS,'dcbst',{R10,R11}),
- t(OS,'dcbt',{R10,R11}),
- t(OS,'dcbtst',{R10,R11}),
- t(OS,'dcbz',{R10,R11}),
- t(OS,'eciwx',{R14,R10,R11}),
- t(OS,'ecowx',{R14,R10,R11}),
- t(OS,'eieio',{}),
- t(OS,'eqv',{R14,R10,R11}),
- t(OS,'eqv.',{R14,R10,R11}),
- t(OS,'extsb',{R14,R10}),
- t(OS,'extsb.',{R14,R10}),
- t(OS,'extsh',{R14,R10}),
- t(OS,'extsh.',{R14,R10}),
- t(OS,'extsw',{R14,R10}),
- t(OS,'extsw.',{R14,R10}),
- t(OS,'fabs',{F2,F8}),
- t(OS,'fabs.',{F2,F8}),
- t(OS,'fcfid',{F2,F8}),
- t(OS,'fcfid.',{F2,F8}),
- t(OS,'fcmpo',{CR7,F4,F8}),
- t(OS,'fcmpu',{CR7,F4,F8}),
- t(OS,'fctid',{F2,F8}),
- t(OS,'fctid.',{F2,F8}),
- t(OS,'fctidz',{F2,F8}),
- t(OS,'fctidz.',{F2,F8}),
- t(OS,'fctiw',{F2,F8}),
- t(OS,'fctiw.',{F2,F8}),
- t(OS,'fctiwz',{F2,F8}),
- t(OS,'fctiwz.',{F2,F8}),
- t(OS,'fmr',{F2,F8}),
- t(OS,'fmr.',{F2,F8}),
- t(OS,'fnabs',{F2,F8}),
- t(OS,'fnabs.',{F2,F8}),
- t(OS,'fneg',{F2,F8}),
- t(OS,'fneg.',{F2,F8}),
- t(OS,'frsp',{F2,F8}),
- t(OS,'frsp.',{F2,F8}),
- t(OS,'icbi',{R10,R11}),
- t(OS,'lbzux',{R14,R10,R11}),
- t(OS,'lbzx',{R14,R10,R11}),
- t(OS,'ldarx',{R14,R10,R11}),
- t(OS,'ldux',{R14,R10,R11}),
- t(OS,'ldx',{R14,R10,R11}),
- t(OS,'lfdux',{F2,R10,R11}),
- t(OS,'lfdx',{F2,R10,R11}),
- t(OS,'lfsux',{F2,R10,R11}),
- t(OS,'lfsx',{F2,R10,R11}),
- t(OS,'lhaux',{R14,R10,R11}),
- t(OS,'lhax',{R14,R10,R11}),
- t(OS,'lhbrx',{R14,R10,R11}),
- t(OS,'lhzux',{R14,R10,R11}),
- t(OS,'lhzx',{R14,R10,R11}),
- t(OS,'lswi',{R14,R10,NB7}),
- t(OS,'lswx',{R14,R10,R11}),
- t(OS,'lwarx',{R14,R10,R11}),
- t(OS,'lwaux',{R14,R10,R11}),
- t(OS,'lwax',{R14,R10,R11}),
- t(OS,'lwbrx',{R14,R10,R11}),
- t(OS,'lwzux',{R14,R10,R11}),
- t(OS,'lwzx',{R14,R10,R11}),
- t(OS,'mcrfs',{CR7,CR5}),
- %% t(OS,'mcrxr',{CR7}),
- t(OS,'mfcr',{R14}),
- t(OS,'mffs',{F2}),
- t(OS,'mffs.',{F2}),
- t(OS,'mfmsr',{R14}),
- t(OS,'mfsr',{R14,SR9}),
- t(OS,'mfsrin',{R14,R11}),
- t(OS,'mtfsb0',{CRB_CR0_LT}),
- t(OS,'mtfsb0.',{CRB_CR0_LT}),
- t(OS,'mtfsb1',{CRB_CR0_LT}),
- t(OS,'mtfsb1.',{CRB_CR0_LT}),
- t(OS,'mtfsfi',{CR7,CRIMM15}),
- t(OS,'mtfsfi.',{CR7,CRIMM15}),
- t(OS,'mtmsr',{R14}),
- t(OS,'mtmsrd',{R14}),
- t(OS,'mtsr',{SR9,R14}),
- t(OS,'mtsrd',{SR9,R14}),
- t(OS,'mtsrdin',{R14,R11}),
- t(OS,'mtsrin',{R14,R11}),
- t(OS,'nand',{R14,R10,R11}),
- t(OS,'nand.',{R14,R10,R11}),
- t(OS,'nor',{R14,R10,R11}),
- t(OS,'nor.',{R14,R10,R11}),
- t(OS,'or',{R14,R10,R11}),
- t(OS,'or.',{R14,R10,R11}),
- t(OS,'orc',{R14,R10,R11}),
- t(OS,'orc.',{R14,R10,R11}),
- t(OS,'slbia',{}),
- t(OS,'slbie',{R11}),
- t(OS,'sld',{R14,R10,R11}),
- t(OS,'sld.',{R14,R10,R11}),
- t(OS,'slw',{R14,R10,R11}),
- t(OS,'slw.',{R14,R10,R11}),
- t(OS,'srad',{R14,R10,R11}),
- t(OS,'srad.',{R14,R10,R11}),
- t(OS,'sraw',{R14,R10,R11}),
- t(OS,'sraw.',{R14,R10,R11}),
- t(OS,'srawi',{R14,R10,SH16}),
- t(OS,'srawi.',{R14,R10,SH16}),
- t(OS,'srd',{R14,R10,R11}),
- t(OS,'srd.',{R14,R10,R11}),
- t(OS,'srw',{R14,R10,R11}),
- t(OS,'srw.',{R14,R10,R11}),
- t(OS,'stbux',{R14,R10,R11}),
- t(OS,'stbx',{R14,R10,R11}),
- t(OS,'stdcx.',{R14,R10,R11}),
- t(OS,'stdux',{R14,R10,R11}),
- t(OS,'stdx',{R14,R10,R11}),
- t(OS,'stfdux',{F2,R10,R11}),
- t(OS,'stfdx',{F2,R10,R11}),
- t(OS,'stfiwx',{F2,R10,R11}),
- t(OS,'stfsux',{F2,R10,R11}),
- t(OS,'stfsx',{F2,R10,R11}),
- t(OS,'sthbrx',{R14,R10,R11}),
- t(OS,'sthux',{R14,R10,R11}),
- t(OS,'sthx',{R14,R10,R11}),
- t(OS,'stswi',{R14,R10,NB7}),
- t(OS,'stswx',{R14,R10,R11}),
- t(OS,'stwbrx',{R14,R10,R11}),
- t(OS,'stwcx.',{R14,R10,R11}),
- t(OS,'stwux',{R14,R10,R11}),
- t(OS,'stwx',{R14,R10,R11}),
- t(OS,'sync',{}),
- t(OS,'td',{TO_LLE,R10,R11}),
- t(OS,'tlbia',{}),
- t(OS,'tlbie',{R11}),
- t(OS,'tlbld',{R11}),
- t(OS,'tlbli',{R11}),
- t(OS,'tlbsync',{}),
- t(OS,'tw',{TO_LLE,R10,R11}),
- t(OS,'xor',{R14,R10,R11}),
- t(OS,'xor.',{R14,R10,R11}),
- %% XL-Form
- t(OS,'bcctr',{BO_NZ_PLUS,BI_CR0_EQ}),
- t(OS,'bcctrl',{BO_NZ_PLUS,BI_CR0_EQ}),
- t(OS,'bclr',{BO_NZ_PLUS,BI_CR0_EQ}),
- t(OS,'bclrl',{BO_NZ_PLUS,BI_CR0_EQ}),
- t(OS,'crand',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'crandc',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'creqv',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'crnand',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'crnor',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'cror',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'crorc',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'crxor',{CRB_CR0_LT,CRB_CR7_SO,CRB_CR1_GT}),
- t(OS,'isync',{}),
- t(OS,'mcrf',{CR7,CR5}),
- t(OS,'rfi',{}),
- t(OS,'rfid',{}),
- %% XFX-Form
- t(OS,'mfspr',{R14,SPR9}),
- t(OS,'mftb',{R14,TBR268}),
- t(OS,'mtcrf',{CRM192,R14}),
- t(OS,'mtspr',{SPR9,R14}),
- %% XFL-Form
- t(OS,'mtfsf',{FM255,F8}),
- t(OS,'mtfsf.',{FM255,F8}),
- %% XS-Form
- t(OS,'sradi',{R14,R10,SH45}),
- t(OS,'sradi.',{R14,R10,SH45}),
- %% XO-Form
- t(OS,'add',{R14,R10,R11}),
- t(OS,'add.',{R14,R10,R11}),
- t(OS,'addo',{R14,R10,R11}),
- t(OS,'addo.',{R14,R10,R11}),
- t(OS,'addc',{R14,R10,R11}),
- t(OS,'addc.',{R14,R10,R11}),
- t(OS,'addco',{R14,R10,R11}),
- t(OS,'addco.',{R14,R10,R11}),
- t(OS,'adde',{R14,R10,R11}),
- t(OS,'adde.',{R14,R10,R11}),
- t(OS,'addeo',{R14,R10,R11}),
- t(OS,'addeo.',{R14,R10,R11}),
- t(OS,'addme',{R14,R10}),
- t(OS,'addme.',{R14,R10}),
- t(OS,'addmeo',{R14,R10}),
- t(OS,'addmeo.',{R14,R10}),
- t(OS,'addze',{R14,R10}),
- t(OS,'addze.',{R14,R10}),
- t(OS,'addzeo',{R14,R10}),
- t(OS,'addzeo.',{R14,R10}),
- t(OS,'divd',{R14,R10,R11}),
- t(OS,'divd.',{R14,R10,R11}),
- t(OS,'divdo',{R14,R10,R11}),
- t(OS,'divdo.',{R14,R10,R11}),
- t(OS,'divdu',{R14,R10,R11}),
- t(OS,'divdu.',{R14,R10,R11}),
- t(OS,'divduo',{R14,R10,R11}),
- t(OS,'divduo.',{R14,R10,R11}),
- t(OS,'divw',{R14,R10,R11}),
- t(OS,'divw.',{R14,R10,R11}),
- t(OS,'divwo',{R14,R10,R11}),
- t(OS,'divwo.',{R14,R10,R11}),
- t(OS,'divwu',{R14,R10,R11}),
- t(OS,'divwu.',{R14,R10,R11}),
- t(OS,'divwuo',{R14,R10,R11}),
- t(OS,'divwuo.',{R14,R10,R11}),
- t(OS,'mulhd',{R14,R10,R11}),
- t(OS,'mulhd.',{R14,R10,R11}),
- t(OS,'mulhdu',{R14,R10,R11}),
- t(OS,'mulhdu.',{R14,R10,R11}),
- t(OS,'mulhw',{R14,R10,R11}),
- t(OS,'mulhw.',{R14,R10,R11}),
- t(OS,'mulhwu',{R14,R10,R11}),
- t(OS,'mulhwu.',{R14,R10,R11}),
- t(OS,'mulld',{R14,R10,R11}),
- t(OS,'mulld.',{R14,R10,R11}),
- t(OS,'mulldo',{R14,R10,R11}),
- t(OS,'mulldo.',{R14,R10,R11}),
- t(OS,'mullw',{R14,R10,R11}),
- t(OS,'mullw.',{R14,R10,R11}),
- t(OS,'mullwo',{R14,R10,R11}),
- t(OS,'mullwo.',{R14,R10,R11}),
- t(OS,'neg',{R14,R10}),
- t(OS,'neg.',{R14,R10}),
- t(OS,'nego',{R14,R10}),
- t(OS,'nego.',{R14,R10}),
- t(OS,'subf',{R14,R10,R11}),
- t(OS,'subf.',{R14,R10,R11}),
- t(OS,'subfo',{R14,R10,R11}),
- t(OS,'subfo.',{R14,R10,R11}),
- t(OS,'subfc',{R14,R10,R11}),
- t(OS,'subfc.',{R14,R10,R11}),
- t(OS,'subfco',{R14,R10,R11}),
- t(OS,'subfco.',{R14,R10,R11}),
- t(OS,'subfe',{R14,R10,R11}),
- t(OS,'subfe.',{R14,R10,R11}),
- t(OS,'subfeo',{R14,R10,R11}),
- t(OS,'subfeo.',{R14,R10,R11}),
- t(OS,'subfme',{R14,R10}),
- t(OS,'subfme.',{R14,R10}),
- t(OS,'subfmeo',{R14,R10}),
- t(OS,'subfmeo.',{R14,R10}),
- t(OS,'subfze',{R14,R10}),
- t(OS,'subfze.',{R14,R10}),
- t(OS,'subfzeo',{R14,R10}),
- t(OS,'subfzeo.',{R14,R10}),
- %% A-Form
- t(OS,'fadd',{F2,F4,F8}),
- t(OS,'fadd.',{F2,F4,F8}),
- t(OS,'fadds',{F2,F4,F8}),
- t(OS,'fadds.',{F2,F4,F8}),
- t(OS,'fdiv',{F2,F4,F8}),
- t(OS,'fdiv.',{F2,F4,F8}),
- t(OS,'fdivs',{F2,F4,F8}),
- t(OS,'fdivs.',{F2,F4,F8}),
- t(OS,'fmadd',{F2,F4,F6,F8}),
- t(OS,'fmadd.',{F2,F4,F6,F8}),
- t(OS,'fmadds',{F2,F4,F6,F8}),
- t(OS,'fmadds.',{F2,F4,F6,F8}),
- t(OS,'fmsub',{F2,F4,F6,F8}),
- t(OS,'fmsub.',{F2,F4,F6,F8}),
- t(OS,'fmsubs',{F2,F4,F6,F8}),
- t(OS,'fmsubs.',{F2,F4,F6,F8}),
- t(OS,'fmul',{F2,F4,F6}),
- t(OS,'fmul.',{F2,F4,F6}),
- t(OS,'fmuls',{F2,F4,F6}),
- t(OS,'fmuls.',{F2,F4,F6}),
- t(OS,'fnmadd',{F2,F4,F6,F8}),
- t(OS,'fnmadd.',{F2,F4,F6,F8}),
- t(OS,'fnmadds',{F2,F4,F6,F8}),
- t(OS,'fnmadds.',{F2,F4,F6,F8}),
- t(OS,'fnmsub',{F2,F4,F6,F8}),
- t(OS,'fnmsub.',{F2,F4,F6,F8}),
- t(OS,'fnmsubs',{F2,F4,F6,F8}),
- t(OS,'fnmsubs.',{F2,F4,F6,F8}),
- t(OS,'fres',{F2,F8}),
- t(OS,'fres.',{F2,F8}),
- t(OS,'frsqrte',{F2,F8}),
- t(OS,'frsqrte.',{F2,F8}),
- t(OS,'fsel',{F2,F4,F6,F8}),
- t(OS,'fsel.',{F2,F4,F6,F8}),
- t(OS,'fsqrt',{F2,F8}),
- t(OS,'fsqrt.',{F2,F8}),
- t(OS,'fsqrts',{F2,F8}),
- t(OS,'fsqrts.',{F2,F8}),
- t(OS,'fsub',{F2,F4,F8}),
- t(OS,'fsub.',{F2,F4,F8}),
- t(OS,'fsubs',{F2,F4,F8}),
- t(OS,'fsubs.',{F2,F4,F8}),
- %% M-Form
- t(OS,'rlwimi',{R14,R10,SH16,MB10,ME20}),
- t(OS,'rlwimi.',{R14,R10,SH16,MB10,ME20}),
- t(OS,'rlwinm',{R14,R10,SH16,MB10,ME20}),
- t(OS,'rlwinm.',{R14,R10,SH16,MB10,ME20}),
- t(OS,'rlwnm',{R14,R10,R11,MB10,ME20}),
- t(OS,'rlwnm.',{R14,R10,R11,MB10,ME20}),
- %% MD-Form
- t(OS,'rldic',{R14,R10,SH45,MB40}),
- t(OS,'rldic.',{R14,R10,SH45,MB40}),
- t(OS,'rldicl',{R14,R10,SH45,MB40}),
- t(OS,'rldicl.',{R14,R10,SH45,MB40}),
- t(OS,'rldicr',{R14,R10,SH45,ME50}),
- t(OS,'rldicr.',{R14,R10,SH45,ME50}),
- t(OS,'rldimi',{R14,R10,SH45,MB40}),
- t(OS,'rldimi.',{R14,R10,SH45,MB40}),
- %% MDS-Form
- t(OS,'rldcl',{R14,R10,R11,MB40}),
- t(OS,'rldcl.',{R14,R10,R11,MB40}),
- t(OS,'rldcr',{R14,R10,R11,ME50}),
- t(OS,'rldcr.',{R14,R10,R11,ME50}),
- [].
-
-dotest() -> dotest1(group_leader()).
-
-dotest(File) ->
- {ok,OS} = file:open(File, [write]),
- dotest1(OS),
- file:close(OS).
-
--endif.
diff --git a/lib/hipe/ppc/hipe_ppc_finalise.erl b/lib/hipe/ppc/hipe_ppc_finalise.erl
deleted file mode 100644
index 8db2bf48a5..0000000000
--- a/lib/hipe/ppc/hipe_ppc_finalise.erl
+++ /dev/null
@@ -1,59 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_finalise).
--export([finalise/1]).
--include("hipe_ppc.hrl").
-
-finalise(Defun) ->
- #defun{code=Code0} = Defun,
- Code1 = peep(expand(Code0)),
- Defun#defun{code=Code1}.
-
-expand(Insns) ->
- expand_list(Insns, []).
-
-expand_list([I|Insns], Accum) ->
- expand_list(Insns, expand_insn(I, Accum));
-expand_list([], Accum) ->
- lists:reverse(Accum).
-
-expand_insn(I, Accum) ->
- case I of
- #pseudo_bc{bcond=BCond,true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
- [hipe_ppc:mk_b_label(FalseLab),
- hipe_ppc:mk_bc(BCond, TrueLab, Pred) |
- Accum];
- #pseudo_call{func=FunC,sdesc=SDesc,contlab=ContLab,linkage=Linkage} ->
- [hipe_ppc:mk_b_label(ContLab),
- case FunC of
- 'ctr' -> hipe_ppc:mk_bctrl(SDesc);
- Fun -> hipe_ppc:mk_bl(Fun, SDesc, Linkage)
- end |
- Accum];
- #pseudo_tailcall_prepare{} ->
- Accum;
- _ ->
- [I|Accum]
- end.
-
-peep(Insns) ->
- peep_list(Insns, []).
-
-peep_list([#b_label{label=Label} | (Insns = [#label{label=Label}|_])], Accum) ->
- peep_list(Insns, Accum);
-peep_list([I|Insns], Accum) ->
- peep_list(Insns, [I|Accum]);
-peep_list([], Accum) ->
- lists:reverse(Accum).
diff --git a/lib/hipe/ppc/hipe_ppc_frame.erl b/lib/hipe/ppc/hipe_ppc_frame.erl
deleted file mode 100644
index b88b75a5bd..0000000000
--- a/lib/hipe/ppc/hipe_ppc_frame.erl
+++ /dev/null
@@ -1,686 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_frame).
--export([frame/1]).
--include("hipe_ppc.hrl").
--include("../rtl/hipe_literals.hrl").
-
-frame(CFG) ->
- Formals = fix_formals(hipe_ppc_cfg:params(CFG)),
- Temps0 = all_temps(CFG, Formals),
- MinFrame = defun_minframe(CFG),
- Temps = ensure_minframe(MinFrame, Temps0),
- ClobbersLR = clobbers_lr(CFG),
- Liveness = hipe_ppc_liveness_all:analyse(CFG),
- do_body(CFG, Liveness, Formals, Temps, ClobbersLR).
-
-fix_formals(Formals) ->
- fix_formals(hipe_ppc_registers:nr_args(), Formals).
-
-fix_formals(0, Rest) -> Rest;
-fix_formals(N, [_|Rest]) -> fix_formals(N-1, Rest);
-fix_formals(_, []) -> [].
-
-do_body(CFG0, Liveness, Formals, Temps, ClobbersLR) ->
- Context = mk_context(Liveness, Formals, Temps, ClobbersLR),
- CFG1 = hipe_ppc_cfg:map_bbs(
- fun(Lbl, BB) -> do_block(Lbl, BB, Context) end, CFG0),
- do_prologue(CFG1, Context).
-
-do_block(Label, Block, Context) ->
- Liveness = context_liveness(Context),
- LiveOut = hipe_ppc_liveness_all:liveout(Liveness, Label),
- Code = hipe_bb:code(Block),
- NewCode = do_block(Code, LiveOut, Context, context_framesize(Context), []),
- hipe_bb:code_update(Block, NewCode).
-
-do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) ->
- {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0),
- do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode));
-do_block([], _, Context, FPoff, RevCode) ->
- FPoff0 = context_framesize(Context),
- if FPoff =:= FPoff0 -> [];
- true -> exit({?MODULE,do_block,FPoff})
- end,
- lists:reverse(RevCode, []).
-
-do_insn(I, LiveOut, Context, FPoff) ->
- case I of
- #blr{} ->
- {do_blr(I, Context, FPoff), context_framesize(Context)};
- #pseudo_call{} ->
- do_pseudo_call(I, LiveOut, Context, FPoff);
- #pseudo_call_prepare{} ->
- do_pseudo_call_prepare(I, FPoff);
- #pseudo_move{} ->
- {do_pseudo_move(I, Context, FPoff), FPoff};
- #pseudo_spill_move{} ->
- {do_pseudo_spill_move(I, Context, FPoff), FPoff};
- #pseudo_tailcall{} ->
- {do_pseudo_tailcall(I, Context), context_framesize(Context)};
- #pseudo_fmove{} ->
- {do_pseudo_fmove(I, Context, FPoff), FPoff};
- #pseudo_spill_fmove{} ->
- {do_pseudo_spill_fmove(I, Context, FPoff), FPoff};
- _ ->
- {[I], FPoff}
- end.
-
-%%%
-%%% Moves, with Dst or Src possibly a pseudo
-%%%
-
-do_pseudo_move(I, Context, FPoff) ->
- Dst = hipe_ppc:pseudo_move_dst(I),
- Src = hipe_ppc:pseudo_move_src(I),
- case temp_is_pseudo(Dst) of
- true ->
- Offset = pseudo_offset(Dst, FPoff, Context),
- mk_store(hipe_ppc:stop_word(), Src, Offset, mk_sp(), []);
- _ ->
- case temp_is_pseudo(Src) of
- true ->
- Offset = pseudo_offset(Src, FPoff, Context),
- mk_load(hipe_ppc:ldop_word(), Dst, Offset, mk_sp(), []);
- _ ->
- case hipe_ppc:temp_reg(Dst) =:= hipe_ppc:temp_reg(Src) of
- true -> [];
- false -> [hipe_ppc:mk_alu('or', Dst, Src, Src)]
- end
- end
- end.
-
-do_pseudo_spill_move(I, Context, FPoff) ->
- #pseudo_spill_move{dst=Dst,temp=Temp,src=Src} = I,
- case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of
- false -> % Register allocator changed its mind, turn back to move
- do_pseudo_move(hipe_ppc:mk_pseudo_move(Dst, Src), Context, FPoff);
- true ->
- SrcOffset = pseudo_offset(Src, FPoff, Context),
- DstOffset = pseudo_offset(Dst, FPoff, Context),
- case SrcOffset =:= DstOffset of
- true -> []; % omit move-to-self
- false ->
- mk_load(hipe_ppc:ldop_word(), Temp, SrcOffset, mk_sp(),
- mk_store(hipe_ppc:stop_word(), Temp, DstOffset, mk_sp(), []))
- end
- end.
-
-do_pseudo_fmove(I, Context, FPoff) ->
- Dst = hipe_ppc:pseudo_fmove_dst(I),
- Src = hipe_ppc:pseudo_fmove_src(I),
- case temp_is_pseudo(Dst) of
- true ->
- Offset = pseudo_offset(Dst, FPoff, Context),
- hipe_ppc:mk_fstore(Src, Offset, mk_sp(), 0);
- _ ->
- case temp_is_pseudo(Src) of
- true ->
- Offset = pseudo_offset(Src, FPoff, Context),
- hipe_ppc:mk_fload(Dst, Offset, mk_sp(), 0);
- _ ->
- [hipe_ppc:mk_fp_unary('fmr', Dst, Src)]
- end
- end.
-
-do_pseudo_spill_fmove(I, Context, FPoff) ->
- #pseudo_spill_fmove{dst=Dst,temp=Temp,src=Src} = I,
- case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of
- false -> % Register allocator changed its mind, turn back to move
- do_pseudo_fmove(hipe_ppc:mk_pseudo_fmove(Dst, Src), Context, FPoff);
- true ->
- SrcOffset = pseudo_offset(Src, FPoff, Context),
- DstOffset = pseudo_offset(Dst, FPoff, Context),
- case SrcOffset =:= DstOffset of
- true -> []; % omit move-to-self
- false ->
- hipe_ppc:mk_fload(Temp, SrcOffset, mk_sp(), 0)
- ++ hipe_ppc:mk_fstore(Temp, DstOffset, mk_sp(), 0)
- end
- end.
-
-pseudo_offset(Temp, FPoff, Context) ->
- FPoff + context_offset(Context, Temp).
-
-%%%
-%%% Return - deallocate frame and emit 'ret $N' insn.
-%%%
-
-do_blr(I, Context, FPoff) ->
- %% XXX: perhaps use explicit pseudo_move;mtlr,
- %% avoiding the need to hard-code Temp1 here
- %% XXX: typically only one instruction between
- %% the mtlr and the blr, ouch
- restore_lr(FPoff, Context,
- adjust_sp(FPoff + word_size() * context_arity(Context),
- [I])).
-
-restore_lr(FPoff, Context, Rest) ->
- case context_clobbers_lr(Context) of
- false -> Rest;
- true ->
- Temp = mk_temp1(),
- mk_load(hipe_ppc:ldop_word(), Temp, FPoff - word_size(), mk_sp(),
- [hipe_ppc:mk_mtspr('lr', Temp) |
- Rest])
- end.
-
-adjust_sp(N, Rest) ->
- if N =:= 0 ->
- Rest;
- true ->
- SP = mk_sp(),
- hipe_ppc:mk_addi(SP, SP, N, Rest)
- end.
-
-%%%
-%%% Recursive calls.
-%%%
-
-do_pseudo_call_prepare(I, FPoff0) ->
- %% Create outgoing arguments area on the stack.
- NrStkArgs = hipe_ppc:pseudo_call_prepare_nrstkargs(I),
- Offset = NrStkArgs * word_size(),
- {adjust_sp(-Offset, []), FPoff0 + Offset}.
-
-do_pseudo_call(I, LiveOut, Context, FPoff0) ->
- #ppc_sdesc{exnlab=ExnLab,arity=OrigArity} = hipe_ppc:pseudo_call_sdesc(I),
- FunC = hipe_ppc:pseudo_call_func(I),
- LiveTemps = [Temp || Temp <- LiveOut, temp_is_pseudo(Temp)],
- SDesc = mk_sdesc(ExnLab, Context, LiveTemps),
- ContLab = hipe_ppc:pseudo_call_contlab(I),
- Linkage = hipe_ppc:pseudo_call_linkage(I),
- CallCode = [hipe_ppc:mk_pseudo_call(FunC, SDesc, ContLab, Linkage)],
- StkArity = erlang:max(0, OrigArity - hipe_ppc_registers:nr_args()),
- context_need_stack(Context, stack_need(FPoff0, StkArity, FunC)),
- ArgsBytes = word_size() * StkArity,
- {CallCode, FPoff0 - ArgsBytes}.
-
-stack_need(FPoff, StkArity, FunC) ->
- case FunC of
- #ppc_prim{} -> FPoff;
- #ppc_mfa{m=M,f=F,a=A} ->
- case erlang:is_builtin(M, F, A) of
- true -> FPoff;
- false -> stack_need_general(FPoff, StkArity)
- end;
- 'ctr' -> stack_need_general(FPoff, StkArity)
- end.
-
-stack_need_general(FPoff, StkArity) ->
- erlang:max(FPoff, FPoff + (?PPC_LEAF_WORDS - StkArity) * word_size()).
-
-%%%
-%%% Create stack descriptors for call sites.
-%%%
-
-mk_sdesc(ExnLab, Context, Temps) -> % for normal calls
- Temps0 = only_tagged(Temps),
- Live = mk_live(Context, Temps0),
- Arity = context_arity(Context),
- FSize = context_framesize(Context),
- hipe_ppc:mk_sdesc(ExnLab, (FSize div word_size())-1, Arity,
- list_to_tuple(Live)).
-
-only_tagged(Temps)->
- [X || X <- Temps, hipe_ppc:temp_type(X) =:= 'tagged'].
-
-mk_live(Context, Temps) ->
- lists:sort([temp_to_slot(Context, Temp) || Temp <- Temps]).
-
-temp_to_slot(Context, Temp) ->
- (context_framesize(Context) + context_offset(Context, Temp))
- div word_size().
-
-mk_minimal_sdesc(Context) -> % for inc_stack_0 calls
- hipe_ppc:mk_sdesc([], 0, context_arity(Context), {}).
-
-%%%
-%%% Tailcalls.
-%%%
-
-do_pseudo_tailcall(I, Context) -> % always at FPoff=context_framesize(Context)
- Arity = context_arity(Context),
- Args = hipe_ppc:pseudo_tailcall_stkargs(I),
- FunC = hipe_ppc:pseudo_tailcall_func(I),
- Linkage = hipe_ppc:pseudo_tailcall_linkage(I),
- {Insns, FPoff1} = do_tailcall_args(Args, Context),
- context_need_stack(Context, FPoff1),
- StkArity = length(Args),
- FPoff2 = FPoff1 + (Arity - StkArity) * word_size(),
- context_need_stack(Context, stack_need(FPoff2, StkArity, FunC)),
- I2 =
- case FunC of
- 'ctr' ->
- hipe_ppc:mk_bctr([]);
- Fun ->
- hipe_ppc:mk_b_fun(Fun, Linkage)
- end,
- %% XXX: break out the LR restore, just like for blr?
- restore_lr(context_framesize(Context), Context,
- Insns ++ adjust_sp(FPoff2, [I2])).
-
-do_tailcall_args(Args, Context) ->
- FPoff0 = context_framesize(Context),
- Arity = context_arity(Context),
- FrameTop = word_size()*Arity,
- DangerOff = FrameTop - word_size()*length(Args),
- %%
- Moves = mk_moves(Args, FrameTop, []),
- %%
- {Stores, Simple, Conflict} =
- split_moves(Moves, Context, DangerOff, [], [], []),
- %% sanity check (shouldn't trigger any more)
- if DangerOff < -FPoff0 ->
- exit({?MODULE,do_tailcall_args,DangerOff,-FPoff0});
- true -> []
- end,
- FPoff1 = FPoff0,
- %%
- {Pushes, Pops, FPoff2} = split_conflict(Conflict, FPoff1, [], []),
- %%
- TempReg = hipe_ppc_registers:temp1(),
- %%
- {adjust_sp(-(FPoff2 - FPoff1),
- simple_moves(Pushes, FPoff2, TempReg,
- store_moves(Stores, FPoff2, TempReg,
- simple_moves(Simple, FPoff2, TempReg,
- simple_moves(Pops, FPoff2, TempReg,
- []))))),
- FPoff2}.
-
-mk_moves([Arg|Args], Off, Moves) ->
- Off1 = Off - word_size(),
- mk_moves(Args, Off1, [{Arg,Off1}|Moves]);
-mk_moves([], _, Moves) ->
- Moves.
-
-split_moves([Move|Moves], Context, DangerOff, Stores, Simple, Conflict) ->
- {Src,DstOff} = Move,
- case src_is_pseudo(Src) of
- false ->
- split_moves(Moves, Context, DangerOff, [Move|Stores],
- Simple, Conflict);
- true ->
- SrcOff = context_offset(Context, Src),
- Type = typeof_temp(Src),
- if SrcOff =:= DstOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, Conflict);
- SrcOff >= DangerOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, [{SrcOff,DstOff,Type}|Conflict]);
- true ->
- split_moves(Moves, Context, DangerOff, Stores,
- [{SrcOff,DstOff,Type}|Simple], Conflict)
- end
- end;
-split_moves([], _, _, Stores, Simple, Conflict) ->
- {Stores, Simple, Conflict}.
-
-split_conflict([{SrcOff,DstOff,Type}|Conflict], FPoff, Pushes, Pops) ->
- FPoff1 = FPoff + word_size(),
- Push = {SrcOff,-FPoff1,Type},
- Pop = {-FPoff1,DstOff,Type},
- split_conflict(Conflict, FPoff1, [Push|Pushes], [Pop|Pops]);
-split_conflict([], FPoff, Pushes, Pops) ->
- {lists:reverse(Pushes), Pops, FPoff}.
-
-simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) ->
- Temp = hipe_ppc:mk_temp(TempReg, Type),
- SP = mk_sp(),
- LoadOff = FPoff+SrcOff,
- StoreOff = FPoff+DstOff,
- simple_moves(Moves, FPoff, TempReg,
- mk_load(hipe_ppc:ldop_word(), Temp, LoadOff, SP,
- mk_store(hipe_ppc:stop_word(), Temp, StoreOff, SP,
- Rest)));
-simple_moves([], _, _, Rest) ->
- Rest.
-
-store_moves([{Src,DstOff}|Moves], FPoff, TempReg, Rest) ->
- %%Type = typeof_temp(Src),
- SP = mk_sp(),
- StoreOff = FPoff+DstOff,
- {NewSrc,FixSrc} =
- case hipe_ppc:is_temp(Src) of
- true ->
- {Src, []};
- _ ->
- Temp = hipe_ppc:mk_temp(TempReg, 'untagged'),
- {Temp, hipe_ppc:mk_li(Temp, Src)}
- end,
- store_moves(Moves, FPoff, TempReg,
- FixSrc ++ mk_store(hipe_ppc:stop_word(), NewSrc,
- StoreOff, SP, Rest));
-store_moves([], _, _, Rest) ->
- Rest.
-
-%%%
-%%% Contexts
-%%%
-
--record(context, {liveness, framesize, arity, map, clobbers_lr, ref_maxstack}).
-
-mk_context(Liveness, Formals, Temps, ClobbersLR) ->
- {Map, MinOff} = mk_temp_map(Formals, ClobbersLR, Temps),
- FrameSize = (-MinOff),
- RefMaxStack = hipe_bifs:ref(FrameSize),
- #context{liveness=Liveness,
- framesize=FrameSize, arity=length(Formals),
- map=Map, clobbers_lr=ClobbersLR, ref_maxstack=RefMaxStack}.
-
-context_need_stack(#context{ref_maxstack=RM}, N) ->
- M = hipe_bifs:ref_get(RM),
- if N > M -> hipe_bifs:ref_set(RM, N);
- true -> []
- end.
-
-context_maxstack(#context{ref_maxstack=RM}) ->
- hipe_bifs:ref_get(RM).
-
-context_arity(#context{arity=Arity}) ->
- Arity.
-
-context_framesize(#context{framesize=FrameSize}) ->
- FrameSize.
-
-context_liveness(#context{liveness=Liveness}) ->
- Liveness.
-
-context_offset(#context{map=Map}, Temp) ->
- tmap_lookup(Map, Temp).
-
-context_clobbers_lr(#context{clobbers_lr=ClobbersLR}) -> ClobbersLR.
-
-mk_temp_map(Formals, ClobbersLR, Temps) ->
- {Map, 0} = enter_vars(Formals, word_size() * length(Formals),
- tmap_empty()),
- TempsList = tset_to_list(Temps),
- AllTemps =
- case ClobbersLR of
- false -> TempsList;
- true ->
- RA = hipe_ppc:mk_new_temp('untagged'),
- [RA|TempsList]
- end,
- enter_vars(AllTemps, 0, Map).
-
-enter_vars([V|Vs], PrevOff, Map) ->
- Off =
- case hipe_ppc:temp_type(V) of
- 'double' -> PrevOff - 8;
- _ -> PrevOff - word_size()
- end,
- enter_vars(Vs, Off, tmap_bind(Map, V, Off));
-enter_vars([], Off, Map) ->
- {Map, Off}.
-
-tmap_empty() ->
- gb_trees:empty().
-
-tmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-tmap_lookup(Map, Key) ->
- gb_trees:get(Key, Map).
-
-%%%
-%%% do_prologue: prepend stack frame allocation code.
-%%%
-%%% NewStart:
-%%% temp1 = *(P + P_SP_LIMIT)
-%%% temp2 = SP - MaxStack
-%%% cmp temp2, temp1
-%%% temp1 = LR [if ClobbersLR][hoisted]
-%%% if (ltu) goto IncStack else goto AllocFrame
-%%% AllocFrame:
-%%% SP = temp2 [if FrameSize == MaxStack]
-%%% SP -= FrameSize [if FrameSize != MaxStack]
-%%% *(SP + FrameSize-WordSize) = temp1 [if ClobbersLR]
-%%% goto OldStart
-%%% OldStart:
-%%% ...
-%%% IncStack:
-%%% temp1 = LR [if not ClobbersLR]
-%%% bl inc_stack
-%%% LR = temp1
-%%% goto NewStart
-
-do_prologue(CFG, Context) ->
- MaxStack = context_maxstack(Context),
- if MaxStack > 0 ->
- FrameSize = context_framesize(Context),
- OldStartLab = hipe_ppc_cfg:start_label(CFG),
- NewStartLab = hipe_gensym:get_next_label(ppc),
- %%
- P = hipe_ppc:mk_temp(hipe_ppc_registers:proc_pointer(), 'untagged'),
- Temp1 = mk_temp1(),
- SP = mk_sp(),
- %%
- ClobbersLR = context_clobbers_lr(Context),
- GotoOldStartCode = [hipe_ppc:mk_b_label(OldStartLab)],
- AllocFrameCodeTail =
- case ClobbersLR of
- false -> GotoOldStartCode;
- true -> mk_store(hipe_ppc:stop_word(), Temp1,
- FrameSize-word_size(), SP, GotoOldStartCode)
- end,
- %%
- Arity = context_arity(Context),
- Guaranteed = erlang:max(0, (?PPC_LEAF_WORDS - Arity) * word_size()),
- %%
- {CFG1,NewStartCode} =
- if MaxStack =< Guaranteed ->
- %% io:format("~w: MaxStack ~w =< Guaranteed ~w :-)\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameCode = adjust_sp(-FrameSize, AllocFrameCodeTail),
- NewStartCode0 =
- case ClobbersLR of
- false -> AllocFrameCode;
- true -> [hipe_ppc:mk_mfspr(Temp1, 'lr') | AllocFrameCode]
- end,
- {CFG,NewStartCode0};
- true ->
- %% io:format("~w: MaxStack ~w > Guaranteed ~w :-(\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameLab = hipe_gensym:get_next_label(ppc),
- IncStackLab = hipe_gensym:get_next_label(ppc),
- Temp2 = mk_temp2(),
- %%
- NewStartCodeTail2 =
- [hipe_ppc:mk_pseudo_bc('lt', IncStackLab, AllocFrameLab, 0.01)],
- NewStartCodeTail1 =
- case ClobbersLR of
- false -> NewStartCodeTail2;
- true -> [hipe_ppc:mk_mfspr(Temp1, 'lr') | NewStartCodeTail2]
- end,
- NewStartCode0 =
- [hipe_ppc:mk_load(hipe_ppc:ldop_word(), Temp1, ?P_NSP_LIMIT, P) |
- hipe_ppc:mk_addi(Temp2, SP, -MaxStack,
- [hipe_ppc:mk_cmp('cmpl', Temp2, Temp1) |
- NewStartCodeTail1])],
- %%
- AllocFrameCode =
- if MaxStack =:= FrameSize ->
- %% io:format("~w: MaxStack =:= FrameSize =:= ~w :-)\n", [?MODULE,MaxStack]),
- [hipe_ppc:mk_alu('or', SP, Temp2, Temp2) |
- AllocFrameCodeTail];
- true ->
- %% io:format("~w: MaxStack ~w =/= FrameSize ~w :-(\n", [?MODULE,MaxStack,FrameSize]),
- adjust_sp(-FrameSize, AllocFrameCodeTail)
- end,
- %%
- IncStackCodeTail =
- [hipe_ppc:mk_bl(hipe_ppc:mk_prim('inc_stack_0'),
- mk_minimal_sdesc(Context), not_remote),
- hipe_ppc:mk_mtspr('lr', Temp1),
- hipe_ppc:mk_b_label(NewStartLab)],
- IncStackCode =
- case ClobbersLR of
- true -> IncStackCodeTail;
- false -> [hipe_ppc:mk_mfspr(Temp1, 'lr') | IncStackCodeTail]
- end,
- %%
- CFG0a = hipe_ppc_cfg:bb_add(CFG, AllocFrameLab,
- hipe_bb:mk_bb(AllocFrameCode)),
- CFG0b = hipe_ppc_cfg:bb_add(CFG0a, IncStackLab,
- hipe_bb:mk_bb(IncStackCode)),
- %%
- {CFG0b,NewStartCode0}
- end,
- %%
- CFG2 = hipe_ppc_cfg:bb_add(CFG1, NewStartLab,
- hipe_bb:mk_bb(NewStartCode)),
- hipe_ppc_cfg:start_label_update(CFG2, NewStartLab);
- true ->
- CFG
- end.
-
-%%% Create a load instruction.
-%%% May clobber Dst early for large offsets. In principle we could
-%%% clobber R0 if Dst =:= Base, but Dst =/= Base here in frame.
-
-mk_load(LdOp, Dst, Offset, Base, Rest) ->
- hipe_ppc:mk_load(LdOp, Dst, Offset, Base, 'error', Rest).
-
-%%% Create a store instruction.
-%%% May clobber R0 for large offsets.
-
-mk_store(StOp, Src, Offset, Base, Rest) ->
- hipe_ppc:mk_store(StOp, Src, Offset, Base, 0, Rest).
-
-%%% typeof_temp -- what's temp's type?
-
-typeof_temp(Temp) ->
- hipe_ppc:temp_type(Temp).
-
-%%% Cons up an 'SP' Temp.
-
-mk_sp() ->
- hipe_ppc:mk_temp(hipe_ppc_registers:stack_pointer(), 'untagged').
-
-%%% Cons up a 'TEMP1' Temp.
-
-mk_temp1() ->
- hipe_ppc:mk_temp(hipe_ppc_registers:temp1(), 'untagged').
-
-%%% Cons up a 'TEMP2' Temp.
-
-mk_temp2() ->
- hipe_ppc:mk_temp(hipe_ppc_registers:temp2(), 'untagged').
-
-%%% Check if an operand is a pseudo-Temp.
-
-src_is_pseudo(Src) ->
- hipe_ppc:is_temp(Src) andalso temp_is_pseudo(Src).
-
-temp_is_pseudo(Temp) ->
- not(hipe_ppc:temp_is_precoloured(Temp)).
-
-%%%
-%%% Detect if a Defun's body clobbers LR.
-%%%
-
-clobbers_lr(CFG) ->
- any_insn(fun(#pseudo_call{}) -> true;
- (_) -> false
- end, CFG).
-
-any_insn(Pred, CFG) ->
- %% Abuse fold to do an efficient "any"-operation using nonlocal control flow
- FoundSatisfying = make_ref(),
- try fold_insns(fun (I, _) ->
- case Pred(I) of
- true -> throw(FoundSatisfying);
- false -> false
- end
- end, false, CFG)
- of _ -> false
- catch FoundSatisfying -> true
- end.
-
-%%%
-%%% Build the set of all temps used in a Defun's body.
-%%%
-
-all_temps(CFG, Formals) ->
- S0 = fold_insns(fun find_temps/2, tset_empty(), CFG),
- S1 = tset_del_list(S0, Formals),
- tset_filter(S1, fun(T) -> temp_is_pseudo(T) end).
-
-find_temps(I, S0) ->
- S1 = tset_add_list(S0, hipe_ppc_defuse:insn_def_all(I)),
- tset_add_list(S1, hipe_ppc_defuse:insn_use_all(I)).
-
-fold_insns(Fun, InitAcc, CFG) ->
- hipe_ppc_cfg:fold_bbs(
- fun(_, BB, Acc0) -> lists:foldl(Fun, Acc0, hipe_bb:code(BB)) end,
- InitAcc, CFG).
-
-tset_empty() ->
- gb_sets:new().
-
-tset_size(S) ->
- gb_sets:size(S).
-
-tset_insert(S, T) ->
- gb_sets:add_element(T, S).
-
-tset_add_list(S, Ts) ->
- gb_sets:union(S, gb_sets:from_list(Ts)).
-
-tset_del_list(S, Ts) ->
- gb_sets:subtract(S, gb_sets:from_list(Ts)).
-
-tset_filter(S, F) ->
- gb_sets:filter(F, S).
-
-tset_to_list(S) ->
- gb_sets:to_list(S).
-
-%%%
-%%% Compute minimum permissible frame size, ignoring spilled temps.
-%%% This is done to ensure that we won't have to adjust the frame size
-%%% in the middle of a tailcall.
-%%%
-
-defun_minframe(CFG) ->
- MaxTailArity = fold_insns(fun insn_mta/2, 0, CFG),
- MyArity = length(fix_formals(hipe_ppc_cfg:params(CFG))),
- erlang:max(MaxTailArity - MyArity, 0).
-
-insn_mta(I, MTA) ->
- case I of
- #pseudo_tailcall{arity=Arity} ->
- erlang:max(MTA, Arity - hipe_ppc_registers:nr_args());
- _ -> MTA
- end.
-
-%%%
-%%% Ensure that we have enough temps to satisfy the minimum frame size,
-%%% if necessary by prepending unused dummy temps.
-%%%
-
-ensure_minframe(MinFrame, Temps) ->
- ensure_minframe(MinFrame, tset_size(Temps), Temps).
-
-ensure_minframe(MinFrame, Frame, Temps) ->
- if MinFrame > Frame ->
- Temp = hipe_ppc:mk_new_temp('untagged'),
- ensure_minframe(MinFrame, Frame+1, tset_insert(Temps, Temp));
- true -> Temps
- end.
-
-word_size() ->
- hipe_rtl_arch:word_size().
diff --git a/lib/hipe/ppc/hipe_ppc_liveness_all.erl b/lib/hipe/ppc/hipe_ppc_liveness_all.erl
deleted file mode 100644
index 42138eea08..0000000000
--- a/lib/hipe/ppc/hipe_ppc_liveness_all.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_liveness_all).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_ppc.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_ppc_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_ppc_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_ppc_cfg:succ(CFG, L).
-uses(Insn) -> hipe_ppc_defuse:insn_use_all(Insn).
-defines(Insn) -> hipe_ppc_defuse:insn_def_all(Insn).
-liveout_no_succ() ->
- ordsets:from_list(lists:map(fun({Reg,Type}) ->
- hipe_ppc:mk_temp(Reg, Type)
- end,
- hipe_ppc_registers:live_at_return())).
diff --git a/lib/hipe/ppc/hipe_ppc_liveness_fpr.erl b/lib/hipe/ppc/hipe_ppc_liveness_fpr.erl
deleted file mode 100644
index eeca0e523e..0000000000
--- a/lib/hipe/ppc/hipe_ppc_liveness_fpr.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_liveness_fpr).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_ppc.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_ppc_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_ppc_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_ppc_cfg:succ(CFG, L).
-uses(Insn) -> hipe_ppc_defuse:insn_use_fpr(Insn).
-defines(Insn) -> hipe_ppc_defuse:insn_def_fpr(Insn).
-liveout_no_succ() -> [].
diff --git a/lib/hipe/ppc/hipe_ppc_liveness_gpr.erl b/lib/hipe/ppc/hipe_ppc_liveness_gpr.erl
deleted file mode 100644
index ab9d28266c..0000000000
--- a/lib/hipe/ppc/hipe_ppc_liveness_gpr.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_liveness_gpr).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_ppc.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_ppc_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_ppc_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_ppc_cfg:succ(CFG, L).
-uses(Insn) -> hipe_ppc_defuse:insn_use_gpr(Insn).
-defines(Insn) -> hipe_ppc_defuse:insn_def_gpr(Insn).
-liveout_no_succ() ->
- ordsets:from_list(lists:map(fun({Reg,Type}) ->
- hipe_ppc:mk_temp(Reg, Type)
- end,
- hipe_ppc_registers:live_at_return())).
diff --git a/lib/hipe/ppc/hipe_ppc_main.erl b/lib/hipe/ppc/hipe_ppc_main.erl
deleted file mode 100644
index a094aa65f7..0000000000
--- a/lib/hipe/ppc/hipe_ppc_main.erl
+++ /dev/null
@@ -1,47 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_main).
--export([rtl_to_ppc/3]).
-
-rtl_to_ppc(MFA, RTL, Options) ->
- PPC1 = hipe_rtl_to_ppc:translate(RTL),
- PPC1CFG = hipe_ppc_cfg:init(PPC1),
- PPC2CFG = hipe_ppc_ra:ra(PPC1CFG, Options),
- PPC3CFG = hipe_ppc_frame:frame(PPC2CFG),
- PPC3 = hipe_ppc_cfg:linearise(PPC3CFG),
- PPC4 = hipe_ppc_finalise:finalise(PPC3),
- ppc_pp(PPC4, MFA, Options),
- {native, powerpc, {unprofiled, PPC4}}.
-
-ppc_pp(PPC, MFA, Options) ->
- case proplists:get_value(pp_native, Options) of
- true ->
- hipe_ppc_pp:pp(PPC);
- {only,Lst} when is_list(Lst) ->
- case lists:member(MFA,Lst) of
- true ->
- hipe_ppc_pp:pp(PPC);
- false ->
- ok
- end;
- {only,MFA} ->
- hipe_ppc_pp:pp(PPC);
- {file,FileName} ->
- {ok, File} = file:open(FileName, [write,append]),
- hipe_ppc_pp:pp(File, PPC),
- ok = file:close(File);
- _ ->
- ok
- end.
diff --git a/lib/hipe/ppc/hipe_ppc_pp.erl b/lib/hipe/ppc/hipe_ppc_pp.erl
deleted file mode 100644
index 4ee91f771e..0000000000
--- a/lib/hipe/ppc/hipe_ppc_pp.erl
+++ /dev/null
@@ -1,350 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_pp).
--export([pp/1, pp/2, pp_insn/1]).
-
--include("hipe_ppc.hrl").
-
-pp(Defun) ->
- pp(standard_io, Defun).
-
-pp(Dev, #defun{mfa={M,F,A}, code=Code, data=Data}) ->
- Fname = atom_to_list(M)++"_"++atom_to_list(F)++"_"++integer_to_list(A),
- io:format(Dev, "\t.text\n", []),
- io:format(Dev, "\t.align 4\n", []),
- io:format(Dev, "\t.global ~s\n", [Fname]),
- io:format(Dev, "~s:\n", [Fname]),
- pp_insns(Dev, Code, Fname),
- io:format(Dev, "\t.rodata\n", []),
- io:format(Dev, "\t.align 4\n", []),
- hipe_data_pp:pp(Dev, Data, ppc, Fname),
- io:format(Dev, "\n", []).
-
-pp_insns(Dev, [I|Is], Fname) ->
- pp_insn(Dev, I, Fname),
- pp_insns(Dev, Is, Fname);
-pp_insns(_, [], _) ->
- [].
-
-pp_insn(I) ->
- pp_insn(standard_io, I, "").
-
-pp_insn(Dev, I, Pre) ->
- case I of
- #alu{aluop=AluOp, dst=Dst, src1=Src1, src2=Src2} ->
- io:format(Dev, "\t~s ", [alu_op_name(AluOp)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src1),
- io:format(Dev, ", ", []),
- pp_src(Dev, Src2),
- io:format(Dev, "\n", []);
- #b_fun{'fun'=Fun, linkage=Linkage} ->
- io:format(Dev, "\tb ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " # ~w\n", [Linkage]);
- #b_label{label=Label} ->
- io:format(Dev, "\tb .~s_~w\n", [Pre, Label]);
- #bc{bcond=BCond, label=Label, pred=Pred} ->
- io:format(Dev, "\tb~w ~s_~w # ~.2f\n", [bcond_name(BCond), Pre, Label, Pred]);
- #bctr{labels=Labels} ->
- io:format(Dev, "\tbctr", []),
- case Labels of
- [] -> [];
- _ ->
- io:format(Dev, " #", []),
- pp_labels(Dev, Labels, Pre)
- end,
- io:format(Dev, "\n", []);
- #bctrl{sdesc=SDesc} ->
- io:format(Dev, "\tbctrl #", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, "\n", []);
- #bl{'fun'=Fun, sdesc=SDesc, linkage=Linkage} ->
- io:format(Dev, "\tbl ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " #", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #blr{} ->
- io:format(Dev, "\tblr\n", []);
- #comment{term=Term} ->
- io:format(Dev, "\t# ~p\n", [Term]);
- #cmp{cmpop=CmpOp, src1=Src1, src2=Src2} ->
- io:format(Dev, "\t~s ", [cmp_op_name(CmpOp)]),
- pp_temp(Dev, Src1),
- io:format(Dev, ", ", []),
- pp_src(Dev, Src2),
- io:format(Dev, "\n", []);
- #label{label=Label} ->
- io:format(Dev, ".~s_~w:~n", [Pre, Label]);
- #load{ldop=LdOp, dst=Dst, disp=Disp, base=Base} ->
- io:format(Dev, "\t~w ", [ldop_name(LdOp)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ~s(", [to_hex(Disp)]),
- pp_temp(Dev, Base),
- io:format(Dev, ")\n", []);
- #loadx{ldxop=LdxOp, dst=Dst, base1=Base1, base2=Base2} ->
- io:format(Dev, "\t~w ", [ldxop_name(LdxOp)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base2),
- io:format(Dev, "\n", []);
- #mfspr{dst=Dst, spr=SPR} ->
- io:format(Dev, "\tmf~w ", [spr_name(SPR)]),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #mtcr{src=Src} ->
- io:format(Dev, "\tmtcrf 0x80, ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #mtspr{spr=SPR, src=Src} ->
- io:format(Dev, "\tmt~w ", [spr_name(SPR)]),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #pseudo_bc{bcond=BCond, true_label=TrueLab, false_label=FalseLab, pred=Pred} ->
- io:format(Dev, "\tpseudo_bc ~w, .~s_~w # .~s_~w ~.2f\n",
- [bcond_name(BCond), Pre, TrueLab, Pre, FalseLab, Pred]);
- #pseudo_call{func=FunC, sdesc=SDesc, contlab=ContLab, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_call ", []),
- pp_func(Dev, FunC),
- io:format(Dev, " # contlab .~s_~w", [Pre, ContLab]),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #pseudo_call_prepare{nrstkargs=NrStkArgs} ->
- SP = hipe_ppc_registers:reg_name_gpr(hipe_ppc_registers:stack_pointer()),
- io:format(Dev, "\taddi ~s, ~s, ~w # pseudo_call_prepare\n",
- [SP, SP, -(4*NrStkArgs)]);
- #pseudo_li{dst=Dst, imm=Imm} ->
- io:format(Dev, "\tpseudo_li ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_imm(Dev, Imm),
- io:format(Dev, "\n", []);
- #pseudo_move{dst=Dst, src=Src} ->
- io:format(Dev, "\tpseudo_move ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #pseudo_tailcall{func=FunC, arity=Arity, stkargs=StkArgs, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_tailcall ", []),
- pp_func(Dev, FunC),
- io:format(Dev, "/~w (", [Arity]),
- pp_args(Dev, StkArgs),
- io:format(Dev, ") ~w\n", [Linkage]);
- #pseudo_tailcall_prepare{} ->
- io:format(Dev, "\tpseudo_tailcall_prepare\n", []);
- #store{stop=StOp, src=Src, disp=Disp, base=Base} ->
- io:format(Dev, "\t~s ", [stop_name(StOp)]),
- pp_temp(Dev, Src),
- io:format(Dev, ", ~s(", [to_hex(Disp)]),
- pp_temp(Dev, Base),
- io:format(Dev, ")\n", []);
- #storex{stxop=StxOp, src=Src, base1=Base1, base2=Base2} ->
- io:format(Dev, "\t~s ", [stxop_name(StxOp)]),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base2),
- io:format(Dev, "\n", []);
- #unary{unop={UnOp,I1,I2,I3}, dst=Dst, src=Src} ->
- io:format(Dev, "\t~s ", [UnOp]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", ~s, ~s, ~s\n", [to_hex(I1),to_hex(I2),to_hex(I3)]);
- #unary{unop=UnOp, dst=Dst, src=Src} ->
- io:format(Dev, "\t~w ", [unop_name(UnOp)]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #lfd{dst=Dst, disp=Disp, base=Base} ->
- io:format(Dev, "\tlfd ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ~s(", [to_hex(Disp)]),
- pp_temp(Dev, Base),
- io:format(Dev, ")\n", []);
- #lfdx{dst=Dst, base1=Base1, base2=Base2} ->
- io:format(Dev, "\tlfdx ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base2),
- io:format(Dev, "\n", []);
- #stfd{src=Src, disp=Disp, base=Base} ->
- io:format(Dev, "\tstfd ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", ~s(", [to_hex(Disp)]),
- pp_temp(Dev, Base),
- io:format(Dev, ")\n", []);
- #stfdx{src=Src, base1=Base1, base2=Base2} ->
- io:format(Dev, "\tstfdx ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Base2),
- io:format(Dev, "\n", []);
- #fp_binary{fp_binop=FpBinOp, dst=Dst, src1=Src1, src2=Src2} ->
- io:format(Dev, "\t~s ", [FpBinOp]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src2),
- io:format(Dev, "\n", []);
- #fp_unary{fp_unop=FpUnOp, dst=Dst, src=Src} ->
- io:format(Dev, "\t~s ", [FpUnOp]),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- #pseudo_fmove{dst=Dst, src=Src} ->
- io:format(Dev, "\tpseudo_fmove ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src),
- io:format(Dev, "\n", []);
- _ ->
- exit({?MODULE, pp_insn, I})
- end.
-
-to_hex(N) ->
- io_lib:format("~.16x", [N, "0x"]).
-
-pp_sdesc(Dev, Pre, #ppc_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live}) ->
- pp_sdesc_exnlab(Dev, Pre, ExnLab),
- io:format(Dev, " ~s ~w [", [to_hex(FSize), Arity]),
- pp_sdesc_live(Dev, Live),
- io:format(Dev, "]", []).
-
-pp_sdesc_exnlab(Dev, _, []) -> io:format(Dev, " []", []);
-pp_sdesc_exnlab(Dev, Pre, ExnLab) -> io:format(Dev, " .~s_~w", [Pre, ExnLab]).
-
-pp_sdesc_live(_, {}) -> [];
-pp_sdesc_live(Dev, Live) -> pp_sdesc_live(Dev, Live, 1).
-
-pp_sdesc_live(Dev, Live, I) ->
- io:format(Dev, "~s", [to_hex(element(I, Live))]),
- if I < tuple_size(Live) ->
- io:format(Dev, ",", []),
- pp_sdesc_live(Dev, Live, I+1);
- true -> []
- end.
-
-pp_labels(Dev, [Label|Labels], Pre) ->
- io:format(Dev, " .~s_~w", [Pre, Label]),
- pp_labels(Dev, Labels, Pre);
-pp_labels(_, [], _) ->
- [].
-
-pp_fun(Dev, Fun) ->
- case Fun of
- #ppc_mfa{m=M, f=F, a=A} ->
- io:format(Dev, "~w:~w/~w", [M, F, A]);
- #ppc_prim{prim=Prim} ->
- io:format(Dev, "~w", [Prim])
- end.
-
-pp_func(Dev, FunC) ->
- case FunC of
- 'ctr' ->
- io:format(Dev, "ctr", []);
- Fun ->
- pp_fun(Dev, Fun)
- end.
-
-alu_op_name(Op) -> Op.
-
-bcond_name(BCond) -> BCond.
-
-cmp_op_name(Op) -> Op.
-
-spr_name(SPR) -> SPR.
-
-ldop_name(LdOp) -> LdOp.
-
-ldxop_name(LdxOp) -> LdxOp.
-
-stop_name(StOp) -> StOp.
-
-stxop_name(StxOp) -> StxOp.
-
-unop_name(UnOp) -> UnOp.
-
-pp_temp(Dev, Temp=#ppc_temp{reg=Reg, type=Type}) ->
- case hipe_ppc:temp_is_precoloured(Temp) of
- true ->
- Name =
- case Type of
- 'double' -> hipe_ppc_registers:reg_name_fpr(Reg);
- _ -> hipe_ppc_registers:reg_name_gpr(Reg)
- end,
- io:format(Dev, "~s", [Name]);
- false ->
- Tag =
- case Type of
- double -> "f";
- tagged -> "t";
- untagged -> "u"
- end,
- io:format(Dev, "~s~w", [Tag, Reg])
- end.
-
-pp_hex(Dev, Value) -> io:format(Dev, "~s", [to_hex(Value)]).
-pp_simm16(Dev, #ppc_simm16{value=Value}) -> pp_hex(Dev, Value).
-pp_uimm16(Dev, #ppc_uimm16{value=Value}) -> pp_hex(Dev, Value).
-
-pp_imm(Dev, Value) ->
- if is_integer(Value) -> pp_hex(Dev, Value);
- true -> io:format(Dev, "~w", [Value])
- end.
-
-pp_src(Dev, Src) ->
- case Src of
- #ppc_temp{} ->
- pp_temp(Dev, Src);
- #ppc_simm16{} ->
- pp_simm16(Dev, Src);
- #ppc_uimm16{} ->
- pp_uimm16(Dev, Src)
- end.
-
-pp_arg(Dev, Arg) ->
- case Arg of
- #ppc_temp{} ->
- pp_temp(Dev, Arg);
- _ ->
- pp_hex(Dev, Arg)
- end.
-
-pp_args(Dev, [A|As]) ->
- pp_arg(Dev, A),
- pp_comma_args(Dev, As);
-pp_args(_, []) ->
- [].
-
-pp_comma_args(Dev, [A|As]) ->
- io:format(Dev, ", ", []),
- pp_arg(Dev, A),
- pp_comma_args(Dev, As);
-pp_comma_args(_, []) ->
- [].
diff --git a/lib/hipe/ppc/hipe_ppc_ra.erl b/lib/hipe/ppc/hipe_ppc_ra.erl
deleted file mode 100644
index b8daf72cef..0000000000
--- a/lib/hipe/ppc/hipe_ppc_ra.erl
+++ /dev/null
@@ -1,54 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_ra).
--export([ra/2]).
-
-ra(CFG0, Options) ->
- %% hipe_ppc_pp:pp(hipe_ppc_cfg:linearise(CFG0)),
- {CFG1, _FPLiveness1, Coloring_fp, SpillIndex}
- = case proplists:get_bool(inline_fp, Options) of
- true ->
- FPLiveness0 = hipe_ppc_specific_fp:analyze(CFG0, no_context),
- hipe_regalloc_loop:ra_fp(CFG0, FPLiveness0, Options,
- hipe_coalescing_regalloc,
- hipe_ppc_specific_fp, no_context);
- false ->
- {CFG0,undefined,[],0}
- end,
- %% hipe_ppc_pp:pp(hipe_ppc_cfg:linearise(CFG1)),
- GPLiveness1 = hipe_ppc_specific:analyze(CFG1, no_context),
- {CFG2, _GPLiveness2, Coloring}
- = case proplists:get_value(regalloc, Options, coalescing) of
- coalescing ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_coalescing_regalloc);
- optimistic ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_optimistic_regalloc);
- graph_color ->
- ra(CFG1, GPLiveness1, SpillIndex, Options,
- hipe_graph_coloring_regalloc);
- linear_scan ->
- hipe_ppc_ra_ls:ra(CFG1, GPLiveness1, SpillIndex, Options);
- naive ->
- hipe_ppc_ra_naive:ra(CFG1, GPLiveness1, Coloring_fp, Options);
- _ ->
- exit({unknown_regalloc_compiler_option,
- proplists:get_value(regalloc,Options)})
- end,
- %% hipe_ppc_pp:pp(hipe_ppc_cfg:linearise(CFG2)),
- hipe_ppc_ra_finalise:finalise(CFG2, Coloring, Coloring_fp).
-
-ra(CFG, Liveness, SpillIndex, Options, RegAllocMod) ->
- hipe_regalloc_loop:ra(CFG, Liveness, SpillIndex, Options, RegAllocMod,
- hipe_ppc_specific, no_context).
diff --git a/lib/hipe/ppc/hipe_ppc_ra_finalise.erl b/lib/hipe/ppc/hipe_ppc_ra_finalise.erl
deleted file mode 100644
index bca504d754..0000000000
--- a/lib/hipe/ppc/hipe_ppc_ra_finalise.erl
+++ /dev/null
@@ -1,281 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_ra_finalise).
--export([finalise/3]).
--include("hipe_ppc.hrl").
-
-finalise(CFG, TempMap, FPMap0) ->
- {_, SpillLimit} = hipe_gensym:var_range(ppc),
- Map = mk_ra_map(TempMap, SpillLimit),
- FPMap1 = mk_ra_map_fp(FPMap0, SpillLimit),
- hipe_ppc_cfg:map_bbs(fun(_Lbl, BB) -> ra_bb(BB, Map, FPMap1) end, CFG).
-
-ra_bb(BB, Map, FpMap) ->
- hipe_bb:code_update(BB, ra_code(hipe_bb:code(BB), Map, FpMap, [])).
-
-ra_code([I|Insns], Map, FPMap, Accum) ->
- ra_code(Insns, Map, FPMap, [ra_insn(I, Map, FPMap) | Accum]);
-ra_code([], _Map, _FPMap, Accum) ->
- lists:reverse(Accum).
-
-ra_insn(I, Map, FPMap) ->
- case I of
- #alu{} -> ra_alu(I, Map);
- #cmp{} -> ra_cmp(I, Map);
- #load{} -> ra_load(I, Map);
- #loadx{} -> ra_loadx(I, Map);
- #mfspr{} -> ra_mfspr(I, Map);
- #mtcr{} -> ra_mtcr(I, Map);
- #mtspr{} -> ra_mtspr(I, Map);
- #pseudo_li{} -> ra_pseudo_li(I, Map);
- #pseudo_move{} -> ra_pseudo_move(I, Map);
- #pseudo_spill_move{} -> ra_pseudo_spill_move(I, Map);
- #pseudo_tailcall{} -> ra_pseudo_tailcall(I, Map);
- #store{} -> ra_store(I, Map);
- #storex{} -> ra_storex(I, Map);
- #unary{} -> ra_unary(I, Map);
- #lfd{} -> ra_lfd(I, Map, FPMap);
- #lfdx{} -> ra_lfdx(I, Map, FPMap);
- #stfd{} -> ra_stfd(I, Map, FPMap);
- #stfdx{} -> ra_stfdx(I, Map, FPMap);
- #fp_binary{} -> ra_fp_binary(I, FPMap);
- #fp_unary{} -> ra_fp_unary(I, FPMap);
- #pseudo_fmove{} -> ra_pseudo_fmove(I, FPMap);
- #pseudo_spill_fmove{} -> ra_pseudo_spill_fmove(I, FPMap);
- _ -> I
- end.
-
-ra_alu(I=#alu{dst=Dst,src1=Src1,src2=Src2}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewSrc1 = ra_temp(Src1, Map),
- NewSrc2 = ra_temp_or_imm(Src2, Map),
- I#alu{dst=NewDst,src1=NewSrc1,src2=NewSrc2}.
-
-ra_cmp(I=#cmp{src1=Src1,src2=Src2}, Map) ->
- NewSrc1 = ra_temp(Src1, Map),
- NewSrc2 = ra_temp_or_imm(Src2, Map),
- I#cmp{src1=NewSrc1,src2=NewSrc2}.
-
-ra_load(I=#load{dst=Dst,base=Base}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewBase = ra_temp(Base, Map),
- I#load{dst=NewDst,base=NewBase}.
-
-ra_loadx(I=#loadx{dst=Dst,base1=Base1,base2=Base2}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewBase1 = ra_temp(Base1, Map),
- NewBase2 = ra_temp(Base2, Map),
- I#loadx{dst=NewDst,base1=NewBase1,base2=NewBase2}.
-
-ra_mfspr(I=#mfspr{dst=Dst}, Map) ->
- NewDst = ra_temp(Dst, Map),
- I#mfspr{dst=NewDst}.
-
-ra_mtcr(I=#mtcr{src=Src}, Map) ->
- NewSrc = ra_temp(Src, Map),
- I#mtcr{src=NewSrc}.
-
-ra_mtspr(I=#mtspr{src=Src}, Map) ->
- NewSrc = ra_temp(Src, Map),
- I#mtspr{src=NewSrc}.
-
-ra_pseudo_li(I=#pseudo_li{dst=Dst}, Map) ->
- NewDst = ra_temp(Dst, Map),
- I#pseudo_li{dst=NewDst}.
-
-ra_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewSrc = ra_temp(Src, Map),
- I#pseudo_move{dst=NewDst,src=NewSrc}.
-
-ra_pseudo_spill_move(I=#pseudo_spill_move{dst=Dst,temp=Temp,src=Src}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewTemp = ra_temp(Temp, Map),
- NewSrc = ra_temp(Src, Map),
- I#pseudo_spill_move{dst=NewDst,temp=NewTemp,src=NewSrc}.
-
-ra_pseudo_tailcall(I=#pseudo_tailcall{stkargs=StkArgs}, Map) ->
- NewStkArgs = ra_args(StkArgs, Map),
- I#pseudo_tailcall{stkargs=NewStkArgs}.
-
-ra_store(I=#store{src=Src,base=Base}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewBase = ra_temp(Base, Map),
- I#store{src=NewSrc,base=NewBase}.
-
-ra_storex(I=#storex{src=Src,base1=Base1,base2=Base2}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewBase1 = ra_temp(Base1, Map),
- NewBase2 = ra_temp(Base2, Map),
- I#storex{src=NewSrc,base1=NewBase1,base2=NewBase2}.
-
-ra_unary(I=#unary{dst=Dst,src=Src}, Map) ->
- NewDst = ra_temp(Dst, Map),
- NewSrc = ra_temp(Src, Map),
- I#unary{dst=NewDst,src=NewSrc}.
-
-ra_lfd(I=#lfd{dst=Dst,base=Base}, Map, FPMap) ->
- NewDst = ra_temp_fp(Dst, FPMap),
- NewBase = ra_temp(Base, Map),
- I#lfd{dst=NewDst,base=NewBase}.
-
-ra_lfdx(I=#lfdx{dst=Dst,base1=Base1,base2=Base2}, Map, FPMap) ->
- NewDst = ra_temp_fp(Dst, FPMap),
- NewBase1 = ra_temp(Base1, Map),
- NewBase2 = ra_temp(Base2, Map),
- I#lfdx{dst=NewDst,base1=NewBase1,base2=NewBase2}.
-
-ra_stfd(I=#stfd{src=Src,base=Base}, Map, FPMap) ->
- NewSrc = ra_temp_fp(Src, FPMap),
- NewBase = ra_temp(Base, Map),
- I#stfd{src=NewSrc,base=NewBase}.
-
-ra_stfdx(I=#stfdx{src=Src,base1=Base1,base2=Base2}, Map, FPMap) ->
- NewSrc = ra_temp_fp(Src, FPMap),
- NewBase1 = ra_temp(Base1, Map),
- NewBase2 = ra_temp(Base2, Map),
- I#stfdx{src=NewSrc,base1=NewBase1,base2=NewBase2}.
-
-ra_fp_binary(I=#fp_binary{dst=Dst,src1=Src1,src2=Src2}, FPMap) ->
- NewDst = ra_temp_fp(Dst, FPMap),
- NewSrc1 = ra_temp_fp(Src1, FPMap),
- NewSrc2 = ra_temp_fp(Src2, FPMap),
- I#fp_binary{dst=NewDst,src1=NewSrc1,src2=NewSrc2}.
-
-ra_fp_unary(I=#fp_unary{dst=Dst,src=Src}, FPMap) ->
- NewDst = ra_temp_fp(Dst, FPMap),
- NewSrc = ra_temp_fp(Src, FPMap),
- I#fp_unary{dst=NewDst,src=NewSrc}.
-
-ra_pseudo_fmove(I=#pseudo_fmove{dst=Dst,src=Src}, FPMap) ->
- NewDst = ra_temp_fp(Dst, FPMap),
- NewSrc = ra_temp_fp(Src, FPMap),
- I#pseudo_fmove{dst=NewDst,src=NewSrc}.
-
-ra_pseudo_spill_fmove(I=#pseudo_spill_fmove{dst=Dst,temp=Temp,src=Src},
- FPMap) ->
- NewDst = ra_temp_fp(Dst, FPMap),
- NewTemp = ra_temp_fp(Temp, FPMap),
- NewSrc = ra_temp_fp(Src, FPMap),
- I#pseudo_spill_fmove{dst=NewDst,temp=NewTemp,src=NewSrc}.
-
-ra_args([Arg|Args], Map) ->
- [ra_temp_or_imm(Arg, Map) | ra_args(Args, Map)];
-ra_args([], _) ->
- [].
-
-ra_temp_or_imm(Arg, Map) ->
- case hipe_ppc:is_temp(Arg) of
- true ->
- ra_temp(Arg, Map);
- false ->
- Arg
- end.
-
-ra_temp_fp(Temp, FPMap) ->
- Reg = hipe_ppc:temp_reg(Temp),
- case hipe_ppc:temp_type(Temp) of
- 'double' ->
- case hipe_ppc_registers:is_precoloured_fpr(Reg) of
- true -> Temp;
- _ -> ra_temp_common(Reg, Temp, FPMap)
- end
- end.
-
-ra_temp(Temp, Map) ->
- Reg = hipe_ppc:temp_reg(Temp),
- case hipe_ppc:temp_type(Temp) of
- 'double' ->
- exit({?MODULE,ra_temp,Temp});
- _ ->
- case hipe_ppc_registers:is_precoloured_gpr(Reg) of
- true -> Temp;
- _ -> ra_temp_common(Reg, Temp, Map)
- end
- end.
-
-ra_temp_common(Reg, Temp, Map) ->
- case gb_trees:lookup(Reg, Map) of
- {value,NewReg} -> Temp#ppc_temp{reg=NewReg};
- _ -> Temp
- end.
-
-mk_ra_map(TempMap, SpillLimit) ->
- %% Build a partial map from pseudo to reg or spill.
- %% Spills are represented as pseudos with indices above SpillLimit.
- %% (I'd prefer to use negative indices, but that breaks
- %% hipe_ppc_registers:is_precoloured/1.)
- %% The frame mapping proper is unchanged, since spills look just like
- %% ordinary (un-allocated) pseudos.
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit, is_precoloured_gpr),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- TempMap).
-
-conv_ra_maplet(MapLet = {From,To}, SpillLimit, IsPrecoloured) ->
- %% From should be a pseudo, or a hard reg mapped to itself.
- if is_integer(From), From =< SpillLimit ->
- case hipe_ppc_registers:IsPrecoloured(From) of
- false -> [];
- _ ->
- case To of
- {reg, From} -> [];
- _ -> exit({?MODULE,conv_ra_maplet,MapLet})
- end
- end;
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of From check
- case To of
- {reg, NewReg} ->
- %% NewReg should be a hard reg, or a pseudo mapped
- %% to itself (formals are handled this way).
- if is_integer(NewReg) ->
- case hipe_ppc_registers:IsPrecoloured(NewReg) of
- true -> [];
- _ -> if From =:= NewReg -> [];
- true ->
- exit({?MODULE,conv_ra_maplet,MapLet})
- end
- end;
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of NewReg check
- {From, NewReg};
- {spill, SpillIndex} ->
- %% SpillIndex should be >= 0.
- if is_integer(SpillIndex), SpillIndex >= 0 -> [];
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of SpillIndex check
- ToTempNum = SpillLimit+SpillIndex+1,
- MaxTempNum = hipe_gensym:get_var(ppc),
- if MaxTempNum >= ToTempNum -> ok;
- true -> hipe_gensym:set_var(ppc, ToTempNum)
- end,
- {From, ToTempNum};
- _ -> exit({?MODULE,conv_ra_maplet,MapLet})
- end.
-
-mk_ra_map_fp(FPMap, SpillLimit) ->
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit,
- is_precoloured_fpr),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- FPMap).
diff --git a/lib/hipe/ppc/hipe_ppc_ra_ls.erl b/lib/hipe/ppc/hipe_ppc_ra_ls.erl
deleted file mode 100644
index d8b2087919..0000000000
--- a/lib/hipe/ppc/hipe_ppc_ra_ls.erl
+++ /dev/null
@@ -1,49 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Linear Scan register allocator for PowerPC
-
--module(hipe_ppc_ra_ls).
--export([ra/4]).
-
-ra(CFG, Liveness, SpillIndex, Options) ->
- SpillLimit = hipe_ppc_specific:number_of_temporaries(CFG, no_context),
- alloc(CFG, Liveness, SpillIndex, SpillLimit, Options).
-
-alloc(CFG, Liveness, SpillIndex, SpillLimit, Options) ->
- {Coloring, _NewSpillIndex} =
- regalloc(
- CFG, Liveness,
- hipe_ppc_registers:allocatable_gpr()--
- [hipe_ppc_registers:temp3(),
- hipe_ppc_registers:temp2(),
- hipe_ppc_registers:temp1()],
- [hipe_ppc_cfg:start_label(CFG)],
- SpillIndex, SpillLimit, Options,
- hipe_ppc_specific, no_context),
- {NewCFG, _DidSpill} =
- hipe_ppc_ra_postconditions:check_and_rewrite(
- CFG, Coloring, 'linearscan'),
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_ppc_specific, no_context),
- {TempMap2,_NewSpillIndex2} =
- hipe_spillmin:stackalloc(CFG, Liveness, [], SpillIndex, Options,
- hipe_ppc_specific, no_context, TempMap),
- Coloring2 =
- hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), TempMap2),
- {NewCFG, Liveness, Coloring2}.
-
-regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options,
- TgtMod, TgtCtx) ->
- hipe_ls_regalloc:regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex,
- DontSpill, Options, TgtMod, TgtCtx).
diff --git a/lib/hipe/ppc/hipe_ppc_ra_naive.erl b/lib/hipe/ppc/hipe_ppc_ra_naive.erl
deleted file mode 100644
index dee89f66f9..0000000000
--- a/lib/hipe/ppc/hipe_ppc_ra_naive.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_ra_naive).
--export([ra/4]).
-
--include("hipe_ppc.hrl").
-
-ra(CFG, Liveness, _Coloring_fp, _Options) -> % -> {CFG, Liveness, Coloring}
- {NewCFG,_DidSpill} =
- hipe_ppc_ra_postconditions:check_and_rewrite2(CFG, [], 'naive'),
- {NewCFG, Liveness, []}.
diff --git a/lib/hipe/ppc/hipe_ppc_ra_postconditions.erl b/lib/hipe/ppc/hipe_ppc_ra_postconditions.erl
deleted file mode 100644
index 0a97129666..0000000000
--- a/lib/hipe/ppc/hipe_ppc_ra_postconditions.erl
+++ /dev/null
@@ -1,248 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_ra_postconditions).
-
--export([check_and_rewrite/3, check_and_rewrite2/3]).
-
--include("hipe_ppc.hrl").
-
-check_and_rewrite(CFG, Coloring, Allocator) ->
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_ppc_specific, no_context),
- check_and_rewrite2(CFG, TempMap, Allocator).
-
-check_and_rewrite2(CFG, TempMap, Allocator) ->
- Strategy = strategy(Allocator),
- do_bbs(hipe_ppc_cfg:labels(CFG), TempMap, Strategy, CFG, false).
-
-strategy(Allocator) ->
- case Allocator of
- 'normal' -> 'new';
- 'linearscan' -> 'fixed';
- 'naive' -> 'fixed'
- end.
-
-do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_ppc_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0),
- CFG = hipe_ppc_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
- do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
-do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap, Strategy) ->
- case I of
- #alu{} -> do_alu(I, TempMap, Strategy);
- #cmp{} -> do_cmp(I, TempMap, Strategy);
- #load{} -> do_load(I, TempMap, Strategy);
- #loadx{} -> do_loadx(I, TempMap, Strategy);
- #mfspr{} -> do_mfspr(I, TempMap, Strategy);
- #mtcr{} -> do_mtcr(I, TempMap, Strategy);
- #mtspr{} -> do_mtspr(I, TempMap, Strategy);
- #pseudo_li{} -> do_pseudo_li(I, TempMap, Strategy);
- #pseudo_move{} -> do_pseudo_move(I, TempMap, Strategy);
- #pseudo_spill_move{} -> do_pseudo_spill_move(I, TempMap, Strategy);
- #store{} -> do_store(I, TempMap, Strategy);
- #storex{} -> do_storex(I, TempMap, Strategy);
- #unary{} -> do_unary(I, TempMap, Strategy);
- #lfd{} -> do_lfd(I, TempMap, Strategy);
- #lfdx{} -> do_lfdx(I, TempMap, Strategy);
- #stfd{} -> do_stfd(I, TempMap, Strategy);
- #stfdx{} -> do_stfdx(I, TempMap, Strategy);
- _ -> {[I], false}
- end.
-
-%%% Fix relevant instruction types.
-
-do_alu(I=#alu{dst=Dst,src1=Src1,src2=Src2}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixSrc1,NewSrc1,DidSpill2} = fix_src1(Src1, TempMap, Strategy),
- {FixSrc2,NewSrc2,DidSpill3} = fix_src2_or_imm(Src2, TempMap, Strategy),
- NewI = I#alu{dst=NewDst,src1=NewSrc1,src2=NewSrc2},
- {FixSrc1 ++ FixSrc2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_cmp(I=#cmp{src1=Src1,src2=Src2}, TempMap, Strategy) ->
- {FixSrc1,NewSrc1,DidSpill1} = fix_src1(Src1, TempMap, Strategy),
- {FixSrc2,NewSrc2,DidSpill2} = fix_src2_or_imm(Src2, TempMap, Strategy),
- NewI = I#cmp{src1=NewSrc1,src2=NewSrc2},
- {FixSrc1 ++ FixSrc2 ++ [NewI], DidSpill1 or DidSpill2}.
-
-do_load(I=#load{dst=Dst,base=Base}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixBase,NewBase,DidSpill2} = fix_src1(Base, TempMap, Strategy),
- NewI = I#load{dst=NewDst,base=NewBase},
- {FixBase ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_loadx(I=#loadx{dst=Dst,base1=Base1,base2=Base2}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixBase1,NewBase1,DidSpill2} = fix_src1(Base1, TempMap, Strategy),
- {FixBase2,NewBase2,DidSpill3} = fix_src2(Base2, TempMap, Strategy),
- NewI = I#loadx{dst=NewDst,base1=NewBase1,base2=NewBase2},
- {FixBase1 ++ FixBase2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_mfspr(I=#mfspr{dst=Dst}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
- NewI = I#mfspr{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_mtcr(I=#mtcr{src=Src}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy),
- NewI = I#mtcr{src=NewSrc},
- {FixSrc ++ [NewI], DidSpill}.
-
-do_mtspr(I=#mtspr{src=Src}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy),
- NewI = I#mtspr{src=NewSrc},
- {FixSrc ++ [NewI], DidSpill}.
-
-do_pseudo_li(I=#pseudo_li{dst=Dst}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
- NewI = I#pseudo_li{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_pseudo_move(I=#pseudo_move{dst=Dst,src=Src}, TempMap, Strategy) ->
- %% Either Dst or Src (but not both) may be a pseudo temp.
- %% pseudo_move, pseudo_spill_move, and pseudo_tailcall are
- %% special cases: in all other instructions, all temps
- %% must be non-pseudos after register allocation.
- case temp_is_spilled(Src, TempMap)
- andalso temp_is_spilled(Dst, TempMap)
- of
- true -> % Turn into pseudo_spill_move
- Temp = clone(Src, temp1(Strategy)),
- NewI = #pseudo_spill_move{dst=Dst,temp=Temp,src=Src},
- {[NewI], true};
- _ ->
- {[I], false}
- end.
-
-do_pseudo_spill_move(I=#pseudo_spill_move{temp=Temp}, TempMap, _Strategy) ->
- %% Temp is above the low water mark and must not have been spilled
- false = temp_is_spilled(Temp, TempMap),
- {[I], false}.
-
-do_store(I=#store{src=Src,base=Base}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
- {FixBase,NewBase,DidSpill2} = fix_src2(Base, TempMap, Strategy),
- NewI = I#store{src=NewSrc,base=NewBase},
- {FixSrc ++ FixBase ++ [NewI], DidSpill1 or DidSpill2}.
-
-do_storex(I=#storex{src=Src,base1=Base1,base2=Base2}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
- {FixBase1,NewBase1,DidSpill2} = fix_src2(Base1, TempMap, Strategy),
- {FixBase2,NewBase2,DidSpill3} = fix_src3(Base2, TempMap, Strategy),
- NewI = I#storex{src=NewSrc,base1=NewBase1,base2=NewBase2},
- {FixSrc ++ FixBase1 ++ FixBase2 ++ [NewI], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_unary(I=#unary{dst=Dst,src=Src}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixSrc,NewSrc,DidSpill2} = fix_src1(Src, TempMap, Strategy),
- NewI = I#unary{dst=NewDst,src=NewSrc},
- {FixSrc ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_lfd(I=#lfd{base=Base}, TempMap, Strategy) ->
- {FixBase,NewBase,DidSpill} = fix_src1(Base, TempMap, Strategy),
- NewI = I#lfd{base=NewBase},
- {FixBase ++ [NewI], DidSpill}.
-
-do_lfdx(I=#lfdx{base1=Base1,base2=Base2}, TempMap, Strategy) ->
- {FixBase1,NewBase1,DidSpill1} = fix_src1(Base1, TempMap, Strategy),
- {FixBase2,NewBase2,DidSpill2} = fix_src2(Base2, TempMap, Strategy),
- NewI = I#lfdx{base1=NewBase1,base2=NewBase2},
- {FixBase1 ++ FixBase2 ++ [NewI], DidSpill1 or DidSpill2}.
-
-do_stfd(I=#stfd{base=Base}, TempMap, Strategy) ->
- {FixBase,NewBase,DidSpill} = fix_src1(Base, TempMap, Strategy),
- NewI = I#stfd{base=NewBase},
- {FixBase ++ [NewI], DidSpill}.
-
-do_stfdx(I=#stfdx{base1=Base1,base2=Base2}, TempMap, Strategy) ->
- {FixBase1,NewBase1,DidSpill1} = fix_src1(Base1, TempMap, Strategy),
- {FixBase2,NewBase2,DidSpill2} = fix_src2(Base2, TempMap, Strategy),
- NewI = I#stfdx{base1=NewBase1,base2=NewBase2},
- {FixBase1 ++ FixBase2 ++ [NewI], DidSpill1 or DidSpill2}.
-
-%%% Fix Dst and Src operands.
-
-fix_src2_or_imm(Src2, TempMap, Strategy) ->
- case Src2 of
- #ppc_temp{} -> fix_src2(Src2, TempMap, Strategy);
- _ -> {[], Src2, false}
- end.
-
-fix_src1(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp1(Strategy)).
-
-temp1('new') -> [];
-temp1('fixed') -> hipe_ppc_registers:temp1().
-
-fix_src2(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp2(Strategy)).
-
-temp2('new') -> [];
-temp2('fixed') -> hipe_ppc_registers:temp2().
-
-fix_src3(Src, TempMap, Strategy) -> % storex :-(
- fix_src(Src, TempMap, temp3(Strategy)).
-
-temp3('new') -> [];
-temp3('fixed') -> hipe_ppc_registers:temp3().
-
-fix_src(Src, TempMap, RegOpt) ->
- case temp_is_spilled(Src, TempMap) of
- true ->
- NewSrc = clone(Src, RegOpt),
- {[hipe_ppc:mk_pseudo_move(NewSrc, Src)],
- NewSrc,
- true};
- _ ->
- {[], Src, false}
- end.
-
-fix_dst(Dst, TempMap, Strategy) ->
- case temp_is_spilled(Dst, TempMap) of
- true ->
- NewDst = clone(Dst, temp3(Strategy)),
- {[hipe_ppc:mk_pseudo_move(Dst, NewDst)],
- NewDst,
- true};
- _ ->
- {[], Dst, false}
- end.
-
-%%% Check if an operand is a pseudo-temp.
-
-temp_is_spilled(Temp, []) -> % special case for naive regalloc
- not(hipe_ppc:temp_is_precoloured(Temp));
-temp_is_spilled(Temp, TempMap) ->
- case hipe_ppc:temp_is_allocatable(Temp) of
- true ->
- Reg = hipe_ppc:temp_reg(Temp),
- tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
- false -> true
- end.
-
-%%% Make a certain reg into a clone of Temp.
-
-clone(Temp, RegOpt) ->
- Type = hipe_ppc:temp_type(Temp),
- case RegOpt of
- [] -> hipe_ppc:mk_new_temp(Type);
- Reg -> hipe_ppc:mk_temp(Reg, Type)
- end.
diff --git a/lib/hipe/ppc/hipe_ppc_ra_postconditions_fp.erl b/lib/hipe/ppc/hipe_ppc_ra_postconditions_fp.erl
deleted file mode 100644
index 7342053620..0000000000
--- a/lib/hipe/ppc/hipe_ppc_ra_postconditions_fp.erl
+++ /dev/null
@@ -1,135 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_ra_postconditions_fp).
--export([check_and_rewrite/2]).
--include("hipe_ppc.hrl").
-
-check_and_rewrite(CFG, Coloring) ->
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_ppc_specific_fp, no_context),
- do_bbs(hipe_ppc_cfg:labels(CFG), TempMap, CFG, false).
-
-do_bbs([], _TempMap, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_ppc_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, [], DidSpill0),
- CFG = hipe_ppc_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap),
- do_insns(Insns, TempMap, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
-do_insns([], _TempMap, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap) ->
- case I of
- #lfd{} -> do_lfd(I, TempMap);
- #lfdx{} -> do_lfdx(I, TempMap);
- #stfd{} -> do_stfd(I, TempMap);
- #stfdx{} -> do_stfdx(I, TempMap);
- #fp_binary{} -> do_fp_binary(I, TempMap);
- #fp_unary{} -> do_fp_unary(I, TempMap);
- #pseudo_fmove{} -> do_pseudo_fmove(I, TempMap);
- #pseudo_spill_fmove{} -> do_pseudo_spill_fmove(I, TempMap);
- _ -> {[I], false}
- end.
-
-%%% Fix relevant instruction types.
-
-do_lfd(I=#lfd{dst=Dst}, TempMap) ->
- {FixDst, NewDst, DidSpill} = fix_dst(Dst, TempMap),
- NewI = I#lfd{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_lfdx(I=#lfdx{dst=Dst}, TempMap) ->
- {FixDst, NewDst, DidSpill} = fix_dst(Dst, TempMap),
- NewI = I#lfdx{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_stfd(I=#stfd{src=Src}, TempMap) ->
- {FixSrc, NewSrc, DidSpill} = fix_src(Src, TempMap),
- NewI = I#stfd{src=NewSrc},
- {FixSrc ++ [NewI], DidSpill}.
-
-do_stfdx(I=#stfdx{src=Src}, TempMap) ->
- {FixSrc, NewSrc, DidSpill} = fix_src(Src, TempMap),
- NewI = I#stfdx{src=NewSrc},
- {FixSrc ++ [NewI], DidSpill}.
-
-do_fp_binary(I=#fp_binary{dst=Dst,src1=Src1,src2=Src2}, TempMap) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap),
- {FixSrc1,NewSrc1,DidSpill2} = fix_src(Src1, TempMap),
- {FixSrc2,NewSrc2,DidSpill3} = fix_src(Src2, TempMap),
- NewI = I#fp_binary{dst=NewDst,src1=NewSrc1,src2=NewSrc2},
- {FixSrc1 ++ FixSrc2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_fp_unary(I=#fp_unary{dst=Dst,src=Src}, TempMap) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap),
- {FixSrc,NewSrc,DidSpill2} = fix_src(Src, TempMap),
- NewI = I#fp_unary{dst=NewDst,src=NewSrc},
- {FixSrc ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_pseudo_fmove(I=#pseudo_fmove{dst=Dst,src=Src}, TempMap) ->
- case temp_is_spilled(Src, TempMap)
- andalso temp_is_spilled(Dst, TempMap)
- of
- true -> % Turn into pseudo_spill_fmove
- Temp = clone(Src),
- NewI = #pseudo_spill_fmove{dst=Dst,temp=Temp,src=Src},
- {[NewI], true};
- _ ->
- {[I], false}
- end.
-
-do_pseudo_spill_fmove(I=#pseudo_spill_fmove{temp=Temp}, TempMap) ->
- %% Temp is above the low water mark and must not have been spilled
- false = temp_is_spilled(Temp, TempMap),
- {[I], false}.
-
-%%% Fix Dst and Src operands.
-
-fix_src(Src, TempMap) ->
- case temp_is_spilled(Src, TempMap) of
- true ->
- NewSrc = clone(Src),
- {[hipe_ppc:mk_pseudo_fmove(NewSrc, Src)], NewSrc, true};
- _ ->
- {[], Src, false}
- end.
-
-fix_dst(Dst, TempMap) ->
- case temp_is_spilled(Dst, TempMap) of
- true ->
- NewDst = clone(Dst),
- {[hipe_ppc:mk_pseudo_fmove(Dst, NewDst)], NewDst, true};
- _ ->
- {[], Dst, false}
- end.
-
-%%% Check if an operand is a pseudo-temp.
-
-temp_is_spilled(Temp, TempMap) ->
- case hipe_ppc:temp_is_allocatable(Temp) of
- true ->
- Reg = hipe_ppc:temp_reg(Temp),
- tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
- false -> true
- end.
-
-%%% Create a new temp with the same type as an old one.
-
-clone(Temp) ->
- Type = hipe_ppc:temp_type(Temp), % XXX: always double?
- hipe_ppc:mk_new_temp(Type).
diff --git a/lib/hipe/ppc/hipe_ppc_registers.erl b/lib/hipe/ppc/hipe_ppc_registers.erl
deleted file mode 100644
index 86bea784f1..0000000000
--- a/lib/hipe/ppc/hipe_ppc_registers.erl
+++ /dev/null
@@ -1,242 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_registers).
-
--export([reg_name_gpr/1,
- reg_name_fpr/1,
- first_virtual/0,
- is_precoloured_gpr/1,
- is_precoloured_fpr/1,
- all_precoloured/0,
- return_value/0,
- temp1/0,
- temp2/0,
- temp3/0, % for base2 in storeix :-(
- heap_pointer/0,
- stack_pointer/0,
- proc_pointer/0,
- %%heap_limit/0,
- %%fcalls/0,
- allocatable_gpr/0,
- allocatable_fpr/0,
- is_fixed/1,
- nr_args/0,
- arg/1,
- args/1,
- is_arg/1, % for linear scan
- call_clobbered/0,
- tailcall_clobbered/0,
- live_at_return/0
- ]).
-
--include("../rtl/hipe_literals.hrl").
-
--define(R0, 0).
--define(R1, 1).
--define(R2, 2).
--define(R3, 3).
--define(R4, 4).
--define(R5, 5).
--define(R6, 6).
--define(R7, 7).
--define(R8, 8).
--define(R9, 9).
--define(R10, 10).
--define(R11, 11).
--define(R12, 12).
--define(R13, 13).
--define(R14, 14).
--define(R15, 15).
--define(R16, 16).
--define(R17, 17).
--define(R18, 18).
--define(R19, 19).
--define(R20, 20).
--define(R21, 21).
--define(R22, 22).
--define(R23, 23).
--define(R24, 24).
--define(R25, 25).
--define(R26, 26).
--define(R27, 27).
--define(R28, 28).
--define(R29, 29).
--define(R30, 30).
--define(R31, 31).
--define(LAST_PRECOLOURED, 31). % must handle both GPR and FPR ranges
-
--define(ARG0, ?R4).
--define(ARG1, ?R5).
--define(ARG2, ?R6).
--define(ARG3, ?R7).
--define(ARG4, ?R8).
--define(ARG5, ?R9).
--define(ARG6, ?R10).
-
--define(TEMP1, ?R28).
--define(TEMP2, ?R27).
--define(TEMP3, ?R26). % XXX: for base2 in storeix, switch to R0 instead?
-
--define(RETURN_VALUE, ?R3).
--define(HEAP_POINTER, ?R29).
--define(STACK_POINTER, ?R30).
--define(PROC_POINTER, ?R31).
-
-reg_name_gpr(R) -> [$r | integer_to_list(R)].
-reg_name_fpr(R) -> [$f | integer_to_list(R)].
-
-%%% Must handle both GPR and FPR ranges.
-first_virtual() -> ?LAST_PRECOLOURED + 1.
-
-%%% These two tests have the same implementation, but that's
-%%% not something we should cast in stone in the interface.
-is_precoloured_gpr(R) -> R =< ?LAST_PRECOLOURED.
-is_precoloured_fpr(R) -> R =< ?LAST_PRECOLOURED.
-
-all_precoloured() ->
- %% XXX: skip R1, R2, and R13. They should never occur anywhere.
- [ ?R0, ?R1, ?R2, ?R3, ?R4, ?R5, ?R6, ?R7,
- ?R8, ?R9, ?R10, ?R11, ?R12, ?R13, ?R14, ?R15,
- ?R16, ?R17, ?R18, ?R19, ?R20, ?R21, ?R22, ?R23,
- ?R24, ?R25, ?R26, ?R27, ?R28, ?R29, ?R30, ?R31].
-
-return_value() -> ?RETURN_VALUE.
-
-temp1() -> ?TEMP1.
-temp2() -> ?TEMP2.
-temp3() -> ?TEMP3. % for base2 in storeix :-(
-
-heap_pointer() -> ?HEAP_POINTER.
-
-stack_pointer() -> ?STACK_POINTER.
-
-proc_pointer() -> ?PROC_POINTER.
-
-allocatable_gpr() ->
- %% r0 is too restricted to be useful for variables
- %% r1, r2, and r13 are reserved for C
- %% r29, r30, and r31 are fixed global registers
- [ ?R3, ?R4, ?R5, ?R6, ?R7,
- ?R8, ?R9, ?R10, ?R11, ?R12, ?R14, ?R15,
- ?R16, ?R17, ?R18, ?R19, ?R20, ?R21, ?R22, ?R23,
- ?R24, ?R25, ?R26, ?R27, ?R28].
-
-allocatable_fpr() ->
- [ 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31].
-
-%% Needed for hipe_graph_coloring_regalloc.
-%% Presumably true for Reg in AllPrecoloured \ Allocatable.
-is_fixed(Reg) ->
- case Reg of
- ?HEAP_POINTER -> true;
- ?STACK_POINTER -> true;
- ?PROC_POINTER -> true;
- %% The following cases are required for linear scan:
- %% it gets confused if it sees a register which is
- %% neither allocatable nor global (fixed or one of
- %% the scratch registers set aside for linear scan).
- ?R0 -> true;
- ?R1 -> true;
- ?R2 -> true;
- ?R13 -> true;
- _ -> false
- end.
-
-nr_args() -> ?PPC_NR_ARG_REGS.
-
-args(Arity) when is_integer(Arity) ->
- N = erlang:min(Arity, ?PPC_NR_ARG_REGS),
- args(N-1, []).
-
-args(I, Rest) when is_integer(I), I < 0 -> Rest;
-args(I, Rest) -> args(I-1, [arg(I) | Rest]).
-
-arg(N) ->
- if N < ?PPC_NR_ARG_REGS ->
- case N of
- 0 -> ?ARG0;
- 1 -> ?ARG1;
- 2 -> ?ARG2;
- 3 -> ?ARG3;
- 4 -> ?ARG4;
- 5 -> ?ARG5;
- 6 -> ?ARG6;
- _ -> exit({?MODULE, arg, N})
- end;
- true ->
- exit({?MODULE, arg, N})
- end.
-
-is_arg(R) ->
- case R of
- ?ARG0 -> ?PPC_NR_ARG_REGS > 0;
- ?ARG1 -> ?PPC_NR_ARG_REGS > 1;
- ?ARG2 -> ?PPC_NR_ARG_REGS > 2;
- ?ARG3 -> ?PPC_NR_ARG_REGS > 3;
- ?ARG4 -> ?PPC_NR_ARG_REGS > 4;
- ?ARG5 -> ?PPC_NR_ARG_REGS > 5;
- ?ARG6 -> ?PPC_NR_ARG_REGS > 6;
- _ -> false
- end.
-
-%% Note: the fact that allocatable_gpr() is a subset of call_clobbered() is
-%% hard-coded in hipe_ppc_defuse:insn_defs_all_gpr/1
-call_clobbered() -> % does the RA strip the type or not?
- [{?R0,tagged},{?R0,untagged},
- %% R1 is reserved for C
- %% R2 is reserved for C
- {?R3,tagged},{?R3,untagged},
- {?R4,tagged},{?R4,untagged},
- {?R5,tagged},{?R5,untagged},
- {?R6,tagged},{?R6,untagged},
- {?R7,tagged},{?R7,untagged},
- {?R8,tagged},{?R8,untagged},
- {?R9,tagged},{?R9,untagged},
- {?R10,tagged},{?R10,untagged},
- {?R11,tagged},{?R11,untagged},
- {?R12,tagged},{?R12,untagged},
- %% R13 is reserved for C
- {?R14,tagged},{?R14,untagged},
- {?R15,tagged},{?R15,untagged},
- {?R16,tagged},{?R16,untagged},
- {?R17,tagged},{?R17,untagged},
- {?R18,tagged},{?R18,untagged},
- {?R19,tagged},{?R19,untagged},
- {?R20,tagged},{?R20,untagged},
- {?R21,tagged},{?R21,untagged},
- {?R22,tagged},{?R22,untagged},
- {?R23,tagged},{?R23,untagged},
- {?R24,tagged},{?R24,untagged},
- {?R25,tagged},{?R25,untagged},
- {?R26,tagged},{?R26,untagged},
- {?R27,tagged},{?R27,untagged},
- {?R28,tagged},{?R28,untagged}
- %% R29 is fixed (HP)
- %% R30 is fixed (NSP)
- %% R31 is fixed (P)
- ].
-
-tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}].
-
-live_at_return() ->
- [%%{?LR,untagged},
- {?HEAP_POINTER,untagged},
- {?STACK_POINTER,untagged},
- {?PROC_POINTER,untagged}
- ].
diff --git a/lib/hipe/ppc/hipe_ppc_subst.erl b/lib/hipe/ppc/hipe_ppc_subst.erl
deleted file mode 100644
index e282b22774..0000000000
--- a/lib/hipe/ppc/hipe_ppc_subst.erl
+++ /dev/null
@@ -1,79 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_subst).
--export([insn_temps/2]).
--include("hipe_ppc.hrl").
-
-%% These should be moved to hipe_ppc and exported
--type temp() :: #ppc_temp{}.
--type oper() :: temp() | #ppc_simm16{} | #ppc_uimm16{}.
--type arg() :: temp() | integer().
--type insn() :: tuple(). % for now
-
--type subst_fun() :: fun((temp()) -> temp()).
-
-%% @doc Maps over the temporaries in an instruction
--spec insn_temps(subst_fun(), insn()) -> insn().
-insn_temps(T, I) ->
- A = fun(O) -> arg_temps(T, O) end,
- O = fun(O) -> oper_temps(T, O) end,
- case I of
- #alu{dst=D,src1=L,src2=R} -> I#alu{dst=T(D),src1=T(L),src2=O(R)};
- #b_label{} -> I;
- %% #bc{} -> I;
- #bctr{} -> I;
- #blr{} -> I;
- #cmp{src1=L,src2=R} -> I#cmp{src1=T(L),src2=O(R)};
- #comment{} -> I;
- #label{} -> I;
- #load{dst=D,base=B} -> I#load{dst=T(D),base=T(B)};
- #loadx{dst=D,base1=L,base2=R} -> I#loadx{dst=T(D),base1=T(L),base2=T(R)};
- #mfspr{dst=D} -> I#mfspr{dst=T(D)};
- #mtcr{src=S} -> I#mtcr{src=T(S)};
- #mtspr{src=S} -> I#mtspr{src=T(S)};
- #pseudo_bc{} -> I;
- #pseudo_call{func=F} when not is_record(F, ppc_temp) -> I;
- #pseudo_call_prepare{} -> I;
- #pseudo_li{dst=D} -> I#pseudo_li{dst=T(D)};
- #pseudo_move{dst=D,src=S} -> I#pseudo_move{dst=T(D),src=T(S)};
- #pseudo_spill_move{dst=D,temp=U,src=S} ->
- I#pseudo_spill_move{dst=T(D),temp=T(U),src=T(S)};
- #pseudo_tailcall{func=F,stkargs=Stk} when not is_record(F, ppc_temp) ->
- I#pseudo_tailcall{stkargs=lists:map(A,Stk)};
- #pseudo_tailcall_prepare{} -> I;
- #store{src=S,base=B} -> I#store{src=T(S),base=T(B)};
- #storex{src=S,base1=L,base2=R} ->
- I#storex{src=T(S),base1=T(L),base2=T(R)};
- #unary{dst=D,src=S} -> I#unary{dst=T(D),src=T(S)};
- #lfd{dst=D,base=B} -> I#lfd{dst=T(D),base=T(B)};
- #lfdx{dst=D,base1=L,base2=R} -> I#lfdx{dst=T(D),base1=T(L),base2=T(R)};
- #stfd{src=S,base=B} -> I#stfd{src=T(S),base=T(B)};
- #stfdx{src=S,base1=L,base2=R} -> I#stfdx{src=T(S),base1=T(L),base2=T(R)};
- #fp_binary{dst=D,src1=L,src2=R} ->
- I#fp_binary{dst=T(D),src1=T(L),src2=T(R)};
- #fp_unary{dst=D,src=S} -> I#fp_unary{dst=T(D),src=T(S)};
- #pseudo_fmove{dst=D,src=S} -> I#pseudo_fmove{dst=T(D),src=T(S)};
- #pseudo_spill_fmove{dst=D,temp=U,src=S} ->
- I#pseudo_spill_fmove{dst=T(D),temp=T(U),src=T(S)}
- end.
-
--spec oper_temps(subst_fun(), oper()) -> oper().
-oper_temps(SubstTemp, T=#ppc_temp{}) -> SubstTemp(T);
-oper_temps(_SubstTemp, I=#ppc_simm16{}) -> I;
-oper_temps(_SubstTemp, I=#ppc_uimm16{}) -> I.
-
--spec arg_temps(subst_fun(), arg()) -> arg().
-arg_temps(_SubstTemp, Imm) when is_integer(Imm) -> Imm;
-arg_temps(SubstTemp, T=#ppc_temp{}) -> SubstTemp(T).
diff --git a/lib/hipe/ppc/hipe_rtl_to_ppc.erl b/lib/hipe/ppc/hipe_rtl_to_ppc.erl
deleted file mode 100644
index c0010a8690..0000000000
--- a/lib/hipe/ppc/hipe_rtl_to_ppc.erl
+++ /dev/null
@@ -1,1336 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% The PowerPC instruction set is quite irregular.
-%%% The following quirks must be handled by the translation:
-%%%
-%%% - The instruction names are different for reg/reg and reg/imm
-%%% source operands. For some operations, completely different
-%%% instructions handle the reg/reg and reg/imm cases.
-%%% - The name of an arithmetic instruction depends on whether any
-%%% condition codes are to be set or not. Overflow is treated
-%%% separately from other conditions.
-%%% - Some combinations or RTL ALU operations, source operand shapes,
-%%% and requested conditions have no direct correspondence in the
-%%% PowerPC instruction set.
-%%% - The tagging of immediate operands as simm16 or uimm16 depends
-%%% on the actual instruction.
-%%% - Conditional branches have no unsigned conditions. Instead there
-%%% are signed and unsigned versions of the compare instruction.
-%%% - The arithmetic overflow flag XER[SO] is sticky: once set it
-%%% remains set until explicitly cleared.
-
--module(hipe_rtl_to_ppc).
--export([translate/1]).
-
--include("../rtl/hipe_rtl.hrl").
-
-translate(RTL) ->
- hipe_gensym:init(ppc),
- hipe_gensym:set_var(ppc, hipe_ppc_registers:first_virtual()),
- hipe_gensym:set_label(ppc, hipe_gensym:get_label(rtl)),
- Map0 = vmap_empty(),
- {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),
- OldData = hipe_rtl:rtl_data(RTL),
- {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),
- {RegFormals, _} = split_args(Formals),
- Code =
- case RegFormals of
- [] -> Code0;
- _ -> [hipe_ppc:mk_label(hipe_gensym:get_next_label(ppc)) |
- move_formals(RegFormals, Code0)]
- end,
- IsClosure = hipe_rtl:rtl_is_closure(RTL),
- IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
- hipe_ppc:mk_defun(hipe_rtl:rtl_fun(RTL),
- Formals,
- IsClosure,
- IsLeaf,
- Code,
- NewData,
- [],
- []).
-
-conv_insn_list([H|T], Map, Data) ->
- {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),
- %% io:format("~w \n ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),
- {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),
- {NewH ++ NewT, NewData2};
-conv_insn_list([], _, Data) ->
- {[], Data}.
-
-conv_insn(I, Map, Data) ->
- case I of
- #alu{} -> conv_alu(I, Map, Data);
- #alub{} -> conv_alub(I, Map, Data);
- #call{} -> conv_call(I, Map, Data);
- #comment{} -> conv_comment(I, Map, Data);
- #enter{} -> conv_enter(I, Map, Data);
- #goto{} -> conv_goto(I, Map, Data);
- #label{} -> conv_label(I, Map, Data);
- #load{} -> conv_load(I, Map, Data);
- #load_address{} -> conv_load_address(I, Map, Data);
- #load_atom{} -> conv_load_atom(I, Map, Data);
- #move{} -> conv_move(I, Map, Data);
- #return{} -> conv_return(I, Map, Data);
- #store{} -> conv_store(I, Map, Data);
- #switch{} -> conv_switch(I, Map, Data);
- #fconv{} -> conv_fconv(I, Map, Data);
- #fmove{} -> conv_fmove(I, Map, Data);
- #fload{} -> conv_fload(I, Map, Data);
- #fstore{} -> conv_fstore(I, Map, Data);
- #fp{} -> conv_fp_binary(I, Map, Data);
- #fp_unop{} -> conv_fp_unary(I, Map, Data);
- _ -> exit({?MODULE,conv_insn,I})
- end.
-
-conv_fconv(I, Map, Data) ->
- %% Dst := (double)Src, where Dst is FP reg and Src is GP reg or imm
- {Dst, Map0} = conv_fpreg(hipe_rtl:fconv_dst(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:fconv_src(I), Map0),
- I2 =
- case hipe_ppc:is_temp(Src) of
- true ->
- mk_fconv(Dst, Src);
- false ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src,
- mk_fconv(Dst, Tmp))
- end,
- {I2, Map1, Data}.
-
-mk_fconv(Dst, Src) ->
- CSP = hipe_ppc:mk_temp(1, 'untagged'),
- case get(hipe_target_arch) of
- powerpc ->
- R0 = hipe_ppc:mk_temp(0, 'untagged'),
- RTmp1 = hipe_ppc:mk_new_temp('untagged'),
- RTmp2 = hipe_ppc:mk_new_temp('untagged'),
- RTmp3 = hipe_ppc:mk_new_temp('untagged'),
- FTmp1 = hipe_ppc:mk_new_temp('double'),
- FTmp2 = hipe_ppc:mk_new_temp('double'),
- [hipe_ppc:mk_pseudo_li(RTmp1, {fconv_constant,c_const}),
- hipe_ppc:mk_lfd(FTmp1, 0, RTmp1),
- hipe_ppc:mk_alu('xoris', RTmp2, Src, hipe_ppc:mk_uimm16(16#8000)),
- hipe_ppc:mk_store('stw', RTmp2, 28, CSP),
- hipe_ppc:mk_alu('addis', RTmp3, R0, hipe_ppc:mk_simm16(16#4330)),
- hipe_ppc:mk_store('stw', RTmp3, 24, CSP),
- hipe_ppc:mk_lfd(FTmp2, 24, CSP),
- hipe_ppc:mk_fp_binary('fsub', Dst, FTmp2, FTmp1)];
- ppc64 ->
- [hipe_ppc:mk_store('std', Src, 24, CSP),
- hipe_ppc:mk_lfd(Dst, 24, CSP),
- hipe_ppc:mk_fp_unary('fcfid', Dst, Dst)]
- end.
-
-conv_fmove(I, Map, Data) ->
- %% Dst := Src, where both Dst and Src are FP regs
- {Dst, Map0} = conv_fpreg(hipe_rtl:fmove_dst(I), Map),
- {Src, Map1} = conv_fpreg(hipe_rtl:fmove_src(I), Map0),
- I2 = mk_fmove(Dst, Src),
- {I2, Map1, Data}.
-
-mk_fmove(Dst, Src) ->
- [hipe_ppc:mk_pseudo_fmove(Dst, Src)].
-
-conv_fload(I, Map, Data) ->
- %% Dst := MEM[Base+Off], where Dst is FP reg
- {Dst, Map0} = conv_fpreg(hipe_rtl:fload_dst(I), Map),
- {Base1, Map1} = conv_src(hipe_rtl:fload_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:fload_offset(I), Map1),
- I2 = mk_fload(Dst, Base1, Base2),
- {I2, Map2, Data}.
-
-mk_fload(Dst, Base1, Base2) ->
- case hipe_ppc:is_temp(Base1) of
- true ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_fload_rr(Dst, Base1, Base2);
- _ ->
- mk_fload_ri(Dst, Base1, Base2)
- end;
- _ ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_fload_ri(Dst, Base2, Base1);
- _ ->
- mk_fload_ii(Dst, Base1, Base2)
- end
- end.
-
-mk_fload_ii(Dst, Base1, Base2) ->
- io:format("~w: RTL fload with two immediates\n", [?MODULE]),
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Base1,
- mk_fload_ri(Dst, Tmp, Base2)).
-
-mk_fload_ri(Dst, Base, Disp) ->
- hipe_ppc:mk_fload(Dst, Disp, Base, 'new').
-
-mk_fload_rr(Dst, Base1, Base2) ->
- [hipe_ppc:mk_lfdx(Dst, Base1, Base2)].
-
-conv_fstore(I, Map, Data) ->
- %% MEM[Base+Off] := Src, where Src is FP reg
- {Base1, Map0} = conv_dst(hipe_rtl:fstore_base(I), Map),
- {Src, Map1} = conv_fpreg(hipe_rtl:fstore_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:fstore_offset(I), Map1),
- I2 = mk_fstore(Src, Base1, Base2),
- {I2, Map2, Data}.
-
-mk_fstore(Src, Base1, Base2) ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_fstore_rr(Src, Base1, Base2);
- _ ->
- mk_fstore_ri(Src, Base1, Base2)
- end.
-
-mk_fstore_ri(Src, Base, Disp) ->
- hipe_ppc:mk_fstore(Src, Disp, Base, 'new').
-
-mk_fstore_rr(Src, Base1, Base2) ->
- [hipe_ppc:mk_stfdx(Src, Base1, Base2)].
-
-conv_fp_binary(I, Map, Data) ->
- {Dst, Map0} = conv_fpreg(hipe_rtl:fp_dst(I), Map),
- {Src1, Map1} = conv_fpreg(hipe_rtl:fp_src1(I), Map0),
- {Src2, Map2} = conv_fpreg(hipe_rtl:fp_src2(I), Map1),
- RtlFpOp = hipe_rtl:fp_op(I),
- I2 = mk_fp_binary(Dst, Src1, RtlFpOp, Src2),
- {I2, Map2, Data}.
-
-mk_fp_binary(Dst, Src1, RtlFpOp, Src2) ->
- FpBinOp =
- case RtlFpOp of
- 'fadd' -> 'fadd';
- 'fdiv' -> 'fdiv';
- 'fmul' -> 'fmul';
- 'fsub' -> 'fsub'
- end,
- [hipe_ppc:mk_fp_binary(FpBinOp, Dst, Src1, Src2)].
-
-conv_fp_unary(I, Map, Data) ->
- {Dst, Map0} = conv_fpreg(hipe_rtl:fp_unop_dst(I), Map),
- {Src, Map1} = conv_fpreg(hipe_rtl:fp_unop_src(I), Map0),
- RtlFpUnOp = hipe_rtl:fp_unop_op(I),
- I2 = mk_fp_unary(Dst, Src, RtlFpUnOp),
- {I2, Map1, Data}.
-
-mk_fp_unary(Dst, Src, RtlFpUnOp) ->
- FpUnOp =
- case RtlFpUnOp of
- 'fchs' -> 'fneg'
- end,
- [hipe_ppc:mk_fp_unary(FpUnOp, Dst, Src)].
-
-conv_alu(I, Map, Data) ->
- %% dst = src1 aluop src2
- {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),
- {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),
- {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),
- RtlAluOp = hipe_rtl:alu_op(I),
- I2 = mk_alu(Dst, Src1, RtlAluOp, Src2),
- {I2, Map2, Data}.
-
-mk_alu(Dst, Src1, RtlAluOp, Src2) ->
- case hipe_ppc:is_temp(Src1) of
- true ->
- case hipe_ppc:is_temp(Src2) of
- true ->
- mk_alu_rr(Dst, Src1, RtlAluOp, Src2);
- _ ->
- mk_alu_ri(Dst, Src1, RtlAluOp, Src2)
- end;
- _ ->
- case hipe_ppc:is_temp(Src2) of
- true ->
- mk_alu_ir(Dst, Src1, RtlAluOp, Src2);
- _ ->
- mk_alu_ii(Dst, Src1, RtlAluOp, Src2)
- end
- end.
-
-mk_alu_ii(Dst, Src1, RtlAluOp, Src2) ->
- io:format("~w: RTL alu with two immediates (~w ~w ~w)\n",
- [?MODULE, Src1, RtlAluOp, Src2]),
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_alu_ri(Dst, Tmp, RtlAluOp, Src2)).
-
-mk_alu_ir(Dst, Src1, RtlAluOp, Src2) ->
- case rtl_aluop_commutes(RtlAluOp) of
- true ->
- mk_alu_ri(Dst, Src2, RtlAluOp, Src1);
- _ ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_alu_rr(Dst, Tmp, RtlAluOp, Src2))
- end.
-
-mk_alu_ri(Dst, Src1, RtlAluOp, Src2) ->
- case RtlAluOp of
- 'sub' -> % there is no 'subi'
- mk_alu_ri_addi(Dst, Src1, -Src2);
- 'add' -> % 'addi' has a 16-bit simm operand
- mk_alu_ri_addi(Dst, Src1, Src2);
- 'mul' -> % 'mulli' has a 16-bit simm operand
- mk_alu_ri_simm16(Dst, Src1, RtlAluOp, 'mulli', Src2);
- 'and' -> % 'andi.' has a 16-bit uimm operand
- if Src2 band (bnot 16#ffffffff) =:= 0 ->
- case rlwinm_mask(Src2) of
- {MB,ME} ->
- [hipe_ppc:mk_unary({'rlwinm',0,MB,ME}, Dst, Src1)];
- _ ->
- mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'andi.', Src2)
- end;
- true ->
- mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'andi.', Src2)
- end;
- 'or' -> % 'ori' has a 16-bit uimm operand
- mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'ori', Src2);
- 'xor' -> % 'xori' has a 16-bit uimm operand
- mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'xori', Src2);
- _ -> % shift ops have 5-bit uimm operands
- mk_alu_ri_shift(Dst, Src1, RtlAluOp, Src2)
- end.
-
-rlwinm_mask(Imm) ->
- Res1 = rlwinm_mask2(Imm),
- case Res1 of
- {_MB,_ME} -> Res1;
- [] ->
- case rlwinm_mask2(bnot Imm) of
- {MB,ME} -> {ME+1,MB-1};
- [] -> []
- end
- end.
-
-rlwinm_mask2(Imm) ->
- case Imm band 16#ffffffff of
- 0 -> [];
- Word ->
- MB = lsb_log2(Word), % first 1 bit
- case bnot(Word bsr MB) band 16#ffffffff of
- 0 -> []; % Imm was all-bits-one XXX: we should handle this
- Word1 ->
- ME1 = lsb_log2(Word1),% first 0 bit after the 1s
- case Word bsr (MB+ME1) of
- 0 ->
- ME = MB+ME1-1, % last 1 bit
- {31-ME, 31-MB}; % convert to PPC sick and twisted bit numbers
- _ ->
- []
- end
- end
- end.
-
-lsb_log2(Word) -> % PRE: Word =/= 0
- bitN_log2(Word band -Word, 0).
-
-bitN_log2(BitN, ShiftN) ->
- if BitN > 16#ffff ->
- bitN_log2(BitN bsr 16, ShiftN + 16);
- true ->
- ShiftN + hweight16(BitN - 1)
- end.
-
-hweight16(Word) -> % PRE: 0 <= Word <= 16#ffff
- Res1 = (Word band 16#5555) + ((Word bsr 1) band 16#5555),
- Res2 = (Res1 band 16#3333) + ((Res1 bsr 2) band 16#3333),
- Res3 = (Res2 band 16#0F0F) + ((Res2 bsr 4) band 16#0F0F),
- (Res3 band 16#00FF) + ((Res3 bsr 8) band 16#00FF).
-
-mk_alu_ri_addi(Dst, Src1, Src2) ->
- mk_alu_ri_simm16(Dst, Src1, 'add', 'addi', Src2).
-
-mk_alu_ri_simm16(Dst, Src1, RtlAluOp, AluOp, Src2) ->
- if is_integer(Src2), -32768 =< Src2, Src2 < 32768 ->
- [hipe_ppc:mk_alu(AluOp, Dst, Src1,
- hipe_ppc:mk_simm16(Src2))];
- true ->
- mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
- end.
-
-mk_alu_ri_bitop(Dst, Src1, RtlAluOp, AluOp, Src2) ->
- if is_integer(Src2), 0 =< Src2, Src2 < 65536 ->
- [hipe_ppc:mk_alu(AluOp, Dst, Src1,
- hipe_ppc:mk_uimm16(Src2))];
- true ->
- mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
- end.
-
-mk_alu_ri_shift(Dst, Src1, RtlAluOp, Src2) ->
- case get(hipe_target_arch) of
- ppc64 ->
- if Src2 < 64, Src2 >= 0 ->
- AluOp =
- case RtlAluOp of
- 'sll' -> 'sldi'; % alias for rldimi %%% buggy
- 'srl' -> 'srdi'; % alias for rldimi %%% buggy
- 'sra' -> 'sradi' %%% buggy
- end,
- [hipe_ppc:mk_alu(AluOp, Dst, Src1,
- hipe_ppc:mk_uimm16(Src2))];
- true ->
- mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
- end;
- powerpc ->
- if Src2 < 32, Src2 >= 0 ->
- AluOp =
- case RtlAluOp of
- 'sll' -> 'slwi'; % alias for rlwinm
- 'srl' -> 'srwi'; % alias for rlwinm
- 'sra' -> 'srawi'
- end,
- [hipe_ppc:mk_alu(AluOp, Dst, Src1,
- hipe_ppc:mk_uimm16(Src2))];
- true ->
- mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
- end
- end.
-
-mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src2,
- mk_alu_rr(Dst, Src1, RtlAluOp, Tmp)).
-
-mk_alu_rr(Dst, Src1, RtlAluOp, Src2) ->
- case RtlAluOp of
- 'sub' -> % PPC weirdness
- [hipe_ppc:mk_alu('subf', Dst, Src2, Src1)];
- _ ->
- AluOp =
- case {get(hipe_target_arch), RtlAluOp} of
- {_, 'add'} -> 'add';
- {_, 'or'} -> 'or';
- {_, 'and'} -> 'and';
- {_, 'xor'} -> 'xor';
-
- {powerpc, 'mul'} -> 'mullw';
- {powerpc, 'sll'} -> 'slw';
- {powerpc, 'srl'} -> 'srw';
- {powerpc, 'sra'} -> 'sraw';
-
- {ppc64, 'mul'} -> 'mulld';
- {ppc64, 'sll'} -> 'sld';
- {ppc64, 'srl'} -> 'srd';
- {ppc64, 'sra'} -> 'srad'
- end,
- [hipe_ppc:mk_alu(AluOp, Dst, Src1, Src2)]
- end.
-
-conv_alub(I, Map, Data) ->
- %% dst = src1 aluop src2; if COND goto label
- HasDst = hipe_rtl:alub_has_dst(I),
- {Src1, Map0} = conv_src(hipe_rtl:alub_src1(I), Map),
- {Src2, Map1} = conv_src(hipe_rtl:alub_src2(I), Map0),
- RtlAlubOp = hipe_rtl:alub_op(I),
- RtlAlubCond = hipe_rtl:alub_cond(I),
- case {HasDst, RtlAlubOp} of
- {false, sub} ->
- {BCond,Sign} = conv_branch_cond(RtlAlubCond),
- I2 = mk_branch(Src1, BCond, Sign, Src2,
- hipe_rtl:alub_true_label(I),
- hipe_rtl:alub_false_label(I),
- hipe_rtl:alub_pred(I)),
- {I2, Map1, Data};
- _ ->
- {Dst, Map2} =
- case HasDst of
- false -> {new_untagged_temp(), Map1};
- true -> conv_dst(hipe_rtl:alub_dst(I), Map1)
- end,
- {AluOp, BCond} =
- case {RtlAlubOp, RtlAlubCond} of
- {'add', 'ltu'} ->
- {'addc', 'eq'};
- {_, _} ->
- {conv_alub_op(RtlAlubOp), conv_alub_cond(RtlAlubCond)}
- end,
- BC = mk_pseudo_bc(BCond,
- hipe_rtl:alub_true_label(I),
- hipe_rtl:alub_false_label(I),
- hipe_rtl:alub_pred(I)),
- I2 =
- case {AluOp, BCond} of
- {'addc', 'eq'} -> % copy XER[CA] to CR0[EQ] before the BC
- TmpR = new_untagged_temp(),
- [hipe_ppc:mk_mfspr(TmpR, 'xer'),
- hipe_ppc:mk_mtcr(TmpR) |
- BC];
- _ -> BC
- end,
- {NewSrc1, NewSrc2} =
- case AluOp of
- 'subf' -> {Src2, Src1};
- _ -> {Src1, Src2}
- end,
- I1 = mk_alub(Dst, NewSrc1, AluOp, NewSrc2, BCond),
- {I1 ++ I2, Map2, Data}
- end.
-
-conv_alub_op(RtlAluOp) ->
- case {get(hipe_target_arch), RtlAluOp} of
- {_, 'add'} -> 'add';
- {_, 'sub'} -> 'subf'; % XXX: must swap operands
- {_, 'or'} -> 'or';
- {_, 'and'} -> 'and';
- {_, 'xor'} -> 'xor';
-
- {powerpc, 'mul'} -> 'mullw';
- {powerpc, 'sll'} -> 'slw';
- {powerpc, 'srl'} -> 'srw';
- {powerpc, 'sra'} -> 'sraw';
-
- {ppc64, 'mul'} -> 'mulld';
- {ppc64, 'sll'} -> 'sld';
- {ppc64, 'srl'} -> 'srd';
- {ppc64, 'sra'} -> 'srad'
- end.
-
-aluop_commutes(AluOp) ->
- case AluOp of
- 'add' -> true;
- 'addc' -> true;
- 'subf' -> false;
- 'mullw' -> true;
- 'or' -> true;
- 'and' -> true;
- 'xor' -> true;
- 'slw' -> false;
- 'srw' -> false;
- 'sraw' -> false;
- 'mulld' -> true; % ppc64
- 'sld' -> false; % ppc64
- 'srd' -> false; % ppc64
- 'srad' -> false % ppc64
- end.
-
-conv_alub_cond(Cond) -> % only signed
- case Cond of
- eq -> 'eq';
- ne -> 'ne';
- gt -> 'gt';
- ge -> 'ge';
- lt -> 'lt';
- le -> 'le';
- overflow -> 'so';
- not_overflow -> 'ns';
- _ -> exit({?MODULE,conv_alub_cond,Cond})
- end.
-
-mk_alub(Dst, Src1, AluOp, Src2, BCond) ->
- case hipe_ppc:is_temp(Src1) of
- true ->
- case hipe_ppc:is_temp(Src2) of
- true ->
- mk_alub_rr(Dst, Src1, AluOp, Src2, BCond);
- _ ->
- mk_alub_ri(Dst, Src1, AluOp, Src2, BCond)
- end;
- _ ->
- case hipe_ppc:is_temp(Src2) of
- true ->
- mk_alub_ir(Dst, Src1, AluOp, Src2, BCond);
- _ ->
- mk_alub_ii(Dst, Src1, AluOp, Src2, BCond)
- end
- end.
-
-mk_alub_ii(Dst, Src1, AluOp, Src2, BCond) ->
- io:format("~w: RTL alub with two immediates\n", [?MODULE]),
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_alub_ri(Dst, Tmp, AluOp, Src2, BCond)).
-
-mk_alub_ir(Dst, Src1, AluOp, Src2, BCond) ->
- case aluop_commutes(AluOp) of
- true ->
- mk_alub_ri(Dst, Src2, AluOp, Src1, BCond);
- _ ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_alub_rr(Dst, Tmp, AluOp, Src2, BCond))
- end.
-
-mk_alub_ri(Dst, Src1, AluOp, Src2, BCond) ->
- true = is_integer(Src2),
- case BCond of
- 'so' -> mk_alub_ri_OE(Dst, Src1, AluOp, Src2);
- 'ns' -> mk_alub_ri_OE(Dst, Src1, AluOp, Src2);
- _ -> mk_alub_ri_Rc(Dst, Src1, AluOp, Src2)
- end.
-
-mk_alub_ri_OE(Dst, Src1, AluOp, Src2) ->
- %% Only 'add', 'subf', and 'mullw' apply here, and 'subf' becomes 'add'.
- %% 'add' and 'mullw' have no immediate+Rc+OE forms.
- %% Rewrite to reg/reg form. Sigh.
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src2,
- mk_alub_rr_OE(Dst, Src1, AluOp, Tmp)).
-
-mk_alub_ri_Rc(Dst, Src1, AluOp, Src2) ->
- case AluOp of
- 'subf' -> % there is no 'subfi.', use 'addic.' or 'add.'
- mk_alub_ri_Rc_addi(Dst, Src1, -Src2, 'addic.', 'add.');
- 'add' -> % 'addic.' has a 16-bit simm operand
- mk_alub_ri_Rc_addi(Dst, Src1, Src2, 'addic.', 'add.');
- 'addc' -> % 'addic' has a 16-bit simm operand
- mk_alub_ri_Rc_addi(Dst, Src1, Src2, 'addic', 'addc');
- 'mullw' -> % there is no 'mulli.'
- mk_alub_ri_Rc_rr(Dst, Src1, 'mullw.', Src2);
- 'mulld' -> % there is no 'mulli.'
- mk_alub_ri_Rc_rr(Dst, Src1, 'mulld.', Src2);
- 'or' -> % there is no 'ori.'
- mk_alub_ri_Rc_rr(Dst, Src1, 'or.', Src2);
- 'xor' -> % there is no 'xori.'
- mk_alub_ri_Rc_rr(Dst, Src1, 'xor.', Src2);
- 'and' -> % 'andi.' has a 16-bit uimm operand
- if
- Src2 band (bnot 16#ffffffff) =:= 0 ->
- case rlwinm_mask(Src2) of
- {MB,ME} ->
- [hipe_ppc:mk_unary({'rlwinm.',0,MB,ME}, Dst, Src1)];
- _ ->
- mk_alub_ri_Rc_andi(Dst, Src1, Src2)
- end;
- true ->
- mk_alub_ri_Rc_andi(Dst, Src1, Src2)
- end;
- _ -> % shift ops have 5-bit uimm operands
- mk_alub_ri_Rc_shift(Dst, Src1, AluOp, Src2)
- end.
-
-mk_alub_ri_Rc_addi(Dst, Src1, Src2, AddImmOp, AddRegOp) ->
- if is_integer(Src2), -32768 =< Src2, Src2 < 32768 ->
- [hipe_ppc:mk_alu(AddImmOp, Dst, Src1,
- hipe_ppc:mk_simm16(Src2))];
- true ->
- mk_alub_ri_Rc_rr(Dst, Src1, AddRegOp, Src2)
- end.
-
-mk_alub_ri_Rc_andi(Dst, Src1, Src2) ->
- if Src2 < 65536, Src2 >= 0 ->
- [hipe_ppc:mk_alu('andi.', Dst, Src1,
- hipe_ppc:mk_uimm16(Src2))];
- true ->
- mk_alub_ri_Rc_rr(Dst, Src1, 'and.', Src2)
- end.
-
-mk_alub_ri_Rc_shift(Dst, Src1, AluOp, Src2) ->
- {AluOpIDot, MaxIShift} =
- case AluOp of
- 'slw' -> {'slwi.', 32}; % alias for rlwinm.
- 'srw' -> {'srwi.', 32}; % alias for rlwinm.
- 'sraw' -> {'srawi.', 32};
- 'sld' -> {'sldi.', 64};
- 'srd' -> {'srdi.', 64};
- 'srad' -> {'sradi.', 64}
- end,
- if Src2 < MaxIShift, Src2 >= 0 ->
- [hipe_ppc:mk_alu(AluOpIDot, Dst, Src1,
- hipe_ppc:mk_uimm16(Src2))];
- true ->
- AluOpDot =
- case AluOp of
- 'slw' -> 'slw.';
- 'srw' -> 'srw.';
- 'sraw' -> 'sraw.';
- 'sld' -> 'sld.';
- 'srd' -> 'srd.';
- 'srad' -> 'srad.'
- end,
- mk_alub_ri_Rc_rr(Dst, Src1, AluOpDot, Src2)
- end.
-
-mk_alub_ri_Rc_rr(Dst, Src1, AluOp, Src2) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src2,
- [hipe_ppc:mk_alu(AluOp, Dst, Src1, Tmp)]).
-
-mk_alub_rr(Dst, Src1, AluOp, Src2, BCond) ->
- case BCond of
- 'so' -> mk_alub_rr_OE(Dst, Src1, AluOp, Src2);
- 'ns' -> mk_alub_rr_OE(Dst, Src1, AluOp, Src2);
- _ -> mk_alub_rr_Rc(Dst, Src1, AluOp, Src2)
- end.
-
-mk_alub_rr_OE(Dst, Src1, AluOp, Src2) ->
- AluOpODot =
- case AluOp of
- 'subf' -> 'subfo.';
- 'add' -> 'addo.';
- 'mullw' -> 'mullwo.';
- 'mulld' -> 'mulldo.'
- %% fail for addc, or, and, xor, slw, srw, sraw
- end,
- [hipe_ppc:mk_alu(AluOpODot, Dst, Src1, Src2)].
-
-mk_alub_rr_Rc(Dst, Src1, AluOp, Src2) ->
- AluOpDot =
- case AluOp of
- 'subf' -> 'subf.';
- 'add' -> 'add.';
- 'addc' -> 'addc'; % only interested in CA, no Rc needed
- 'mullw' -> 'mullw.';
- 'mulld' -> 'mulld.';
- 'or' -> 'or.';
- 'and' -> 'and.';
- 'xor' -> 'xor.';
- 'slw' -> 'slw.';
- 'sld' -> 'sld.';
- 'srw' -> 'srw.';
- 'srd' -> 'srd.';
- 'sraw' -> 'sraw.';
- 'srad' -> 'srad.'
- end,
- [hipe_ppc:mk_alu(AluOpDot, Dst, Src1, Src2)].
-
-conv_branch_cond(Cond) -> % may be unsigned
- case Cond of
- gtu -> {'gt', 'unsigned'};
- geu -> {'ge', 'unsigned'};
- ltu -> {'lt', 'unsigned'};
- leu -> {'le', 'unsigned'};
- _ -> {conv_alub_cond(Cond), 'signed'}
- end.
-
-mk_branch(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
- case hipe_ppc:is_temp(Src1) of
- true ->
- case hipe_ppc:is_temp(Src2) of
- true ->
- mk_branch_rr(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred);
- _ ->
- mk_branch_ri(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred)
- end;
- _ ->
- case hipe_ppc:is_temp(Src2) of
- true ->
- NewBCond = commute_bcond(BCond),
- mk_branch_ri(Src2, NewBCond, Sign, Src1, TrueLab, FalseLab, Pred);
- _ ->
- mk_branch_ii(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred)
- end
- end.
-
-commute_bcond(BCond) -> % if x BCond y, then y commute_bcond(BCond) x
- case BCond of
- 'eq' -> 'eq'; % ==, ==
- 'ne' -> 'ne'; % !=, !=
- 'gt' -> 'lt'; % >, <
- 'ge' -> 'le'; % >=, <=
- 'lt' -> 'gt'; % <, >
- 'le' -> 'ge'; % <=, >=
- %% so/ns: n/a
- _ -> exit({?MODULE,commute_bcond,BCond})
- end.
-
-mk_branch_ii(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
- io:format("~w: RTL branch with two immediates\n", [?MODULE]),
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src1,
- mk_branch_ri(Tmp, BCond, Sign, Src2,
- TrueLab, FalseLab, Pred)).
-
-mk_branch_ri(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
- {FixSrc2,NewSrc2,CmpOp} =
- case Sign of
- 'signed' ->
- if is_integer(Src2), -32768 =< Src2, Src2 < 32768 ->
- {[], hipe_ppc:mk_simm16(Src2), hipe_ppc:cmpiop_word()};
- true ->
- Tmp = new_untagged_temp(),
- {mk_li(Tmp, Src2), Tmp, hipe_ppc:cmpop_word()}
- end;
- 'unsigned' ->
- if is_integer(Src2), 0 =< Src2, Src2 < 65536 ->
- {[], hipe_ppc:mk_uimm16(Src2), hipe_ppc:cmpliop_word()};
- true ->
- Tmp = new_untagged_temp(),
- {mk_li(Tmp, Src2), Tmp, hipe_ppc:cmplop_word()}
- end
- end,
- FixSrc2 ++
- mk_cmp_bc(CmpOp, Src1, NewSrc2, BCond, TrueLab, FalseLab, Pred).
-
-mk_branch_rr(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
- CmpOp =
- case Sign of
- 'signed' -> hipe_ppc:cmpop_word();
- 'unsigned' -> hipe_ppc:cmplop_word()
- end,
- mk_cmp_bc(CmpOp, Src1, Src2, BCond, TrueLab, FalseLab, Pred).
-
-mk_cmp_bc(CmpOp, Src1, Src2, BCond, TrueLab, FalseLab, Pred) ->
- [hipe_ppc:mk_cmp(CmpOp, Src1, Src2) |
- mk_pseudo_bc(BCond, TrueLab, FalseLab, Pred)].
-
-conv_call(I, Map, Data) ->
- {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),
- {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),
- {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),
- ContLab = hipe_rtl:call_continuation(I),
- ExnLab = hipe_rtl:call_fail(I),
- Linkage = hipe_rtl:call_type(I),
- I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage),
- {I2, Map2, Data}.
-
-mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- case hipe_ppc:is_prim(Fun) of
- true ->
- mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);
- false ->
- mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)
- end.
-
-mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->
- case hipe_ppc:prim_prim(Prim) of
- 'extsh' ->
- mk_extsh_call(Dsts, Args, ContLab, ExnLab, Linkage);
- 'lhbrx' ->
- mk_lhbrx_call(Dsts, Args, ContLab, ExnLab, Linkage);
- 'lwbrx' ->
- mk_lwbrx_call(Dsts, Args, ContLab, ExnLab, Linkage);
- _ ->
- mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)
- end.
-
-mk_extsh_call([Dst], [Src], [], [], not_remote) ->
- true = hipe_ppc:is_temp(Src),
- [hipe_ppc:mk_unary('extsh', Dst, Src)].
-
-mk_lhbrx_call(Dsts, [Base,Offset], [], [], not_remote) ->
- case Dsts of
- [Dst] -> mk_loadx('lhbrx', Dst, Base, Offset);
- [] -> [] % result unused, cancel the operation
- end.
-
-mk_lwbrx_call([Dst], [Base,Offset], [], [], not_remote) ->
- mk_loadx('lwbrx', Dst, Base, Offset).
-
-mk_loadx(LdxOp, Dst, Base, Offset) ->
- true = hipe_ppc:is_temp(Base),
- {FixOff,NewOff} =
- case hipe_ppc:is_temp(Offset) of
- true -> {[], Offset};
- false ->
- Tmp = new_untagged_temp(),
- {mk_li(Tmp, Offset), Tmp}
- end,
- FixOff ++ [hipe_ppc:mk_loadx(LdxOp, Dst, Base, NewOff)].
-
-mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- %% The backend does not support pseudo_calls without a
- %% continuation label, so we make sure each call has one.
- {RealContLab, Tail} =
- case mk_call_results(Dsts) of
- [] ->
- %% Avoid consing up a dummy basic block if the moves list
- %% is empty, as is typical for calls to suspend/0.
- %% This should be subsumed by a general "optimise the CFG"
- %% module, and could probably be removed.
- case ContLab of
- [] ->
- NewContLab = hipe_gensym:get_next_label(ppc),
- {NewContLab, [hipe_ppc:mk_label(NewContLab)]};
- _ ->
- {ContLab, []}
- end;
- Moves ->
- %% Change the call to continue at a new basic block.
- %% In this block move the result registers to the Dsts,
- %% then continue at the call's original continuation.
- NewContLab = hipe_gensym:get_next_label(ppc),
- case ContLab of
- [] ->
- %% This is just a fallthrough
- %% No jump back after the moves.
- {NewContLab,
- [hipe_ppc:mk_label(NewContLab) |
- Moves]};
- _ ->
- %% The call has a continuation. Jump to it.
- {NewContLab,
- [hipe_ppc:mk_label(NewContLab) |
- Moves ++
- [hipe_ppc:mk_b_label(ContLab)]]}
- end
- end,
- SDesc = hipe_ppc:mk_sdesc(ExnLab, 0, length(Args), {}),
- {FixFunC,FunC} = fix_func(Fun),
- CallInsn = hipe_ppc:mk_pseudo_call(FunC, SDesc, RealContLab, Linkage),
- {RegArgs,StkArgs} = split_args(Args),
- FixFunC ++
- mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).
-
-mk_call_results([]) ->
- [];
-mk_call_results([Dst]) ->
- RV = hipe_ppc:mk_temp(hipe_ppc_registers:return_value(), 'tagged'),
- [hipe_ppc:mk_pseudo_move(Dst, RV)];
-mk_call_results(Dsts) ->
- exit({?MODULE,mk_call_results,Dsts}).
-
-fix_func(Fun) ->
- case hipe_ppc:is_temp(Fun) of
- true -> {[hipe_ppc:mk_mtspr('ctr', Fun)], 'ctr'};
- _ -> {[], Fun}
- end.
-
-mk_push_args(StkArgs, Tail) ->
- case length(StkArgs) of
- 0 ->
- Tail;
- NrStkArgs ->
- [hipe_ppc:mk_pseudo_call_prepare(NrStkArgs) |
- mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)]
- end.
-
-mk_store_args([Arg|Args], PrevOffset, Tail) ->
- Offset = PrevOffset - word_size(),
- {Src,FixSrc} =
- case hipe_ppc:is_temp(Arg) of
- true ->
- {Arg, []};
- _ ->
- Tmp = new_tagged_temp(),
- {Tmp, mk_li(Tmp, Arg)}
- end,
- Store = hipe_ppc:mk_store(hipe_ppc:stop_word(), Src, Offset, mk_sp()),
- mk_store_args(Args, Offset, FixSrc ++ [Store | Tail]);
-mk_store_args([], _, Tail) ->
- Tail.
-
-conv_comment(I, Map, Data) ->
- I2 = [hipe_ppc:mk_comment(hipe_rtl:comment_text(I))],
- {I2, Map, Data}.
-
-conv_enter(I, Map, Data) ->
- {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),
- {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),
- I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)),
- {I2, Map1, Data}.
-
-mk_enter(Fun, Args, Linkage) ->
- {FixFunC,FunC} = fix_func(Fun),
- Arity = length(Args),
- {RegArgs,StkArgs} = split_args(Args),
- FixFunC ++
- move_actuals(RegArgs,
- [hipe_ppc:mk_pseudo_tailcall_prepare(),
- hipe_ppc:mk_pseudo_tailcall(FunC, Arity, StkArgs, Linkage)]).
-
-conv_goto(I, Map, Data) ->
- I2 = [hipe_ppc:mk_b_label(hipe_rtl:goto_label(I))],
- {I2, Map, Data}.
-
-conv_label(I, Map, Data) ->
- I2 = [hipe_ppc:mk_label(hipe_rtl:label_name(I))],
- {I2, Map, Data}.
-
-conv_load(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),
- {Base1, Map1} = conv_src(hipe_rtl:load_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:load_offset(I), Map1),
- LoadSize = hipe_rtl:load_size(I),
- LoadSign = hipe_rtl:load_sign(I),
- I2 = mk_load(Dst, Base1, Base2, LoadSize, LoadSign),
- {I2, Map2, Data}.
-
-mk_load(Dst, Base1, Base2, LoadSize, LoadSign) ->
- {LdOp, Rest} =
- case {LoadSize, LoadSign} of
- {byte, signed} -> {'lbz', [hipe_ppc:mk_unary('extsb', Dst, Dst)]};
- {byte, unsigned} -> {'lbz', []};
- {int16, signed} -> {'lha', []};
- {int16, unsigned} -> {'lhz', []};
- {int32, signed} ->
- case get(hipe_target_arch) of
- powerpc -> {'lwz', []};
- ppc64 -> {'lwa', []}
- end;
- {int32, unsigned} -> {'lwz', []};
- {word, _} -> {hipe_ppc:ldop_word(), []}
- end,
- case hipe_ppc:is_temp(Base1) of
- true ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_load_rr(Dst, Base1, Base2, LdOp, Rest);
- _ ->
- mk_load_ri(Dst, Base1, Base2, LdOp, Rest)
- end;
- _ ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_load_ri(Dst, Base2, Base1, LdOp, Rest);
- _ ->
- mk_load_ii(Dst, Base1, Base2, LdOp, Rest)
- end
- end.
-
-mk_load_ii(Dst, Base1, Base2, LdOp, Rest) ->
- io:format("~w: RTL load with two immediates\n", [?MODULE]),
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Base1,
- mk_load_ri(Dst, Tmp, Base2, LdOp, Rest)).
-
-mk_load_ri(Dst, Base, Disp, LdOp, Rest) ->
- hipe_ppc:mk_load(LdOp, Dst, Disp, Base, 'new', Rest).
-
-mk_load_rr(Dst, Base1, Base2, LdOp, Rest) ->
- LdxOp = hipe_ppc:ldop_to_ldxop(LdOp),
- [hipe_ppc:mk_loadx(LdxOp, Dst, Base1, Base2) | Rest].
-
-conv_load_address(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map),
- Addr = hipe_rtl:load_address_addr(I),
- Type = hipe_rtl:load_address_type(I),
- Src = {Addr,Type},
- I2 = [hipe_ppc:mk_pseudo_li(Dst, Src)],
- {I2, Map0, Data}.
-
-conv_load_atom(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map),
- Src = hipe_rtl:load_atom_atom(I),
- I2 = [hipe_ppc:mk_pseudo_li(Dst, Src)],
- {I2, Map0, Data}.
-
-conv_move(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0),
- I2 = mk_move(Dst, Src, []),
- {I2, Map1, Data}.
-
-mk_move(Dst, Src, Tail) ->
- case hipe_ppc:is_temp(Src) of
- true -> [hipe_ppc:mk_pseudo_move(Dst, Src) | Tail];
- _ -> mk_li(Dst, Src, Tail)
- end.
-
-conv_return(I, Map, Data) ->
- %% TODO: multiple-value returns
- {[Arg], Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map),
- I2 = mk_move(mk_rv(), Arg,
- [hipe_ppc:mk_blr()]),
- {I2, Map0, Data}.
-
-conv_store(I, Map, Data) ->
- {Base1, Map0} = conv_src(hipe_rtl:store_base(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),
- StoreSize = hipe_rtl:store_size(I),
- I2 = mk_store(Src, Base1, Base2, StoreSize),
- {I2, Map2, Data}.
-
-mk_store(Src, Base1, Base2, StoreSize) ->
- StOp =
- case StoreSize of
- byte -> 'stb';
- int16 -> 'sth';
- int32 -> 'stw';
- word -> hipe_ppc:stop_word()
- end,
- case hipe_ppc:is_temp(Src) of
- true ->
- mk_store2(Src, Base1, Base2, StOp);
- _ ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Src,
- mk_store2(Tmp, Base1, Base2, StOp))
- end.
-
-mk_store2(Src, Base1, Base2, StOp) ->
- case hipe_ppc:is_temp(Base1) of
- true ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_store_rr(Src, Base1, Base2, StOp);
- _ ->
- mk_store_ri(Src, Base1, Base2, StOp)
- end;
- _ ->
- case hipe_ppc:is_temp(Base2) of
- true ->
- mk_store_ri(Src, Base2, Base1, StOp);
- _ ->
- mk_store_ii(Src, Base1, Base2, StOp)
- end
- end.
-
-mk_store_ii(Src, Base, Disp, StOp) ->
- Tmp = new_untagged_temp(),
- mk_li(Tmp, Base,
- mk_store_ri(Src, Tmp, Disp, StOp)).
-
-mk_store_ri(Src, Base, Disp, StOp) ->
- hipe_ppc:mk_store(StOp, Src, Disp, Base, 'new', []).
-
-mk_store_rr(Src, Base1, Base2, StOp) ->
- StxOp = hipe_ppc:stop_to_stxop(StOp),
- [hipe_ppc:mk_storex(StxOp, Src, Base1, Base2)].
-
-conv_switch(I, Map, Data) ->
- Labels = hipe_rtl:switch_labels(I),
- LMap = [{label,L} || L <- Labels],
- {NewData, JTabLab} =
- case hipe_rtl:switch_sort_order(I) of
- [] ->
- hipe_consttab:insert_block(Data, word, LMap);
- SortOrder ->
- hipe_consttab:insert_sorted_block(
- Data, word, LMap, SortOrder)
- end,
- %% no immediates allowed here
- {IndexR, Map1} = conv_dst(hipe_rtl:switch_src(I), Map),
- JTabR = new_untagged_temp(),
- OffsetR = new_untagged_temp(),
- DestR = new_untagged_temp(),
- ShiftInstruction =
- case get(hipe_target_arch) of
- powerpc -> 'slwi';
- ppc64 -> 'sldi'
- end,
- I2 =
- [hipe_ppc:mk_pseudo_li(JTabR, {JTabLab,constant}),
- hipe_ppc:mk_alu(ShiftInstruction, OffsetR, IndexR,
- hipe_ppc:mk_uimm16(log2_word_size())),
- hipe_ppc:mk_loadx(hipe_ppc:ldop_wordx(), DestR, JTabR, OffsetR),
- hipe_ppc:mk_mtspr('ctr', DestR),
- hipe_ppc:mk_bctr(Labels)],
- {I2, Map1, NewData}.
-
-%%% Create a conditional branch.
-%%% If the condition tests CR0[SO], rewrite the path
-%%% corresponding to SO being set to clear XER[SO].
-
-mk_pseudo_bc(BCond, TrueLabel, FalseLabel, Pred) ->
- case BCond of
- 'so' ->
- NewTrueLabel = hipe_gensym:get_next_label(ppc),
- ZeroR = new_untagged_temp(),
- [hipe_ppc:mk_pseudo_bc(BCond, NewTrueLabel, FalseLabel, Pred),
- hipe_ppc:mk_label(NewTrueLabel) |
- mk_li(ZeroR, 0,
- [hipe_ppc:mk_mtspr('xer', ZeroR),
- hipe_ppc:mk_b_label(TrueLabel)])];
- 'ns' ->
- NewFalseLabel = hipe_gensym:get_next_label(ppc),
- ZeroR = new_untagged_temp(),
- [hipe_ppc:mk_pseudo_bc(BCond, TrueLabel, NewFalseLabel, Pred),
- hipe_ppc:mk_label(NewFalseLabel) |
- mk_li(ZeroR, 0,
- [hipe_ppc:mk_mtspr('xer', ZeroR),
- hipe_ppc:mk_b_label(FalseLabel)])];
- _ ->
- [hipe_ppc:mk_pseudo_bc(BCond, TrueLabel, FalseLabel, Pred)]
- end.
-
-%%% Load an integer constant into a register.
-
-mk_li(Dst, Value) -> mk_li(Dst, Value, []).
-
-mk_li(Dst, Value, Tail) ->
- hipe_ppc:mk_li(Dst, Value, Tail).
-
-%%% Check if an RTL ALU or ALUB operator commutes.
-
-rtl_aluop_commutes(RtlAluOp) ->
- case RtlAluOp of
- 'add' -> true;
- 'mul' -> true;
- 'or' -> true;
- 'and' -> true;
- 'xor' -> true;
- _ -> false
- end.
-
-%%% Split a list of formal or actual parameters into the
-%%% part passed in registers and the part passed on the stack.
-%%% The parameters passed in registers are also tagged with
-%%% the corresponding registers.
-
-split_args(Args) ->
- split_args(0, hipe_ppc_registers:nr_args(), Args, []).
-
-split_args(I, N, [Arg|Args], RegArgs) when I < N ->
- Reg = hipe_ppc_registers:arg(I),
- Temp = hipe_ppc:mk_temp(Reg, 'tagged'),
- split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]);
-split_args(_, _, StkArgs, RegArgs) ->
- {RegArgs, StkArgs}.
-
-%%% Convert a list of actual parameters passed in
-%%% registers (from split_args/1) to a list of moves.
-
-move_actuals([{Src,Dst}|Actuals], Rest) ->
- move_actuals(Actuals, mk_move(Dst, Src, Rest));
-move_actuals([], Rest) ->
- Rest.
-
-%%% Convert a list of formal parameters passed in
-%%% registers (from split_args/1) to a list of moves.
-
-move_formals([{Dst,Src}|Formals], Rest) ->
- move_formals(Formals, [hipe_ppc:mk_pseudo_move(Dst, Src) | Rest]);
-move_formals([], Rest) ->
- Rest.
-
-%%% Convert a 'fun' operand (MFA, prim, or temp)
-
-conv_fun(Fun, Map) ->
- case hipe_rtl:is_var(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- case hipe_rtl:is_reg(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- if is_atom(Fun) ->
- {hipe_ppc:mk_prim(Fun), Map};
- true ->
- {conv_mfa(Fun), Map}
- end
- end
- end.
-
-%%% Convert an MFA operand.
-
-conv_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
- hipe_ppc:mk_mfa(M, F, A).
-
-%%% Convert an RTL source operand (imm/var/reg).
-%%% Returns a temp or a naked integer.
-
-conv_src(Opnd, Map) ->
- case hipe_rtl:is_imm(Opnd) of
- true ->
- Value = hipe_rtl:imm_value(Opnd),
- if is_integer(Value) ->
- {Value, Map}
- end;
- false ->
- conv_dst(Opnd, Map)
- end.
-
-conv_src_list([O|Os], Map) ->
- {V, Map1} = conv_src(O, Map),
- {Vs, Map2} = conv_src_list(Os, Map1),
- {[V|Vs], Map2};
-conv_src_list([], Map) ->
- {[], Map}.
-
-%%% Convert an RTL destination operand (var/reg).
-
-conv_fpreg(Opnd, Map) ->
- case hipe_rtl:is_fpreg(Opnd) of
- true -> conv_dst(Opnd, Map)
- end.
-
-conv_dst(Opnd, Map) ->
- {Name, Type} =
- case hipe_rtl:is_var(Opnd) of
- true ->
- {hipe_rtl:var_index(Opnd), 'tagged'};
- false ->
- case hipe_rtl:is_fpreg(Opnd) of
- true ->
- {hipe_rtl:fpreg_index(Opnd), 'double'};
- false ->
- {hipe_rtl:reg_index(Opnd), 'untagged'}
- end
- end,
- IsPrecoloured =
- case Type of
- 'double' -> hipe_ppc_registers:is_precoloured_fpr(Name);
- _ -> hipe_ppc_registers:is_precoloured_gpr(Name)
- end,
- case IsPrecoloured of
- true ->
- {hipe_ppc:mk_temp(Name, Type), Map};
- false ->
- case vmap_lookup(Map, Opnd) of
- {value, NewTemp} ->
- {NewTemp, Map};
- _ ->
- NewTemp = hipe_ppc:mk_new_temp(Type),
- {NewTemp, vmap_bind(Map, Opnd, NewTemp)}
- end
- end.
-
-conv_dst_list([O|Os], Map) ->
- {Dst, Map1} = conv_dst(O, Map),
- {Dsts, Map2} = conv_dst_list(Os, Map1),
- {[Dst|Dsts], Map2};
-conv_dst_list([], Map) ->
- {[], Map}.
-
-conv_formals(Os, Map) ->
- conv_formals(hipe_ppc_registers:nr_args(), Os, Map, []).
-
-conv_formals(N, [O|Os], Map, Res) ->
- Type =
- case hipe_rtl:is_var(O) of
- true -> 'tagged';
- _ -> 'untagged'
- end,
- Dst =
- if N > 0 -> hipe_ppc:mk_new_temp(Type); % allocatable
- true -> hipe_ppc:mk_new_nonallocatable_temp(Type)
- end,
- Map1 = vmap_bind(Map, O, Dst),
- conv_formals(N-1, Os, Map1, [Dst|Res]);
-conv_formals(_, [], Map, Res) ->
- {lists:reverse(Res), Map}.
-
-%%% Create a temp representing the stack pointer register.
-
-mk_sp() ->
- hipe_ppc:mk_temp(hipe_ppc_registers:stack_pointer(), 'untagged').
-
-%%% Create a temp representing the return value register.
-
-mk_rv() ->
- hipe_ppc:mk_temp(hipe_ppc_registers:return_value(), 'tagged').
-
-%%% new_untagged_temp -- conjure up an untagged scratch reg
-
-new_untagged_temp() ->
- hipe_ppc:mk_new_temp('untagged').
-
-%%% new_tagged_temp -- conjure up a tagged scratch reg
-
-new_tagged_temp() ->
- hipe_ppc:mk_new_temp('tagged').
-
-%%% Map from RTL var/reg operands to temps.
-
-vmap_empty() ->
- gb_trees:empty().
-
-vmap_lookup(Map, Key) ->
- gb_trees:lookup(Key, Map).
-
-vmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-word_size() ->
- hipe_rtl_arch:word_size().
-
-log2_word_size() ->
- hipe_rtl_arch:log2_word_size().
diff --git a/lib/hipe/prebuild.skip b/lib/hipe/prebuild.skip
deleted file mode 100644
index 9c558e357c..0000000000
--- a/lib/hipe/prebuild.skip
+++ /dev/null
@@ -1 +0,0 @@
-.
diff --git a/lib/hipe/regalloc/Makefile b/lib/hipe/regalloc/Makefile
deleted file mode 100644
index 662efc9707..0000000000
--- a/lib/hipe/regalloc/Makefile
+++ /dev/null
@@ -1,133 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = hipe_ig hipe_ig_moves hipe_moves \
- hipe_node_sets hipe_spillcost hipe_reg_worklists \
- hipe_adj_list \
- hipe_temp_map \
- hipe_optimistic_regalloc \
- hipe_coalescing_regalloc \
- hipe_graph_coloring_regalloc \
- hipe_range_split \
- hipe_regalloc_loop \
- hipe_regalloc_prepass \
- hipe_restore_reuse \
- hipe_ls_regalloc \
- hipe_ppc_specific hipe_ppc_specific_fp \
- hipe_sparc_specific hipe_sparc_specific_fp \
- hipe_arm_specific \
- hipe_x86_specific hipe_x86_specific_x87 \
- hipe_amd64_specific hipe_amd64_specific_sse2 hipe_amd64_specific_x87
-
-HRL_FILES=
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars #+warn_missing_spec +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-$(EBIN)/hipe_amd64_specific.beam: hipe_x86_specific.erl
-$(EBIN)/hipe_amd64_specific_x87.beam: hipe_x86_specific_x87.erl
-$(EBIN)/hipe_coalescing_regalloc.beam: ../main/hipe.hrl
-$(EBIN)/hipe_graph_coloring_regalloc.beam: ../main/hipe.hrl
-$(EBIN)/hipe_ig.beam: ../main/hipe.hrl ../flow/cfg.hrl hipe_spillcost.hrl
-$(EBIN)/hipe_ls_regalloc.beam: ../main/hipe.hrl
-$(EBIN)/hipe_optimistic_regalloc.beam: ../main/hipe.hrl
-$(EBIN)/hipe_regalloc_loop.beam: ../main/hipe.hrl
-$(EBIN)/hipe_spillcost.beam: hipe_spillcost.hrl
-$(EBIN)/hipe_temp_map.beam: ../main/hipe.hrl
diff --git a/lib/hipe/regalloc/hipe_adj_list.erl b/lib/hipe/regalloc/hipe_adj_list.erl
deleted file mode 100644
index 5066106074..0000000000
--- a/lib/hipe/regalloc/hipe_adj_list.erl
+++ /dev/null
@@ -1,138 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_adj_list.erl
-%% Author : Andreas Wallin <d96awa@it.uu.se>
-%% Purpose : Keeps track of adjacency lists for the inference graph.
-%% Created : 18 Mar 2000 by Andreas Wallin <d96awa@it.uu.se>
-%%----------------------------------------------------------------------
-
--module(hipe_adj_list).
--author("Andreas Wallin").
--export([new/1,
- add_edge/3,
- %% add_edges/3,
- remove_edge/3,
- %% remove_edges/3,
- edges/2]).
-
-%%----------------------------------------------------------------------
-%% Function: new
-%%
-%% Description: Creates an empty structure for adjacency lists
-%%
-%% Parameters:
-%% Max_nodes -- Limit for node numbers
-%%
-%% Returns:
-%% Empty adj_list structure
-%%
-%%----------------------------------------------------------------------
-
-new(Max_nodes) ->
- hipe_vectors:new(Max_nodes, []).
-
-%%----------------------------------------------------------------------
-%% Function: add_edges
-%%
-%% Description: Adds edges from a node to other nodes
-%%
-%% Parameters:
-%% U -- A node
-%% Vs -- Nodes to add edges to
-%% Adj_list -- Old adjacency lists
-%%
-%% Returns:
-%% An updated adj_list data-structure
-%%
-%%----------------------------------------------------------------------
-
-%%add_edges(_, [], Adj_list) -> Adj_list;
-%%add_edges(U, Vs, Adj_list) when is_list(Vs), is_integer(U) ->
-%% hipe_vectors:set(Adj_list, U, ordsets:union(Vs, hipe_vectors:get(Adj_list, U))).
-
-%%----------------------------------------------------------------------
-%% Function: add_edge
-%%
-%% Description: Creates an edge between two nodes
-%%
-%% Parameters:
-%% U -- A node
-%% V -- Another node
-%% Adj_list -- Old adjacency lists
-%%
-%% Returns:
-%% New adj_list data-structure with (U and V connected)
-%%
-%%----------------------------------------------------------------------
-
-add_edge(U, V, Adj_list) -> % PRE: U =/= V, not V \in adjList[U]
- hipe_vectors:set(Adj_list, U,
- [V | hipe_vectors:get(Adj_list, U)]).
-
-%%----------------------------------------------------------------------
-%% Function: remove_edges
-%%
-%% Description: Removes edges from a node to other nodes
-%%
-%% Parameters:
-%% U -- A node
-%% Vs -- Nodes to remove edges to
-%% Adj_list -- Old adjacency lists
-%%
-%% Returns:
-%% An updated adj_list data-structure
-%%
-%%----------------------------------------------------------------------
-
-%% remove_edges(_, [], Adj_list) -> Adj_list;
-remove_edges(U, Vs, Adj_list) when is_list(Vs), is_integer(U) ->
- hipe_vectors:set(Adj_list, U, hipe_vectors:get(Adj_list, U) -- Vs).
-
-%%----------------------------------------------------------------------
-%% Function: remove_edge
-%%
-%% Description: Removes an edge between two nodes
-%%
-%% Parameters:
-%% U -- A node
-%% V -- Another node
-%% Adj_list -- Old adjacency lists
-%%
-%% Returns:
-%% New adjacency lists with (U and V not connected)
-%%
-%%----------------------------------------------------------------------
-
-remove_edge(U, U, Adj_list) -> Adj_list;
-remove_edge(U, V, Adj_list) when is_integer(U), is_integer(V) ->
- remove_edges(U, [V], Adj_list).
-
-%%----------------------------------------------------------------------
-%% Function: edges
-%%
-%% Description: Tells where the edges of a node go
-%%
-%% Parameters:
-%% U -- A node
-%% Adj_list -- Adjacency lists
-%%
-%% Returns:
-%% The set of nodes connected to U
-%%
-%%----------------------------------------------------------------------
-
-edges(U, Adj_list) ->
- hipe_vectors:get(Adj_list, U).
diff --git a/lib/hipe/regalloc/hipe_amd64_specific.erl b/lib/hipe/regalloc/hipe_amd64_specific.erl
deleted file mode 100644
index 72900563e6..0000000000
--- a/lib/hipe/regalloc/hipe_amd64_specific.erl
+++ /dev/null
@@ -1,14 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--define(HIPE_AMD64, true).
--include("hipe_x86_specific.erl").
diff --git a/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl b/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl
deleted file mode 100644
index d592ba391c..0000000000
--- a/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl
+++ /dev/null
@@ -1,245 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_amd64_specific_sse2).
-
--export([number_of_temporaries/2]).
-
-% The following exports are used as M:F(...) calls from other modules;
-%% e.g. hipe_amd64_ra_ls.
--export([analyze/2,
- bb/3,
- args/2,
- labels/2,
- livein/3,
- liveout/3,
- uses/2,
- defines/2,
- defines_all_alloc/2,
- def_use/2,
- is_arg/2, %% used by hipe_ls_regalloc
- is_move/2,
- is_spill_move/2,
- is_fixed/2, %% used by hipe_graph_coloring_regalloc
- is_global/2,
- is_precoloured/2,
- reg_nr/2,
- non_alloc/2,
- allocatable/1,
- allocatable/2,
- temp0/1,
- physical_name/2,
- all_precoloured/1,
- new_spill_index/2, %% used by hipe_ls_regalloc
- var_range/2,
- breadthorder/2,
- postorder/2,
- reverse_postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3,
- check_and_rewrite/4]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights
--export([branch_preds/2]).
-
-%%----------------------------------------------------------------------------
-
--include("../flow/cfg.hrl").
-
-%%----------------------------------------------------------------------------
-
-check_and_rewrite(CFG, Coloring, no_context) ->
- hipe_amd64_ra_sse2_postconditions:check_and_rewrite(CFG, Coloring).
-
-check_and_rewrite(CFG, Coloring, Strategy, no_context) ->
- hipe_amd64_ra_sse2_postconditions:check_and_rewrite(
- CFG, Coloring, Strategy).
-
-reverse_postorder(CFG, _) ->
- hipe_x86_cfg:reverse_postorder(CFG).
-
-breadthorder(CFG, _) ->
- hipe_x86_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_x86_cfg:postorder(CFG).
-
-is_global(Reg, _) ->
- hipe_amd64_registers:sse2_temp0() =:= Reg.
-
-is_fixed(_Reg, _) ->
- false.
-
-is_arg(_Reg, _) ->
- false.
-
--spec args(#cfg{}, no_context) -> [].
-args(_CFG, _) ->
- [].
-
-non_alloc(_, _) ->
- [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- hipe_amd64_liveness:analyze(CFG).
-
-livein(Liveness, L, _) ->
- [X || X <- hipe_amd64_liveness:livein(Liveness, L),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'].
-
-liveout(BB_in_out_liveness, Label, _) ->
- [X || X <- hipe_amd64_liveness:liveout(BB_in_out_liveness, Label),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'].
-
-%% Registers stuff
-
-allocatable(Ctx) ->
- allocatable('normal', Ctx).
-
-allocatable('normal', _) ->
- hipe_amd64_registers:allocatable_sse2();
-allocatable('linearscan', _) ->
- hipe_amd64_registers:allocatable_sse2() --
- [hipe_amd64_registers:sse2_temp0()].
-
-temp0(_) ->
- hipe_amd64_registers:sse2_temp0().
-
-all_precoloured(Ctx) ->
- allocatable(Ctx).
-
-is_precoloured(Reg, _) ->
- hipe_amd64_registers:is_precoloured_sse2(Reg).
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_x86_cfg:labels(CFG).
-
-var_range(_CFG, _) ->
- hipe_gensym:var_range(x86).
-
--spec number_of_temporaries(#cfg{}, no_context) -> non_neg_integer().
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(x86),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG, L, _) ->
- hipe_x86_cfg:bb(CFG, L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_x86_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Instr,_) ->
- hipe_x86_cfg:branch_preds(Instr).
-
-%% AMD64 stuff
-
-def_use(Instruction, _) ->
- {[X || X <- hipe_amd64_defuse:insn_def(Instruction),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'],
- [X || X <- hipe_amd64_defuse:insn_use(Instruction),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double']
- }.
-
-uses(I, _) ->
- [X || X <- hipe_amd64_defuse:insn_use(I),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'].
-
-defines(I, _) ->
- [X || X <- hipe_amd64_defuse:insn_def(I),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'].
-
-defines_all_alloc(I, _) -> hipe_amd64_defuse:insn_defs_all(I).
-
-is_move(Instruction, _) ->
- case hipe_x86:is_fmove(Instruction) of
- true ->
- Src = hipe_x86:fmove_src(Instruction),
- Dst = hipe_x86:fmove_dst(Instruction),
- hipe_x86:is_temp(Src) andalso hipe_x86:temp_is_allocatable(Src)
- andalso hipe_x86:is_temp(Dst) andalso hipe_x86:temp_is_allocatable(Dst);
- false -> false
- end.
-
-is_spill_move(Instruction,_) ->
- hipe_x86:is_pseudo_spill_fmove(Instruction).
-
-reg_nr(Reg, _) ->
- hipe_x86:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_x86:mk_fmove(Src, Dst).
-
-mk_goto(Label, _) ->
- hipe_x86:mk_jmp_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- Ref = make_ref(),
- put(Ref, false),
- I = hipe_x86_subst:insn_lbls(
- fun(Tgt) ->
- if Tgt =:= ToOld -> put(Ref, true), ToNew;
- is_integer(Tgt) -> Tgt
- end
- end, Jmp),
- true = erase(Ref), % Assert that something was rewritten
- I.
-
-new_label(_) ->
- hipe_gensym:get_next_label(x86).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(x86).
-
-update_reg_nr(Nr, _Temp, _) ->
- hipe_x86:mk_temp(Nr, 'double').
-
-subst_temps(SubstFun, Instr, _) ->
- hipe_amd64_subst:insn_temps(
- fun(Op) ->
- case hipe_x86:temp_is_allocatable(Op)
- andalso hipe_x86:temp_type(Op) =:= 'double'
- of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
--spec new_spill_index(non_neg_integer(), no_context) -> pos_integer().
-new_spill_index(SpillIndex, _) when is_integer(SpillIndex) ->
- SpillIndex + 1.
diff --git a/lib/hipe/regalloc/hipe_amd64_specific_x87.erl b/lib/hipe/regalloc/hipe_amd64_specific_x87.erl
deleted file mode 100644
index 918f72f5f2..0000000000
--- a/lib/hipe/regalloc/hipe_amd64_specific_x87.erl
+++ /dev/null
@@ -1,14 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--define(HIPE_AMD64, true).
--include("hipe_x86_specific_x87.erl").
diff --git a/lib/hipe/regalloc/hipe_arm_specific.erl b/lib/hipe/regalloc/hipe_arm_specific.erl
deleted file mode 100644
index 7ebc6aa336..0000000000
--- a/lib/hipe/regalloc/hipe_arm_specific.erl
+++ /dev/null
@@ -1,221 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_arm_specific).
-
-%% for hipe_coalescing_regalloc:
--export([number_of_temporaries/2
- ,analyze/2
- ,labels/2
- ,all_precoloured/1
- ,bb/3
- ,liveout/3
- ,reg_nr/2
- ,def_use/2
- ,is_move/2
- ,is_spill_move/2
- ,is_precoloured/2
- ,var_range/2
- ,allocatable/1
- ,non_alloc/2
- ,physical_name/2
- ,reverse_postorder/2
- ,livein/3
- ,uses/2
- ,defines/2
- ,defines_all_alloc/2
- ]).
-
-%% for hipe_graph_coloring_regalloc:
--export([is_fixed/2]).
-
-%% for hipe_ls_regalloc:
--export([args/2, is_arg/2, is_global/2, new_spill_index/2]).
--export([breadthorder/2, postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights, hipe_range_split
--export([branch_preds/2]).
-
-check_and_rewrite(CFG, Coloring, no_context) ->
- hipe_arm_ra_postconditions:check_and_rewrite(CFG, Coloring, 'normal').
-
-reverse_postorder(CFG, _) ->
- hipe_arm_cfg:reverse_postorder(CFG).
-
-non_alloc(CFG, no_context) ->
- non_alloc_1(hipe_arm_registers:nr_args(), hipe_arm_cfg:params(CFG)).
-
-%% same as hipe_arm_frame:fix_formals/2
-non_alloc_1(0, Rest) -> Rest;
-non_alloc_1(N, [_|Rest]) -> non_alloc_1(N-1, Rest);
-non_alloc_1(_, []) -> [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- hipe_arm_liveness_gpr:analyse(CFG).
-
-livein(Liveness,L,_) ->
- [X || X <- hipe_arm_liveness_gpr:livein(Liveness,L),
- hipe_arm:temp_is_allocatable(X)].
-
-liveout(BB_in_out_liveness,Label,_) ->
- [X || X <- hipe_arm_liveness_gpr:liveout(BB_in_out_liveness,Label),
- hipe_arm:temp_is_allocatable(X)].
-
-%% Registers stuff
-
-allocatable(no_context) ->
- hipe_arm_registers:allocatable_gpr().
-
-all_precoloured(no_context) ->
- hipe_arm_registers:all_precoloured().
-
-is_precoloured(Reg, _) ->
- hipe_arm_registers:is_precoloured_gpr(Reg).
-
-is_fixed(R, _) ->
- hipe_arm_registers:is_fixed(R).
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_arm_cfg:labels(CFG).
-
-var_range(_CFG, _) ->
- hipe_gensym:var_range(arm).
-
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(arm),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG,L,_) ->
- hipe_arm_cfg:bb(CFG,L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_arm_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Branch,_) ->
- hipe_arm_cfg:branch_preds(Branch).
-
-%% ARM stuff
-
-def_use(Instruction, Ctx) ->
- {defines(Instruction, Ctx), uses(Instruction, Ctx)}.
-
-uses(I, _) ->
- [X || X <- hipe_arm_defuse:insn_use_gpr(I),
- hipe_arm:temp_is_allocatable(X)].
-
-defines(I, _) ->
- [X || X <- hipe_arm_defuse:insn_def_gpr(I),
- hipe_arm:temp_is_allocatable(X)].
-
-defines_all_alloc(I, _) ->
- hipe_arm_defuse:insn_defs_all_gpr(I).
-
-is_move(Instruction, _) ->
- case hipe_arm:is_pseudo_move(Instruction) of
- true ->
- Dst = hipe_arm:pseudo_move_dst(Instruction),
- case hipe_arm:temp_is_allocatable(Dst) of
- false -> false;
- _ ->
- Src = hipe_arm:pseudo_move_src(Instruction),
- hipe_arm:temp_is_allocatable(Src)
- end;
- false -> false
- end.
-
-is_spill_move(Instruction, _) ->
- hipe_arm:is_pseudo_spill_move(Instruction).
-
-reg_nr(Reg, _) ->
- hipe_arm:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_arm:mk_pseudo_move(Dst, Src).
-
-mk_goto(Label, _) ->
- hipe_arm:mk_b_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- Ref = make_ref(),
- put(Ref, false),
- I = hipe_arm_subst:insn_lbls(
- fun(Tgt) ->
- if Tgt =:= ToOld -> put(Ref, true), ToNew;
- is_integer(Tgt) -> Tgt
- end
- end, Jmp),
- true = erase(Ref), % Assert that something was rewritten
- I.
-
-new_label(_) ->
- hipe_gensym:get_next_label(arm).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(arm).
-
-update_reg_nr(Nr, Temp, _) ->
- hipe_arm:mk_temp(Nr, hipe_arm:temp_type(Temp)).
-
-subst_temps(SubstFun, Instr, _) ->
- hipe_arm_subst:insn_temps(
- fun(Op) ->
- case hipe_arm:temp_is_allocatable(Op) of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
-%%% Linear Scan stuff
-
-new_spill_index(SpillIndex, _) when is_integer(SpillIndex) ->
- SpillIndex+1.
-
-breadthorder(CFG, _) ->
- hipe_arm_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_arm_cfg:postorder(CFG).
-
-is_global(R, _) ->
- R =:= hipe_arm_registers:temp1() orelse
- R =:= hipe_arm_registers:temp2() orelse
- R =:= hipe_arm_registers:temp3() orelse
- hipe_arm_registers:is_fixed(R).
-
-is_arg(R, _) ->
- hipe_arm_registers:is_arg(R).
-
-args(CFG, _) ->
- hipe_arm_registers:args(hipe_arm_cfg:arity(CFG)).
diff --git a/lib/hipe/regalloc/hipe_coalescing_regalloc.erl b/lib/hipe/regalloc/hipe_coalescing_regalloc.erl
deleted file mode 100644
index b8f0a1974c..0000000000
--- a/lib/hipe/regalloc/hipe_coalescing_regalloc.erl
+++ /dev/null
@@ -1,1040 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-----------------------------------------------------------------------
-%% File : hipe_coalescing_regalloc.erl
-%% Authors : Andreas Wallin <d96awa@it.uu.se>
-%% Thorild Selén <d95ths@.it.uu.se>
-%% Ingemar Ã…berg <d95ina@it.uu.se>
-%% Purpose : Play paintball with registers on a target machine. We win
-%% if they are all colored. This is an iterated coalescing
-%% register allocator.
-%% Created : 4 Mar 2000
-%%-----------------------------------------------------------------------
-
--module(hipe_coalescing_regalloc).
--export([regalloc/7]).
-
-%%-ifndef(DEBUG).
-%%-define(DEBUG,true).
-%%-endif.
--include("../main/hipe.hrl").
-
-%%-----------------------------------------------------------------------
-%% Function: regalloc
-%%
-%% Description: Creates a K coloring for a function.
-%% Parameters:
-%% CFG -- A control flow graph
-%% SpillIndex -- Last index of spill variable
-%% SpillLimit -- Temporaries with numbers higher than this have
-%% infinite spill cost.
-%% Consider changing this to a set.
-%% Target -- The module containing the target-specific functions.
-%%
-%% Returns:
-%% Coloring -- A coloring for specified CFG
-%% SpillIndex2 -- A new spill index
-%%-----------------------------------------------------------------------
-
-regalloc(CFG, Liveness, SpillIndex, SpillLimit, TargetMod, TargetContext,
- _Options) ->
- Target = {TargetMod, TargetContext},
- %% Build interference graph
- ?debug_msg("Build IG\n", []),
- IG = hipe_ig:build(CFG, Liveness, TargetMod, TargetContext),
- %% io:format("IG: ~p\n", [IG]),
-
- ?debug_msg("Init\n", []),
- Num_Temps = TargetMod:number_of_temporaries(CFG,TargetContext),
- ?debug_msg("Coalescing RA: num_temps = ~p~n", [Num_Temps]),
- Allocatable = TargetMod:allocatable(TargetContext),
- K = length(Allocatable),
- All_colors = colset_from_list(Allocatable),
-
- %% Add registers with their own coloring
- ?debug_msg("Moves\n", []),
- Move_sets = hipe_moves:new(IG),
-
- ?debug_msg("Build Worklist\n", []),
- Worklists = hipe_reg_worklists:new(IG, TargetMod, TargetContext, CFG,
- Move_sets, K, Num_Temps),
- Alias = initAlias(Num_Temps),
-
- ?debug_msg("Do coloring\n~p~n", [Worklists]),
- {_IG0, Worklists0, _Moves0, Alias0} =
- do_coloring(IG, Worklists, Move_sets, Alias, K, SpillLimit, Target),
- %% io:format("SelStk0 ~w\n",[SelStk0]),
- ?debug_msg("Init node sets\n", []),
- Node_sets = hipe_node_sets:new(),
- %% io:format("NodeSet: ~w\n NonAlloc ~w\n",[Node_sets,non_alloc(CFG,Target)]),
- ?debug_msg("Default coloring\n", []),
- {Color0,Node_sets1} =
- defaultColoring(TargetMod:all_precoloured(TargetContext),
- initColor(Num_Temps), Node_sets, Target),
-
- ?debug_msg("Assign colors\n", []),
- {Color1,Node_sets2} =
- assignColors(hipe_reg_worklists:stack(Worklists0), Node_sets1, Color0,
- Alias0, All_colors, Target),
- %% io:format("color0:~w\nColor1:~w\nNodes:~w\nNodes2:~w\nNum_Temps:~w\n",[Color0,Color1,Node_sets,Node_sets2,Num_Temps]),
-
- ?debug_msg("Build mapping ~p\n", [Node_sets2]),
- {Coloring, SpillIndex2} =
- build_namelist(Node_sets2, SpillIndex, Alias0, Color1),
- ?debug_msg("Coloring ~p\n", [Coloring]),
- {Coloring, SpillIndex2}.
-
-%%----------------------------------------------------------------------
-%% Function: do_coloring
-%%
-%% Description: Create a coloring. That is, play paintball.
-%% Parameters:
-%% IG -- An interference graph
-%% Worklists -- Worklists, that is simplify, spill and freeze
-%% Moves -- Moves sets, that is coalesced, constrained
-%% and so on.
-%% Alias -- Tells if two temporaries can have their value
-%% in the same register.
-%% K -- Want to create a K coloring.
-%% SpillLimit -- Try not to spill nodes that are above the spill limit.
-%%
-%% Returns:
-%% IG -- Updated interference graph
-%% Worklists -- Updated Worklists structure
-%% Moves -- Updated Moves structure
-%% Alias -- Updates Alias structure
-%%
-%%----------------------------------------------------------------------
-
-do_coloring(IG, Worklists, Moves, Alias, K, SpillLimit, Target) ->
- Simplify = not(hipe_reg_worklists:is_empty_simplify(Worklists)),
- Coalesce = not(hipe_moves:is_empty_worklist(Moves)),
- Freeze = not(hipe_reg_worklists:is_empty_freeze(Worklists)),
- Spill = not(hipe_reg_worklists:is_empty_spill(Worklists)),
- if Simplify =:= true ->
- {IG0, Worklists0, Moves0} =
- simplify(hipe_reg_worklists:simplify(Worklists),
- IG,
- Worklists,
- Moves,
- K),
- do_coloring(IG0, Worklists0, Moves0, Alias, K, SpillLimit, Target);
- Coalesce =:= true ->
- {Moves0, IG0, Worklists0, Alias0} =
- coalesce(Moves, IG, Worklists, Alias, K, Target),
- do_coloring(IG0, Worklists0, Moves0, Alias0, K, SpillLimit, Target);
- Freeze =:= true ->
- {Worklists0,Moves0} =
- freeze(K, Worklists, Moves, IG, Alias),
- do_coloring(IG, Worklists0, Moves0, Alias,
- K, SpillLimit, Target);
- Spill =:= true ->
- {Worklists0, Moves0} =
- selectSpill(Worklists, Moves, IG, K, Alias, SpillLimit),
- do_coloring(IG, Worklists0, Moves0, Alias, K, SpillLimit, Target);
- true -> % Catchall case
- {IG, Worklists, Moves, Alias}
- end.
-
-%%----------------------------------------------------------------------
-%% Function: adjacent
-%%
-%% Description: Adjacent nodes that's not coalesced, on the stack or
-%% precoloured.
-%% Parameters:
-%% Node -- Node that you want to adjacents of
-%% IG -- The interference graph
-%%
-%% Returns:
-%% A set with nodes/temporaries that are not coalesced, on the
-%% stack or precoloured.
-%%----------------------------------------------------------------------
-
-adjacent(Node, IG, Worklists) ->
- Adjacent_edges = hipe_ig:node_adj_list(Node, IG),
- hipe_reg_worklists:non_stacked_or_coalesced_nodes(Adjacent_edges, Worklists).
-
-%%----------------------------------------------------------------------
-%% Function: simplify
-%%
-%% Description: Simplify graph by removing nodes of low degree. This
-%% function simplifies all nodes it can at once.
-%% Parameters:
-%% [Node|Nodes] -- The simplify worklist
-%% IG -- The interference graph
-%% Worklists -- The worklists data-structure
-%% Moves -- The moves data-structure
-%% K -- Produce a K coloring
-%%
-%% Returns:
-%% IG -- An updated interference graph
-%% Worklists -- An updated worklists data-structure
-%% Moves -- An updated moves data-structure
-%%----------------------------------------------------------------------
-
-simplify([], IG, Worklists, Moves, _K) ->
- {IG, Worklists, Moves};
-simplify([Node|Nodes], IG, Worklists, Moves, K) ->
- Worklists0 = hipe_reg_worklists:remove_simplify(Node, Worklists),
- ?debug_msg("putting ~w on stack~n",[Node]),
- Adjacent = adjacent(Node, IG, Worklists0),
- Worklists01 = hipe_reg_worklists:push_stack(Node, Adjacent, Worklists0),
- {New_ig, Worklists1, New_moves} =
- decrement_degree(Adjacent, IG, Worklists01, Moves, K),
- simplify(Nodes, New_ig, Worklists1, New_moves, K).
-
-%%----------------------------------------------------------------------
-%% Function: decrement_degree
-%%
-%% Description: Decrement the degree on a number of nodes/temporaries.
-%% Parameters:
-%% [Node|Nodes] -- Decrement degree on these nodes
-%% IG -- The interference graph
-%% Worklists -- The Worklists data structure
-%% Moves -- The Moves data structure.
-%% K -- We want to create a coloring with K colors
-%%
-%% Returns:
-%% IG -- An updated interference graph (the degrees)
-%% Worklists -- Updated Worklists. Changed if one degree goes
-%% down to K.
-%% Moves -- Updated Moves. Changed if a move related temporary
-%% gets degree K.
-%%----------------------------------------------------------------------
-
-decrement_degree([], IG, Worklists, Moves, _K) ->
- {IG, Worklists, Moves};
-decrement_degree([Node|Nodes], IG, Worklists, Moves, K) ->
- PrevDegree = hipe_ig:get_node_degree(Node, IG),
- IG0 = hipe_ig:dec_node_degree(Node, IG),
- if PrevDegree =:= K ->
- AdjList = hipe_ig:node_adj_list(Node, IG0),
- %% Ok since Node (a) is still in IG, and (b) cannot be adjacent to itself
- Moves00 = enable_moves_active_to_worklist(hipe_moves:node_movelist(Node, Moves),
- Moves),
- Moves0 = enable_moves(AdjList, Worklists, Moves00),
- Worklists0 = hipe_reg_worklists:remove_spill(Node, Worklists),
- case hipe_moves:move_related(Node, Moves0) of
- true ->
- Worklists1 = hipe_reg_worklists:add_freeze(Node, Worklists0),
- decrement_degree(Nodes, IG0, Worklists1, Moves0, K);
- _ ->
- Worklists1 = hipe_reg_worklists:add_simplify(Node, Worklists0),
- decrement_degree(Nodes, IG0, Worklists1, Moves0, K)
- end;
- true ->
- decrement_degree(Nodes, IG0, Worklists, Moves, K)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: enable_moves
-%%
-%% Description: Make (move-related) nodes that are not yet considered for
-%% coalescing, ready for possible coalescing.
-%%
-%% Parameters:
-%% [Node|Nodes] -- A list of move nodes
-%% Moves -- The moves data-structure
-%%
-%% Returns:
-%% An updated moves data-structure
-%%----------------------------------------------------------------------
-
-enable_moves([], _Worklists, Moves) -> Moves;
-enable_moves([Node|Nodes], Worklists, Moves) ->
- case hipe_reg_worklists:member_stack_or_coalesced(Node, Worklists) of
- true -> enable_moves(Nodes, Worklists, Moves);
- _ ->
- %% moveList[n] suffices since we're checking for activeMoves membership
- Node_moves = hipe_moves:node_movelist(Node, Moves),
- New_moves = enable_moves_active_to_worklist(Node_moves, Moves),
- enable_moves(Nodes, Worklists, New_moves)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: enable_moves_active_to_worklist
-%%
-%% Description: Make (move-related) nodes that are not yet considered for
-%% coalescing, ready for possible coalescing.
-%%
-%% Parameters:
-%% [Node|Nodes] -- A list of move nodes
-%% Moves -- The moves data structure
-%%
-%% Returns:
-%% An updated moves data structure
-%%----------------------------------------------------------------------
-
-enable_moves_active_to_worklist([], Moves) -> Moves;
-enable_moves_active_to_worklist([Node|Nodes], Moves) ->
- NewMoves =
- case hipe_moves:member_active(Node, Moves) of
- true ->
- hipe_moves:add_worklist(Node, hipe_moves:remove_active(Node, Moves));
- _ ->
- Moves
- end,
- enable_moves_active_to_worklist(Nodes, NewMoves).
-
-%% Build the namelists, these functions are fast hacks, they use knowledge
-%% about data representation that they shouldn't know, bad abstraction.
-
-build_namelist(NodeSets, Index, Alias, Color) ->
- ?debug_msg("Building mapping\n",[]),
- ?debug_msg("Vector to list\n",[]),
- AliasList = build_alias_list(aliasToList(Alias),
- 0, %% The first temporary has index 0
- []), %% Accumulator
- ?debug_msg("Alias list:~p\n",[AliasList]),
- ?debug_msg("Coalesced\n",[]),
- NL1 = build_coalescedlist(AliasList, Color, Alias, []),
- ?debug_msg("Coalesced list:~p\n",[NL1]),
- ?debug_msg("Regs\n",[]),
- NL2 = build_reglist(hipe_node_sets:colored(NodeSets), Color, NL1),
- ?debug_msg("Regs list:~p\n",[NL2]),
- ?debug_msg("Spills\n",[]),
- build_spillist(hipe_node_sets:spilled(NodeSets), Index, NL2).
-
-build_spillist([], Index, List) ->
- {List,Index};
-build_spillist([Node|Nodes], Index, List) ->
- ?debug_msg("[~p]: Spill ~p to ~p\n", [?MODULE,Node,Index]),
- build_spillist(Nodes, Index+1, [{Node,{spill,Index}}|List]).
-
-build_coalescedlist([], _Color, _Alias, List) ->
- List;
-build_coalescedlist([Node|Ns], Color, Alias, List) when is_integer(Node) ->
- ?debug_msg("Alias of ~p is ~p~n", [Node, getAlias(Node,Alias)]),
- AC = getColor(getAlias(Node, Alias), Color),
- build_coalescedlist(Ns, Color, Alias, [{Node,{reg,AC}}|List]).
-
-build_reglist([], _Color, List) ->
- List;
-build_reglist([Node|Ns], Color, List) ->
- build_reglist(Ns, Color, [{Node,{reg,getColor(Node,Color)}}|List]).
-
-build_alias_list([], _I, List) ->
- List;
-build_alias_list([Alias|Aliases], I, List) when is_integer(Alias) ->
- build_alias_list(Aliases, I+1, [I|List]);
-build_alias_list([_Alias|Aliases], I, List) ->
- build_alias_list(Aliases, I+1, List).
-
-%%----------------------------------------------------------------------
-%% Function: assignColors
-%%
-%% Description: Tries to assign colors to nodes in a stack.
-%% Parameters:
-%% Stack -- The SelectStack built by the Select function,
-%% this stack contains tuples in the form {Node,Edges}
-%% where Node is the Node number and Edges is an ordset
-%% containing the numbers of all the adjacent nodes.
-%% NodeSets -- This is a record containing all the different node
-%% sets that are used in the register allocator.
-%% Alias -- This is a mapping from nodes to nodes, if a node has
-%% been coalesced this mapping shows the alias for that
-%% node.
-%% AllColors -- This is an ordset containing all the available colors
-%%
-%% Target -- The module containing the target-specific functions.
-%%
-%% Returns:
-%% Color -- A mapping from nodes to their respective color.
-%% NodeSets -- The updated node sets.
-%%----------------------------------------------------------------------
-
-assignColors(Stack, NodeSets, Color, Alias, AllColors, Target) ->
- case Stack of
- [] ->
- {Color,NodeSets};
- [{Node,Edges}|Stack1] ->
- ?debug_msg("Coloring Node: ~p~n",[Node]),
- ?IF_DEBUG(lists:foreach(fun (_E) ->
- ?msg(" Edge ~w-><~w>->~w~n",
- begin A = getAlias(_E,Alias),
- [_E,A,getColor(A,Color)]
- end)
- end, Edges),
- []),
- %% When debugging, check that Node isn't precoloured.
- OkColors = findOkColors(Edges, AllColors, Color, Alias),
- case colset_is_empty(OkColors) of
- true -> % Spill case
- NodeSets1 = hipe_node_sets:add_spilled(Node, NodeSets),
- assignColors(Stack1, NodeSets1, Color, Alias, AllColors, Target);
- false -> % Colour case
- Col = colset_smallest(OkColors),
- NodeSets1 = hipe_node_sets:add_colored(Node, NodeSets),
- Color1 = setColor(Node, physical_name(Col,Target), Color),
- assignColors(Stack1, NodeSets1, Color1, Alias, AllColors, Target)
- end
- end.
-
-%%---------------------------------------------------------------------
-%% Function: defaultColoring
-%%
-%% Description: Make the default coloring
-%% Parameters:
-%% Regs -- The list of registers to be default colored
-%% Color -- The color mapping that shall be changed
-%% NodeSets -- The node sets that shall be updated
-%% Target -- The module containing the target-specific functions.
-%%
-%% Returns:
-%% NewColor -- The updated color mapping
-%% NewNodeSets -- The updated node sets
-%%---------------------------------------------------------------------
-
-defaultColoring([], Color, NodeSets, _Target) ->
- {Color,NodeSets};
-defaultColoring([Reg|Regs], Color, NodeSets, Target) ->
- Color1 = setColor(Reg,physical_name(Reg,Target), Color),
- NodeSets1 = hipe_node_sets:add_colored(Reg, NodeSets),
- defaultColoring(Regs, Color1, NodeSets1, Target).
-
-%% Find the colors that are OK for a node with certain edges.
-
-findOkColors(Edges, AllColors, Color, Alias) ->
- find(Edges, AllColors, Color, Alias).
-
-%% Find all the colors of the nodes in the list [Node|Nodes] and remove them
-%% from the set OkColors, when the list is empty, return OkColors.
-
-find([], OkColors, _Color, _Alias) ->
- OkColors;
-find([Node0|Nodes], OkColors, Color, Alias) ->
- Node = getAlias(Node0, Alias),
- case getColor(Node, Color) of
- [] ->
- find(Nodes, OkColors, Color, Alias);
- Col ->
- OkColors1 = colset_del_element(Col, OkColors),
- find(Nodes, OkColors1, Color, Alias)
- end.
-
-%%%
-%%% ColSet -- ADT for the set of available colours while
-%%% assigning colours.
-%%%
--ifdef(notdef). % old ordsets-based implementation
-colset_from_list(Allocatable) ->
- ordsets:from_list(Allocatable).
-
-colset_del_element(Colour, ColSet) ->
- ordsets:del_element(Colour, ColSet).
-
-colset_is_empty(ColSet) ->
- case ColSet of
- [] -> true;
- [_|_] -> false
- end.
-
-colset_smallest([Colour|_]) ->
- Colour.
--endif.
-
--ifdef(notdef). % new gb_sets-based implementation
-colset_from_list(Allocatable) ->
- gb_sets:from_list(Allocatable).
-
-colset_del_element(Colour, ColSet) ->
- %% Must use gb_sets:delete_any/2 since gb_sets:del_element/2
- %% fails if the element isn't present. Bummer.
- gb_sets:delete_any(Colour, ColSet).
-
-colset_is_empty(ColSet) ->
- gb_sets:is_empty(ColSet).
-
-colset_smallest(ColSet) ->
- gb_sets:smallest(ColSet).
--endif.
-
-%%-ifdef(notdef). % new bitmask-based implementation
-colset_from_list(Allocatable) ->
- colset_from_list(Allocatable, 0).
-
-colset_from_list([], ColSet) ->
- ColSet;
-colset_from_list([Colour|Allocatable], ColSet) ->
- colset_from_list(Allocatable, ColSet bor (1 bsl Colour)).
-
-colset_del_element(Colour, ColSet) ->
- ColSet band bnot(1 bsl Colour).
-
-colset_is_empty(0) -> true;
-colset_is_empty(_) -> false.
-
-colset_smallest(ColSet) ->
- bitN_log2(ColSet band -ColSet, 0).
-
-bitN_log2(BitN, ShiftN) ->
- if BitN > 16#ffff ->
- bitN_log2(BitN bsr 16, ShiftN + 16);
- true ->
- ShiftN + hweight16(BitN - 1)
- end.
-
-hweight16(W) ->
- Res1 = ( W band 16#5555) + (( W bsr 1) band 16#5555),
- Res2 = (Res1 band 16#3333) + ((Res1 bsr 2) band 16#3333),
- Res3 = (Res2 band 16#0F0F) + ((Res2 bsr 4) band 16#0F0F),
- (Res3 band 16#00FF) + ((Res3 bsr 8) band 16#00FF).
-%%-endif.
-
-%%%
-%%% Colour ADT providing a partial mapping from nodes to colours.
-%%%
-
-initColor(NrNodes) ->
- {colmap, hipe_bifs:array(NrNodes, [])}.
-
-getColor(Node, {colmap, ColMap}) ->
- hipe_bifs:array_sub(ColMap, Node).
-
-setColor(Node, Colour, {colmap, ColMap} = Col) ->
- hipe_bifs:array_update(ColMap, Node, Colour),
- Col.
-
-%%%
-%%% Alias ADT providing a partial mapping from nodes to nodes.
-%%%
-
-initAlias(NrNodes) ->
- {alias, hipe_bifs:array(NrNodes, [])}.
-
-getAlias(Node, {alias, AliasMap} = Alias) ->
- case hipe_bifs:array_sub(AliasMap, Node) of
- [] ->
- Node;
- AliasNode ->
- getAlias(AliasNode, Alias)
- end.
-
-setAlias(Node, AliasNode, {alias, AliasMap} = Alias) ->
- hipe_bifs:array_update(AliasMap, Node, AliasNode),
- Alias.
-
-aliasToList({alias,AliasMap}) ->
- aliasToList(AliasMap, hipe_bifs:array_length(AliasMap), []).
-
-aliasToList(AliasMap, I1, Tail) ->
- I0 = I1 - 1,
- if I0 >= 0 ->
- aliasToList(AliasMap, I0, [hipe_bifs:array_sub(AliasMap, I0)|Tail]);
- true ->
- Tail
- end.
-
-%%----------------------------------------------------------------------
-%% Function: coalesce
-%%
-%% Description: Coalesces nodes in worklist
-%% Parameters:
-%% Moves -- Current move information
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Alias -- Current aliases for temporaries
-%% K -- Number of registers
-%%
-%% Returns:
-%% {Moves, IG, Worklists, Alias}
-%% (Updated versions of above structures, after coalescing)
-%%----------------------------------------------------------------------
-
-coalesce(Moves, IG, Worklists, Alias, K, Target) ->
- case hipe_moves:worklist_get_and_remove(Moves) of
- {[],Moves0} ->
- %% Moves marked for removal from worklistMoves by FreezeMoves()
- %% are removed by worklist_get_and_remove(). This case is unlikely,
- %% but can occur if only stale moves remain in worklistMoves.
- {Moves0,IG,Worklists,Alias};
- {Move,Moves0} ->
- {Dest,Source} = hipe_moves:get_move(Move, Moves0),
- ?debug_msg("Testing nodes ~p and ~p for coalescing~n",[Dest,Source]),
- Alias_src = getAlias(Source, Alias),
- Alias_dst = getAlias(Dest, Alias),
- {U,V} = case is_precoloured(Alias_dst,Target) of
- true -> {Alias_dst, Alias_src};
- false -> {Alias_src, Alias_dst}
- end,
- %% When debugging, check that neither V nor U is on the stack.
- if U =:= V ->
- Moves1 = Moves0, % drop coalesced move Move
- Worklists1 = add_worklist(Worklists, U, K, Moves1, IG, Target),
- {Moves1, IG, Worklists1, Alias};
- true ->
- case (is_precoloured(V,Target) orelse
- hipe_ig:nodes_are_adjacent(U, V, IG)) of
- true ->
- Moves1 = Moves0, % drop constrained move Move
- Worklists1 = add_worklist(Worklists, U, K, Moves1, IG, Target),
- Worklists2 = add_worklist(Worklists1, V, K, Moves1, IG, Target),
- {Moves1, IG, Worklists2, Alias};
- false ->
- case (case is_precoloured(U,Target) of
- true ->
- AdjV = hipe_ig:node_adj_list(V, IG),
- all_adjacent_ok(AdjV, U, Worklists, IG, K, Target);
- false ->
- AdjV = hipe_ig:node_adj_list(V, IG),
- AdjU = hipe_ig:node_adj_list(U, IG),
- conservative(AdjU, AdjV, U, Worklists, IG, K)
- end) of
- true ->
- Moves1 = Moves0, % drop coalesced move Move
- {IG1,Worklists1,Moves2,Alias1} =
- combine(U, V, IG, Worklists, Moves1, Alias, K, Target),
- Worklists2 = add_worklist(Worklists1, U, K, Moves2, IG1, Target),
- {Moves2, IG1, Worklists2, Alias1};
- false ->
- Moves1 = hipe_moves:add_active(Move, Moves0),
- {Moves1, IG, Worklists, Alias}
- end
- end
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Function: add_worklist
-%%
-%% Description: Builds new worklists where U is transferred from freeze
-%% to simplify, if possible
-%%
-%% Parameters:
-%% Worklists -- Current worklists
-%% U -- Node to operate on
-%% K -- Number of registers
-%% Moves -- Current move information
-%% IG -- Interference graph
-%% Target -- The containing the target-specific functions
-%%
-%% Returns:
-%% Worklists (updated)
-%%----------------------------------------------------------------------
-
-add_worklist(Worklists, U, K, Moves, IG, Target) ->
- case (not(is_precoloured(U,Target))
- andalso not(hipe_moves:move_related(U, Moves))
- andalso (hipe_ig:is_trivially_colourable(U, K, IG))) of
- true ->
- hipe_reg_worklists:transfer_freeze_simplify(U, Worklists);
- false ->
- Worklists
- end.
-
-%%----------------------------------------------------------------------
-%% Function: combine
-%%
-%% Description: Combines two nodes into one (used when coalescing)
-%%
-%% Parameters:
-%% U -- First node to operate on
-%% V -- Second node to operate on
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Moves -- Current move information
-%% Alias -- Current aliases for temporaries
-%% K -- Number of registers
-%%
-%% Returns:
-%% {IG, Worklists, Moves, Alias} (updated)
-%%----------------------------------------------------------------------
-
-combine(U, V, IG, Worklists, Moves, Alias, K, Target) ->
- Worklists1 = case hipe_reg_worklists:member_freeze(V, Worklists) of
- true -> hipe_reg_worklists:remove_freeze(V, Worklists);
- false -> hipe_reg_worklists:remove_spill(V, Worklists)
- end,
- Worklists11 = hipe_reg_worklists:add_coalesced(V, Worklists1),
-
- ?debug_msg("Coalescing ~p and ~p to ~p~n",[V,U,U]),
-
- Alias1 = setAlias(V, U, Alias),
-
- %% Typo in published algorithm: s/nodeMoves/moveList/g to fix.
- %% XXX: moveList[u] \union moveList[v] OR NodeMoves(u) \union NodeMoves(v) ???
- %% XXX: NodeMoves() is correct, but unnecessarily strict. The ordsets:union
- %% constrains NodeMoves() to return an ordset.
- Moves1 = hipe_moves:update_movelist(U,
- ordsets:union(hipe_moves:node_moves(U, Moves),
- hipe_moves:node_moves(V, Moves)),
- Moves),
- %% Missing in published algorithm. From Tiger book Errata.
- Moves2 = enable_moves_active_to_worklist(hipe_moves:node_movelist(V, Moves1), Moves1),
- AdjV = hipe_ig:node_adj_list(V, IG),
-
- {IG1, Worklists2, Moves3} =
- combine_edges(AdjV, U, IG, Worklists11, Moves2, K, Target),
-
- New_worklists = case (not(hipe_ig:is_trivially_colourable(U, K, IG1))
- andalso
- hipe_reg_worklists:member_freeze(U, Worklists2)) of
- true ->
- hipe_reg_worklists:transfer_freeze_spill(U, Worklists2);
- false -> Worklists2
- end,
- {IG1, New_worklists, Moves3, Alias1}.
-
-%%----------------------------------------------------------------------
-%% Function: combine_edges
-%%
-%% Description: For each node in a list, make an edge between that node
-%% and node U, and decrement its degree by 1
-%% (Used when two nodes are coalesced, to connect all nodes
-%% adjacent to one node to the other node)
-%%
-%% Parameters:
-%% [T|Ts] -- List of nodes to make edges to
-%% U -- Node to make edges from
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Moves -- Current move information
-%% K -- Number of registers
-%%
-%% Returns:
-%% {IG, Worklists, Moves} (updated)
-%%----------------------------------------------------------------------
-
-combine_edges([], _U, IG, Worklists, Moves, _K, _Target) ->
- {IG, Worklists, Moves};
-combine_edges([T|Ts], U, IG, Worklists, Moves, K, Target={TgtMod,TgtCtx}) ->
- case hipe_reg_worklists:member_stack_or_coalesced(T, Worklists) of
- true -> combine_edges(Ts, U, IG, Worklists, Moves, K, Target);
- _ ->
- %% XXX: The issue below occurs because the T->V edge isn't removed.
- %% This causes adjList[T] to contain stale entries, to possibly grow
- %% (if T isn't already adjacent to U), and degree[T] to possibly
- %% increase (again, if T isn't already adjacent to U).
- %% The decrement_degree() call repairs degree[T] but not adjList[T].
- %% It would be better to physically replace T->V with T->U, and only
- %% decrement_degree(T) if T->U already existed.
- %%
- %% add_edge() may change a low-degree move-related node to be of
- %% significant degree. In this case the node belongs in the spill
- %% worklist, and that's where decrement_degree() expects to find it.
- %% This issue is not covered in the published algorithm.
- OldDegree = hipe_ig:get_node_degree(T, IG),
- IG1 = hipe_ig:add_edge(T, U, IG, TgtMod, TgtCtx),
- NewDegree = hipe_ig:get_node_degree(T, IG1),
- Worklists0 =
- if NewDegree =:= K, OldDegree =:= K-1 ->
- %% io:format("~w:combine_edges(): repairing worklist membership for node ~w\n", [?MODULE,T]),
- %% The node T must be on the freeze worklist:
- %% 1. Since we're coalescing, the simplify worklist must have been
- %% empty when combine_edges() started.
- %% 2. decrement_degree() may put the node T back on the simplify
- %% worklist, but that occurs after the worklists repair step.
- %% 3. There are no duplicates among the edges.
- Worklists00 = hipe_reg_worklists:remove_freeze(T, Worklists),
- hipe_reg_worklists:add_spill(T, Worklists00);
- true ->
- Worklists
- end,
- {IG2, Worklists1, Moves1} =
- decrement_degree([T], IG1, Worklists0, Moves, K),
- combine_edges(Ts, U, IG2, Worklists1, Moves1, K, Target)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: ok
-%%
-%% Description: Checks if a node T is suitable to coalesce with R
-%%
-%% Parameters:
-%% T -- Node to test
-%% R -- Other node to test
-%% IG -- Interference graph
-%% K -- Number of registers
-%% Target -- The module containing the target-specific functions
-%%
-%% Returns:
-%% true iff coalescing is OK
-%%----------------------------------------------------------------------
-
-ok(T, R, IG, K, Target) ->
- ((hipe_ig:is_trivially_colourable(T, K, IG))
- orelse is_precoloured(T,Target)
- orelse hipe_ig:nodes_are_adjacent(T, R, IG)).
-
-%%----------------------------------------------------------------------
-%% Function: all_ok
-%%
-%% Description: True iff, for every T in the list, OK(T,U)
-%%
-%% Parameters:
-%% [T|Ts] -- Nodes to test
-%% U -- Node to test for coalescing
-%% IG -- Interference graph
-%% K -- Number of registers
-%% Target -- The module containing the target-specific functions
-%%
-%% Returns:
-%% true iff coalescing is OK for all nodes in the list
-%%----------------------------------------------------------------------
-
-all_adjacent_ok([], _U, _Worklists, _IG, _K, _Target) -> true;
-all_adjacent_ok([T|Ts], U, Worklists, IG, K, Target) ->
- case hipe_reg_worklists:member_stack_or_coalesced(T, Worklists) of
- true -> all_adjacent_ok(Ts, U, Worklists, IG, K, Target);
- _ ->
- %% 'andalso' does not preserve tail-recursion
- case ok(T, U, IG, K, Target) of
- true -> all_adjacent_ok(Ts, U, Worklists, IG, K, Target);
- false -> false
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Function: conservative
-%%
-%% Description: Checks if nodes can be safely coalesced according to
-%% the Briggs' conservative coalescing heuristic
-%%
-%% Parameters:
-%% Nodes -- Adjacent nodes
-%% IG -- Interference graph
-%% K -- Number of registers
-%%
-%% Returns:
-%% true iff coalescing is safe
-%%----------------------------------------------------------------------
-
-conservative(AdjU, AdjV, U, Worklists, IG, K) ->
- conservative_countU(AdjU, AdjV, U, Worklists, IG, K, 0).
-
-%%----------------------------------------------------------------------
-%% Function: conservative_count
-%%
-%% Description: Counts degrees for conservative (Briggs' heuristic)
-%%
-%% Parameters:
-%% Nodes -- (Remaining) adjacent nodes
-%% IG -- Interference graph
-%% K -- Number of registers
-%% Cnt -- Accumulator for counting
-%%
-%% Returns:
-%% Final value of accumulator
-%%----------------------------------------------------------------------
-
-conservative_countU([], AdjV, U, Worklists, IG, K, Cnt) ->
- conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
-conservative_countU([Node|AdjU], AdjV, U, Worklists, IG, K, Cnt) ->
- case hipe_reg_worklists:member_stack_or_coalesced(Node, Worklists) of
- true -> conservative_countU(AdjU, AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- case hipe_ig:is_trivially_colourable(Node, K, IG) of
- true -> conservative_countU(AdjU, AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- Cnt1 = Cnt + 1,
- if Cnt1 < K ->
- conservative_countU(AdjU, AdjV, U, Worklists, IG, K, Cnt1);
- true -> false
- end
- end
- end.
-
-conservative_countV([], _U, _Worklists, _IG, _K, _Cnt) -> true;
-conservative_countV([Node|AdjV], U, Worklists, IG, K, Cnt) ->
- case hipe_reg_worklists:member_stack_or_coalesced(Node, Worklists) of
- true -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- case hipe_ig:nodes_are_adjacent(Node, U, IG) of
- true -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- case hipe_ig:is_trivially_colourable(Node, K, IG) of
- true -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- Cnt1 = Cnt + 1,
- if Cnt1 < K ->
- conservative_countV(AdjV, U, Worklists, IG, K, Cnt1);
- true -> false
- end
- end
- end
- end.
-
-%%---------------------------------------------------------------------
-%% Function: selectSpill
-%%
-%% Description: Select the node to spill and spill it
-%% Parameters:
-%% WorkLists -- A datatype containing the different worklists
-%% Moves -- A datatype containing the move sets
-%% IG -- The interference graph
-%% K -- The number of available registers
-%% Alias -- The alias mapping
-%% SpillLimit -- Try not to spill any nodes above the spill limit
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%% Moves -- The updated moves
-%%---------------------------------------------------------------------
-
-selectSpill(WorkLists, Moves, IG, K, Alias, SpillLimit) ->
- [CAR|CDR] = hipe_reg_worklists:spill(WorkLists),
-
- SpillCost = getCost(CAR, IG, SpillLimit),
- M = findCheapest(CDR, IG, SpillCost, CAR, SpillLimit),
-
- WorkLists1 = hipe_reg_worklists:remove_spill(M, WorkLists),
- %% The published algorithm adds M to the simplify worklist
- %% before the freezeMoves() call. That breaks the worklist
- %% invariants, which is why the order is switched here.
- {WorkLists2,Moves1} = freezeMoves(M, K, WorkLists1, Moves, IG, Alias),
- WorkLists3 = hipe_reg_worklists:add_simplify(M, WorkLists2),
- {WorkLists3,Moves1}.
-
-%% Find the node that is cheapest to spill
-
-findCheapest([], _IG, _Cost, Cheapest, _SpillLimit) ->
- Cheapest;
-findCheapest([Node|Nodes], IG, Cost, Cheapest, SpillLimit) ->
- ThisCost = getCost(Node, IG, SpillLimit),
- case ThisCost < Cost of
- true ->
- findCheapest(Nodes, IG, ThisCost, Node, SpillLimit);
- false ->
- findCheapest(Nodes, IG, Cost, Cheapest, SpillLimit)
- end.
-
-%% Get the cost for spilling a certain node, node numbers above the spill
-%% limit are extremely expensive.
-
-getCost(Node, IG, SpillLimit) ->
- case Node >= SpillLimit of
- true -> inf;
- false -> hipe_ig:node_spill_cost(Node, IG)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: freeze
-%%
-%% Description: When both simplifying and coalescing is impossible we
-%% rather freezes a node in stead of spilling, this function
-%% selects a node for freezing (it just picks the first one in
-%% the list)
-%%
-%% Parameters:
-%% K -- The number of available registers
-%% WorkLists -- A datatype containing the different worklists
-%% Moves -- A datatype containing the different movelists
-%% IG -- Interference graph
-%% Alias -- An alias mapping, shows the alias of all coalesced
-%% nodes
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%% Moves -- The updated movelists
-%%----------------------------------------------------------------------
-
-freeze(K, WorkLists, Moves, IG, Alias) ->
- [U|_] = hipe_reg_worklists:freeze(WorkLists), % Smarter routine?
- ?debug_msg("freezing node ~p~n", [U]),
- WorkLists0 = hipe_reg_worklists:remove_freeze(U, WorkLists),
- %% The published algorithm adds U to the simplify worklist
- %% before the freezeMoves() call. That breaks the worklist
- %% invariants, which is why the order is switched here.
- {WorkLists1,Moves1} = freezeMoves(U,K,WorkLists0,Moves,IG,Alias),
- WorkLists2 = hipe_reg_worklists:add_simplify(U, WorkLists1),
- {WorkLists2,Moves1}.
-
-%%----------------------------------------------------------------------
-%% Function: freezeMoves
-%%
-%% Description: Make all move related interferences for a certain node
-%% into ordinary interference arcs.
-%%
-%% Parameters:
-%% U -- The node we want to freeze
-%% K -- The number of available registers
-%% WorkLists -- A datatype containing the different worklists
-%% Moves -- A datatype containing the different movelists
-%% IG -- Interference graph
-%% Alias -- An alias mapping, shows the alias of all coalesced
-%% nodes
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%% Moves -- The updated movelists
-%%----------------------------------------------------------------------
-
-freezeMoves(U, K, WorkLists, Moves, IG, Alias) ->
- Nodes = hipe_moves:node_moves(U, Moves),
- freezeEm(U, Nodes, K, WorkLists, Moves, IG, Alias).
-
-%% Find what the other value in a copy instruction is, return false if
-%% the instruction isn't a move with the first argument in it.
-
-moves(U, Move, Alias, Moves) ->
- {X,Y} = hipe_moves:get_move(Move, Moves),
- %% The old code (which followed the published algorithm) did
- %% not follow aliases before looking for "the other" node.
- %% This caused moves() to skip some moves, making some nodes
- %% still move-related after freezeMoves(). These move-related
- %% nodes were then added to the simplify worklist (by freeze()
- %% or selectSpill()), breaking the worklist invariants. Nodes
- %% already simplified appeared in coalesce(), were re-added to
- %% the simplify worklist by add_worklist(), simplified again,
- %% and coloured multiple times by assignColors(). Ouch!
- X1 = getAlias(X, Alias),
- Y1 = getAlias(Y, Alias),
- if U =:= X1 -> Y1;
- U =:= Y1 -> X1;
- true -> exit({?MODULE,moves}) % XXX: shouldn't happen
- end.
-
-freezeEm(_U, [], _K, WorkLists, Moves, _IG, _Alias) ->
- {WorkLists,Moves};
-freezeEm(U,[M|Ms], K, WorkLists, Moves, IG, Alias) ->
- V = moves(U, M, Alias, Moves),
- {WorkLists2,Moves2} = freezeEm2(U, V, M, K, WorkLists, Moves, IG, Alias),
- freezeEm(U, Ms, K, WorkLists2, Moves2, IG, Alias).
-
-freezeEm2(U, V, M, K, WorkLists, Moves, IG, Alias) ->
- case hipe_moves:member_active(M, Moves) of
- true ->
- Moves1 = hipe_moves:remove_active(M, Moves),
- freezeEm3(U, V, M, K, WorkLists, Moves1, IG, Alias);
- false ->
- Moves1 = hipe_moves:remove_worklist(M, Moves),
- freezeEm3(U, V, M, K, WorkLists, Moves1, IG, Alias)
- end.
-
-freezeEm3(_U, V, _M, K, WorkLists, Moves, IG, _Alias) ->
- Moves1 = Moves, % drop frozen move M
- V1 = V, % getAlias(V,Alias),
- %% "not MoveRelated(v)" is cheaper than "NodeMoves(v) = {}"
- case ((not hipe_moves:move_related(V1, Moves1)) andalso
- hipe_ig:is_trivially_colourable(V1, K, IG)) of
- true ->
- ?debug_msg("freezing move to ~p~n", [V]),
- Worklists1 = hipe_reg_worklists:transfer_freeze_simplify(V1, WorkLists),
- {Worklists1, Moves1};
- false ->
- {WorkLists, Moves1}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to external functions.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-is_precoloured(R, {TgtMod,TgtCtx}) ->
- TgtMod:is_precoloured(R,TgtCtx).
-
-physical_name(R, {TgtMod,TgtCtx}) ->
- TgtMod:physical_name(R,TgtCtx).
diff --git a/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl b/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl
deleted file mode 100644
index f82d3a2cbc..0000000000
--- a/lib/hipe/regalloc/hipe_graph_coloring_regalloc.erl
+++ /dev/null
@@ -1,807 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% GRAPH COLORING REGISTER ALLOCATOR
-%%
-%% A simple graph coloring register allocator:
-%%
-%% - build interference graph + estimate spill costs
-%% - simplify graph (push on stack + spill)
-%% - select colors
-%%
-%% Emits a coloring: a list of {TempName,Location}
-%% where Location is {reg,N} or {spill,M}
-%% and {reg,N} denotes some register N
-%% and {spill,M} denotes the Mth spilled node
-%% You have to figure out how to rewrite the code yourself.
-%%
-%% This version uses vectors rather than hash tables, and uses
-%% faster algorithms since all vars are known at the start.
-%% The result should be considerably quicker than earlier versions.
-%%
-%% Deficiencies:
-%% - no renaming (to reduce unnecessary register pressure)
-%% - spill costs are naive (should use better; e.g., exec.estimates)
-%% - no biased coloring (which coalesces moves)
-%% - no live range splitting (possibly not critical)
-%%
-%% *** NOTE ***
-%% Uses apply for target specific functions, takes the module name as
-%% argument. This target specific module should implement all target
-%% specific functions, see the end of the file.
-%%
-
--module(hipe_graph_coloring_regalloc).
--export([regalloc/7]).
-
-%%-ifndef(DO_ASSERT).
-%%-define(DO_ASSERT, true).
-%%-endif.
-
-%%-ifndef(DEBUG).
-%%-define(DEBUG,0).
-%%-endif.
--include("../main/hipe.hrl").
-
-%% Define these as 'ok' or 'report(X,Y)' depending on how much output you want.
--define(report0(X,Y), ?IF_DEBUG_LEVEL(0,?msg(X, Y),ok)).
--define(report(X,Y), ?IF_DEBUG_LEVEL(1,?msg(X, Y),ok)).
--define(report2(X,Y), ?IF_DEBUG_LEVEL(2,?msg(X, Y),ok)).
--define(report3(X,Y), ?IF_DEBUG_LEVEL(3,?msg(X, Y),ok)).
-
-%% Given CFG and number of colors K, produce a coloring list
-%% of items {reg,N} (0 =< N =< K) and {spill,M}, where M is
-%% an index denoting 'a location'.
-%% (You might use it as a stack index, perhaps.)
-%%
-%% You can in principle delete check_coloring/2; it merely checks
-%% that the coloring agrees with the interference graph (that is, that
-%% no neighbors have the same register or spill location).
-
-%% @spec regalloc(#cfg{}, liveness(), non_neg_fixnum(), non_neg_fixnum(),
-%% module(), tgt_ctx(), list()) -> {, non_neg_fixnum()}
-
-regalloc(CFG, Live, SpillIndex, SpillLimit, TargetMod, TargetContext,
- _Options) ->
- Target = {TargetMod, TargetContext},
- PhysRegs = allocatable(Target),
- ?report2("building IG~n", []),
- {IG, Spill} = build_ig(CFG, Live, Target),
-
- %% check_ig(IG),
- ?report3("graph: ~p~nphysical regs: ~p~n", [list_ig(IG), PhysRegs]),
-
- %% These nodes *can't* be allocated to registers.
- NotAllocatable = non_alloc(CFG, Target),
- %% i.e. Arguments on x86
- ?report2("Nonalloc ~w~n", [NotAllocatable]),
-
- {Cols, NewSpillIndex} =
- color(IG, Spill,
- ordsets:from_list(PhysRegs),
- SpillIndex,
- SpillLimit,
- number_of_temporaries(CFG, Target),
- Target, NotAllocatable),
- Coloring = [{X, {reg, X}} || X <- NotAllocatable] ++ Cols,
- ?ASSERT(check_coloring(Coloring, IG, Target)),
-
- {Coloring, NewSpillIndex}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** BUILD THE INTERFERENCE GRAPH ***
-%%
-%% Returns {Interference_graph, Spill_cost_dictionary}
-%%
-
-build_ig(CFG, Live, Target) ->
- NumN = number_of_temporaries(CFG, Target), % poss. N-1?
- {IG, Spill} = build_ig_bbs(labels(CFG, Target),
- CFG,
- Live,
- empty_ig(NumN),
- empty_spill(NumN),
- Target),
- {normalize_ig(IG), Spill}.
-
-build_ig_bbs([], _CFG, _Live, IG, Spill, _Target) ->
- {IG, Spill};
-build_ig_bbs([L|Ls], CFG, Live, IG, Spill, Target) ->
- Xs = bb(CFG, L, Target),
- {_, NewIG, NewSpill} =
- build_ig_bb(Xs, liveout(Live, L, Target), IG, Spill, Target),
- build_ig_bbs(Ls, CFG, Live, NewIG, NewSpill, Target).
-
-build_ig_bb([], LiveOut, IG, Spill, _Target) ->
- {LiveOut, IG, Spill};
-build_ig_bb([X|Xs], LiveOut, IG, Spill, Target) ->
- {Live,NewIG,NewSpill} = build_ig_bb(Xs, LiveOut, IG, Spill, Target),
- build_ig_instr(X, Live, NewIG, NewSpill, Target).
-
-%% Note: We could add move-related arcs here as well.
-%%
-%% Note: Ideally, we would like to add all registers to the IG
-%% at once rather than doing 'add_nodes' for each instruction.
-%% (This is costly, since nodes that already are present are checked!)
-
-build_ig_instr(X, Live, IG, Spill, Target) ->
- {Def, Use} = def_use(X, Target),
- ?report3("Live ~w\n~w : Def: ~w Use ~w\n", [Live, X, Def,Use]),
- DefList = ordsets:to_list(Def),
- NewSpill = inc_spill_costs(DefList,
- inc_spill_costs(ordsets:to_list(Use), Spill)),
- NewIG = interference_arcs(DefList, ordsets:to_list(Live), IG),
- NewLive = ordsets:union(Use, ordsets:subtract(Live, Def)),
- {NewLive, NewIG, NewSpill}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-interference_arcs([], _Live, IG) ->
- IG;
-interference_arcs([X|Xs], Live, IG) ->
- interference_arcs(Xs, Live, i_arcs(X, Live, IG)).
-
-i_arcs(_X, [], IG) ->
- IG;
-i_arcs(X, [Y|Ys], IG) ->
- i_arcs(X, Ys, add_edge(X,Y, IG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-inc_spill_costs([], Spill) -> Spill;
-inc_spill_costs([X|Xs], Spill) ->
- inc_spill_costs(Xs, inc_spill_cost(X, Spill)).
-
-inc_spill_cost(X, Spill) ->
- set_spill_cost(X, get_spill_cost(X, Spill)+1, Spill).
-
-get_spill_cost(X, Spill) ->
- spill_cost_lookup(X, Spill).
-
-set_spill_cost(X, N, Spill) ->
- spill_cost_update(X, N, Spill).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** COLORING ***
-%%
-%% Coloring is done straightforwardly:
-%% - find the low-degree nodes, put them in low
-%% - while low non-empty:
-%% * remove x from low
-%% * push x on stack
-%% * decrement degree of neighbors of x
-%% * for each neighbor y of low degree, put y on low
-%% - when low empty:
-%% - if graph empty, return stack
-%% - otherwise
-%% * select a node z to spill
-%% * push z on stack
-%% * decrement degree of neighbors of z
-%% * add low-degree neighbors of z to low
-%% * restart the while-loop above
-
-color(IG, Spill, PhysRegs, SpillIx, SpillLimit, NumNodes, Target,
- NotAllocatable) ->
- ?report("simplification of IG~n", []),
- K = ordsets:size(PhysRegs),
- Nodes = list_ig(IG),
-
- Low = low_degree_nodes(Nodes, K, NotAllocatable),
-
- %% Any nodes above the spillimit must be colored first...
- MustNotSpill =
- if NumNodes > SpillLimit ->
- sort_on_degree(lists:seq(SpillLimit,NumNodes-1) -- Low,IG);
- true -> []
- end,
-
- ?report(" starting with low degree nodes ~p~n",[Low]),
- EmptyStk = [],
- Precolored = all_precoloured(Target),
- {Stk, NewSpillIx} =
- simplify(Low, NumNodes, Precolored,
- IG, Spill, K, SpillIx, EmptyStk,
- SpillLimit, Target, NotAllocatable, MustNotSpill),
- ?report("selecting colors~n",[]),
- {select(Stk, Precolored, IG, K, PhysRegs, NumNodes, Target),
- NewSpillIx}.
-
-sort_on_degree(Nodes, IG) ->
- [ Node3 || {_,Node3} <-
- lists:sort([{degree(Info),Node2} ||
- {Info,Node2} <- [{hipe_vectors:get(IG, Node),
- Node} || Node <-
- Nodes]])].
-
-%%%%%%%%%%%%%%%%%%%%
-%%
-%% Simplification: push all easily colored nodes on a stack;
-%% when the list of easy nodes becomes empty, see if graph is
-%% empty as well. If it is not, spill a node and continue.
-%% If it is empty, return the stack.
-%%
-%% Notes:
-%% - We keep the set of visited nodes around for spill purposes
-%% (visited nodes are not considered for spilling)
-%%
-%% - At present, nodes can be pushed onto the stack even if they
-%% already are on the stack. This can be fixed by another 'Vis'
-%% dictionary that keeps track of what is on the stack.
-%% Currently, we just skip already colored nodes.
-%%
-%% - Arguments:
-%% Low: low-degree nodes (ready to color)
-%% NumNodes: number of remaining nodes in graph
-%% IG: interference graph
-%% Spill: spill costs of nodes
-%% K: number of colors
-%% Ix: next spill index
-%% Stk: stack of already simplified nodes
-%%
-%% Physical registers are marked as 'visited' prior to simplify.
-%% This has the following effect:
-%% - they are not considered for spilling
-%% - they are not pushed on the stack
-%% - since we do NOT decrement degrees of surrounding vars, the
-%% non-physreg variables must still take them into account.
-
-simplify(Low, NumNodes, PreC, IG, Spill, K, Ix, Stk, SpillLimit,
- Target, NotAllocatable, MustNotSpill) ->
- Vis = visit_all(PreC, none_visited(NumNodes)),
- Vis1 = visit_all(NotAllocatable, Vis),
- ActualNumNodes = (NumNodes-length(PreC))-length(NotAllocatable),
- %% Make sure that the registers that must not be spilled
- %% get a degree less than K by spilling other regs.
- {Stk2, Ix2, Vis2, Low2} =
- handle_non_spill(MustNotSpill, IG, Spill, K, Ix, Stk, Vis1, Low,
- SpillLimit, Target),
- simplify_ig(Low2, ActualNumNodes-length(Stk2), IG, Spill, K, Ix2, Stk2, Vis2,
- SpillLimit, Target).
-
-handle_non_spill([], _IG, _Spill, _K, Ix, Stk, Vis, Low, _SpillLimit, _Target) ->
- {Stk, Ix, Vis, Low};
-handle_non_spill([X|Xs] = L, IG, Spill, K, Ix, Stk, Vis, Low, SpillLimit, Target) ->
- Info = hipe_vectors:get(IG, X),
- Degree = degree(Info),
- ?report("Can't Spill ~w with degree ~w\n", [X,Degree]),
- if Degree > K ->
- ?report(" *** spill required (N<~w)***~n", [SpillLimit]),
- {Y, NewLow, NewIG} = spill(IG, Vis, Spill, K, SpillLimit, Target),
- NewVis = visit(Y,Vis),
- {NewStk, NewIx} = push_spill_node(Y, Ix, Stk),
- ?report(" node ~w spilled~n", [Y]),
- handle_non_spill(L, NewIG, Spill, K, NewIx, NewStk, NewVis,
- Low ++ NewLow, SpillLimit, Target);
- true ->
- {NewLow, NewIG} = decrement_neighbors(X, Low, IG, Vis, K),
- ?report(" node ~w pushed\n(~w now ready)~n", [X,NewLow]),
- NewStk = push_colored(X, Stk),
- handle_non_spill(Xs, NewIG, Spill, K, Ix, NewStk, visit(X,Vis),
- NewLow, SpillLimit, Target)
- end.
-
-simplify_ig([], 0, _IG, _Spill, _K, Ix, Stk, _Vis, _SpillLimit, _Target) ->
- {Stk, Ix};
-simplify_ig([], N, IG, Spill, K, Ix, Stk, Vis, SpillLimit, Target)
- when N > 0 ->
- ?report3("N: ~w Stk: ~w N+Stk ~w\n", [N,length(Stk),N+length(Stk)]),
- ?report(" *** spill required (N<~w)***~n", [SpillLimit]),
- {X, Low, NewIG} = spill(IG, Vis, Spill, K, SpillLimit, Target),
- NewVis = visit(X,Vis),
- {NewStk, NewIx} = push_spill_node(X, Ix, Stk),
- ?report(" node ~w spilled\n(~w now ready)~n", [X, Low]),
- simplify_ig(Low, N-1, NewIG, Spill, K, NewIx, NewStk, NewVis,
- SpillLimit, Target);
-simplify_ig([X|Xs], N, IG, Spill, K, Ix, Stk, Vis, SpillLimit, Target) ->
- ?report3("N: ~w Stk: ~w N+Stk ~w\n", [N,length(Stk),N+length(Stk)]),
- case is_visited(X,Vis) of
- true ->
- ?report(" node ~p already visited~n",[X]),
- simplify_ig(Xs, N, IG, Spill, K, Ix, Stk, Vis, SpillLimit, Target);
- false ->
- ?report("Stack ~w\n", [Stk]),
- {NewLow, NewIG} = decrement_neighbors(X, Xs, IG, Vis, K),
- ?report(" node ~w pushed\n(~w now ready)~n", [X,NewLow]),
- NewStk = push_colored(X, Stk),
- simplify_ig(NewLow, N-1, NewIG, Spill, K, Ix, NewStk, visit(X,Vis),
- SpillLimit, Target)
- end.
-
-%% Returns { NowLowDegreeNeighbors, NewIG }
-
-decrement_neighbors(X, Xs, IG, Vis, K) ->
- Ns = unvisited_neighbors(X, Vis, IG),
- ?report(" node ~p has neighbors ~w\n(unvisited ~p)~n",
- [X, neighbors(X, IG), Ns]),
- decrement_each(Ns, Xs, IG, Vis, K).
-
-%% For each node, decrement its degree and check if it is now
-%% a low-degree node. In that case, add it to the 'low list'.
-
-decrement_each([], Low, IG, _Vis, _K) ->
- {Low, IG};
-decrement_each([N|Ns], OldLow, IG, Vis, K) ->
- {Low, CurrIG} = Res = decrement_each(Ns, OldLow, IG, Vis, K),
- case is_visited(N, Vis) of
- true ->
- Res;
- false ->
- {D, NewIG} = decrement_degree(N, CurrIG),
- if
- D =:= K-1 ->
- {[N|Low], NewIG};
- true ->
- {Low, NewIG}
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%
-%%
-%% The spill cost of a node is:
-%% est_spill_cost / current_degree
-%%
-%% For all unvisited nodes, compute spill cost and select the minimum.
-%% This node is chosen to be spilled. Then decrement the degree of its
-%% neighbors, and return those of low degree.
-%%
-%% Notes:
-%% - A better method for computing spill costs is to just keep the
-%% minimum cost node. But for debugging purposes, we compute a list
-%% of {node,spillcost} pairs and select the minimum.
-%%
-%% Returns:
-%% {Spilled_node, Low_degree_neighbors, New_interference_graph}
-
-spill(IG, Vis, Spill, K, SpillLimit, Target) ->
- Ns = list_ig(IG),
- Costs = spill_costs(Ns, IG, Vis, Spill, SpillLimit, Target),
- ?report3("spill costs are ~p~n", [Costs]),
- ActualCosts = lists:sort(Costs),
- ?report3("actual costs are ~p~n", [ActualCosts]),
- case ActualCosts of
- [] ->
- ?error_msg("There is no node to spill", []),
- ?EXIT('no node to spill');
- [{_Cost,N}|_] ->
- {Low, NewIG} = decrement_neighbors(N, [], IG, Vis, K),
- %% ?report("spilled node ~p at cost ~p (~p now ready)~n", [N,Cost,Low]),
- {N, Low, NewIG}
- end.
-
-spill_costs([], _IG, _Vis, _Spill, _SpillLimit, _Target) ->
- [];
-spill_costs([{N,Info}|Ns], IG, Vis, Spill, SpillLimit, Target) ->
- case degree(Info) of
- 0 -> spill_costs(Ns,IG,Vis,Spill, SpillLimit, Target);
- Deg ->
- case is_visited(N,Vis) of
- true ->
- spill_costs(Ns,IG,Vis,Spill, SpillLimit, Target);
- _ ->
- case is_fixed(N, Target) of
- true ->
- spill_costs(Ns, IG, Vis, Spill, SpillLimit, Target);
- false ->
- if N >= SpillLimit ->
- spill_costs(Ns, IG, Vis, Spill, SpillLimit, Target);
- true ->
- [{spill_cost_of(N,Spill)/Deg,N} |
- spill_costs(Ns,IG, Vis, Spill, SpillLimit, Target)]
- end
- end
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%
-%%
-%% Returns a list of {Name,Location}, where Location is
-%% either {spill,M} or {reg,R}
-%%
-%% Note: we use pessimistic coloring here.
-%% - we could use optimistic coloring: for spilled node, check if there is
-%% an unused color among the neighbors and choose that.
-
-select(Stk, PreC, IG, K, PhysRegs, NumNodes, Target) ->
- %% NumNodes = length(Stk)+length(PreC),
- {PhysColors, Cols} = precolor(PreC, none_colored(NumNodes), Target),
- ?report("precoloring has yielded ~p~n",[list_coloring(Cols)]),
- PhysColors ++ select_colors(Stk, IG, Cols, PhysRegs, K).
-
-select_colors([], _IG, _Cols, _PhysRegs, _K) ->
- ?report("all nodes colored~n",[]),
- [];
-select_colors([{X,colorable}|Xs], IG, Cols, PhysRegs, K) ->
- ?report("color of ~p\n",[X]),
- {Reg,NewCols} = select_color(X, IG, Cols, PhysRegs),
- ?report("~p~n",[Reg]),
- [{X,{reg,Reg}} | select_colors(Xs, IG, NewCols, PhysRegs, K)];
-%%select_colors([{X,{spill,M}}|Xs], IG, Cols, PhysRegs, K) ->
-%% ?report('spilled: ~p~n',[X]),
-%% %% Check if optimistic coloring could have found a color
-%% case catch select_color(X,IG,Cols,K) of
-%% {'EXIT',_} -> % no color possible
-%% ?report('(no optimistic color)~n',[]),
-%% [{X,{spill,M}}|select_colors(Xs, IG, Cols, PhysRegs, K)];
-%% {Reg,NewCols} ->
-%% ?report('(optimistic color: ~p)~n',[Reg]),
-%% [{X,{reg,Reg}}|select_colors(Xs, IG, Cols, PhysRegs, K)]
-%% end.
-
-%% Old code / pessimistic coloring:
-select_colors([{X,{spill,M}}|Xs], IG, Cols, PhysRegs, K) ->
- ?report("spilled: ~p~n",[X]),
- %% Check if optimistic coloring could have found a color
-%% case catch select_color(X,IG,Cols,K) of
-%% {'EXIT',_} -> % no color possible
-%% ?report('(no optimistic color)~n',[]);
-%% {Reg,NewCols} ->
-%% ?report('(optimistic color: ~p)~n',[Reg])
-%% end,
- [{X,{spill,M}} | select_colors(Xs, IG, Cols, PhysRegs, K)].
-
-select_color(X, IG, Cols, PhysRegs) ->
- UsedColors = get_colors(neighbors(X, IG), Cols),
- Reg = select_unused_color(UsedColors, PhysRegs),
- {Reg, set_color(X, Reg, Cols)}.
-
-%%%%%%%%%%%%%%%%%%%%
-
-get_colors([], _Cols) -> [];
-get_colors([X|Xs], Cols) ->
- case color_of(X, Cols) of
- uncolored ->
- get_colors(Xs, Cols);
- {color,R} ->
- [R|get_colors(Xs, Cols)]
- end.
-
-select_unused_color(UsedColors, PhysRegs) ->
- Summary = ordsets:from_list(UsedColors),
- AvailRegs = ordsets:to_list(ordsets:subtract(PhysRegs, Summary)),
- hd(AvailRegs).
- %% select_avail_reg(AvailRegs).
-
-%% We choose the register to use randomly from the set of available
-%% registers.
-%%
-%% Note: Another way of doing it is LRU-order:
-%% - Have an LRU-queue of register names; when coloring, try the colors in that
-%% order (some may be occupied).
-%% - When a color has been selected, put it at the end of the LRU.
-
-%% select_avail_reg(Regs) ->
-%% case get(seeded) of
-%% undefined ->
-%% random:seed(),
-%% put(seeded,true);
-%% true ->
-%% ok
-%% end,
-%% NReg = length(Regs),
-%% RegNo = random:uniform(NReg),
-%% lists:nth(RegNo, Regs).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-push_spill_node(X, M, Stk) ->
- {[{X,{spill,M}}|Stk], M+1}.
-
-push_colored(X, Stk) ->
- [{X, colorable} | Stk].
-
-%%%%%%%%%%%%%%%%%%%%
-
-low_degree_nodes([], _K, _NotAllocatable) -> [];
-low_degree_nodes([{N,Info}|Xs], K, NotAllocatable) ->
- case lists:member(N, NotAllocatable) of
- true ->
- low_degree_nodes(Xs,K, NotAllocatable);
- false ->
- ?report0("node ~p has degree ~p: ~w~n",[N,degree(Info),neighbors(Info)]),
- Deg = degree(Info),
- if
- Deg < K ->
- [N|low_degree_nodes(Xs, K, NotAllocatable)];
- true ->
- low_degree_nodes(Xs, K, NotAllocatable)
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%
-
-unvisited_neighbors(X, Vis, IG) ->
- ordsets:from_list(unvisited(neighbors(X,IG), Vis)).
-
-unvisited([], _Vis) -> [];
-unvisited([X|Xs], Vis) ->
- case is_visited(X, Vis) of
- true ->
- unvisited(Xs, Vis);
- false ->
- [X|unvisited(Xs, Vis)]
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** ABSTRACT DATATYPES ***
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The ig datatype:
-%%
-%% Note: if we know the number of temps used, we can use a VECTOR
-%% instead, which will speed up things.
-%%
-%% Note: later on, we may wish to add 'move-related' support.
-
--record(ig_info, {neighbors=[], degree=0 :: integer()}).
-
-empty_ig(NumNodes) ->
- hipe_vectors:new(NumNodes, #ig_info{neighbors=[], degree=0}).
-
-degree(Info) ->
- Info#ig_info.degree.
-
-neighbors(Info) ->
- Info#ig_info.neighbors.
-
-add_edge(X, X, IG) -> IG;
-add_edge(X, Y, IG) ->
- add_arc(X, Y, add_arc(Y, X, IG)).
-
-add_arc(X, Y, IG) ->
- Info = hipe_vectors:get(IG, X),
- Old = neighbors(Info),
- New = Info#ig_info{neighbors=[Y|Old]},
- hipe_vectors:set(IG, X, New).
-
-normalize_ig(IG) ->
- Size = hipe_vectors:size(IG),
- normalize_ig(Size-1, IG).
-
-normalize_ig(-1, IG) ->
- IG;
-normalize_ig(I, IG) ->
- Info = hipe_vectors:get(IG, I),
- N = ordsets:from_list(neighbors(Info)),
- NewIG = hipe_vectors:set(IG, I, Info#ig_info{neighbors=N, degree=length(N)}),
- normalize_ig(I-1, NewIG).
-
-%%degree(X, IG) ->
-%% Info = hipe_vectors:get(IG, X),
-%% Info#ig_info.degree.
-
-neighbors(X, IG) ->
- Info = hipe_vectors:get(IG, X),
- Info#ig_info.neighbors.
-
-decrement_degree(X, IG) ->
- Info = hipe_vectors:get(IG, X),
- Degree = degree(Info),
- NewDegree = Degree-1,
- NewInfo = Info#ig_info{degree=NewDegree},
- {NewDegree, hipe_vectors:set(IG,X,NewInfo)}.
-
-list_ig(IG) ->
- hipe_vectors:list(IG).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The spill cost datatype:
-%%
-%% Note: if we know the number of temps used, we can use a VECTOR
-%% instead, which will speed up things.
-
-empty_spill(NumNodes) ->
- hipe_vectors:new(NumNodes, 0).
-
-spill_cost_of(X, Spill) ->
- hipe_vectors:get(Spill, X).
-
-spill_cost_lookup(X, Spill) ->
- spill_cost_of(X, Spill).
-
-spill_cost_update(X, N, Spill) ->
- hipe_vectors:set(Spill, X, N).
-
-%%list_spill_costs(Spill) ->
-%% hipe_vectors:list(Spill).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The coloring datatype:
-
-none_colored(NumNodes) ->
- hipe_vectors:new(NumNodes,uncolored).
-
-color_of(X,Cols) ->
- hipe_vectors:get(Cols,X).
-
-set_color(X,R,Cols) ->
- hipe_vectors:set(Cols,X,{color,R}).
-
--ifdef(DEBUG).
-list_coloring(Cols) ->
- hipe_vectors:list(Cols).
--endif.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Note: there might be a slight gain in separating the two versions
-%% of visit/2 and visited/2. (So that {var,X} selects X and calls the
-%% integer version.
-
-none_visited(NumNodes) ->
- hipe_vectors:new(NumNodes, false).
-
-visit(X,Vis) ->
- hipe_vectors:set(Vis, X, true).
-
-is_visited(X,Vis) ->
- hipe_vectors:get(Vis, X).
-
-visit_all([], Vis) -> Vis;
-visit_all([X|Xs], Vis) ->
- visit_all(Xs, visit(X, Vis)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Check that all arcs in IG are bidirectional + degree is correct
-
-%% check_ig(IG) ->
-%% check_ig(list_ig(IG),IG).
-
-%% check_ig([],IG) ->
-%% ok;
-%% check_ig([{N,Info}|Xs],IG) ->
-%% Ns = neighbors(Info),
-%% NumNs = length(Ns),
-%% D = degree(Info),
-%% if
-%% D =:= NumNs ->
-%% ok;
-%% true ->
-%% ?WARNING_MSG('node ~p has degree ~p but ~p neighbors~n',[N,D,NumNs])
-%% end,
-%% check_neighbors(N,Ns,IG),
-%% check_ig(Xs,IG).
-
-%% check_neighbors(N,[],IG) ->
-%% ok;
-%% check_neighbors(N,[M|Ms],IG) ->
-%% Ns = neighbors(M,IG),
-%% case member(N,Ns) of
-%% true ->
-%% ok;
-%% true ->
-%% ?WARNING_MSG('node ~p should have ~p as neighbor (has ~p)~n',[M,N,Ns])
-%% end,
-%% check_neighbors(N,Ms,IG).
-
--ifdef(DO_ASSERT).
-%%%%%%%%%%%%%%%%%%%%
-%% Check that the coloring is correct (if the IG is correct):
-%%
-
-check_coloring(Coloring, IG, Target) ->
- ?report0("checking coloring ~p~n",[Coloring]),
- check_cols(list_ig(IG),init_coloring(Coloring, Target)).
-
-init_coloring(Xs, Target) ->
- hipe_temp_map:cols2tuple(Xs, Target).
-
-check_color_of(X, Cols) ->
-%% if
-%% is_precoloured(X) ->
-%% phys_reg_color(X,Cols);
-%% true ->
- case hipe_temp_map:find(X, Cols) of
- unknown ->
- ?WARNING_MSG("node ~p: color not found~n", [X]),
- uncolored;
- C ->
- C
- end.
-
-check_cols([], Cols) ->
- ?report("coloring valid~n",[]),
- true;
-check_cols([{X,Info}|Xs], Cols) ->
- Cs = [{N, check_color_of(N, Cols)} || N <- neighbors(Info)],
- C = check_color_of(X, Cols),
- case valid_coloring(X, C, Cs) of
- yes ->
- check_cols(Xs, Cols);
- {no,Invalids} ->
- ?WARNING_MSG("node ~p has same color (~p) as ~p~n", [X,C,Invalids]),
- check_cols(Xs, Cols)
- end.
-
-valid_coloring(X, C, []) ->
- yes;
-valid_coloring(X, C, [{Y,C}|Ys]) ->
- case valid_coloring(X, C, Ys) of
- yes -> {no, [Y]};
- {no,Zs} -> {no, [Y|Zs]}
- end;
-valid_coloring(X, C, [_|Ys]) ->
- valid_coloring(X, C, Ys).
--endif.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% *** INTERFACES TO OTHER MODULES ***
-%%
-
-all_precoloured({TgtMod,TgtCtx}) ->
- TgtMod:all_precoloured(TgtCtx).
-
-allocatable({TgtMod,TgtCtx}) ->
- TgtMod:allocatable(TgtCtx).
-
-is_fixed(Reg, {TgtMod,TgtCtx}) ->
- TgtMod:is_fixed(Reg, TgtCtx).
-
-labels(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:labels(CFG, TgtCtx).
-
-liveout(CFG, L, Target={TgtMod,TgtCtx}) ->
- ordsets:from_list(reg_names(TgtMod:liveout(CFG, L, TgtCtx), Target)).
-
-bb(CFG, L, {TgtMod,TgtCtx}) ->
- hipe_bb:code(TgtMod:bb(CFG, L, TgtCtx)).
-
-def_use(X, Target={TgtMod,TgtCtx}) ->
- {ordsets:from_list(reg_names(TgtMod:defines(X,TgtCtx), Target)),
- ordsets:from_list(reg_names(TgtMod:uses(X,TgtCtx), Target))}.
-
-non_alloc(CFG, Target={TgtMod,TgtCtx}) ->
- reg_names(TgtMod:non_alloc(CFG, TgtCtx), Target).
-
-number_of_temporaries(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:number_of_temporaries(CFG, TgtCtx).
-
-reg_names(Regs, {TgtMod,TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
-%%
-%% Precoloring: use this version when a proper implementation of
-%% physical_name(X) is available!
-%%
-
-precolor(Xs, Cols, Target) ->
- ?report("precoloring ~p~n", [Xs]),
- {_Cs, _NewCol} = Res = precolor0(Xs, Cols, Target),
- ?report(" yielded ~p~n", [_Cs]),
- Res.
-
-precolor0([], Cols, _Target) ->
- {[], Cols};
-precolor0([R|Rs], Cols, Target) ->
- {Cs, Cols1} = precolor0(Rs, Cols, Target),
- {[{R, {reg, physical_name(R, Target)}}|Cs],
- set_color(R, physical_name(R, Target), Cols1)}.
-
-physical_name(X, {TgtMod,TgtCtx}) ->
- TgtMod:physical_name(X, TgtCtx).
diff --git a/lib/hipe/regalloc/hipe_ig.erl b/lib/hipe/regalloc/hipe_ig.erl
deleted file mode 100644
index 14a1ae77f2..0000000000
--- a/lib/hipe/regalloc/hipe_ig.erl
+++ /dev/null
@@ -1,806 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_ig.erl
-%% Author : Andreas Wallin <d96awa@csd.uu.se>
-%% Purpose : Creates an interference graph that tells which temporaries
-%% interfere with each other.
-%% Created : 5 Feb 2000
-%%----------------------------------------------------------------------
-
--module(hipe_ig).
-
--export([build/4,
- nodes_are_adjacent/3,
- node_spill_cost/2,
- node_adj_list/2,
- get_moves/1,
- %% degree/1,
- %% number_of_temps/1,
- spill_costs/1,
- adj_list/1,
- %% adj_set/1,
- add_edge/5,
- remove_edge/5,
- %% set_adj_set/2,
- %% set_adj_list/2,
- %% set_ig_moves/2,
- %% set_spill_costs/2,
- %% set_degree/2
- get_node_degree/2,
- dec_node_degree/2,
- is_trivially_colourable/3
- ]).
--ifdef(DEBUG_PRINTOUTS).
--export([print_spill_costs/1,
- print_adjacent/1,
- print_degrees/1
- ]).
--endif.
-
-%%-ifndef(DEBUG).
-%%-define(DEBUG,true).
-%%-endif.
-
--include("../main/hipe.hrl").
--include("../flow/cfg.hrl").
--include("hipe_spillcost.hrl").
-
--type target_context() :: any().
--type target() :: {TargetMod :: module(), TargetContext :: target_context()}.
-
-%%----------------------------------------------------------------------
-
--record(igraph, {adj_set, adj_list, ig_moves, degree,
- spill_costs :: #spill_cost{},
- num_temps :: non_neg_integer()}).
-
-%%----------------------------------------------------------------------
-%% Degree: array mapping nodes to integer degrees.
-%% Precoloured nodes have 'infinite' degrees: they are initialised with
-%% degrees K + number_of_temporaries.
-%% Operations include incrementing, decrementing, and querying a node's
-%% degree, and testing for trivial colourability (degree < K).
-%%----------------------------------------------------------------------
-
-degree_new(No_temporaries, {TargetMod, TargetCtx}) ->
- Degree = hipe_bifs:array(No_temporaries, 0),
- K = length(TargetMod:allocatable(TargetCtx)),
- Inf = K + No_temporaries,
- precoloured_to_inf_degree(TargetMod:all_precoloured(TargetCtx), Inf, Degree).
-
-precoloured_to_inf_degree([], _Inf, Degree) -> Degree;
-precoloured_to_inf_degree([P|Ps], Inf, Degree) ->
- hipe_bifs:array_update(Degree, P, Inf),
- precoloured_to_inf_degree(Ps, Inf, Degree).
-
-degree_inc(Node, Degree) ->
- hipe_bifs:array_update(Degree, Node, hipe_bifs:array_sub(Degree, Node) + 1).
-
-degree_dec(Node, Degree) ->
- hipe_bifs:array_update(Degree, Node, hipe_bifs:array_sub(Degree, Node) - 1).
-
-degree_get(Node, Degree) ->
- hipe_bifs:array_sub(Degree, Node).
-
-degree_is_trivially_colourable(Node, K, Degree) ->
- hipe_bifs:array_sub(Degree, Node) < K.
-
-%%----------------------------------------------------------------------
-%% AdjSet:
-%% Implements sets of adjacent nodes.
-%% Symmetry implies that when (U,V) is a member, then so is (V,U).
-%% Hence, only (U,V), where U<V, is actually stored.
-%% Supports queries and destructive updates, but not enumeration.
-%% Implemented as a bit array in an array of bytes, augmented by an
-%% index vector for fast address calculations.
-%%----------------------------------------------------------------------
-
--define(USE_NEW_BITARRAY_BIFS, true).
-%%-define(EMULATE_BITARRAY_BIFS, true).
-
--ifdef(USE_NEW_BITARRAY_BIFS).
--define(HIPE_BIFS_BITARRAY(ArrayBits, Val), hipe_bifs:bitarray(ArrayBits, Val)).
--define(HIPE_BIFS_BITARRAY_UPDATE(Array, BitNr, Val), hipe_bifs:bitarray_update(Array, BitNr, Val)).
--define(HIPE_BIFS_BITARRAY_SUB(Array, BitNr), hipe_bifs:bitarray_sub(Array, BitNr)).
--endif.
-
--ifdef(EMULATE_BITARRAY_BIFS).
-
--define(LOG2_BITS_PER_WORD, 3).
--define(BITS_PER_WORD, (1 bsl ?LOG2_BITS_PER_WORD)).
-
-hipe_bifs_bitarray(ArrayBits, Val) ->
- ArrayWords = (ArrayBits + (?BITS_PER_WORD - 1)) bsr ?LOG2_BITS_PER_WORD,
- Byte =
- case Val of
- true -> 16#FF;
- false -> 16#00
- end,
- hipe_bifs:bytearray(ArrayWords, Byte).
-
-hipe_bifs_bitarray_update(Array, BitNr, Val) ->
- WordNr = BitNr bsr ?LOG2_BITS_PER_WORD,
- WordMask = 1 bsl (BitNr band (?BITS_PER_WORD - 1)),
- Word = hipe_bifs:bytearray_sub(Array, WordNr),
- NewWord =
- case Val of
- true -> Word bor WordMask;
- false -> Word band (bnot WordMask)
- end,
- hipe_bifs:bytearray_update(Array, WordNr, NewWord).
-
-hipe_bifs_bitarray_sub(Array, BitNr) ->
- WordNr = BitNr bsr ?LOG2_BITS_PER_WORD,
- WordMask = 1 bsl (BitNr band (?BITS_PER_WORD - 1)),
- Word = hipe_bifs:bytearray_sub(Array, WordNr),
- Word band WordMask =/= 0.
-
--define(HIPE_BIFS_BITARRAY(ArrayBits, Val), hipe_bifs_bitarray(ArrayBits, Val)).
--define(HIPE_BIFS_BITARRAY_UPDATE(Array, BitNr, Val), hipe_bifs_bitarray_update(Array, BitNr, Val)).
--define(HIPE_BIFS_BITARRAY_SUB(Array, BitNr), hipe_bifs_bitarray_sub(Array, BitNr)).
-
--endif. % EMULATE_BITARRAY_BIFS
-
--record(adjset, {index, array}).
--record(adjset_chunked, {index, chunks}).
-
--spec adjset_new(non_neg_integer()) -> #adjset{} | #adjset_chunked{}.
-
-adjset_new(NrTemps) ->
- ArrayBits = (NrTemps * (NrTemps - 1)) div 2,
- Index = adjset_mk_index(NrTemps, []),
- try ?HIPE_BIFS_BITARRAY(ArrayBits, false) of
- Array ->
- #adjset{index=Index,array=Array}
- catch
- _:_ ->
- #adjset_chunked{index=Index,chunks=adjset_mk_chunks(ArrayBits)}
- end.
-
--define(LOG2_CHUNK_BITS, 19). % 2^19 bits == 64KB
--define(CHUNK_BITS, (1 bsl ?LOG2_CHUNK_BITS)).
-
-adjset_mk_chunks(ArrayBits) ->
- Tail =
- case ArrayBits band (?CHUNK_BITS - 1) of
- 0 -> [];
- LastChunkBits -> [?HIPE_BIFS_BITARRAY(LastChunkBits, false)]
- end,
- N = ArrayBits bsr ?LOG2_CHUNK_BITS,
- adjset_mk_chunks(N, Tail).
-
-adjset_mk_chunks(0, Tail) ->
- list_to_tuple(Tail);
-adjset_mk_chunks(N, Tail) ->
- adjset_mk_chunks(N-1, [?HIPE_BIFS_BITARRAY(?CHUNK_BITS, false) | Tail]).
-
-adjset_mk_index(0, Tail) ->
- list_to_tuple(Tail);
-adjset_mk_index(N, Tail) ->
- I = N - 1,
- adjset_mk_index(I, [(I * (I-1)) div 2 | Tail]).
-
-adjset_add_edge(U0, V0, #adjset{index=Index,array=Array}) -> % PRE: U0 =/= V0
- {U,V} =
- if U0 < V0 -> {U0,V0};
- true -> {V0,U0}
- end,
- %% INV: U < V
- BitNr = element(V+1, Index) + U,
- ?HIPE_BIFS_BITARRAY_UPDATE(Array, BitNr, true);
-adjset_add_edge(U0, V0, #adjset_chunked{index=Index,chunks=Chunks}) -> % PRE: U0 =/= V0
- {U,V} =
- if U0 < V0 -> {U0,V0};
- true -> {V0,U0}
- end,
- %% INV: U < V
- BitNr = element(V+1, Index) + U,
- %% here things become different
- ChunkNr = BitNr bsr ?LOG2_CHUNK_BITS,
- ChunkBit = BitNr band (?CHUNK_BITS - 1),
- Chunk = element(ChunkNr+1, Chunks),
- ?HIPE_BIFS_BITARRAY_UPDATE(Chunk, ChunkBit, true).
-
-adjset_remove_edge(U0, V0, #adjset{index=Index,array=Array}) -> % PRE: U0 =/= V0
- {U,V} =
- if U0 < V0 -> {U0,V0};
- true -> {V0,U0}
- end,
- %% INV: U < V
- BitNr = element(V+1, Index) + U,
- ?HIPE_BIFS_BITARRAY_UPDATE(Array, BitNr, false);
-adjset_remove_edge(U0, V0, #adjset_chunked{index=Index,chunks=Chunks}) -> % PRE: U0 =/= V0
- {U,V} =
- if U0 < V0 -> {U0,V0};
- true -> {V0,U0}
- end,
- %% INV: U < V
- BitNr = element(V+1, Index) + U,
- %% here things become different
- ChunkNr = BitNr bsr ?LOG2_CHUNK_BITS,
- ChunkBit = BitNr band (?CHUNK_BITS - 1),
- Chunk = element(ChunkNr+1, Chunks),
- ?HIPE_BIFS_BITARRAY_UPDATE(Chunk, ChunkBit, false).
-
-adjset_are_adjacent(U0, V0, #adjset{index=Index,array=Array}) ->
- {U,V} =
- if U0 < V0 -> {U0,V0};
- U0 =:= V0 -> exit({?MODULE,adjacent,U0,V0}); % XXX: probably impossible
- true -> {V0,U0}
- end,
- %% INV: U < V
- BitNr = element(V+1, Index) + U,
- ?HIPE_BIFS_BITARRAY_SUB(Array, BitNr);
-adjset_are_adjacent(U0, V0, #adjset_chunked{index=Index,chunks=Chunks}) ->
- {U,V} =
- if U0 < V0 -> {U0,V0};
- U0 =:= V0 -> exit({?MODULE,adjacent,U0,V0}); % XXX: probably impossible
- true -> {V0,U0}
- end,
- %% INV: U < V
- BitNr = element(V+1, Index) + U,
- %% here things become different
- ChunkNr = BitNr bsr ?LOG2_CHUNK_BITS,
- ChunkBit = BitNr band (?CHUNK_BITS - 1),
- Chunk = element(ChunkNr+1, Chunks),
- ?HIPE_BIFS_BITARRAY_SUB(Chunk, ChunkBit).
-
-%%---------------------------------------------------------------------
-%% Print functions - only used for debugging
-
--ifdef(DEBUG_PRINTOUTS).
-print_adjacent(IG) ->
- ?debug_msg("Adjacent nodes:\n", []),
- adjset_print(number_of_temps(IG),IG).
-
-adjset_print(2, IG) ->
- adjset_print(1, 0, IG);
-adjset_print(Ntemps, IG) ->
- adjset_print(Ntemps - 1, Ntemps - 2, IG),
- adjset_print(Ntemps - 1, IG).
-
-adjset_print(U, 0, IG) ->
- case nodes_are_adjacent(U, 0, IG) of
- true -> ?debug_msg("edge ~w ~w\n", [U, 0]);
- _ -> true
- end;
-adjset_print(U, V, IG) ->
- case nodes_are_adjacent(U, V, IG) of
- true -> ?debug_msg("edge ~w ~w\n", [U, V]);
- _ -> true
- end,
- adjset_print(U, V - 1, IG).
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: adj_set, adj_list, degree, spill_costs
-%%
-%% Description: Selector functions. Used to get one of the encapsulated
-%% data-structure contained in the IG structure.
-%% Parameters:
-%% IG -- An interference graph
-%%
-%% Returns:
-%% One of the encapsulated data-structures.
-%%----------------------------------------------------------------------
-adj_set(IG) -> IG#igraph.adj_set.
-adj_list(IG) -> IG#igraph.adj_list.
-ig_moves(IG) -> IG#igraph.ig_moves.
-degree(IG) -> IG#igraph.degree.
-
--spec spill_costs(#igraph{}) -> #spill_cost{}.
-spill_costs(IG) -> IG#igraph.spill_costs.
-
--ifdef(DEBUG_PRINTOUTS).
-number_of_temps(IG) -> IG#igraph.no_temps.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: set_adj_set, set_adj_list, set_degree, set_spill_costs
-%%
-%% Description: Modifier functions. Used to set one of the encapsulated
-%% data-structure contained in the IG structure.
-%% Parameters:
-%% Data-structure -- Data-structure you want to set. An adj_set
-%% data-structure for example.
-%% IG -- An interference graph
-%%
-%% Returns:
-%% An updated interference graph.
-%%----------------------------------------------------------------------
-
-%%set_adj_set(Adj_set, IG) -> IG#igraph{adj_set = Adj_set}.
-set_adj_list(Adj_list, IG) -> IG#igraph{adj_list = Adj_list}.
-set_ig_moves(IG_moves, IG) -> IG#igraph{ig_moves = IG_moves}.
-%%set_degree(Degree, IG) -> IG#igraph{degree = Degree}.
-set_spill_costs(Spill_costs, IG) -> IG#igraph{spill_costs = Spill_costs}.
-
-%%----------------------------------------------------------------------
-%% Function: initial_ig
-%%
-%% Description: The initial interference record that we start with when
-%% building the interference graph.
-%% Parameters:
-%% NumTemps -- Number of temporaries in the CFG we work on. This is
-%% because we have some data structures built out of vectors.
-%%
-%% Returns:
-%% A new interference record
-%%----------------------------------------------------------------------
-
--spec initial_ig(non_neg_integer(), target()) -> #igraph{}.
-
-initial_ig(NumTemps, Target) ->
- #igraph{adj_set = adjset_new(NumTemps),
- adj_list = hipe_adj_list:new(NumTemps),
- ig_moves = hipe_ig_moves:new(NumTemps),
- degree = degree_new(NumTemps, Target),
- spill_costs = hipe_spillcost:new(NumTemps),
- num_temps = NumTemps
- }.
-
-%%----------------------------------------------------------------------
-%% Function: build
-%%
-%% Description: Constructs an interference graph for the specifyed CFG.
-%%
-%% Parameters:
-%% CFG -- A Control Flow Graph
-%% TargetMod -- The module that contains the target-specific functions
-%% TargetCtx -- Context data to pass to TargetMod
-%%
-%% Returns:
-%% An interference graph for the given CFG.
-%%----------------------------------------------------------------------
-
--spec build(#cfg{}, Liveness::_, module(), target_context()) -> #igraph{}.
-
-build(CFG, BBs_in_out_liveness, TargetMod, TargetCtx) ->
- Target = {TargetMod, TargetCtx},
- Labels = TargetMod:labels(CFG, TargetCtx),
- %% How many temporaries exist?
- NumTemps = TargetMod:number_of_temporaries(CFG, TargetCtx),
- IG0 = initial_ig(NumTemps, Target),
- %%?debug_msg("initial adjset: ~p\n",[element(2, IG0)]),
- %%?debug_msg("initial adjset array: ~.16b\n",[element(3, element(2, IG0))]),
- analyze_bbs(Labels, BBs_in_out_liveness, IG0, CFG, Target).
-
-%%----------------------------------------------------------------------
-%% Function: analyze_bbs
-%%
-%% Description: Looks up the code that exists in all basic blocks and
-%% analyse instructions use and def's to see what
-%% temporaries that interfere with each other.
-%%
-%% Parameters:
-%% L -- A label
-%% Ls -- Other labels that exits in the CFG
-%% BBs_in_out_liveness -- The in and out liveness on all basic blocks
-%% IG -- The interference graph in it's current state
-%% CFG -- The Control Flow Graph that we constructs
-%% the interference graph from.
-%% Target -- The module containing the target-specific
-%% functions, along with its context data
-%%
-%% Returns:
-%% An interference graph for the given CFG.
-%%----------------------------------------------------------------------
-
-analyze_bbs([], _, IG, _, _) -> IG;
-analyze_bbs([L|Ls], BBs_in_out_liveness, IG, CFG, Target) ->
- % Get basic block associated with label L
- BB = bb(CFG, L, Target),
- % Get basic block code
- BB_code = hipe_bb:code(BB),
- % Temporaries that are live out from this basic block, only numbers
- BB_liveout_numbers = liveout(BBs_in_out_liveness, L, Target),
- % {Liveness, New Interference Graph}
- {_, New_ig, Ref} = analyze_bb_instructions(BB_code,
- ordsets:from_list(BB_liveout_numbers),
- IG,
- Target),
- Newer_ig = set_spill_costs(hipe_spillcost:ref_in_bb(Ref,
- spill_costs(New_ig)),
- New_ig),
- analyze_bbs(Ls, BBs_in_out_liveness, Newer_ig, CFG, Target).
-
-%%----------------------------------------------------------------------
-%% Function: analyze_bb_instructions
-%%
-%% Description: Analyzes all instructions that is contained in a basic
-%% block in reverse order.
-%%
-%% Parameters:
-%% Instruction -- An instruction
-%% Instructions -- The remaining instructions
-%% Live -- All temporaries that are live at the time.
-%% Live is a set of temporary "numbers only".
-%% IG -- The interference graph in it's current state
-%% Target -- The mopdule containing the target-specific functions,
-%% along with its context data.
-%%
-%% Returns:
-%% Live -- Temporaries that are live at entery of basic block
-%% that we analyze.
-%% IG -- Updated interference graph.
-%% Ref -- Set of temporaries referred to in this bb.
-%%----------------------------------------------------------------------
-
-%% Ref: set of temporaries referred to in this bb
-analyze_bb_instructions([], Live, IG, _) -> {Live, IG, ordsets:new()};
-analyze_bb_instructions([Instruction|Instructions], Live, IG, Target) ->
- %% Analyze last instruction first.
- {Live0, IG0, Ref} = analyze_bb_instructions(Instructions, Live,
- IG, Target),
- %% Check for temporaries that are defined and used in instruction
- {Def, Use} = def_use(Instruction, Target),
- %% Convert to register numbers
- Def_numbers = ordsets:from_list(reg_numbers(Def, Target)),
- Use_numbers = ordsets:from_list(reg_numbers(Use, Target)),
- Ref_numbers = ordsets:union(Ref, ordsets:union(Def_numbers, Use_numbers)),
- %% Increase spill cost on all used temporaries
- IG1 = set_spill_costs(hipe_spillcost:inc_costs(Use_numbers,
- spill_costs(IG0)),
- IG0),
- {Live1, IG2} = analyze_move(Instruction,
- Live0,
- Def_numbers,
- Use_numbers,
- IG1,
- Target),
- %% Adding Def to Live here has the effect of creating edges between
- %% the defined registers, which is O(N^2) for an instruction that
- %% clobbers N registers.
- %%
- %% Adding Def to Live is redundant when:
- %% 1. Def is empty, or
- %% 2. Def is a singleton, or
- %% 3. Def contains only precoloured registers, or
- %% 4. Def contains exactly one non-precoloured register, and the
- %% remaining ones are all non-allocatable precoloured registers.
- %%
- %% HiPE's backends only create multiple-element Def sets
- %% for CALL instructions, and then all elements are precoloured.
- %%
- %% Therefore we can avoid adding Def to Live. The benefit is greatest
- %% on backends with many physical registers, since CALLs clobber all
- %% physical registers.
- Live2 = Live1, % ordsets:union(Live1, Def_numbers),
- IG3 = interfere(Def_numbers, Live2, IG2, Target),
- Live3 = ordsets:union(Use_numbers, ordsets:subtract(Live2, Def_numbers)),
- {Live3, IG3, Ref_numbers}.
-
-%%----------------------------------------------------------------------
-%% Function: analyze_move
-%%
-%% Description: If a move instructions is discovered, this function is
-%% called. It is used to remember what move instructions
-%% a temporary is associated with and all moves that exists
-%% in the CFG.
-%%
-%% Parameters:
-%% Instruction -- An instruction
-%% Live -- All temporaries that are live at the time.
-%% Live is a set of temporary "numbers only".
-%% Def_numbers -- Temporaries that are defined at this instruction
-%% Use_numbers -- Temporaries that are used at this instruction
-%% IG -- The interference graph in its current state
-%% Target -- The module containing the target-specific functions, along
-%% with its context data
-%% Returns:
-%% Live -- An updated live set
-%% IG -- An updated interference graph
-%%----------------------------------------------------------------------
-
-analyze_move(Instruction, Live, Def_numbers, Use_numbers, IG, Target) ->
- case is_move(Instruction,Target) of
- true ->
- case {Def_numbers, Use_numbers} of
- {[Dst], [Src]} ->
- New_IG = set_ig_moves(hipe_ig_moves:new_move(Dst, Src, ig_moves(IG)), IG),
- New_live = ordsets:del_element(Src, Live),
- {New_live, New_IG};
- _ ->
- {Live, IG}
- end;
- _ ->
- {Live, IG}
- end.
-
-%%----------------------------------------------------------------------
-%% Function: interfere
-%%
-%% Description: A number of temporaries that are defined interfere with
-%% everything in the current live set.
-%%
-%% Parameters:
-%% Define -- A Define temporary
-%% Defines -- Rest of temporaries.
-%% Live -- Current live set
-%% IG -- An interference graph
-%%
-%% Returns:
-%% An updated interference graph.
-%%----------------------------------------------------------------------
-
-interfere([], _, IG, _) -> IG;
-interfere([Define|Defines], Living, IG, Target) ->
- New_ig = interfere_with_living(Define, Living, IG, Target),
- interfere(Defines, Living, New_ig, Target).
-
-%%----------------------------------------------------------------------
-%% Function: interfere_with_living
-%%
-%% Description: Let one temporary that is in the define set interfere
-%% with all live temporaries.
-%%
-%% Parameters:
-%% Define -- A Define temporary
-%% Live -- Current live set
-%% Lives -- Rest of living temporaries.
-%% IG -- An interference graph
-%% Target -- The module containing the target-specific functions, along
-%% with its context data.
-%% Returns:
-%% An updated interference graph
-%%----------------------------------------------------------------------
-
-interfere_with_living(_, [], IG, _) -> IG;
-interfere_with_living(Define, [Live|Living], IG, Target) ->
- New_ig = add_edge(Define, Live, IG, Target),
- interfere_with_living(Define, Living, New_ig, Target).
-
-%%
-%% nodes_are_adjacent(U, V, IG)
-%% returns true if nodes U and V are adjacent in interference graph IG
-%%
--spec nodes_are_adjacent(integer(), integer(), #igraph{}) -> boolean().
-nodes_are_adjacent(U, V, IG) ->
- adjset_are_adjacent(U, V, adj_set(IG)).
-
-%%
-%% node_adj_set(Node, IG)
-%% returns list of Node's adjacent nodes in interference graph IG
-%%
-node_adj_list(Node, IG) ->
- hipe_adj_list:edges(Node, adj_list(IG)).
-
-%%
-%% node_spill_cost(Node, IG)
-%% returns the Node's spill cost
-%%
-node_spill_cost(Node, IG) ->
- hipe_spillcost:spill_cost(Node, spill_costs(IG)).
-
-%%----------------------------------------------------------------------
-%% Print functions - only used for debugging
-
--ifdef(DEBUG_PRINTOUTS).
-print_spill_costs(IG) ->
- ?debug_msg("Spill costs:\n", []),
- print_spill_costs(number_of_temps(IG), IG).
-
-print_spill_costs(0, _) ->
- true;
-print_spill_costs(Node, IG) ->
- NextNode = Node - 1,
- case hipe_spillcost:nr_of_use(NextNode, spill_costs(IG)) of
- 0 ->
- ?debug_msg("node ~w not used\n", [NextNode]);
- _ ->
- ?debug_msg("node ~w sc ~p\n", [NextNode, node_spill_cost(NextNode, IG)])
- end,
- print_spill_costs(NextNode, IG).
--endif.
-
-%%----------------------------------------------------------------------
-
-get_moves(IG) ->
- hipe_ig_moves:get_moves(ig_moves(IG)).
-
-%%----------------------------------------------------------------------
-%% Function: add_edge
-%%
-%% Description: Adds an edge to the adj_set data structure if it is
-%% not already a part of it and if U is not precoloured
-%% we add V to its adj_list. If V is not precoloured
-%% we add U to its adj_list.
-%%
-%% Parameters:
-%% U -- A temporary number
-%% V -- A temporary number
-%% TargetMod -- The module containing the target-specific functions.
-%% TargetCtx -- Context data to pass to TargetMod
-%% Returns:
-%% An updated interference graph.
-%%----------------------------------------------------------------------
-
-add_edge(U, V, IG, TargetMod, TargetCtx) ->
- add_edge(U, V, IG, {TargetMod, TargetCtx}).
-
-add_edge(U, U, IG, _) -> IG;
-add_edge(U, V, IG, Target) ->
- case nodes_are_adjacent(U, V, IG) of
- true ->
- IG;
- false ->
- _ = adjset_add_edge(U, V, adj_set(IG)),
- Degree = degree(IG),
- AdjList0 = interfere_if_uncolored(U, V, adj_list(IG), Degree, Target),
- AdjList1 = interfere_if_uncolored(V, U, AdjList0, Degree, Target),
- set_adj_list(AdjList1, IG)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: remove_edge
-%%
-%% Description: Removes an edge to the adj_set data-structure if it's
-%% a part of it and if U is not precoloured
-%% we remove V from it's adj_list. If V is not precoloured
-%% we remove U from it's adj_list.
-%%
-%% Parameters:
-%% U -- A temporary number
-%% V -- A temporary number
-%% TargetMod -- The module containing the target-specific functions.
-%% TargetCtx -- Context data for TargetMod.
-%% Returns:
-%% An updated interference graph.
-%%----------------------------------------------------------------------
-
-remove_edge(U, V, IG, TargetMod, TargetCtx) ->
- remove_edge(U, V, IG, {TargetMod, TargetCtx}).
-
-remove_edge(U, U, IG, _) -> IG;
-remove_edge(U, V, IG, Target) ->
- case nodes_are_adjacent(U, V, IG) of
- false ->
- IG;
- true ->
- _ = adjset_remove_edge(U, V, adj_set(IG)),
- Degree = degree(IG),
- AdjList0 = remove_if_uncolored(U, V, adj_list(IG), Degree, Target),
- AdjList1 = remove_if_uncolored(V, U, AdjList0, Degree, Target),
- set_adj_list(AdjList1, IG)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: remove_if_uncolored
-%%
-%% Description:
-%%
-%% Parameters:
-%% Temporary -- A temporary that is added to the adjacent
-%% list if it's not precoloured.
-%% Interfere_temporary -- Temporary will interfere with
-%% Interfere_temporary if temporary is not
-%% precoloured.
-%% Adj_list -- An adj_list
-%% Degree -- The degree that all nodes currently have
-%% Target -- The module containing the target-specific
-%% functions, along with its context data.
-%%
-%% Returns:
-%% Adj_list -- An updated adj_list data structure
-%% Degree -- An updated degree data structure (via side-effects)
-%%----------------------------------------------------------------------
-
-remove_if_uncolored(Temp, InterfereTemp, Adj_list, Degree, Target) ->
- case is_precoloured(Temp,Target) of
- false ->
- New_adj_list = hipe_adj_list:remove_edge(Temp, InterfereTemp, Adj_list),
- degree_dec(Temp, Degree),
- New_adj_list;
- true ->
- Adj_list
- end.
-
-%%----------------------------------------------------------------------
-%% Function: interfere_if_uncolored
-%%
-%% Description: Let a not precoloured temporary interfere with another.
-%%
-%% Parameters:
-%% Temporary -- A temporary that is added to the adjacent
-%% list if it's not precoloured.
-%% Interfere_temporary -- Temporary will interfere with
-%% Interfere_temporary if temporary is not
-%% precoloured.
-%% Adj_list -- An adj_list
-%% Degree -- The degree that all nodes currently have
-%% Target -- The module containing the target-specific
-%% functions, along with its context data.
-%%
-%% Returns:
-%% Adj_list -- An updated adj_list data structure
-%% Degree -- An updated degree data structure (via side-effects)
-%%----------------------------------------------------------------------
-
-interfere_if_uncolored(Temp, InterfereTemp, Adj_list, Degree, Target) ->
- case is_precoloured(Temp, Target) of
- false ->
- New_adj_list = hipe_adj_list:add_edge(Temp, InterfereTemp, Adj_list),
- degree_inc(Temp, Degree),
- New_adj_list;
- true ->
- Adj_list
- end.
-
-%%----------------------------------------------------------------------
-%% Function: reg_numbers
-%%
-%% Description: Converts a list of tuple with {something, reg_number}
-%% to a list of register numbers.
-%%
-%% Parameters:
-%% TRs -- A list of temporary registers
-%% Target -- The module containing the target-specific functions, along with
-%% its context data.
-%% Returns:
-%% A list of register numbers.
-%%----------------------------------------------------------------------
-
-reg_numbers(Regs, {TgtMod, TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
-%%---------------------------------------------------------------------
-%% Print functions - only used for debugging
-
--ifdef(DEBUG_PRINTOUTS).
-print_degrees(IG) ->
- ?debug_msg("The nodes degrees:\n", []),
- print_node_degree(number_of_temps(IG), IG).
-
-print_node_degree(0, _) ->
- true;
-print_node_degree(Node, IG) ->
- NextNode = Node - 1,
- ?debug_msg("node ~w ~w\n", [NextNode, get_node_degree(NextNode, IG)]),
- print_node_degree(NextNode, IG).
--endif.
-
-%%----------------------------------------------------------------------
-
-get_node_degree(Node, IG) ->
- degree_get(Node, degree(IG)).
-
-dec_node_degree(Node, IG) ->
- degree_dec(Node, degree(IG)),
- IG.
-
-is_trivially_colourable(Node, K, IG) ->
- degree_is_trivially_colourable(Node, K, degree(IG)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to external functions.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bb(CFG, L, {TgtMod,TgtCtx}) ->
- TgtMod:bb(CFG,L,TgtCtx).
-
-def_use(Instruction, {TgtMod,TgtCtx}) ->
- TgtMod:def_use(Instruction, TgtCtx).
-
-is_move(Instruction, {TgtMod,TgtCtx}) ->
- TgtMod:is_move(Instruction, TgtCtx).
-
-is_precoloured(R, {TgtMod,TgtCtx}) ->
- TgtMod:is_precoloured(R,TgtCtx).
-
-liveout(Liveness,L, Target={TgtMod,TgtCtx}) ->
- reg_numbers(TgtMod:liveout(Liveness,L,TgtCtx), Target).
diff --git a/lib/hipe/regalloc/hipe_ig_moves.erl b/lib/hipe/regalloc/hipe_ig_moves.erl
deleted file mode 100644
index e193a682bf..0000000000
--- a/lib/hipe/regalloc/hipe_ig_moves.erl
+++ /dev/null
@@ -1,77 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%=============================================================================
-
--module(hipe_ig_moves).
--export([new/1,
- new_move/3,
- get_moves/1]).
-
-%%-----------------------------------------------------------------------------
-%% The main data structure; its fields are:
-%% - movelist : mapping from temp to set of associated move numbers
-%% - nrmoves : number of distinct move instructions seen so far
-%% - moveinsns : list of move instructions, in descending move number order
-%% - moveset : set of move instructions
-
--record(ig_moves, {movelist :: movelist(),
- nrmoves = 0 :: non_neg_integer(),
- moveinsns = [] :: [{_,_}],
- moveset = gb_sets:empty() :: gb_sets:set()}).
-
--type movelist() :: hipe_vectors:vector(ordsets:ordset(non_neg_integer())).
-
-%%-----------------------------------------------------------------------------
-
--spec new(non_neg_integer()) -> #ig_moves{}.
-
-new(NrTemps) ->
- MoveList = hipe_vectors:new(NrTemps, ordsets:new()),
- #ig_moves{movelist = MoveList}.
-
--spec new_move(_, _, #ig_moves{}) -> #ig_moves{}.
-
-new_move(Dst, Src, IG_moves) ->
- MoveSet = IG_moves#ig_moves.moveset,
- MoveInsn = {Dst, Src},
- case gb_sets:is_member(MoveInsn, MoveSet) of
- true ->
- IG_moves;
- false ->
- MoveNr = IG_moves#ig_moves.nrmoves,
- Movelist0 = IG_moves#ig_moves.movelist,
- Movelist1 = add_movelist(MoveNr, Dst,
- add_movelist(MoveNr, Src, Movelist0)),
- IG_moves#ig_moves{nrmoves = MoveNr+1,
- movelist = Movelist1,
- moveinsns = [MoveInsn|IG_moves#ig_moves.moveinsns],
- moveset = gb_sets:insert(MoveInsn, MoveSet)}
- end.
-
--spec add_movelist(non_neg_integer(), non_neg_integer(), movelist())
- -> movelist().
-
-add_movelist(MoveNr, Temp, MoveList) ->
- AssocMoves = hipe_vectors:get(MoveList, Temp),
- %% XXX: MoveNr does not occur in moveList[Temp], but the new list must be an
- %% ordset due to the ordsets:union in hipe_coalescing_regalloc:combine().
- hipe_vectors:set(MoveList, Temp, ordsets:add_element(MoveNr, AssocMoves)).
-
--spec get_moves(#ig_moves{}) -> {movelist(), non_neg_integer(), tuple()}.
-
-get_moves(IG_moves) -> % -> {MoveList, NrMoves, MoveInsns}
- {IG_moves#ig_moves.movelist,
- IG_moves#ig_moves.nrmoves,
- list_to_tuple(lists:reverse(IG_moves#ig_moves.moveinsns))}.
diff --git a/lib/hipe/regalloc/hipe_ls_regalloc.erl b/lib/hipe/regalloc/hipe_ls_regalloc.erl
deleted file mode 100644
index 785aa2b080..0000000000
--- a/lib/hipe/regalloc/hipe_ls_regalloc.erl
+++ /dev/null
@@ -1,786 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% =====================================================================
-%% @doc
-%% <pre>
-%% Module : hipe_ls_regalloc
-%% Purpose : Perform a register allocation based on the
-%% "linear-scan algorithm".
-%% Notes : * This is an implementation of
-%% "Linear Scan Register Allocation" by
-%% Massimiliano Poletto &amp; Vivek Sarkar described in
-%% ACM TOPLAS Vol 21, No 5, September 1999.
-%%
-%% * This implementation is target-independent and
-%% requires a target specific interface module
-%% as argument.
-%% (Still waiting for a modular module system for Erlang.)
-%% </pre>
-%% @end
-%%
-%% History : * 2000-04-07 Erik Johansson (happi@it.uu.se): Created.
-%% * 2001-07-16 Erik Johansson: Made less sparc-specific.
-%% =====================================================================
-%% Exported functions (short description):
-%% regalloc(CFG,PhysRegs,Entrypoints, Options) ->
-%% {Coloring, NumberOfSpills}
-%% Takes a CFG and returns a coloring of all used registers.
-%% PhysRegs should be a list of available physical registers.
-%% Entrypoints should be a list of names of Basic Blocks that have
-%% external entry points.
-%%
-%% The Coloring will be in the form of the "allocation datastructure"
-%% described below, that is, a list of tuples on the form
-%% {Name, {reg, PhysicalRegister}} or
-%% {Name, {spill, SpillIndex}}
-%% The NumberOfSpills is either 0 indicating no spill or the
-%% SpillIndex of the last spilled register.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_ls_regalloc).
--export([regalloc/9]).
-
-%%-define(DEBUG,1).
--define(HIPE_INSTRUMENT_COMPILER, true).
-
--include("../main/hipe.hrl").
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% @spec
-%% regalloc(CFG, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options,
-%% Target) ->
-%% {Coloring, NumberOfSpills}
-%% CFG = cfg()
-%% PhysRegs = [reg()]
-%% Entrypoints = [labelname()]
-%% DontSpill = reg()
-%% Options = proplists:proplist()
-%% Target = atom()
-%% Coloring = [{temp(), pos()}]
-%% NumberOfSpills = integer()
-%% reg() = integer()
-%% temp() = integer()
-%% pos() = {reg, reg()} | {spill, integer()}
-%%
-%% @doc
-%% Calculates an allocation of registers using a linear_scan algorithm.
-%% There are three steps in the algorithm:
-%% <ol>
-%% <li> Calculate live-ranges for all registers.</li>
-%% <li> Calculate live-intervals for each register.
-%% The live interval consists of a start position and an end
-%% position. These are the first definition and last use of the
-%% register given as instruction numbers in a breadth-first
-%% traversal of the control-flow-graph.</li>
-%% <li> Perform a linear scan allocation over the live intervals.</li>
-%% </ol>
-%% @end
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options,
- TargetMod, TargetContext) ->
- Target = {TargetMod, TargetContext},
- ?debug_msg("LinearScan: ~w\n", [erlang:statistics(runtime)]),
- USIntervals = calculate_intervals(CFG, Liveness,
- Entrypoints, Options, Target),
- ?debug_msg("intervals (done) ~w\n", [erlang:statistics(runtime)]),
- Intervals = sort_on_start(USIntervals),
- ?debug_msg("sort intervals (done) ~w\n", [erlang:statistics(runtime)]),
- %% ?debug_msg("Intervals ~w\n", [Intervals]),
- ?debug_msg("No intervals: ~w\n",[length(Intervals)]),
- ?debug_msg("count intervals (done) ~w\n", [erlang:statistics(runtime)]),
- {Coloring, NewSpillIndex}
- = allocate(Intervals, PhysRegs, SpillIndex, DontSpill, Target),
- ?debug_msg("allocation (done) ~w\n", [erlang:statistics(runtime)]),
- {Coloring, NewSpillIndex}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Step 2: Calculate live-intervals for each register. %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% calculate_intervals(CFG,Liveness,Entrypoints, Options, Target)
-%% CFG: The Control-Flow Graph.
-%% Liveness: A map of live-in and live-out sets for each Basic-Block.
-%% Entrypoints: A set of BB names that have external entrypoints.
-%%
-calculate_intervals(CFG,Liveness,_Entrypoints, Options,
- Target={TgtMod,TgtCtx}) ->
- %% Add start point for the argument registers.
- Args = arg_vars(CFG, Target),
- Interval =
- add_def_point(Args, 0, empty_interval(number_of_temporaries(CFG, Target))),
- %% Interval = add_livepoint(Args, 0, empty_interval()),
- Worklist =
- case proplists:get_value(ls_order, Options) of
- reversepostorder ->
- TgtMod:reverse_postorder(CFG, TgtCtx);
- breadth ->
- TgtMod:breadthorder(CFG, TgtCtx);
- postorder ->
- TgtMod:postorder(CFG, TgtCtx);
- inorder ->
- TgtMod:inorder(CFG, TgtCtx);
- reverse_inorder ->
- TgtMod:reverse_inorder(CFG, TgtCtx);
- preorder ->
- TgtMod:preorder(CFG, TgtCtx);
- prediction ->
- TgtMod:predictionorder(CFG, TgtCtx);
- random ->
- TgtMod:labels(CFG, TgtCtx);
- _ ->
- TgtMod:reverse_postorder(CFG, TgtCtx)
- end,
- %% ?inc_counter(bbs_counter, length(Worklist)),
- %% ?debug_msg("No BBs ~w\n",[length(Worklist)]),
- intervals(Worklist, Interval, 1, CFG, Liveness, Target).
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% intervals(WorkList, Intervals, InstructionNr, CFG, Liveness, Target)
-%% WorkList: List of BB-names to handle.
-%% Intervals: Intervals seen so far (sorted on register names).
-%% InstructionNr: The number of examined insturctions.
-%% CFG: The Control-Flow Graph.
-%% Liveness: A map of live-in and live-out sets for each Basic-Block.
-%% Target: The backend for which we generate code.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-intervals([L|ToDO], Intervals, InstructionNr, CFG, Liveness, Target) ->
- %% Add all variables that are live at the entry of this block
- %% to the interval data structure.
- LiveIn = livein(Liveness, L, Target),
- Intervals2 = add_def_point(LiveIn, InstructionNr, Intervals),
- LiveOut = liveout(Liveness, L, Target),
-
- %% Traverse this block instruction by instruction and add all
- %% uses and defines to the intervals.
- Code = hipe_bb:code(bb(CFG, L, Target)),
- {Intervals3, NewINr} =
- traverse_block(Code, InstructionNr+1, Intervals2, Target),
-
- %% Add end points for the registers that are in the live-out set.
- Intervals4 = add_use_point(LiveOut, NewINr+1, Intervals3),
-
- intervals(ToDO, Intervals4, NewINr+1, CFG, Liveness, Target);
-intervals([], Intervals, _, _, _, _) ->
- %% Return the calculated intervals
- LI = interval_to_list(Intervals),
- %% io:format("Intervals:~n~p~n", [LI]),
- LI.
-
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% traverse_block(Code, InstructionNo, Intervals, Unchanged)
-%% Examine each instruction in the Code:
-%% For each temporary T used or defined by instruction number N:
-%% extend the interval of T to include N.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-traverse_block([Instruction|Is],InstrNo,Intervals, Target) ->
- %% Get defined temps.
- DefsSet = defines(Instruction, Target),
- Intervals1 = add_def_point(DefsSet, InstrNo, Intervals),
-
- %% Get used temps.
- UsesSet = uses(Instruction, Target),
- %% Extend the intervals for these temporaries to include InstrNo.
- Intervals2 = add_use_point(UsesSet, InstrNo, Intervals1),
-
- %% Handle the next instruction.
- traverse_block(Is,InstrNo+1,Intervals2,Target);
-traverse_block([], InstrNo, Intervals, _) ->
- %% Return the new intervals and the number of the next instruction.
- {Intervals,InstrNo}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Step 3. Do a linear scan allocation over the live intervals. %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% allocate(Intervals, PhysicalRegisters, DontSpill, Target)
-%%
-%% This function performs the linear scan algorithm.
-%% Intervals contains the start and stop position of each register,
-%% sorted on increasing startpositions
-%% PhysicalRegisters is a list of available Physical registers to use.
-%%
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-allocate(Intervals, PhysRegs, SpillIndex, DontSpill, Target) ->
- ActiveRegisters =[],
- AllocatedRegisters = empty_allocation(),
- AllFree = create_freeregs(PhysRegs),
- allocate(Intervals, AllFree, ActiveRegisters,
- AllocatedRegisters, SpillIndex, DontSpill, Target).
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-%% allocate(Intervals, Free, Active, Allocated, SpillIndex, Target)
-%% Iterates of each register interval.
-%% Intervals: The list of register intervals.
-%% Free: Currently available physical registers.
-%% Active: Currently used physical registers (sorted on increasing
-%% interval enpoints)
-%% Allocated: The mapping of register names to physical registers or
-%% to spill positions.
-%% SpillIndex: The number of spilled registers.
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-allocate([RegInt|RIS], Free, Active, Alloc, SpillIndex, DontSpill, Target) ->
- %io:format("~nAlloc:~n~p", [Alloc]),
- %% Remove from the active list those registers who's intervals
- %% ends before the start of the current interval.
- {NewActive, NewFree} =
- expire_old_intervals(Active, startpoint(RegInt), Free, Target),
- ?debug_msg("Alloc interval: ~w, Free ~w\n",[RegInt, NewFree]),
- %% Get the name of the temp in the current interval.
- Temp = reg(RegInt),
- case is_precoloured(Temp, Target) of
- true ->
- %% This is a precoloured register we don't need to find a color
- %% Get the physical name of the register.
- PhysName = physical_name(Temp, Target),
- %% Bind it to the precoloured name.
- NewAlloc = alloc(Temp, PhysName, Alloc),
- case is_global(Temp, Target) of
- true ->
- %% this is a global precoloured register
- allocate(RIS, NewFree, NewActive,
- NewAlloc, SpillIndex, DontSpill, Target);
- false ->
- case is_free(PhysName, NewFree) of
- {true,Rest} ->
- allocate(RIS, Rest,
- add_active(endpoint(RegInt), startpoint(RegInt),
- PhysName, Temp, NewActive),
- NewAlloc,
- SpillIndex, DontSpill, Target);
- false ->
- %% Some other temp has taken this precoloured register,
- %% throw it out.
- {OtherActive, NewActive2} = deactivate(PhysName, NewActive),
- OtherTemp = active_name(OtherActive),
- OtherEnd = active_endpoint(OtherActive),
- OtherStart = active_startpoint(OtherActive),
- NewActive3 = add_active(endpoint(RegInt), startpoint(RegInt),
- PhysName, Temp, NewActive2),
- case exists_free_register(OtherStart, NewFree) of
- {true, NewPhys, RestFree} ->
- allocate(RIS, RestFree,
- add_active(OtherEnd, OtherStart,
- NewPhys, OtherTemp, NewActive3),
- alloc(OtherTemp,NewPhys,NewAlloc),
- SpillIndex, DontSpill, Target);
- false ->
- NewSpillIndex = new_spill_index(SpillIndex, Target),
- {NewAlloc2, NewActive4} =
- spill(OtherTemp, OtherEnd, OtherStart, NewActive3,
- NewAlloc, SpillIndex, DontSpill, Target),
- allocate(RIS,
- NewFree,
- NewActive4,
- NewAlloc2, NewSpillIndex, DontSpill, Target)
- end
- end
- end;
- false ->
- %% This is not a precoloured register.
- case NewFree of
- [] ->
- %% No physical registers available, we have to spill.
- NewSpillIndex = new_spill_index(SpillIndex, Target),
- {NewAlloc, NewActive2} =
- spill(Temp, endpoint(RegInt), startpoint(RegInt),
- Active, Alloc, SpillIndex, DontSpill, Target),
- %% io:format("Spilled ~w\n",[NewAlloc]),
- allocate(RIS, NewFree, NewActive2, NewAlloc, NewSpillIndex,
- DontSpill, Target);
-
- [{FreeReg,_Start} | Regs] ->
- %% The register FreeReg is available, let's use it.
- %%io:format("Allocating Reg:~p~n",[FreeReg]),
- allocate(RIS,Regs,
- add_active(endpoint(RegInt), startpoint(RegInt),
- FreeReg, Temp, NewActive),
- alloc(Temp, FreeReg, Alloc),
- SpillIndex, DontSpill, Target)
- end
- end;
-allocate([],_,_,Alloc,SpillIndex, _, _) ->
- %% No more register intervals to handle
- %% return the result.
- %%io:format("~nAlloc:~n~p", [Alloc]),
- {Alloc, SpillIndex}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% expire_old_intervals(ActiveRegisters, CurrentPos, FreeRegisters)
-%% Remove all registers that have live-ranges that ends before the
-%% current position from the active list and put them into the free
-%% list instead.
-%%
-%% ---------------------------------------------------------------------
-expire_old_intervals([Act|Acts] = AllActives, CurrentPos, Free, Target) ->
- %% Does the live-range of the first active register end before
- %% the current position?
-
- %% We expand multimove before regalloc, ignore the next 2 lines.
- %% %% We don't free registers that end at the current position,
- %% %% since a multimove can decide to do the moves in another order...
- case active_endpoint(Act) =< CurrentPos of
- true -> %% Yes -> Then we can free that register.
- Reg = active_reg(Act),
- %% Add the register to the free pool.
- NewFree =
- case is_arg(Reg, Target) of
- true ->
- [{Reg, CurrentPos}|Free];
- false ->
- [{Reg, CurrentPos}|Free]
- %% Here we could try appending the
- %% register to get a more widespread
- %% use of registers.
- %% Free ++ [active_reg(Act)]);
- %% At the moment this does not seem to
- %% improve performance at all,
- %% on the other hand, the cost is very low.
- end,
- expire_old_intervals(Acts, CurrentPos, NewFree, Target);
- false ->
- %% No -> Then we cannot free any more registers.
- %% (Since they are sorted on endpoints...)
- {AllActives, Free}
- end;
-expire_old_intervals([], _, Free, _) ->
- {[], Free}.
-
-deactivate(Reg, [Active|Actives]) ->
- case Reg =:= active_reg(Active) of
- true ->
- {Active, Actives};
- false ->
- {TheActive, NewActives} = deactivate(Reg, Actives),
- {TheActive, [Active|NewActives]}
- end;
-deactivate(_,[]) -> {no,[]}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% spill(CurrentReg, CurrentEndpoint, Active, Alloc, SpillIndex,
-%% DontSpill, Target)
-%% Find the register with the longest live range and spill it to memory.
-%%
-%% ---------------------------------------------------------------------
-spill(CurrentReg, CurrentEndpoint,CurrentStartpoint,
- Active = [_|_],
- Alloc, SpillIndex,
- DontSpill, Target) ->
- ?debug_msg("spilling one of ~w\nDOnt spill ~w\n",
- [[CurrentReg|Active], DontSpill]),
-
- %% Find a spill candidate (one of the active):
- %% The register with the longest live-range.
- {NewActive, SpillCandidate} = butlast_last(Active),
-
- SpillStartpoint = active_startpoint(SpillCandidate) ,
- SpillEndpoint = active_endpoint(SpillCandidate) ,
- SpillName = active_name(SpillCandidate),
- SpillPhysName = active_reg(SpillCandidate),
-
- case SpillEndpoint > CurrentEndpoint of
- true ->
- %% There is an already allocated register that has
- %% a longer live-range than the current register.
- case can_spill(SpillName, DontSpill, Target) and
- (SpillStartpoint =< CurrentStartpoint) of
- false ->
- {NewAlloc, NewActive2} =
- spill(CurrentReg, CurrentEndpoint, CurrentStartpoint,
- NewActive, Alloc, SpillIndex, DontSpill, Target),
- {NewAlloc,
- add_active(SpillEndpoint, SpillStartpoint, SpillPhysName,
- SpillName, NewActive2)};
- true ->
- %% It is not precoloured... or have too short liverange
-
- %% Allocate SpillCandidate to spill-slot SpillIndex
- SpillAlloc =
- spillalloc(active_name(SpillCandidate), SpillIndex,
- Alloc),
-
- %% Allocated the current register to the physical register
- %% used by the spill candidate.
- NewAlloc = alloc(CurrentReg, SpillPhysName, SpillAlloc),
-
- %% Add the current register to the active registers
- NewActive2 =
- add_active(CurrentEndpoint, CurrentStartpoint,
- SpillPhysName, CurrentReg, NewActive),
- {NewAlloc, NewActive2}
- end;
-
- false ->
- %% The current register has the longest live-range.
-
- case can_spill(CurrentReg, DontSpill, Target) of
- false ->
- %% Cannot spill a precoloured register
- {NewAlloc, NewActive2} =
- spill(SpillName, SpillEndpoint, SpillStartpoint,
- NewActive, Alloc, SpillIndex, DontSpill, Target),
- NewActive3 =
- add_active(CurrentEndpoint, CurrentStartpoint,
- SpillPhysName, CurrentReg, NewActive2),
- {NewAlloc, NewActive3};
- true ->
- %% It is not precoloured...
- %% Allocate the current register to spill-slot SpillIndex
- {spillalloc(CurrentReg, SpillIndex, Alloc), Active}
- end
- end;
-spill(CurrentReg, _CurrentEndpoint, _CurrentStartpoint, [],
- Alloc, SpillIndex, DontSpill, Target) ->
- case can_spill(CurrentReg, DontSpill, Target) of
- false -> %% Can't spill current!
- ?error_msg("Can't allocate registers\n",[]),
- ?EXIT({cannot_allocate_regs});
- true -> %% Can spill current.
- %% Allocate the current register to spill-slot SpillIndex
- {spillalloc(CurrentReg, SpillIndex, Alloc), []}
- end.
-
-can_spill(Name, DontSpill, Target) ->
- (Name < DontSpill) and (not is_precoloured(Name, Target)).
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% D A T A S T R U C T U R E S %%
-%% & %%
-%% A U X I L I A R Y F U N C T I O N S %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The "allocation datastructure"
-%%
-%% This is an order list of register names paired with their allocations.
-%% {Name, Allocation}
-%% The allocation is either {reg, physical register} or
-%% {spill, spill index}
-%%
-%% ---------------------------------------------------------------------
-empty_allocation() -> [].
-
-alloc(Name,Reg,[{Name,_}|A]) ->
- [{Name,{reg,Reg}}|A];
-alloc(Name,Reg,[{Name2,Binding}|Bindings]) when Name > Name2 ->
- [{Name2,Binding}|alloc(Name,Reg,Bindings)];
-alloc(Name,Reg,Bindings) ->
- [{Name,{reg,Reg}}|Bindings].
-
-spillalloc(Name,N,[{Name,_}|A]) ->
- ?debug_msg("Spilled ~w\n",[Name]),
- [{Name,{spill,N}}|A];
-spillalloc(Name,N,[{Name2,Binding}|Bindings]) when Name > Name2 ->
- [{Name2,Binding}|spillalloc(Name,N,Bindings)];
-spillalloc(Name,N,Bindings) ->
- [{Name,{spill,N}}|Bindings].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%%
-butlast_last([X]) ->
- {[],X};
-butlast_last([X|Y]) ->
- {L,Last} = butlast_last(Y),
- {[X|L],Last}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The active datastructure.
-%% Keeps tracks of currently active (allocated) physical registers.
-%% It is sorted on end points in the intervals
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_active(Endpoint, StartPoint, PhysReg, RegName,
- [{P1,R1,O1,S1}|Active]) when P1 < Endpoint ->
- [{P1,R1,O1,S1}|add_active(Endpoint, StartPoint, PhysReg, RegName, Active)];
-add_active(Endpoint, StartPoint, PhysReg, RegName, Active) ->
- [{Endpoint, PhysReg, RegName, StartPoint}|Active].
-
-active_reg({_,PhysReg,_,_}) ->
- PhysReg.
-active_endpoint({EndPoint,_,_,_}) ->
- EndPoint.
-active_startpoint({_,_,_,StartPoint}) ->
- StartPoint.
-active_name({_,_,RegName,_}) ->
- RegName.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The Interval data structure.
-%%
-%%
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-
-%% mk_interval(Name, Start, End) ->
-%% {Name, Start, End}.
-
-endpoint({_R,_S,Endpoint}) ->
- Endpoint.
-startpoint({_R,Startpoint,_E}) ->
- Startpoint.
-reg({RegName,_S,_E}) ->
- RegName.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The Intervals data structure.
-
-sort_on_start(I) ->
- lists:keysort(2, I).
-
--ifdef(gb_intervals).
-empty_interval(_) ->
- gb_trees:empty().
-
-interval_to_list(Intervals) ->
- lists:flatten(
- lists:map(
- fun({T, I}) when list(I) ->
- lists:map(
- fun ({none, End}) ->
- {T,End,End};
- ({Beg, none}) ->
- {T,Beg, Beg}
- end,
- I);
- ({T,{B,E}}) -> {T, B, E}
- end,
- gb_trees:to_list(Intervals))).
-
-add_use_point([Temp|Temps],Pos,Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case gb_trees:lookup(Temp, Intervals) of
- %% This temp has an old interval...
- {value, Value} ->
- %% ... extend it.
- extend_interval(Pos, Value);
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos}
- end,
- %% Add or update the extended interval.
- Intervals2 = gb_trees:enter(Temp, NewInterval, Intervals),
- %% Add the rest of teh temporaries.
- add_use_point(Temps, Pos, Intervals2);
-add_use_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-add_def_point([Temp|Temps],Pos,Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case gb_trees:lookup(Temp, Intervals) of
- %% This temp has an old interval...
- {value, Value} ->
- %% ... extend it.
- extend_interval(Pos, Value);
-
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos}
- end,
- %% Add or update the extended interval.
- Intervals2 = gb_trees:enter(Temp, NewInterval, Intervals),
- %% Add the rest of the temporaries.
- add_def_point(Temps, Pos, Intervals2);
-add_def_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-extend_interval(Pos, {Beginning, End}) ->
- %% If this position occures before the beginning
- %% of the interval, then extend the beginning to
- %% this position.
- NewBeginning = erlang:min(Pos, Beginning),
- %% If this position occures after the end
- %% of the interval, then extend the end to
- %% this position.
- NewEnd = erlang:max(Pos, End),
- {NewBeginning, NewEnd}.
-
--else. %% isdef gb_intervals
-
-empty_interval(N) ->
- hipe_vectors:new(N, none).
-
-interval_to_list(Intervals) ->
- add_indices(hipe_vectors:vector_to_list(Intervals),0).
-
-add_indices([{B,E}|Xs],N) ->
- [{N,B,E}|add_indices(Xs,N+1)];
-add_indices([List|Xs],N) when is_list(List) ->
- flatten(List,N,Xs);
-add_indices([none|Xs],N) ->
- add_indices(Xs,N+1);
-add_indices([],_N) -> [].
-
-flatten([{none, End}|Rest], N, More) ->
- [{N,End,End} | flatten(Rest, N, More)];
-flatten([{Beg, none}|Rest], N ,More) ->
- [{N,Beg,Beg} | flatten(Rest, N, More)];
-flatten([],N,More) ->
- add_indices(More,N+1).
-
-add_use_point([Temp|Temps],Pos,Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case hipe_vectors:get(Intervals, Temp) of
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos};
- %% This temp has an old interval...
- Value ->
- %% ... extend it.
- extend_interval(Pos, Value)
- end,
- %% Add or update the extended interval.
- Intervals2 = hipe_vectors:set(Intervals, Temp, NewInterval),
- %% Add the rest of the temporaries.
- add_use_point(Temps, Pos, Intervals2);
-add_use_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-add_def_point([Temp|Temps],Pos,Intervals) ->
- %% Extend the old interval...
- NewInterval =
- case hipe_vectors:get(Intervals, Temp) of
- %% This is the first time we see this temp...
- none ->
- %% ... create a new interval
- {Pos, Pos};
- %% This temp has an old interval...
- Value ->
- %% ... extend it.
- extend_interval(Pos, Value)
- end,
- %% Add or update the extended interval.
- Intervals2 = hipe_vectors:set(Intervals, Temp, NewInterval),
- %% Add the rest of teh temporaries.
- add_def_point(Temps, Pos, Intervals2);
-add_def_point([], _, I) ->
- %% No more to add return the interval.
- I.
-
-extend_interval(Pos, {Beginning, End}) ->
- %% If this position occurs before the beginning of the interval,
- %% then extend the beginning to this position.
- NewBeginning = erlang:min(Pos, Beginning),
- %% If this position occures after the end
- %% of the interval, then extend the end to
- %% this position.
- NewEnd = erlang:max(Pos, End),
- {NewBeginning, NewEnd}.
--endif. %% gb_intervals
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The Freel data structure.
-%%
-%%- - - - - - - - - - - - - - - - - - - - - - - -
-
-is_free(R, Free) ->
- is_free(R, Free, []).
-
-is_free(R, [{R,_}|Rest], Acc) ->
- {true, lists:reverse(Acc, Rest)};
-is_free(R, [X|Rs],Acc) ->
- is_free(R, Rs, [X|Acc]);
-is_free(_, [], _) ->
- false.
-
-exists_free_register(Start, Regs) ->
- exists_free_register(Start, Regs, []).
-
-exists_free_register(Start, [{Phys, Start0}|Rest], Acc)
- when Start > Start0 ->
- {true, Phys, lists:reverse(Acc, Rest)};
-exists_free_register(Start, [Free|Rest], Acc) ->
- exists_free_register(Start, Rest, [Free|Acc]);
-exists_free_register(_, [], _) ->
- false.
-
-create_freeregs([Phys|Rest]) ->
- [{Phys,-1}|create_freeregs(Rest)];
-create_freeregs([]) ->
- [].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to external functions.
-%% XXX: Make this efficient somehow...
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bb(CFG, L, {TgtMod, TgtCtx}) ->
- TgtMod:bb(CFG,L,TgtCtx).
-
-livein(Liveness,L, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:livein(Liveness,L,TgtCtx), Target).
-
-liveout(Liveness,L, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:liveout(Liveness,L,TgtCtx), Target).
-
-uses(I, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:uses(I,TgtCtx), Target).
-
-defines(I, Target={TgtMod,TgtCtx}) ->
- regnames(TgtMod:defines(I,TgtCtx), Target).
-
-is_precoloured(R, {TgtMod,TgtCtx}) ->
- TgtMod:is_precoloured(R,TgtCtx).
-
-is_global(R, {TgtMod,TgtCtx}) ->
- TgtMod:is_global(R,TgtCtx).
-
-new_spill_index(SpillIndex, {TgtMod,TgtCtx}) ->
- TgtMod:new_spill_index(SpillIndex, TgtCtx).
-
-number_of_temporaries(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:number_of_temporaries(CFG, TgtCtx).
-
-physical_name(R, {TgtMod,TgtCtx}) ->
- TgtMod:physical_name(R,TgtCtx).
-
-regnames(Regs, {TgtMod,TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
-arg_vars(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:args(CFG,TgtCtx).
-
-is_arg(Reg, {TgtMod,TgtCtx}) ->
- TgtMod:is_arg(Reg,TgtCtx).
diff --git a/lib/hipe/regalloc/hipe_moves.erl b/lib/hipe/regalloc/hipe_moves.erl
deleted file mode 100644
index 409217bb03..0000000000
--- a/lib/hipe/regalloc/hipe_moves.erl
+++ /dev/null
@@ -1,159 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_moves).
--export([new/1,
- update_movelist/3,
- node_moves/2,
- move_related/2,
- node_movelist/2,
- get_move/2,
- is_empty_worklist/1,
- worklist_get_and_remove/1,
- remove_worklist/2,
- remove_active/2,
- add_worklist/2,
- add_active/2,
- member_active/2
- ]).
--ifdef(DEBUG_PRINTOUTS).
--export([print_memberships/1]).
--endif.
-
--record(movesets,
- {worklist, % Moves enabled for possible coalescing
- membership, % Maps move numbers to 'worklist' or 'active' or 'none'
- moveinsns, % Maps move numbers to move insns ({Dst,Src}-tuples)
- movelist % Mapping from node to list of moves it's associated with
- }).
-
-%%-ifndef(DEBUG).
-%%-define(DEBUG,true).
-%%-endif.
--include("../main/hipe.hrl").
-
-worklist(MoveSets) -> MoveSets#movesets.worklist.
-movelist(MoveSets) -> MoveSets#movesets.movelist.
-
-set_worklist(New_worklist, MoveSets) ->
- MoveSets#movesets{worklist = New_worklist}.
-set_movelist(New_movelist, MoveSets) ->
- MoveSets#movesets{movelist = New_movelist}.
-
-update_movelist(Node, MoveList, MoveSets) ->
- set_movelist(hipe_vectors:set(movelist(MoveSets), Node, MoveList),
- MoveSets).
-
-new(IG) ->
- {MoveList,NrMoves,MoveInsns} = hipe_ig:get_moves(IG),
- Worklist = case NrMoves of 0 -> []; _ -> lists:seq(0, NrMoves-1) end,
- #movesets{worklist = Worklist,
- membership = hipe_bifs:array(NrMoves, 'worklist'),
- moveinsns = MoveInsns,
- movelist = MoveList}.
-
-remove_worklist(Element, MoveSets) ->
- Membership = MoveSets#movesets.membership,
- %% check for 'worklist' membership here, if debugging
- hipe_bifs:array_update(Membership, Element, 'none'),
- %% Implementing this faithfully would require a SET structure, such
- %% as an ordset or a gb_set. However, removal of elements not at the
- %% head of the structure is a fairly infrequent event (only done by
- %% FreezeMoves()), so instead we let the elements remain but mark
- %% them as being removed. It is the task of worklist_get_and_remove()
- %% to filter out any stale elements.
- MoveSets.
-
-remove_active(Element, MoveSets) ->
- Membership = MoveSets#movesets.membership,
- %% check for 'active' membership here, if debugging
- hipe_bifs:array_update(Membership, Element, 'none'),
- MoveSets.
-
-add_worklist(Element, MoveSets) ->
- Membership = MoveSets#movesets.membership,
- %% check for 'none' membership here, if debugging
- hipe_bifs:array_update(Membership, Element, 'worklist'),
- set_worklist([Element | worklist(MoveSets)], MoveSets).
-
-add_active(Element, MoveSets) ->
- Membership = MoveSets#movesets.membership,
- %% check for 'none' membership here, if debugging
- hipe_bifs:array_update(Membership, Element, 'active'),
- MoveSets.
-
-member_active(Element, MoveSets) ->
- hipe_bifs:array_sub(MoveSets#movesets.membership, Element) =:= 'active'.
-
-is_empty_worklist(MoveSets) ->
- %% This is an approximation. See worklist_get_and_remove().
- worklist(MoveSets) =:= [].
-
-worklist_get_and_remove(MoveSets) ->
- worklist_get_and_remove(worklist(MoveSets), MoveSets#movesets.membership, MoveSets).
-
-worklist_get_and_remove([], _Membership, MoveSets) ->
- {[], set_worklist([], MoveSets)};
-worklist_get_and_remove([Move|Worklist], Membership, MoveSets) ->
- case hipe_bifs:array_sub(Membership, Move) of
- 'worklist' ->
- hipe_bifs:array_update(Membership, Move, 'none'),
- {Move, set_worklist(Worklist, MoveSets)};
- _ ->
- worklist_get_and_remove(Worklist, Membership, MoveSets)
- end.
-
-node_moves(Node, MoveSets) ->
- Associated = node_movelist(Node, MoveSets),
- Membership = MoveSets#movesets.membership,
- %% The ordsets:union() in hipe_coalescing_regalloc:combine()
- %% constrains us to return an ordset here.
- [X || X <- Associated, hipe_bifs:array_sub(Membership, X) =/= 'none'].
-
-move_related(Node, MoveSets) ->
- %% Same as node_moves(Node, MoveSets) =/= [], but less expensive to compute.
- %% XXX: George&Appel'96 hints that this should be maintained as a per-node counter.
- move_related2(node_movelist(Node, MoveSets), MoveSets#movesets.membership).
-
-move_related2([], _Membership) -> false;
-move_related2([Move|MoveSets], Membership) ->
- case hipe_bifs:array_sub(Membership, Move) of
- 'none' -> move_related2(MoveSets, Membership);
- _ -> true % 'active' or 'worklist'
- end.
-
-node_movelist(Node, MoveSets) ->
- hipe_vectors:get(movelist(MoveSets), Node).
-
-get_move(Move, MoveSets) ->
- element(Move+1, MoveSets#movesets.moveinsns).
-
-%%----------------------------------------------------------------------
-%% Print functions - only used for debugging
-
--ifdef(DEBUG_PRINTOUTS).
-print_memberships(MoveSets) ->
- ?debug_msg("Move memeberships:\n", []),
- Membership = MoveSets#movesets.membership,
- NrMoves = hipe_bifs:array_length(Membership),
- print_membership(NrMoves, Membership).
-
-print_membership(0, _) ->
- true;
-print_membership(Element, Membership) ->
- NextElement = Element - 1,
- ?debug_msg("move ~w ~w\n", [NextElement, hipe_bifs:array_sub(Membership, NextElement)]),
- print_membership(NextElement, Membership).
--endif.
-
diff --git a/lib/hipe/regalloc/hipe_node_sets.erl b/lib/hipe/regalloc/hipe_node_sets.erl
deleted file mode 100644
index 3cdfb62090..0000000000
--- a/lib/hipe/regalloc/hipe_node_sets.erl
+++ /dev/null
@@ -1,42 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_node_sets).
-
--export([new/0,
- spilled/1,
- colored/1,
- add_spilled/2,
- add_colored/2
- ]).
-
--record(node_sets,
- {spilled, % Nodes marked for spilling
- colored % Nodes successfully colored
- }).
-
-spilled(Node_sets) -> Node_sets#node_sets.spilled.
-colored(Node_sets) -> Node_sets#node_sets.colored.
-
-set_spilled(Spilled, Node_sets) -> Node_sets#node_sets{spilled = Spilled}.
-set_colored(Colored, Node_sets) -> Node_sets#node_sets{colored = Colored}.
-
-new() ->
- #node_sets{spilled = [], colored = []}.
-
-add_spilled(Node, Node_sets) ->
- set_spilled([Node | spilled(Node_sets)], Node_sets).
-
-add_colored(Node, Node_sets) ->
- set_colored([Node | colored(Node_sets)], Node_sets).
diff --git a/lib/hipe/regalloc/hipe_optimistic_regalloc.erl b/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
deleted file mode 100644
index a019c46b90..0000000000
--- a/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
+++ /dev/null
@@ -1,2075 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-----------------------------------------------------------------------
-%% File : hipe_optimistic_regalloc.erl
-%% Authors : NilsOla Linnermark <nilsola@abc.se>
-%% Petter Holmberg <petter.holmberg@usa.net>
-%% Purpose : Play paintball with registers on a target machine. We win
-%% if they are all colored. This is an optimistic coalescing
-%% register allocator.
-%% Created : Spring 2005
-%%-----------------------------------------------------------------------
-
--module(hipe_optimistic_regalloc).
--export([regalloc/7]).
-
--ifndef(DEBUG).
-%%-define(DEBUG,true).
--else.
--ifndef(COMPARE_ITERATED_OPTIMISTIC).
-%% If this macro is turned on you can easily compare
-%% each intermediate step in the iterated coalescing
-%% register allocator and the optimitsitc coalescing
-%% register allocator. This is useful for debugging -
-%% many small erlang functions should render the same
-%% register allocaton for both allocators.
--define(COMPARE_ITERATED_OPTIMISTIC, true).
--endif.
--endif.
--include("../main/hipe.hrl").
--ifdef(DEBUG_PRINTOUTS).
--define(print_adjacent(IG), hipe_ig:print_adjacent(IG)).
--define(print_degrees(IG), hipe_ig:print_degrees(IG)).
--define(print_spill_costs(IG), hipe_ig:print_spill_costs(IG)).
--define(mov_print_memberships(MV), hipe_moves:print_memberships(MV)).
--define(reg_print_memberships(WL), hipe_reg_worklists:print_memberships(WL)).
--define(print_alias(A), printAlias(A)).
--define(print_colors(T,C), printColors(T,C)).
--else.
--define(print_adjacent(IG), no_print).
--define(print_degrees(IG), no_print).
--define(print_spill_costs(IG), no_print).
--define(mov_print_memberships(MV), no_print).
--define(reg_print_memberships(WL), no_print).
--define(print_alias(A), no_print).
--define(print_colors(T,C), no_print).
--endif.
-
-
-%%-----------------------------------------------------------------------
-%% Function: regalloc
-%%
-%% Description: Creates a K coloring for a function.
-%% Parameters:
-%% CFG -- A control flow graph
-%% SpillIndex -- Last index of spill variable
-%% SpillLimit -- Temporaris with numbers higher than this have
-%% infinit spill cost.
-%% Consider changing this to a set.
-%% TgtMod -- The module containing the target-specific functions.
-%% TgtCtx -- Context data for TgtMod
-%%
-%% Returns:
-%% Coloring -- A coloring for specified CFG
-%% SpillIndex2 -- A new spill index
-%%-----------------------------------------------------------------------
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-regalloc(CFG, Liveness, SpillIndex, SpillLimit, TgtMod, TgtCtx, _Options) ->
- Target = {TgtMod, TgtCtx},
- ?debug_msg("optimistic ~w\n",[TgtMod]),
- ?debug_msg("CFG: ~p\n",[CFG]),
- %% Build interference graph
- ?debug_msg("Build IG\n",[]),
- IG_O = hipe_ig:build(CFG, Liveness, TgtMod, TgtCtx),
- IG = hipe_ig:build(CFG, Liveness, TgtMod, TgtCtx),
- ?debug_msg("adjlist: ~p\n",[hipe_ig:adj_list(IG)]),
- ?debug_msg("IG:\n",[]),
- ?print_adjacent(IG),
- ?print_degrees(IG),
- ?print_spill_costs(IG),
-
- SavedSpillCosts = hipe_ig:spill_costs(IG),
- SavedAdjList = hipe_ig:adj_list(IG),
-
- ?debug_msg("Init\n",[]),
- No_temporaries = number_of_temporaries(CFG, Target),
- ?debug_msg("Coalescing RA: num_temps = ~p~n", [No_temporaries]),
- Allocatable = allocatable(Target),
- K = length(Allocatable),
- All_colors = colset_from_list(Allocatable),
- ?debug_msg("K: ~w~nAll_colors: ~p\n",[K, All_colors]),
-
- %% Add registers with their own coloring
- ?debug_msg("Moves\n",[]),
- Move_sets_O = hipe_moves:new(IG_O),
- Move_sets = hipe_moves:new(IG),
- ?debug_msg("Move_sets:\n ~p\n",[Move_sets]),
- ?mov_print_memberships(Move_sets),
-
- ?debug_msg("Build Worklist\n",[]),
- Worklists_O = hipe_reg_worklists:new(IG_O, TgtMod, TgtCtx, CFG, Move_sets_O,
- K, No_temporaries),
- ?debug_msg("Worklists:\n ~p\n", [Worklists_O]),
- ?reg_print_memberships(Worklists_O),
-
- Worklists = hipe_reg_worklists:new(IG, TgtMod, TgtCtx, CFG, K,
- No_temporaries),
- ?debug_msg("New Worklists:\n ~p\n", [Worklists]),
- ?reg_print_memberships(Worklists),
-
- Alias_O = initAlias(No_temporaries),
- Alias = initAlias(No_temporaries),
- ?print_alias(Alias),
-
- ?debug_msg("Do coloring\n~p~n",[Worklists_O]),
- {IG0_O, Worklists0_O, Moves0_O, Alias0_O} =
- do_coloring(IG_O, Worklists_O, Move_sets_O, Alias_O,
- K, SpillLimit, Target),
- ?debug_msg("IG_O after color:\n ~p\n",[IG0_O]),
- ?print_adjacent(IG0_O),
- ?print_degrees(IG0_O),
- ?print_spill_costs(IG0_O),
- ?debug_msg("Move_sets after color:\n ~p\n",[Moves0_O]),
- ?mov_print_memberships(Moves0_O),
- ?debug_msg("Worklists after color:\n ~p\n", [Worklists0_O]),
- ?reg_print_memberships(Worklists0_O),
-
- {IG0, Moves0, Alias0, Worklists0} =
- do_coalescing(IG, Worklists, Move_sets, Alias, K, Target),
- ?debug_msg("IG after coalescing:\n",[]),
- ?print_adjacent(IG0),
- ?print_degrees(IG0),
- ?print_spill_costs(IG0),
- ?debug_msg("Move_sets after coalescing:\n ~p\n",[Moves0]),
- ?mov_print_memberships(Moves0),
- ?debug_msg("New Worklists after coalescing:\n ~p\n",
- [Worklists0]),
- ?reg_print_memberships(Worklists0),
-
- {IG1, Worklists1, Moves1, Alias1} =
- do_simplify_or_spill(IG0, Worklists0, Moves0, Alias0,
- K, SpillLimit, Target),
- ?debug_msg("IG after simplify_or_spill:\n",[]),
- ?print_adjacent(IG1),
- ?print_degrees(IG1),
- ?print_spill_costs(IG1),
- ?debug_msg("Saved spill costs ~p~n", [SavedSpillCosts]),
- ?debug_msg("Move_sets after simplify_or_spill:\n ~p\n",[Moves1]),
- ?mov_print_memberships(Moves1),
- ?debug_msg("New Worklists after simplify_or_spill:\n ~p\n",
- [Worklists1]),
- ?reg_print_memberships(Worklists1),
- ?print_alias(Alias1),
-
- %% only for testing undoCoalescing and member_coalesced_to
- %test_undoCoalescing(No_temporaries, Alias1, Worklists1),
-
- %% only for testing fixAdj
- %?debug_msg("adj_lists_before_fixAdj ~n~p~n", [hipe_ig:adj_list(IG1)]),
- %IG2 = test_fixAdj(No_temporaries, SavedAdjList, IG1, Target),
- %?debug_msg("adj_lists__after_fixAdj ~n~p~n", [hipe_ig:adj_list(IG2)]),
-
- ?debug_msg("Init node sets\n",[]),
- Node_sets = hipe_node_sets:new(),
- %% ?debug_msg("NodeSet: ~w\n NonAlloc ~w\n",[Node_sets,non_alloc(CFG,Target)]),
- ?debug_msg("Default coloring\n",[]),
- {Color0,Node_sets1} =
- defaultColoring(all_precoloured(Target),
- initColor(No_temporaries), Node_sets, Target),
- ?debug_msg("Color0\n",[]),
- ?print_colors(No_temporaries, Color0),
-
- ?debug_msg("----------------------Assign colors _N\n",[]),
-
- Stack = hipe_reg_worklists:stack(Worklists1),
- ?debug_msg("The stack _N ~p~n", [Stack]),
- %SortedStack = sort_stack(Stack),
- %?debug_msg("The stack _N ~p~n", [SortedStack]),
-
- %?debug_msg("Nodes _N ~w~n", [Node_sets1]),
-
- {Color1,Node_sets2,Alias2} =
- assignColors(Worklists1, Stack, Node_sets1, Color0,
- No_temporaries, SavedAdjList, SavedSpillCosts, IG1, Alias1, All_colors, Target),
- ?print_colors(No_temporaries, Color1),
- ?debug_msg("Nodes:~w\nNodes2:~w\nNo_temporaries:~w\n",[Node_sets,Node_sets2,No_temporaries]),
-
- ?debug_msg("Build mapping _N ~w\n",[Node_sets2]),
- {Coloring,SpillIndex2} =
- build_namelist(Node_sets2,SpillIndex,Alias2,Color1),
- ?debug_msg("Coloring ~p\n",[Coloring]),
- SortedColoring = {sort_stack(Coloring), SpillIndex2},
- ?debug_msg("SortedColoring ~p\n",[SortedColoring]),
- %%Coloring.
- ?debug_msg("----------------------Assign colors _O\n",[]),
- {Color1_O,Node_sets2_O} =
- assignColors_O(hipe_reg_worklists:stack(Worklists0_O), Node_sets1, Color0,
- Alias0_O, All_colors, Target),
- ?print_colors(No_temporaries, Color1_O),
- ?debug_msg("Nodes:~w\nNodes2:~w\nNo_temporaries:~w\n",[Node_sets,Node_sets2_O,No_temporaries]),
-
- ?debug_msg("Build mapping ~w\n",[Node_sets2_O]),
- Coloring_O = build_namelist_O(Node_sets2_O,SpillIndex,Alias0_O,Color1_O),
- ?debug_msg("Coloring_O ~p\n",[Coloring_O]),
- SortedColoring_O = {sort_stack(element(1, Coloring_O)), element(2, Coloring_O)},
- ?debug_msg("SortedColoring_O ~p\n",[SortedColoring_O]),
- sanity_compare(SortedColoring_O, SortedColoring),
- {Coloring,SpillIndex2}.
--else.
-regalloc(CFG, Liveness, SpillIndex, SpillLimit, TgtMod, TgtCtx, _Options) ->
- Target = {TgtMod, TgtCtx},
- ?debug_msg("optimistic ~w\n",[TgtMod]),
- ?debug_msg("CFG: ~p\n",[CFG]),
- %% Build interference graph
- ?debug_msg("Build IG\n",[]),
- IG = hipe_ig:build(CFG, Liveness, TgtMod, TgtCtx),
- ?debug_msg("adjlist: ~p\n",[hipe_ig:adj_list(IG)]),
- ?debug_msg("IG:\n",[]),
- ?print_adjacent(IG),
- ?print_degrees(IG),
- ?print_spill_costs(IG),
-
- SavedSpillCosts = hipe_ig:spill_costs(IG),
- SavedAdjList = hipe_ig:adj_list(IG),
-
- ?debug_msg("Init\n",[]),
- No_temporaries = number_of_temporaries(CFG, Target),
- ?debug_msg("Coalescing RA: num_temps = ~p~n", [No_temporaries]),
- Allocatable = allocatable(Target),
- K = length(Allocatable),
- All_colors = colset_from_list(Allocatable),
- ?debug_msg("K: ~w~nAll_colors: ~p\n",[K, All_colors]),
-
- %% Add registers with their own coloring
- ?debug_msg("Moves\n",[]),
- Move_sets = hipe_moves:new(IG),
- ?debug_msg("Move_sets:\n ~p\n",[Move_sets]),
- ?mov_print_memberships(Move_sets),
-
- ?debug_msg("Build Worklist\n",[]),
-
- Worklists = hipe_reg_worklists:new(IG, TgtMod, TgtCtx, CFG, K,
- No_temporaries),
- ?debug_msg("New Worklists:\n ~p\n", [Worklists]),
- ?reg_print_memberships(Worklists),
-
- Alias = initAlias(No_temporaries),
- ?print_alias(Alias),
-
- {IG0, Moves0, Alias0, Worklists0} =
- do_coalescing(IG, Worklists, Move_sets, Alias, K, Target),
- ?debug_msg("IG after coalescing:\n",[]),
- ?print_adjacent(IG0),
- ?print_degrees(IG0),
- ?print_spill_costs(IG0),
- ?debug_msg("Move_sets after coalescing:\n ~p\n",[Moves0]),
- ?mov_print_memberships(Moves0),
- ?debug_msg("New Worklists after coalescing:\n ~p\n",
- [Worklists0]),
- ?reg_print_memberships(Worklists0),
-
- {IG1, Worklists1, _Moves1, Alias1} =
- do_simplify_or_spill(IG0, Worklists0, Moves0, Alias0,
- K, SpillLimit, Target),
- ?debug_msg("IG after simplify_or_spill:\n",[]),
- ?print_adjacent(IG1),
- ?print_degrees(IG1),
- ?print_spill_costs(IG1),
- ?debug_msg("Saved spill costs ~p~n", [SavedSpillCosts]),
- ?debug_msg("New Worklists after simplify_or_spill:\n ~p\n",
- [Worklists1]),
- ?reg_print_memberships(Worklists1),
- ?print_alias(Alias1),
-
- %% only for testing undoCoalescing and member_coalesced_to
- %test_undoCoalescing(No_temporaries, Alias1, Worklists1),
-
- %% only for testing fixAdj
- %?debug_msg("adj_lists_before_fixAdj ~n~p~n", [hipe_ig:adj_list(IG1)]),
- %IG2 = test_fixAdj(No_temporaries, SavedAdjList, IG1, Target),
- %?debug_msg("adj_lists__after_fixAdj ~n~p~n", [hipe_ig:adj_list(IG2)]),
-
- ?debug_msg("Init node sets\n",[]),
- Node_sets = hipe_node_sets:new(),
- %% ?debug_msg("NodeSet: ~w\n NonAlloc ~w\n",[Node_sets,non_alloc(CFG,Target)]),
- ?debug_msg("Default coloring\n",[]),
- {Color0,Node_sets1} =
- defaultColoring(all_precoloured(Target),
- initColor(No_temporaries), Node_sets, Target),
- ?debug_msg("Color0\n",[]),
- ?print_colors(No_temporaries, Color0),
-
- ?debug_msg("----------------------Assign colors _N\n",[]),
-
- Stack = hipe_reg_worklists:stack(Worklists1),
- ?debug_msg("The stack _N ~p~n", [Stack]),
- %SortedStack = sort_stack(Stack),
- %?debug_msg("The stack _N ~p~n", [SortedStack]),
-
- %?debug_msg("Nodes _N ~w~n", [Node_sets1]),
-
- {Color1,Node_sets2,Alias2} =
- assignColors(Worklists1, Stack, Node_sets1, Color0,
- No_temporaries, SavedAdjList, SavedSpillCosts, IG1, Alias1, All_colors, Target),
- ?print_colors(No_temporaries, Color1),
- ?debug_msg("Nodes:~w\nNodes2:~w\nNo_temporaries:~w\n",[Node_sets,Node_sets2,No_temporaries]),
-
- ?debug_msg("Build mapping _N ~w\n",[Node_sets2]),
- {Coloring, SpillIndex2} = build_namelist(Node_sets2,SpillIndex,Alias2,Color1),
- ?debug_msg("Coloring ~p\n",[Coloring]),
- {Coloring,SpillIndex2}.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: do_coloring
-%%
-%% Description: Create a coloring. That is, play paintball.
-%% Parameters:
-%% IG -- An interference graph
-%% Worklists -- Worklists, that is simplify, spill and freeze
-%% Moves -- Moves sets, that is coalesced, constrained
-%% and so on.
-%% Alias -- Tells if two temporaries can have their value
-%% in the same register.
-%% K -- Want to create a K coloring.
-%% SpillLimit -- Try not to spill nodes that are above the spill limit.
-%%
-%% Returns:
-%% IG -- Updated interference graph
-%% Worklists -- Updated Worklists structure
-%% Moves -- Updated Moves structure
-%% Alias -- Updates Alias structure
-%%
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-do_coloring(IG, Worklists, Moves, Alias, K, SpillLimit, Target) ->
- Simplify = not(hipe_reg_worklists:is_empty_simplify(Worklists)),
- Coalesce = not(hipe_moves:is_empty_worklist(Moves)),
- Freeze = not(hipe_reg_worklists:is_empty_freeze(Worklists)),
- Spill = not(hipe_reg_worklists:is_empty_spill(Worklists)),
- if Simplify =:= true ->
- {IG0, Worklists0, Moves0} =
- simplify_O(hipe_reg_worklists:simplify(Worklists),
- IG,
- Worklists,
- Moves,
- K),
- do_coloring(IG0, Worklists0, Moves0, Alias, K, SpillLimit, Target);
- Coalesce =:= true ->
- {Moves0, IG0, Worklists0, Alias0} =
- coalesce_O(Moves, IG, Worklists, Alias, K, Target),
- do_coloring(IG0, Worklists0, Moves0, Alias0, K, SpillLimit, Target);
- Freeze =:= true ->
- {Worklists0, Moves0} =
- freeze(K, Worklists, Moves, IG, Alias),
- do_coloring(IG, Worklists0, Moves0, Alias, K, SpillLimit, Target);
- Spill =:= true ->
- {Worklists0, Moves0} =
- selectSpill_O(Worklists, Moves, IG, K, Alias, SpillLimit),
- do_coloring(IG, Worklists0, Moves0, Alias, K, SpillLimit, Target);
- true -> % Catchall case
- {IG, Worklists, Moves, Alias}
- end.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: do_coalescing
-%%
-%% Description: Try to coalesce everything (find out later if it was
-%% possible).
-%% Parameters:
-%% IG -- An interference graph
-%% Moves -- Moves sets, that is coalesced, constrained
-%% and so on.
-%% Alias -- Tells if two temporaries can have their value
-%% in the same register.
-%%
-%% Returns:
-%% IG -- Updated interference graph
-%% Moves -- Updated Moves structure
-%% Alias -- Updates Alias structure
-%%
-%%----------------------------------------------------------------------
-
-do_coalescing(IG, Worklists, Moves, Alias, K, Target) ->
- case hipe_moves:is_empty_worklist(Moves) of
- true ->
- {IG, Moves, Alias, Worklists};
- _ ->
- {Moves0, IG0, Alias0, Worklists0} =
- coalesce(Moves, IG, Worklists, Alias, K, Target),
- do_coalescing(IG0, Worklists0, Moves0, Alias0, K, Target)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: do_simplify_or_spill
-%%
-%% Parameters:
-%% IG -- An interference graph
-%% Worklists -- Worklists, that is simplify, spill and freeze
-%% Moves -- Moves sets, that is coalesced, constrained
-%% and so on.
-%% Alias -- Tells if two temporaries can have their value
-%% in the same register.
-%% K -- Want to create a K coloring.
-%% SpillLimit -- Try not to spill nodes that are above the spill limit.
-%%
-%% Returns:
-%% IG -- Updated interference graph
-%% Worklists -- Updated Worklists structure
-%% Moves -- Updated Moves structure
-%% Alias -- Updates Alias structure
-%%
-%%----------------------------------------------------------------------
-
-do_simplify_or_spill(IG, Worklists, Moves, Alias, K, SpillLimit, Target) ->
- Simplify = not(hipe_reg_worklists:is_empty_simplify(Worklists)),
- Spill = not(hipe_reg_worklists:is_empty_spill(Worklists)),
- if Simplify =:= true ->
- {IG0, Worklists0, Moves0} =
- simplify(hipe_reg_worklists:simplify(Worklists),
- IG,
- Worklists,
- Moves,
- K),
- do_simplify_or_spill(IG0, Worklists0, Moves0, Alias,
- K, SpillLimit, Target);
- Spill =:= true ->
- Worklists0 =
- selectSpill(Worklists, IG, SpillLimit),
- do_simplify_or_spill(IG, Worklists0, Moves, Alias,
- K, SpillLimit, Target);
- true -> % Catchall case
- {IG, Worklists, Moves, Alias}
- end.
-
-%%----------------------------------------------------------------------
-%% Function: adjacent
-%%
-%% Description: Adjacent nodes that's not coalesced, on the stack or
-%% precoloured.
-%% Parameters:
-%% Node -- Node that you want to adjacents of
-%% IG -- The interference graph
-%%
-%% Returns:
-%% A set with nodes/temporaries that are not coalesced, on the
-%% stack or precoloured.
-%%----------------------------------------------------------------------
-
-adjacent(Node, IG, Worklists) ->
- Adjacent_edges = hipe_ig:node_adj_list(Node, IG),
- hipe_reg_worklists:non_stacked_or_coalesced_nodes(Adjacent_edges, Worklists).
-
-%%----------------------------------------------------------------------
-%% Function: simplify
-%%
-%% Description: Simplify graph by removing nodes of low degree. This
-%% function simplify all nodes it can at once.
-%% Parameters:
-%% [Node|Nodes] -- The simplify worklist
-%% IG -- The interference graph
-%% Worklists -- The worklists data-structure
-%% Moves -- The moves data-structure
-%% K -- Produce a K coloring
-%%
-%% Returns:
-%% IG -- An updated interference graph
-%% Worklists -- An updated worklists data-structure
-%% Moves -- An updated moves data-structure
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-simplify_O([], IG, Worklists, Moves, _K) ->
- {IG, Worklists, Moves};
-simplify_O([Node|Nodes], IG, Worklists, Moves, K) ->
- Worklists0 = hipe_reg_worklists:remove_simplify(Node, Worklists),
- ?debug_msg("putting ~w on stack~n",[Node]),
- Adjacent = adjacent(Node, IG, Worklists0),
- Worklists01 = hipe_reg_worklists:push_stack(Node, Adjacent, Worklists0),
- {New_ig, Worklists1, New_moves} =
- decrement_degree_O(Adjacent, IG, Worklists01, Moves, K),
- simplify_O(Nodes, New_ig, Worklists1, New_moves, K).
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: simplify
-%%
-%% Description: Simplify graph by removing nodes of low degree. This
-%% function simplify all nodes it can at once.
-%% Parameters:
-%% [Node|Nodes] -- The simplify worklist
-%% IG -- The interference graph
-%% Worklists -- The worklists data-structure
-%% Moves -- The moves data-structure
-%% K -- Produce a K coloring
-%%
-%% Returns:
-%% IG -- An updated interference graph
-%% Worklists -- An updated worklists data-structure
-%% Moves -- An updated moves data-structure
-%%----------------------------------------------------------------------
-
-simplify([], IG, Worklists, Moves, _K) ->
- {IG, Worklists, Moves};
-simplify([Node|Nodes], IG, Worklists, Moves, K) ->
- Worklists0 = hipe_reg_worklists:remove_simplify(Node, Worklists),
- ?debug_msg("putting ~w on stack~n",[Node]),
- Adjacent = adjacent(Node, IG, Worklists0),
- Worklists01 = hipe_reg_worklists:push_stack(Node, Adjacent, Worklists0),
- {New_ig, Worklists1} = decrement_degree(Adjacent, IG, Worklists01, K),
- simplify(Nodes, New_ig, Worklists1, Moves, K).
-
-%%----------------------------------------------------------------------
-%% Function: decrement_degree
-%%
-%% Description: Decrement the degree on a number of nodes/temporaries.
-%% Parameters:
-%% [Node|Nodes] -- Decrement degree on these nodes
-%% IG -- The interference graph
-%% Worklists -- The Worklists data structure
-%% Moves -- The Moves data structure.
-%% K -- We want to create a coloring with K colors
-%%
-%% Returns:
-%% IG -- An updated interference graph (the degrees)
-%% Worklists -- Updated Worklists. Changed if one degree goes
-%% down to K.
-%% Moves -- Updated Moves. Changed if a move related temporary
-%% gets degree K.
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-decrement_degree_O([], IG, Worklists, Moves, _K) ->
- {IG, Worklists, Moves};
-decrement_degree_O([Node|Nodes], IG, Worklists, Moves, K) ->
- PrevDegree = hipe_ig:get_node_degree(Node, IG),
- IG0 = hipe_ig:dec_node_degree(Node, IG),
- case PrevDegree =:= K of
- true ->
- AdjList = hipe_ig:node_adj_list(Node, IG0),
- %% OK since Node (a) is still in IG, and (b) cannot be adjacent to itself.
- Moves00 = enable_moves_active_to_worklist(hipe_moves:node_movelist(Node, Moves),
- Moves),
- Moves0 = enable_moves(AdjList, Worklists, Moves00),
- Worklists0 = hipe_reg_worklists:remove_spill(Node, Worklists),
- case hipe_moves:move_related(Node, Moves0) of
- true ->
- Worklists1 = hipe_reg_worklists:add_freeze(Node, Worklists0),
- decrement_degree_O(Nodes, IG0, Worklists1, Moves0, K);
- _ ->
- Worklists1 = hipe_reg_worklists:add_simplify(Node, Worklists0),
- decrement_degree_O(Nodes, IG0, Worklists1, Moves0, K)
- end;
- _ ->
- decrement_degree_O(Nodes, IG0, Worklists, Moves, K)
- end.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: decrement_degree
-%%
-%% Description: Decrement the degree on a number of nodes/temporaries.
-%% Parameters:
-%% [Node|Nodes] -- Decrement degree on these nodes
-%% IG -- The interference graph
-%% Worklists -- The Worklists data structure
-%% Moves -- The Moves data structure.
-%% K -- We want to create a coloring with K colors
-%%
-%% Returns:
-%% IG -- An updated interference graph (the degrees)
-%% Worklists -- Updated Worklists. Changed if one degree goes
-%% down to K.
-%% Moves -- Updated Moves. Changed if a move related temporary
-%% gets degree K.
-%%----------------------------------------------------------------------
-
-decrement_degree([], IG, Worklists, _K) ->
- {IG, Worklists};
-decrement_degree([Node|Nodes], IG, Worklists, K) ->
- PrevDegree = hipe_ig:get_node_degree(Node, IG),
- IG0 = hipe_ig:dec_node_degree(Node, IG),
- case PrevDegree =:= K of
- true ->
- Worklists0 = hipe_reg_worklists:remove_spill(Node, Worklists),
- Worklists1 = hipe_reg_worklists:add_simplify(Node, Worklists0),
- decrement_degree(Nodes, IG0, Worklists1, K);
- _ ->
- decrement_degree(Nodes, IG0, Worklists, K)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: enable_moves
-%%
-%% Description: Make (move-related) nodes that are not yet considered for
-%% coalescing, ready for possible coalescing.
-%%
-%% Parameters:
-%% [Node|Nodes] -- A list of move nodes
-%% Moves -- The moves data-structure
-%%
-%% Returns:
-%% An updated moves data-structure
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-enable_moves([], _Worklists, Moves) -> Moves;
-enable_moves([Node|Nodes], Worklists, Moves) ->
- case hipe_reg_worklists:member_stack_or_coalesced(Node, Worklists) of
- true -> enable_moves(Nodes, Worklists, Moves);
- _ ->
- %% moveList[n] suffices since we're checking for activeMoves membership
- Node_moves = hipe_moves:node_movelist(Node, Moves),
- New_moves = enable_moves_active_to_worklist(Node_moves, Moves),
- enable_moves(Nodes, Worklists, New_moves)
- end.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: enable_moves_active_to_worklist
-%%
-%% Description: Make (move-related) nodes that are not yeat considered for
-%% coalescing, ready for possible coalescing.
-%%
-%% Parameters:
-%% [Node|Nodes] -- A list of move nodes
-%% Moves -- The moves data-structure
-%%
-%% Returns:
-%% An updated moves data-structure
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-enable_moves_active_to_worklist([], Moves) -> Moves;
-enable_moves_active_to_worklist([Node|Nodes], Moves) ->
- case hipe_moves:member_active(Node, Moves) of
- true ->
- New_moves =
- hipe_moves:add_worklist(Node, hipe_moves:remove_active(Node, Moves)),
- enable_moves_active_to_worklist(Nodes, New_moves);
- _ ->
- enable_moves_active_to_worklist(Nodes, Moves)
- end.
--endif.
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-sanity_compare(Coloring, Coloring_N) ->
- case compare_sanity(Coloring, Coloring_N) of
- false ->
- ?debug_msg("mismatch for coloring: ~n~p~n~p", [Coloring, Coloring_N]);
- _ -> true
- end.
-compare_sanity({[], _C}, {[], _C_N}) ->
- ?debug_msg("Sanity - OK!~n", []),
- true;
-compare_sanity({_Coloring_list, _C}, {[], _C_N}) ->
- ?debug_msg("Sanity - unequal numbers~n", []),
- false;
-compare_sanity({[], _C}, {_Coloring_list_N, _C_N}) ->
- ?debug_msg("Sanity - unequal numbers~n", []),
- false;
-compare_sanity({[Color|Coloring_list], C}, {[Color_N|Coloring_list_N], C_N}) ->
- case element(1, Color) =:= element(1, Color_N) of
- false ->
- ?debug_msg("Sanity - unequal measure~n", []),
- false;
- _ ->
- case element(2, Color) =:= element(2, Color_N) of
- false ->
- ?debug_msg("Sanity - unequal color~n", []),
- false;
- _ ->
- case C =:= C_N of
- false ->
- ?debug_msg("Sanity - unequal last element~n", []),
- false;
- _ ->
- compare_sanity({Coloring_list, C}, {Coloring_list_N, C_N})
- end
- end
- end.
--endif.
-
-
-%% Build the namelists, these functions are fast hacks, they use knowledge
-%% about data representation that they shouldn't know, bad abstraction.
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-build_namelist_O(NodeSets,Index,Alias,Color) ->
- ?debug_msg("NodeSets ~w~n", [NodeSets]),
- ?debug_msg("Building mapping\n",[]),
- ?debug_msg("Vector to list\n",[]),
- AliasList =
- build_alias_list(aliasToList(Alias),
- 0, %% The first temporary has index 0
- []), %% Accumulator
- ?debug_msg("Alias list:~p\n",[AliasList]),
- ?debug_msg("Coalesced\n",[]),
- NL1 = build_coalescedlist(AliasList,Color,Alias,[]),
- ?debug_msg("Coalesced list:~p\n",[NL1]),
- ?debug_msg("Regs\n",[]),
- NL2 = build_reglist_O(hipe_node_sets:colored(NodeSets),Color,NL1),
- ?debug_msg("Regs list:~p\n",[NL2]),
- ?debug_msg("Spills\n",[]),
- build_spillist(hipe_node_sets:spilled(NodeSets),Index,NL2).
--endif.
-
-build_namelist(NodeSets,Index,Alias,Color) ->
- ?debug_msg("NodeSets _N ~w~n", [NodeSets]),
- ?debug_msg("Building mapping _N\n",[]),
- ?debug_msg("Vector to list _N\n",[]),
- AliasList =
- build_alias_list(aliasToList(Alias),
- 0, %% The first temporary has index 0
- []), %% Accumulator
- ?debug_msg("Alias list _N:~p\n",[AliasList]),
- ?debug_msg("Coalesced\n",[]),
- NL1 = build_coalescedlist(AliasList,Color,Alias,[]),
- ?debug_msg("Coalesced list:~p\n",[NL1]),
- ?debug_msg("Regs _N\n",[]),
- ColoredNodes = hipe_node_sets:colored(NodeSets),
- ?debug_msg("ColoredNodes ~p~n", [ColoredNodes]),
- NL2 = build_reglist_N(ColoredNodes,Color,NL1,NL1),
- ?debug_msg("Regs list _N:~p\n",[NL2]),
- ?debug_msg("Spills _N\n",[]),
- build_spillist(hipe_node_sets:spilled(NodeSets),Index,NL2).
-
-build_spillist([],Index,List) ->
- {List,Index};
-build_spillist([Node|Nodes],Index,List) ->
- ?debug_msg("[~p]: Spill ~p to ~p\n", [?MODULE,Node,Index]),
- build_spillist(Nodes,Index+1,[{Node,{spill,Index}}|List]).
-
-build_coalescedlist([],_Color,_Alias,List) ->
- List;
-build_coalescedlist([Node|Ns],Color,Alias,List) when is_integer(Node) ->
- ?debug_msg("Alias of ~p is ~p~n",[Node,getAlias(Node,Alias)]),
- AC = getColor(getAlias(Node,Alias),Color),
- build_coalescedlist(Ns,Color,Alias,[{Node,{reg,AC}}|List]).
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-build_reglist_O([],_Color,List) ->
- List;
-build_reglist_O([Node|Ns],Color,List) ->
- build_reglist_O(Ns,Color,[{Node,{reg,getColor(Node,Color)}}|List]).
--endif.
-
-build_reglist_N([],_Color,List,_OrgList) ->
- List;
-build_reglist_N([Node|Ns],Color,List,OrgList) ->
- %% XXX this could be done more efficiently if both lists were sorted
- case is_already_in_list(Node, OrgList) of
- true -> build_reglist_N(Ns, Color, List, OrgList);
- _ -> build_reglist_N(Ns,Color,[{Node,{reg,getColor(Node,Color)}}|List], OrgList)
- end.
-
-is_already_in_list(_Node, []) ->
- false;
-is_already_in_list(Node, [L|List]) ->
- ?debug_msg("---test--- Node ~w element ~w~n", [Node, element(1, L)]),
- case Node =:= element(1, L) of
- true -> true;
- _ -> is_already_in_list(Node, List)
- end.
-
-build_alias_list([], _I, List) ->
- List;
-build_alias_list([Alias|Aliases], I, List) when is_integer(Alias) ->
- build_alias_list(Aliases, I+1, [I|List]);
-build_alias_list([_Alias|Aliases], I, List) ->
- build_alias_list(Aliases, I+1, List).
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-sort_stack([]) -> [];
-sort_stack([Pivot|Rest]) ->
- {Smaller, Bigger} = sort_stack_split(Pivot, Rest),
- lists:append(sort_stack(Smaller), [Pivot|sort_stack(Bigger)]).
-
-sort_stack_split(Pivot, L) ->
- sort_stack_split(Pivot, L, [], []).
-
-sort_stack_split(_Pivot, [], Smaller, Bigger) ->
- {Smaller, Bigger};
-sort_stack_split(Pivot, [H|T], Smaller, Bigger) when element(1, H) > element(1, Pivot) ->
- sort_stack_split(Pivot, T, [H|Smaller], Bigger);
-sort_stack_split(Pivot, [H|T], Smaller, Bigger) ->
- sort_stack_split(Pivot, T, Smaller, [H|Bigger]).
--endif.
-
-%sort([]) -> [];
-%sort([Pivot|Rest]) ->
-% {Smaller, Bigger} = sort_split(Pivot, Rest),
-% lists:append(sort(Smaller), [Pivot|sort(Bigger)]).
-%
-%sort_split(Pivot, L) ->
-% sort_split(Pivot, L, [], []).
-%
-%sort_split(_Pivot, [], Smaller, Bigger) -> {Smaller, Bigger};
-%sort_split(Pivot, [H|T], Smaller, Bigger) when H > Pivot ->
-% sort_split(Pivot, T, [H|Smaller], Bigger);
-%sort_split(Pivot, [H|T], Smaller, Bigger) ->
-% sort_split(Pivot, T, Smaller, [H|Bigger]).
-
-%%----------------------------------------------------------------------
-%% Function: assignColors
-%%
-%% Description: Tries to assign colors to nodes in a stack.
-%% Parameters:
-%% Worklists -- The Worklists data structure.
-%% Stack -- The SelectStack built by the Select function,
-%% this stack contains tuples in the form {Node,Edges}
-%% where Node is the Node number and Edges is an ordset
-%% containing the numbers of all the adjacent nodes.
-%% NodeSets -- This is a record containing all the different node
-%% sets that are used in the register allocator.
-%% Color -- A mapping from nodes to their respective color.
-%% No_temporaries -- Number of temporaries.
-%% SavedAdjList -- Saved adjacency list (from before coalescing).
-%% SavedSpillCosts -- Saved spill costs (from before coalescing).
-%% IG -- The interference graph.
-%% Alias -- This is a mapping from nodes to nodes. If a node has
-%% been coalesced, this mapping shows the alias for that
-%% node.
-%% AllColors -- This is an ordset containing all the available colors
-%% Target -- The module containing the target-specific functions,
-%% along with its context data.
-%%
-%% Returns:
-%% Color -- A mapping from nodes to their respective color.
-%% NodeSets -- The updated node sets.
-%% Alias -- The updated aliases.
-%%----------------------------------------------------------------------
-
-assignColors(Worklists, Stack, NodeSets, Color, No_Temporaries,
- SavedAdjList, SavedSpillCosts, IG, Alias, AllColors, Target) ->
- case Stack of
- [] ->
- {Color,NodeSets,Alias};
- [{Node,Edges}|Stack1] ->
- ?debug_msg("Coloring Node: ~p~n",[Node]),
- ?IF_DEBUG(lists:foreach(fun (_E) ->
- ?msg(" Edge ~w-><~w>->~w~n",
- begin A = getAlias(_E,Alias),
- [_E,A,getColor(A,Color)]
- end)
- end, Edges),
- []),
- %% When debugging, check that Node isn't precoloured.
- OkColors = findOkColors(Edges, AllColors, Color, Alias),
- case colset_is_empty(OkColors) of
- true -> % Spill case
- case hipe_reg_worklists:member_coalesced_to(Node, Worklists) of
- true ->
- ?debug_msg("Alias case. Undoing coalescing.~n", []),
- {Alias1, IG1, NodeSets1, Color1, Stack2} = tryPrimitiveNodes(Node, Stack1, NodeSets, AllColors, Color, No_Temporaries, SavedAdjList, SavedSpillCosts, IG, Alias, Target),
- %{Alias1, IG1, NodeSets1, Color1, Stack2} = {Alias, IG, NodeSets, Color, Stack1},
- assignColors(Worklists, Stack2, NodeSets1, Color1, No_Temporaries, SavedAdjList, SavedSpillCosts, IG1, Alias1, AllColors, Target);
- false ->
- ?debug_msg("Spill case. Spilling node.~n", []),
- NodeSets1 = hipe_node_sets:add_spilled(Node, NodeSets),
- assignColors(Worklists, Stack1, NodeSets1, Color, No_Temporaries, SavedAdjList, SavedSpillCosts, IG, Alias, AllColors, Target)
- end;
- false -> % Color case
- Col = colset_smallest(OkColors),
- NodeSets1 = hipe_node_sets:add_colored(Node, NodeSets),
- Color1 = setColor(Node, physical_name(Col,Target), Color),
- ?debug_msg("Color case. Assigning color ~p to node.~n", [Col]),
- assignColors(Worklists, Stack1, NodeSets1, Color1, No_Temporaries, SavedAdjList, SavedSpillCosts, IG, Alias, AllColors, Target)
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Function: tryPrimitiveNodes
-%%
-%% Description: Undoes coalescing of a non-colorable coalesced node and tries
-%% to assign colors to its primitives, such that the cheapest
-%% potential spill cost is achieved.
-%% Parameters:
-%% Node -- The representative node to undo coalescing for.
-%% Stack -- The SelectStack built by the Select function,
-%% this stack contains tuples in the form {Node,Edges}
-%% where Node is the Node number and Edges is an ordset
-%% containing the numbers of all the adjacent nodes.
-%% NodeSets -- This is a record containing all the different node
-%% sets that are used in the register allocator.
-%% AllColors -- This is an ordset containing all the available colors.
-%% No_temporaries -- Number of temporaries.
-%% SavedAdjList -- Saved adjacency list (from before coalescing).
-%% SavedSpillCosts -- Saved spill costs (from before coalescing).
-%% IG -- The interference graph.
-%% Alias -- This is a mapping from nodes to nodes. If a node has
-%% been coalesced, this mapping shows the alias for that
-%% node.
-%% Target -- The module containing the target-specific functions,
-%% along with its context data.
-%%
-%% Returns:
-%% Alias -- The restored aliases after the uncoalescing.
-%% IG -- An updated interference graph after the uncoalescing.
-%% NodeSets -- The updated node sets.
-%% Color -- A mapping from nodes to their respective color.
-%% Stack -- The updated SelectStack with non-colored primitives
-%% placed at the bottom.
-%%----------------------------------------------------------------------
-
-tryPrimitiveNodes(Node, Stack, NodeSets, AllColors, Color, No_temporaries, SavedAdjList, SavedSpillCosts, IG, Alias, Target) ->
- ?debug_msg("Undoing coalescing of node ~p.~n", [Node]),
- {PrimitiveNodes, Alias1, IG1} = undoCoalescing(Node, No_temporaries, Alias, SavedAdjList, IG, Target),
- ?debug_msg("Spilling non-colorable primitives.~n", []),
- {ColorableNodes, NodeSets1} = spillNonColorablePrimitives([], PrimitiveNodes, NodeSets, AllColors, Color, SavedAdjList, Alias1),
- ?debug_msg("Generating splits of colorable nodes.~n", []),
- Splits = splits(ColorableNodes, SavedSpillCosts),
- {NodeSets2, Color1, Stack1} = processSplits(Splits, AllColors, IG1, Color, NodeSets1, Alias1, Target, Stack),
- {Alias1, IG1, NodeSets2, Color1, Stack1}.
-
-%% Spill all non-colorable primitives and return the remaining set of nodes.
-
-spillNonColorablePrimitives(ColorableNodes, [], NodeSets, _AllColors, _Color, _SavedAdjList, _Alias) ->
- {ColorableNodes, NodeSets};
-spillNonColorablePrimitives(ColorableNodes, [Primitive|Primitives], NodeSets, AllColors, Color, SavedAdjList, Alias) ->
- OkColors = findOkColors(hipe_adj_list:edges(Primitive, SavedAdjList), AllColors, Color, Alias),
- case colset_is_empty(OkColors) of
- true -> % Spill case
- ?debug_msg(" Spilling primitive node ~p.~n", [Primitive]),
- NodeSets1 = hipe_node_sets:add_spilled(Primitive, NodeSets),
- spillNonColorablePrimitives(ColorableNodes, Primitives, NodeSets1, AllColors, Color, SavedAdjList, Alias);
- false -> % Colorable case
- ?debug_msg(" Primitive node ~p is colorable.~n", [Primitive]),
- spillNonColorablePrimitives([Primitive|ColorableNodes], Primitives, NodeSets, AllColors, Color, SavedAdjList, Alias)
- end.
-
-%% Generate all splits of colorable primitives, sorted in spill cost order.
-
-splits([], _SavedSpillCosts) ->
- [{[], [], 0}];
-splits([L|Ls], SavedSpillCosts) ->
- Spl = splits(Ls, SavedSpillCosts),
- SpillCost = hipe_spillcost:spill_cost(L, SavedSpillCosts),
- Spl1 = [splits_1(S, L) || S <- Spl],
- Spl2 = [splits_2(S, L, SpillCost) || S <- Spl],
- spillCostOrderedMerge(Spl1, Spl2, []).
-
-splits_1({Cols, NonCols, OldSpillCost}, L) ->
- {[L|Cols], NonCols, OldSpillCost}.
-
-splits_2({Cols, NonCols, OldSpillCost}, L, SpillCost) ->
- {Cols, [L|NonCols], OldSpillCost + SpillCost}.
-
-%% Merge two ordered sub-splits into one.
-
-spillCostOrderedMerge(Spl1, [], Spl) ->
- lists:reverse(Spl, Spl1);
-spillCostOrderedMerge([], Spl2, Spl) ->
- lists:reverse(Spl, Spl2);
-spillCostOrderedMerge(Spl1, Spl2, Spl) ->
- {_, _, SpillCost1} = hd(Spl1),
- {_, _, SpillCost2} = hd(Spl2),
- case SpillCost1 =< SpillCost2 of
- true ->
- spillCostOrderedMerge(tl(Spl1), Spl2, [hd(Spl1)|Spl]);
- false ->
- spillCostOrderedMerge(Spl1, tl(Spl2), [hd(Spl2)|Spl])
- end.
-
-%% Process splits, finding the one with the smallest spill cost that
-%% can be assigned one color.
-
-processSplits([], _AllColors, _IG, Color, NodeSets, _Alias, _Target, Stack) ->
- {NodeSets, Color, Stack};
-processSplits([{Cols, NonCols, _SpillCost}|Splits], AllColors, IG, Color, NodeSets, Alias, Target, Stack) ->
- OkColors = findCommonColors(Cols, IG, Color, Alias, AllColors),
- case colset_is_empty(OkColors) of
- false -> % This split can be colored with one color - use it
- ?debug_msg("Found a colorable split.~n", []),
- Col = colset_smallest(OkColors),
- {NodeSets1, Color1} = colorSplit(Cols, Col, NodeSets, Color, Target),
- Stack1 = enqueueSplit(NonCols, IG, Stack),
- {NodeSets1, Color1, Stack1};
- true -> % This split cannot be colored with one color - try another
- ?debug_msg("Unable to color split.~n", []),
- processSplits(Splits, AllColors, IG, Color, NodeSets, Alias, Target, Stack)
- end.
-
-%% Find the set of colors that can be assigned to one split.
-
-findCommonColors([], _IG, _Color, _Alias, OkColors) ->
- OkColors;
-findCommonColors([Primitive|Primitives], IG, Color, Alias, OkColors) ->
- OkColors1 = findOkColors(hipe_ig:node_adj_list(Primitive, IG), OkColors, Color, Alias),
- findCommonColors(Primitives, IG, Color, Alias, OkColors1).
-
-%% Color nodes in a split.
-
-colorSplit([], _Col, NodeSets, Color, _Target) ->
- {NodeSets, Color};
-colorSplit([Node|Nodes], Col, NodeSets, Color, Target) ->
- ?debug_msg(" Coloring node ~p with color ~p.~n", [Node, Col]),
- NodeSets1 = hipe_node_sets:add_colored(Node, NodeSets),
- Color1 = setColor(Node, physical_name(Col,Target), Color),
- colorSplit(Nodes, Col, NodeSets1, Color1, Target).
-
-%% Place non-colorable nodes in a split at the bottom of the SelectStack.
-
-enqueueSplit([], _IG, Stack) ->
- Stack;
-enqueueSplit([Node|Nodes], IG, Stack) ->
- ?debug_msg(" Placing node ~p at the bottom of the stack.~n", [Node]),
- Edges = hipe_ig:node_adj_list(Node, IG),
- Stack1 = Stack ++ [{Node, Edges}],
- enqueueSplit(Nodes, IG, Stack1).
-
-%%----------------------------------------------------------------------
-%% Function: assignColors
-%%
-%% Description: Tries to assign colors to nodes in a stack.
-%% Parameters:
-%% Stack -- The SelectStack built by the Select function,
-%% this stack contains tuples in the form {Node,Edges}
-%% where Node is the Node number and Edges is an ordset
-%% containing the numbers of all the adjacent nodes.
-%% NodeSets -- This is a record containing all the different node
-%% sets that are used in the register allocator.
-%% Alias -- This is a mapping from nodes to nodes, if a node has
-%% been coalesced this mapping shows the alias for that
-%% node.
-%% AllColors -- This is an ordset containing all the available colors
-%%
-%% Target -- The module containing the target-specific functions,
-%% along with its context data.
-%%
-%% Returns:
-%% Color -- A mapping from nodes to their respective color.
-%% NodeSets -- The updated node sets.
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-assignColors_O(Stack,NodeSets,Color,Alias,AllColors,Target) ->
- case Stack of
- [] ->
- {Color,NodeSets};
- [{Node,Edges}|Stack1] ->
- ?debug_msg("Coloring Node: ~p~n",[Node]),
- ?IF_DEBUG(lists:foreach(fun (_E) ->
- ?msg(" Edge ~w-><~w>->~w~n",
- begin A = getAlias(_E,Alias),
- [_E,A,getColor(A,Color)]
- end)
- end, Edges),
- []),
- %% When debugging, check that Node isn't precoloured.
- OkColors = findOkColors(Edges, AllColors, Color, Alias),
- case colset_is_empty(OkColors) of
- true -> % Spill case
- NodeSets1 = hipe_node_sets:add_spilled(Node, NodeSets),
- assignColors_O(Stack1, NodeSets1, Color, Alias, AllColors, Target);
- false -> % Colour case
- Col = colset_smallest(OkColors),
- NodeSets1 = hipe_node_sets:add_colored(Node, NodeSets),
- Color1 = setColor(Node, physical_name(Col,Target), Color),
- assignColors_O(Stack1, NodeSets1, Color1, Alias, AllColors, Target)
- end
- end.
--endif.
-
-%%---------------------------------------------------------------------
-%% Function: defaultColoring
-%%
-%% Description: Make the default coloring
-%% Parameters:
-%% Regs -- The list of registers to be default colored
-%% Color -- The color mapping that shall be changed
-%% NodeSets -- The node sets that shall be updated
-%% Target -- The module containing the target-specific functions,
-%% along with its context data.
-%%
-%% Returns:
-%% NewColor -- The updated color mapping
-%% NewNodeSets -- The updated node sets
-%%---------------------------------------------------------------------
-
-defaultColoring([], Color, NodeSets, _Target) ->
- {Color,NodeSets};
-defaultColoring([Reg|Regs], Color, NodeSets, Target) ->
- Color1 = setColor(Reg,physical_name(Reg,Target), Color),
- NodeSets1 = hipe_node_sets:add_colored(Reg, NodeSets),
- defaultColoring(Regs, Color1, NodeSets1, Target).
-
-%% Find the colors that are OK for a node with certain edges.
-
-findOkColors(Edges, AllColors, Color, Alias) ->
- find(Edges, AllColors, Color, Alias).
-
-%% Find all the colors of the nodes in the list [Node|Nodes] and remove them
-%% from the set OkColors, when the list is empty, return OkColors.
-
-find([], OkColors, _Color, _Alias) ->
- OkColors;
-find([Node0|Nodes], OkColors, Color, Alias) ->
- Node = getAlias(Node0, Alias),
- case getColor(Node, Color) of
- [] ->
- find(Nodes, OkColors, Color, Alias);
- Col ->
- OkColors1 = colset_del_element(Col, OkColors),
- find(Nodes, OkColors1, Color, Alias)
- end.
-
-%%%
-%%% ColSet -- ADT for the set of available colours while
-%%% assigning colours.
-%%%
--ifdef(notdef). % old ordsets-based implementation
-colset_from_list(Allocatable) ->
- ordsets:from_list(Allocatable).
-
-colset_del_element(Colour, ColSet) ->
- ordsets:del_element(Colour, ColSet).
-
-colset_is_empty(ColSet) ->
- case ColSet of
- [] -> true;
- [_|_] -> false
- end.
-
-colset_smallest([Colour|_]) ->
- Colour.
--endif.
-
--ifdef(notdef). % new gb_sets-based implementation
-colset_from_list(Allocatable) ->
- gb_sets:from_list(Allocatable).
-
-colset_del_element(Colour, ColSet) ->
- %% Must use gb_sets:delete_any/2 since gb_sets:del_element/2
- %% fails if the element isn't present. Bummer.
- gb_sets:delete_any(Colour, ColSet).
-
-colset_is_empty(ColSet) ->
- gb_sets:is_empty(ColSet).
-
-colset_smallest(ColSet) ->
- gb_sets:smallest(ColSet).
--endif.
-
-%%-ifdef(notdef). % new bitmask-based implementation
-colset_from_list(Allocatable) ->
- colset_from_list(Allocatable, 0).
-
-colset_from_list([], ColSet) ->
- ColSet;
-colset_from_list([Colour|Allocatable], ColSet) ->
- colset_from_list(Allocatable, ColSet bor (1 bsl Colour)).
-
-colset_del_element(Colour, ColSet) ->
- ColSet band bnot(1 bsl Colour).
-
-colset_is_empty(0) -> true;
-colset_is_empty(_) -> false.
-
-colset_smallest(ColSet) ->
- bitN_log2(ColSet band -ColSet, 0).
-
-bitN_log2(BitN, ShiftN) ->
- case BitN > 16#ffff of
- true ->
- bitN_log2(BitN bsr 16, ShiftN + 16);
- _ ->
- ShiftN + hweight16(BitN - 1)
- end.
-
-hweight16(W) ->
- Res1 = ( W band 16#5555) + (( W bsr 1) band 16#5555),
- Res2 = (Res1 band 16#3333) + ((Res1 bsr 2) band 16#3333),
- Res3 = (Res2 band 16#0F0F) + ((Res2 bsr 4) band 16#0F0F),
- (Res3 band 16#00FF) + ((Res3 bsr 8) band 16#00FF).
-%%-endif.
-
-%%%
-%%% Colour ADT providing a partial mapping from nodes to colours.
-%%%
-
-initColor(NrNodes) ->
- {colmap, hipe_bifs:array(NrNodes, [])}.
-
-getColor(Node, {colmap, ColMap}) ->
- hipe_bifs:array_sub(ColMap, Node).
-
-setColor(Node, Color, {colmap, ColMap} = C) ->
- hipe_bifs:array_update(ColMap, Node, Color),
- C.
-
--ifdef(DEBUG_PRINTOUTS).
-printColors(0, _) ->
- true;
-printColors(Node, {colmap, ColMap} = C) ->
- NextNode = Node - 1,
- ?debug_msg("node ~w color ~w~n", [NextNode, hipe_bifs:array_sub(ColMap, NextNode)]),
- printColors(NextNode, C).
--endif.
-
-%%%
-%%% Alias ADT providing a partial mapping from nodes to nodes.
-%%%
-
-initAlias(NrNodes) ->
- {alias, hipe_bifs:array(NrNodes, [])}.
-
-%% Get alias for a node.
-%% Note that non-aliased nodes could be represented in
-%% two ways, either not aliased or aliased to itself.
-%% Including the latter case prevents looping bugs.
-getAlias(Node, {alias, AliasMap} = Alias) ->
- case hipe_bifs:array_sub(AliasMap, Node) of
- [] ->
- Node;
- Node ->
- Node;
- AliasNode ->
- getAlias(AliasNode, Alias)
- end.
-
--ifdef(DEBUG_PRINTOUTS).
-printAlias({alias, AliasMap} = Alias) ->
- ?debug_msg("Aliases:\n",[]),
- printAlias(hipe_bifs:array_length(AliasMap), Alias).
-
-printAlias(0, {alias, _}) ->
- true ;
-printAlias(Node, {alias, _AliasMap} = Alias) ->
- ?debug_msg("alias ~p ~p\n", [Node - 1, getAlias(Node - 1, Alias)]),
- printAlias(Node - 1, Alias).
--endif.
-
-setAlias(Node, AliasNode, {alias, AliasMap} = Alias) ->
- hipe_bifs:array_update(AliasMap, Node, AliasNode),
- Alias.
-
-aliasToList({alias, AliasMap}) ->
- aliasToList(AliasMap, hipe_bifs:array_length(AliasMap), []).
-
-aliasToList(AliasMap, I1, Tail) ->
- I0 = I1 - 1,
- case I0 >= 0 of
- true ->
- aliasToList(AliasMap, I0, [hipe_bifs:array_sub(AliasMap, I0)|Tail]);
- _ ->
- Tail
- end.
-
-%%----------------------------------------------------------------------
-%% Function: coalesce
-%%
-%% Description: Coalesces nodes in worklist
-%% Parameters:
-%% Moves -- Current move information
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Alias -- Current aliases for temporaries
-%% K -- Number of registers
-%%
-%% Returns:
-%% {Moves, IG, Worklists, Alias}
-%% (Updated versions of above structures, after coalescing)
-%%----------------------------------------------------------------------
-
-coalesce(Moves, IG, Worklists, Alias, K, Target) ->
- case hipe_moves:worklist_get_and_remove(Moves) of
- {[],Moves0} ->
- %% Moves marked for removal from worklistMoves by FreezeMoves()
- %% are removed by worklist_get_and_remove(). This case is unlikely,
- %% but can occur if only stale moves remain in worklistMoves.
- {Moves0, IG, Alias};
- {Move,Moves0} ->
- {Dest,Source} = hipe_moves:get_move(Move, Moves0),
- ?debug_msg("Testing nodes ~p and ~p for coalescing~n",[Dest,Source]),
- Alias_src = getAlias(Source, Alias),
- Alias_dst = getAlias(Dest, Alias),
- {U,V} = case is_precoloured(Alias_dst, Target) of
- true -> {Alias_dst, Alias_src};
- false -> {Alias_src, Alias_dst}
- end,
- %% When debugging, check that neither V nor U is on the stack.
- case U =:= V of
- true ->
- %% drop coalesced move Move
- {Moves0, IG, Alias, Worklists};
- _ ->
- case (is_precoloured(V, Target) orelse
- hipe_ig:nodes_are_adjacent(U, V, IG)) of
- true ->
- %% drop constrained move Move
- {Moves0, IG, Alias, Worklists};
- false ->
- case (case is_precoloured(U, Target) of
- true ->
- AdjV = hipe_ig:node_adj_list(V, IG),
- all_adjacent_ok(AdjV, U, Worklists, IG, K, Target);
- false ->
- AdjV = hipe_ig:node_adj_list(V, IG),
- AdjU = hipe_ig:node_adj_list(U, IG),
- conservative(AdjU, AdjV, U, Worklists, IG, K)
- end) of
- true ->
- %% drop coalesced move Move
- {IG1, Alias1, Worklists1} =
- combine(U, V, IG, Alias, Worklists, K, Target),
- {Moves0, IG1, Alias1, Worklists1};
- false ->
- Moves1 = hipe_moves:add_active(Move, Moves0),
- {Moves1, IG, Alias, Worklists}
- end
- end
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Function: coalesce_O
-%%
-%% Description: Coalesces nodes in worklist
-%% Parameters:
-%% Moves -- Current move information
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Alias -- Current aliases for temporaries
-%% K -- Number of registers
-%%
-%% Returns:
-%% {Moves, IG, Worklists, Alias}
-%% (Updated versions of above structures, after coalescing)
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-coalesce_O(Moves, IG, Worklists, Alias, K, Target) ->
- case hipe_moves:worklist_get_and_remove(Moves) of
- {[],Moves0} ->
- %% Moves marked for removal from worklistMoves by FreezeMoves()
- %% are removed by worklist_get_and_remove(). This case is unlikely,
- %% but can occur if only stale moves remain in worklistMoves.
- {Moves0,IG,Worklists,Alias};
- {Move,Moves0} ->
- {Dest,Source} = hipe_moves:get_move(Move, Moves0),
- ?debug_msg("Testing nodes ~p and ~p for coalescing~n",[Dest,Source]),
- Alias_src = getAlias(Source, Alias),
- Alias_dst = getAlias(Dest, Alias),
- {U,V} = case is_precoloured(Alias_dst, Target) of
- true -> {Alias_dst, Alias_src};
- false -> {Alias_src, Alias_dst}
- end,
- %% When debugging, check that neither V nor U is on the stack.
- case U =:= V of
- true ->
- Moves1 = Moves0, % drop coalesced move Move
- Worklists1 = add_worklist(Worklists, U, K, Moves1, IG, Target),
- {Moves1, IG, Worklists1, Alias};
- _ ->
- case (is_precoloured(V, Target) orelse
- hipe_ig:nodes_are_adjacent(U, V, IG)) of
- true ->
- Moves1 = Moves0, % drop constrained move Move
- Worklists1 = add_worklist(Worklists, U, K, Moves1, IG, Target),
- Worklists2 = add_worklist(Worklists1, V, K, Moves1, IG, Target),
- {Moves1, IG, Worklists2, Alias};
- false ->
- case (case is_precoloured(U, Target) of
- true ->
- AdjV = hipe_ig:node_adj_list(V, IG),
- all_adjacent_ok(AdjV, U, Worklists, IG, K, Target);
- false ->
- AdjV = hipe_ig:node_adj_list(V, IG),
- AdjU = hipe_ig:node_adj_list(U, IG),
- conservative(AdjU, AdjV, U, Worklists, IG, K)
- end) of
- true ->
- Moves1 = Moves0, % drop coalesced move Move
- {IG1,Worklists1,Moves2,Alias1} =
- combine_O(U, V, IG, Worklists, Moves1, Alias, K, Target),
- Worklists2 = add_worklist(Worklists1, U, K, Moves2, IG1, Target),
- {Moves2, IG1, Worklists2, Alias1};
- false ->
- Moves1 = hipe_moves:add_active(Move, Moves0),
- {Moves1, IG, Worklists, Alias}
- end
- end
- end
- end.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: add_worklist
-%%
-%% Description: Builds new worklists where U is transferred from freeze
-%% to simplify, if possible
-%%
-%% Parameters:
-%% Worklists -- Current worklists
-%% U -- Node to operate on
-%% K -- Number of registers
-%% Moves -- Current move information
-%% IG -- Interference graph
-%% Target -- The containing the target-specific functions, along with
-%% its context data.
-%%
-%% Returns:
-%% Worklists (updated)
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-add_worklist(Worklists, U, K, Moves, IG, Target) ->
- case (not(is_precoloured(U, Target))
- andalso not(hipe_moves:move_related(U, Moves))
- andalso (hipe_ig:is_trivially_colourable(U, K, IG))) of
- true ->
- hipe_reg_worklists:transfer_freeze_simplify(U, Worklists);
- false ->
- Worklists
- end.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: combine
-%%
-%% Description: Combines two nodes into one (used when coalescing)
-%%
-%% Parameters:
-%% U -- First node to operate on
-%% V -- Second node to operate on
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Moves -- Current move information
-%% Alias -- Current aliases for temporaries
-%% K -- Number of registers
-%%
-%% Returns:
-%% {IG, Worklists, Moves, Alias} (updated)
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-combine_O(U, V, IG, Worklists, Moves, Alias, K, Target) ->
- Worklists1 = case hipe_reg_worklists:member_freeze(V, Worklists) of
- true -> hipe_reg_worklists:remove_freeze(V, Worklists);
- false -> hipe_reg_worklists:remove_spill(V, Worklists)
- end,
- Worklists11 = hipe_reg_worklists:add_coalesced(V, Worklists1),
-
- ?debug_msg("Coalescing ~p and ~p to ~p~n",[V,U,U]),
-
- Alias1 = setAlias(V, U, Alias),
-
- %% Typo in published algorithm: s/nodeMoves/moveList/g to fix.
- %% XXX: moveList[u] \union moveList[v] OR NodeMoves(u) \union NodeMoves(v) ???
- %% XXX: NodeMoves() is correct, but unnecessarily strict. The ordsets:union
- %% constrains NodeMoves() to return an ordset.
- Moves1 = hipe_moves:update_movelist(U,
- ordsets:union(hipe_moves:node_moves(U, Moves),
- hipe_moves:node_moves(V, Moves)),
- Moves),
- %% Missing in published algorithm. From Tiger book Errata.
- Moves2 = enable_moves_active_to_worklist(hipe_moves:node_movelist(V, Moves1), Moves1),
- AdjV = hipe_ig:node_adj_list(V, IG),
-
- {IG1, Worklists2, Moves3} =
- combine_edges_O(AdjV, U, IG, Worklists11, Moves2, K, Target),
-
- New_worklists = case (not(hipe_ig:is_trivially_colourable(U, K, IG1))
- andalso hipe_reg_worklists:member_freeze(U, Worklists2)) of
- true -> hipe_reg_worklists:transfer_freeze_spill(U, Worklists2);
- false -> Worklists2
- end,
- {IG1, New_worklists, Moves3, Alias1}.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: combine
-%%
-%% Description: Combines two nodes into one (used when coalescing)
-%%
-%% Parameters:
-%% U -- First node to operate on
-%% V -- Second node to operate on
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Moves -- Current move information
-%% Alias -- Current aliases for temporaries
-%% K -- Number of registers
-%%
-%% Returns:
-%% {IG, Worklists, Moves, Alias} (updated)
-%%----------------------------------------------------------------------
-
-combine(U, V, IG, Alias, Worklists, K, Target) ->
- ?debug_msg("N_Coalescing ~p and ~p to ~p~n",[V,U,U]),
- Worklists1 = hipe_reg_worklists:add_coalesced(V, U, Worklists),
- Alias1 = setAlias(V, U, Alias),
- AdjV = hipe_ig:node_adj_list(V, IG),
- IG1 = combine_edges(AdjV, U, IG, Worklists1, K, Target),
- {IG1, Alias1, Worklists1}.
-
-%%----------------------------------------------------------------------
-%% Function: combine_edges
-%%
-%% Description: For each node in a list, make an edge between that node
-%% and node U, and decrement its degree by 1
-%% (Used when two nodes are coalesced, to connect all nodes
-%% adjacent to one node to the other node)
-%%
-%% Parameters:
-%% [T|Ts] -- List of nodes to make edges to
-%% U -- Node to make edges from
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Moves -- Current move information
-%% K -- Number of registers
-%%
-%% Returns:
-%% {IG, Worklists, Moves} (updated)
-%%----------------------------------------------------------------------
-
-combine_edges([], _U, IG, _Worklists, _K, _Target) ->
- IG;
-combine_edges([T|Ts], U, IG, Worklists, K, Target={TgtMod,TgtCtx}) ->
- case hipe_reg_worklists:member_stack_or_coalesced(T, Worklists) of
- true -> combine_edges(Ts, U, IG, Worklists, K, Target);
- _ ->
- IG1 = hipe_ig:add_edge(T, U, IG, TgtMod, TgtCtx),
- IG2 = case is_precoloured(T, Target) of
- true -> IG1;
- false -> hipe_ig:dec_node_degree(T, IG1)
- end,
- combine_edges(Ts, U, IG2, Worklists, K, Target)
- end.
-
-%%----------------------------------------------------------------------
-%% Function: combine_edges
-%%
-%% Description: For each node in a list, make an edge between that node
-%% and node U, and decrement its degree by 1
-%% (Used when two nodes are coalesced, to connect all nodes
-%% adjacent to one node to the other node)
-%%
-%% Parameters:
-%% [T|Ts] -- List of nodes to make edges to
-%% U -- Node to make edges from
-%% IG -- Interference graph
-%% Worklists -- Current worklists
-%% Moves -- Current move information
-%% K -- Number of registers
-%%
-%% Returns:
-%% {IG, Worklists, Moves} (updated)
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-combine_edges_O([], _U, IG, Worklists, Moves, _K, _Target) ->
- {IG, Worklists, Moves};
-combine_edges_O([T|Ts], U, IG, Worklists, Moves, K, Target={TgtMod,TgtCtx}) ->
- case hipe_reg_worklists:member_stack_or_coalesced(T, Worklists) of
- true -> combine_edges_O(Ts, U, IG, Worklists, Moves, K, Target);
- _ ->
- %% XXX: The issue below occurs because the T->V edge isn't removed.
- %% This causes adjList[T] to contain stale entries, to possibly grow
- %% (if T isn't already adjacent to U), and degree[T] to possibly
- %% increase (again, if T isn't already adjacent to U).
- %% The decrement_degree() call repairs degree[T] but not adjList[T].
- %% It would be better to physically replace T->V with T->U, and only
- %% decrement_degree(T) if T->U already existed.
- %%
- %% add_edge() may change a low-degree move-related node to be of
- %% significant degree. In this case the node belongs in the spill
- %% worklist, and that's where decrement_degree() expects to find it.
- %% This issue is not covered in the published algorithm.
- OldDegree = hipe_ig:get_node_degree(T, IG),
- IG1 = hipe_ig:add_edge(T, U, IG, TgtMod, TgtCtx),
- NewDegree = hipe_ig:get_node_degree(T, IG1),
- Worklists0 =
- if NewDegree =:= K, OldDegree =:= K-1 ->
- %% ?debug_msg("~w:combine_edges_O(): repairing worklist membership for node ~w\n", [?MODULE,T]),
- %% The node T must be on the freeze worklist:
- %% 1. Since we're coalescing, the simplify worklist must have been
- %% empty when combine_edges_O() started.
- %% 2. decrement_degree() may put the node T back on the simplify
- %% worklist, but that occurs after the worklists repair step.
- %% 3. There are no duplicates among the edges.
- Worklists00 = hipe_reg_worklists:remove_freeze(T, Worklists),
- hipe_reg_worklists:add_spill(T, Worklists00);
- true ->
- Worklists
- end,
- {IG2, Worklists1, Moves1} =
- decrement_degree_O([T], IG1, Worklists0, Moves, K),
- combine_edges_O(Ts, U, IG2, Worklists1, Moves1, K, Target)
- end.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: undoCoalescing
-%%
-%% Description: Returns necessary information for a coalesced node
-%%
-%% Parameters:
-%% N -- The node to uncoalesce
-%% No_temporaries -- Number of temporaries
-%% Alias -- The Alias vector before undoing
-%% SavedAdj -- Saved adjacency list
-%% IG -- Interference graph
-%% Target -- The module containing the target-specific functions,
-%% along with its context data.
-%%
-%% Returns:
-%% list of primitive nodes, that is all nodes that were previously
-%% coalesced to N
-%% updated alias vector
-%% updated Interferece graph
-%%----------------------------------------------------------------------
-undoCoalescing(N, No_temporaries, Alias, SavedAdj, IG, Target) ->
- Primitives = findPrimitiveNodes(No_temporaries, N, Alias),
- Alias1 = restoreAliases(Primitives, Alias),
- IG1 = fixAdj(N, SavedAdj, IG, Target),
- {Primitives, Alias1, IG1}.
-
-%% Restore aliasinfo for primitive nodes, that is
-%% unalias the node sthat were aliased to the primitive
-%% nodes. Note that an unaliased node could be
-%% represented in two ways, either not aliased or aliased
-%% to itself. See also getAlias
-restoreAliases([], Alias) ->
- Alias;
-restoreAliases([Primitive|Primitives], Alias) ->
- Alias1 = setAlias(Primitive, Primitive, Alias),
- restoreAliases(Primitives, Alias1).
-
-%% find the primitive nodes to N, that is find all
-%% nodes that are aliased to N
-findPrimitiveNodes(No_temporaries, N, Alias) ->
- findPrimitiveNodes(No_temporaries, N, Alias, []).
-
-findPrimitiveNodes(0, _N, _Alias, PrimitiveNodes) ->
- PrimitiveNodes;
-findPrimitiveNodes(Node, N, Alias, PrimitiveNodes) ->
- NextNode = Node - 1,
- case (getAlias(NextNode, Alias) =:= N) of
- true -> findPrimitiveNodes(NextNode, N, Alias, [NextNode | PrimitiveNodes]);
- _ -> findPrimitiveNodes(NextNode, N, Alias, PrimitiveNodes)
- end.
-
-%test_undoCoalescing(No_temporaries, Alias, Worklists) ->
-% test_undoCoalescing(No_temporaries, No_temporaries, Alias, Worklists).
-%
-%test_undoCoalescing(0, _No_temporaries, _Alias, _Worklists) ->
-% true;
-%test_undoCoalescing(Node, No_temporaries, Alias, Worklists) ->
-% %?debug_msg("++ the adj list: ~p~n", [SavedAdj]),
-% %?debug_msg("Node ~p~n", [Node]),
-% NextNode = Node - 1,
-% Coalesced_to = hipe_reg_worklists:member_coalesced_to(NextNode, Worklists),
-% ?debug_msg("³³-- member coalesced: ~p~n", [Coalesced_to]),
-% {Primitives, Alias1} = undoCoalescing(NextNode, No_temporaries, Alias),
-% ?debug_msg("½½-- primitivenodes ~w\n", [Primitives]),
-% case (Coalesced_to) of
-% true -> printAlias(Alias1);
-% _ -> true
-% end,
-% test_undoCoalescing(NextNode, No_temporaries, Alias, Worklists).
-
-%%----------------------------------------------------------------------
-%% Function: fixAdj
-%%
-%% Description: Fixes adajency set and adjacency list when undoing coalescing
-%%
-%% Parameters:
-%% N -- Node that should be uncoalesced
-%% SavedAdj -- Saved adjacency list
-%% IG -- Interference graph
-%% Target -- The module containing the target-specific functions, along
-%% with its context data.
-%%
-%% Returns:
-%% updated Interferece graph
-%%----------------------------------------------------------------------
-fixAdj(N, SavedAdj, IG, Target) ->
- %Saved = hipe_vectors:get(SavedAdj, N),
- Saved = hipe_adj_list:edges(N, SavedAdj),
- ?debug_msg("§§--adj to ~p: ~p~n", [N, Saved]),
- Adj = hipe_ig:node_adj_list(N, IG),
- ?debug_msg("««--adj to ~p: ~p~n", [N, Adj]),
- New = findNew(Adj, Saved),
- ?debug_msg("++--new adj to ~p: ~p~n", [N, New]),
- removeAdj(New, N, IG, Target),
- %% XXX the following lines seems to make double nodes in
- %% some adj_lists, which is a bug, apart from that they
- %% don't seem to make any difference at all (even though
- %% they are in the pseudocode of "optimistic coalescing")
- %% addedge for all in the restored adj_list
- %%RestoredAdj = hipe_ig:node_adj_list(N, IG),
- %%?debug_msg("adj_lists_before_restore_o ~n~p~n", [hipe_ig:adj_list(IG)]),
- %%restoreAdj(RestoredAdj, N, IG, Alias, Target).
- IG.
-
-removeAdj([], _N, _IG, _Target) ->
- true;
-removeAdj([V| New], N, IG, Target={TgtMod,TgtCtx}) ->
- hipe_ig:remove_edge(V, N, IG, TgtMod, TgtCtx),
- removeAdj(New, N, IG, Target).
-
-%%restoreAdj([], _N, IG, _Alias, _Target) ->
-%% %%?debug_msg("adj_lists__after_restore_o ~n~p~n", [hipe_ig:adj_list(IG)]),
-%% IG;
-%%restoreAdj([V| AdjToN], N, IG, Alias, Target={TgtMod,TgtCtx}) ->
-%% AliasToV = getAlias(V, Alias),
-%% IG1 = hipe_ig:add_edge(N, AliasToV, IG, TgtMod, TgtCtx),
-%% restoreAdj(AdjToN, N, IG1, Alias, Target).
-
-%% XXX This is probably a clumsy way of doing it
-%% better to assure the lists are sorted from the beginning
-%% also coalesce findNew and removeAdj should improve performance
-findNew(Adj, Saved) ->
- findNew(Adj, Saved, []).
-
-findNew([], _Saved, New) ->
- New;
-findNew([A| Adj], Saved, New) ->
- case lists:member(A, Saved) of
- true -> findNew(Adj, Saved, New);
- _ -> findNew(Adj, Saved, [A| New])
- end.
-
-%test_fixAdj(0, _SavedAdj, IG, _Target) ->
-% IG;
-%test_fixAdj(Node, SavedAdj, IG, Target) ->
-% NextNode = Node - 1,
-% IG1 = fixAdj(NextNode, SavedAdj, IG, Target),
-% test_fixAdj(NextNode, SavedAdj, IG1, Target).
-%%----------------------------------------------------------------------
-%% Function: ok
-%%
-%% Description: Checks if a node T is suitable to coalesce with R
-%%
-%% Parameters:
-%% T -- Node to test
-%% R -- Other node to test
-%% IG -- Interference graph
-%% K -- Number of registers
-%% Target -- The module containing the target-specific functions, along
-%% with its context data.
-%%
-%% Returns:
-%% true iff coalescing is OK
-%%----------------------------------------------------------------------
-
-ok(T, R, IG, K, Target) ->
- ((hipe_ig:is_trivially_colourable(T, K, IG))
- orelse is_precoloured(T, Target)
- orelse hipe_ig:nodes_are_adjacent(T, R, IG)).
-
-%%----------------------------------------------------------------------
-%% Function: all_ok
-%%
-%% Description: True iff, for every T in the list, OK(T,U)
-%%
-%% Parameters:
-%% [T|Ts] -- Nodes to test
-%% U -- Node to test for coalescing
-%% IG -- Interference graph
-%% K -- Number of registers
-%% Target -- The module containing the target-specific functions, along
-%% with its context data.
-%%
-%% Returns:
-%% true iff coalescing is OK for all nodes in the list
-%%----------------------------------------------------------------------
-
-all_adjacent_ok([], _U, _Worklists, _IG, _K, _Target) -> true;
-all_adjacent_ok([T|Ts], U, Worklists, IG, K, Target) ->
- case hipe_reg_worklists:member_stack_or_coalesced(T, Worklists) of
- true -> all_adjacent_ok(Ts, U, Worklists, IG, K, Target);
- _ ->
- %% 'andalso' does not preserve tail-recursion
- case ok(T, U, IG, K, Target) of
- true -> all_adjacent_ok(Ts, U, Worklists, IG, K, Target);
- false -> false
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Function: conservative
-%%
-%% Description: Checks if nodes can be safely coalesced according to
-%% the Briggs' conservative coalescing heuristic
-%%
-%% Parameters:
-%% Nodes -- Adjacent nodes
-%% IG -- Interference graph
-%% K -- Number of registers
-%%
-%% Returns:
-%% true iff coalescing is safe
-%%----------------------------------------------------------------------
-
-conservative(AdjU, AdjV, U, Worklists, IG, K) ->
- conservative_countU(AdjU, AdjV, U, Worklists, IG, K, 0).
-
-%%----------------------------------------------------------------------
-%% Function: conservative_count
-%%
-%% Description: Counts degrees for conservative (Briggs' heuristics)
-%%
-%% Parameters:
-%% Nodes -- (Remaining) adjacent nodes
-%% IG -- Interference graph
-%% K -- Number of registers
-%% Cnt -- Accumulator for counting
-%%
-%% Returns:
-%% Final value of accumulator
-%%----------------------------------------------------------------------
-
-conservative_countU([], AdjV, U, Worklists, IG, K, Cnt) ->
- conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
-conservative_countU([Node|AdjU], AdjV, U, Worklists, IG, K, Cnt) ->
- case hipe_reg_worklists:member_stack_or_coalesced(Node, Worklists) of
- true -> conservative_countU(AdjU, AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- case hipe_ig:is_trivially_colourable(Node, K, IG) of
- true -> conservative_countU(AdjU, AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- Cnt1 = Cnt + 1,
- if Cnt1 < K -> conservative_countU(AdjU, AdjV, U, Worklists, IG, K, Cnt1);
- true -> false
- end
- end
- end.
-
-conservative_countV([], _U, _Worklists, _IG, _K, _Cnt) -> true;
-conservative_countV([Node|AdjV], U, Worklists, IG, K, Cnt) ->
- case hipe_reg_worklists:member_stack_or_coalesced(Node, Worklists) of
- true -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- case hipe_ig:nodes_are_adjacent(Node, U, IG) of
- true -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- case hipe_ig:is_trivially_colourable(Node, K, IG) of
- true -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt);
- _ ->
- Cnt1 = Cnt + 1,
- if Cnt1 < K -> conservative_countV(AdjV, U, Worklists, IG, K, Cnt1);
- true -> false
- end
- end
- end
- end.
-
-%%---------------------------------------------------------------------
-%% Function: selectSpill
-%%
-%% Description: Select the node to spill and spill it
-%% Parameters:
-%% WorkLists -- A datatype containing the different worklists
-%% IG -- The interference graph
-%% K -- The number of available registers
-%% Alias -- The alias mapping
-%% SpillLimit -- Try not to spill any nodes above the spill limit
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%%---------------------------------------------------------------------
-
-selectSpill(WorkLists, IG, SpillLimit) ->
- [CAR|CDR] = hipe_reg_worklists:spill(WorkLists),
- SpillCost = getCost(CAR, IG, SpillLimit),
- M = findCheapest(CDR, IG, SpillCost, CAR, SpillLimit),
- WorkLists1 = hipe_reg_worklists:remove_spill(M, WorkLists),
- hipe_reg_worklists:add_simplify(M, WorkLists1).
-
-%%---------------------------------------------------------------------
-%% Function: selectSpill
-%%
-%% Description: Select the node to spill and spill it
-%% Parameters:
-%% WorkLists -- A datatype containing the different worklists
-%% Moves -- A datatype containing the move sets
-%% IG -- The interference graph
-%% K -- The number of available registers
-%% Alias -- The alias mapping
-%% SpillLimit -- Try not to spill any nodes above the spill limit
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%% Moves -- The updated moves
-%%---------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-selectSpill_O(WorkLists, Moves, IG, K, Alias, SpillLimit) ->
- [CAR|CDR] = hipe_reg_worklists:spill(WorkLists),
-
- SpillCost = getCost(CAR, IG, SpillLimit),
- M = findCheapest(CDR, IG, SpillCost, CAR, SpillLimit),
-
- WorkLists1 = hipe_reg_worklists:remove_spill(M, WorkLists),
- %% The published algorithm adds M to the simplify worklist
- %% before the freezeMoves() call. That breaks the worklist
- %% invariants, which is why the order is switched here.
- {WorkLists2,Moves1} = freezeMoves(M, K, WorkLists1, Moves, IG, Alias),
- WorkLists3 = hipe_reg_worklists:add_simplify(M, WorkLists2),
- {WorkLists3,Moves1}.
--endif.
-
-%% Find the node that is cheapest to spill
-
-findCheapest([], _IG, _Cost, Cheapest, _SpillLimit) ->
- Cheapest;
-findCheapest([Node|Nodes], IG, Cost, Cheapest, SpillLimit) ->
- ThisCost = getCost(Node, IG, SpillLimit),
- case ThisCost < Cost of
- true ->
- findCheapest(Nodes, IG, ThisCost, Node, SpillLimit);
- false ->
- findCheapest(Nodes, IG, Cost, Cheapest, SpillLimit)
- end.
-
-%% Get the cost for spilling a certain node, node numbers above the spill
-%% limit are extremely expensive.
-
-getCost(Node, IG, SpillLimit) ->
- case Node >= SpillLimit of
- true -> inf;
- false ->
- SpillCost = hipe_ig:node_spill_cost(Node, IG),
- ?debug_msg("Actual spillcost f node ~w is ~w~n", [Node, SpillCost]),
- SpillCost
- end.
-
-%%----------------------------------------------------------------------
-%% Function: freeze
-%%
-%% Description: When both simplifying and coalescing is impossible we
-%% rather freezes a node in stead of spilling, this function
-%% selects a node for freezing (it just picks the first one in
-%% the list)
-%%
-%% Parameters:
-%% K -- The number of available registers
-%% WorkLists -- A datatype containing the different worklists
-%% Moves -- A datatype containing the different movelists
-%% IG -- Interference graph
-%% Alias -- An alias mapping, shows the alias of all coalesced
-%% nodes
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%% Moves -- The updated movelists
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-freeze(K, WorkLists, Moves, IG, Alias) ->
- [U|_] = hipe_reg_worklists:freeze(WorkLists), % Smarter routine?
- ?debug_msg("freezing node ~p~n", [U]),
- WorkLists0 = hipe_reg_worklists:remove_freeze(U, WorkLists),
- %% The published algorithm adds U to the simplify worklist
- %% before the freezeMoves() call. That breaks the worklist
- %% invariants, which is why the order is switched here.
- {WorkLists1, Moves1} = freezeMoves(U, K, WorkLists0, Moves, IG, Alias),
- WorkLists2 = hipe_reg_worklists:add_simplify(U, WorkLists1),
- {WorkLists2, Moves1}.
--endif.
-
-%%----------------------------------------------------------------------
-%% Function: freezeMoves
-%%
-%% Description: Make all move related interferences for a certain node
-%% into ordinary interference arcs.
-%%
-%% Parameters:
-%% U -- The node we want to freeze
-%% K -- The number of available registers
-%% WorkLists -- A datatype containing the different worklists
-%% Moves -- A datatype containing the different movelists
-%% IG -- Interference graph
-%% Alias -- An alias mapping, shows the alias of all coalesced
-%% nodes
-%%
-%% Returns:
-%% WorkLists -- The updated worklists
-%% Moves -- The updated movelists
-%%----------------------------------------------------------------------
-
--ifdef(COMPARE_ITERATED_OPTIMISTIC).
-freezeMoves(U, K, WorkLists, Moves, IG, Alias) ->
- Nodes = hipe_moves:node_moves(U, Moves),
- freezeEm(U, Nodes, K, WorkLists, Moves, IG, Alias).
-
-%% Find what the other value in a copy instruction is, return false if
-%% the instruction isn't a move with the first argument in it.
-
-moves(U, Move, Alias, Moves) ->
- {X,Y} = hipe_moves:get_move(Move, Moves),
- %% The old code (which followed the published algorithm) did
- %% not follow aliases before looking for "the other" node.
- %% This caused moves() to skip some moves, making some nodes
- %% still move-related after freezeMoves(). These move-related
- %% nodes were then added to the simplify worklist (by freeze()
- %% or selectSpill()), breaking the worklist invariants. Nodes
- %% already simplified appeared in coalesce_O(), were re-added to
- %% the simplify worklist by add_worklist(), simplified again,
- %% and coloured multiple times by assignColors(). Ouch!
- X1 = getAlias(X, Alias),
- Y1 = getAlias(Y, Alias),
- if U =:= X1 -> Y1;
- U =:= Y1 -> X1;
- true -> exit({?MODULE,moves}) % XXX: shouldn't happen
- end.
-
-freezeEm(_U, [], _K, WorkLists, Moves, _IG, _Alias) ->
- {WorkLists,Moves};
-freezeEm(U, [M|Ms], K, WorkLists, Moves, IG, Alias) ->
- V = moves(U, M, Alias, Moves),
- {WorkLists2,Moves2} = freezeEm2(U, V, M, K, WorkLists, Moves, IG, Alias),
- freezeEm(U, Ms, K, WorkLists2, Moves2, IG, Alias).
-
-freezeEm2(U, V, M, K, WorkLists, Moves, IG, Alias) ->
- case hipe_moves:member_active(M, Moves) of
- true ->
- Moves1 = hipe_moves:remove_active(M, Moves),
- freezeEm3(U, V, M, K, WorkLists, Moves1, IG, Alias);
- false ->
- Moves1 = hipe_moves:remove_worklist(M, Moves),
- freezeEm3(U, V, M, K, WorkLists, Moves1, IG, Alias)
- end.
-
-freezeEm3(_U,V,_M,K,WorkLists,Moves,IG,_Alias) ->
- Moves1 = Moves, % drop frozen move M
- V1 = V, % getAlias(V,Alias),
- %% "not MoveRelated(v)" is cheaper than "NodeMoves(v) = {}"
- case ((not hipe_moves:move_related(V1,Moves1)) andalso
- hipe_ig:is_trivially_colourable(V1,K,IG)) of
- true ->
- ?debug_msg("freezing move to ~p~n", [V]),
- Worklists1 = hipe_reg_worklists:transfer_freeze_simplify(V1, WorkLists),
- {Worklists1,Moves1};
- false ->
- {WorkLists,Moves1}
- end.
--endif.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to external functions.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-all_precoloured({TgtMod,TgtCtx}) ->
- TgtMod:all_precoloured(TgtCtx).
-
-allocatable({TgtMod,TgtCtx}) ->
- TgtMod:allocatable(TgtCtx).
-
-is_precoloured(R, {TgtMod,TgtCtx}) ->
- TgtMod:is_precoloured(R,TgtCtx).
-
-number_of_temporaries(CFG, {TgtMod,TgtCtx}) ->
- TgtMod:number_of_temporaries(CFG, TgtCtx).
-
-physical_name(R, {TgtMod,TgtCtx}) ->
- TgtMod:physical_name(R,TgtCtx).
diff --git a/lib/hipe/regalloc/hipe_ppc_specific.erl b/lib/hipe/regalloc/hipe_ppc_specific.erl
deleted file mode 100644
index 81bb551bd2..0000000000
--- a/lib/hipe/regalloc/hipe_ppc_specific.erl
+++ /dev/null
@@ -1,214 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_specific).
-
-%% for hipe_coalescing_regalloc:
--export([number_of_temporaries/2
- ,analyze/2
- ,labels/2
- ,all_precoloured/1
- ,bb/3
- ,liveout/3
- ,reg_nr/2
- ,def_use/2
- ,is_move/2
- ,is_spill_move/2
- ,is_precoloured/2
- ,var_range/2
- ,allocatable/1
- ,non_alloc/2
- ,physical_name/2
- ,reverse_postorder/2
- ,livein/3
- ,uses/2
- ,defines/2
- ,defines_all_alloc/2
- ]).
-
-%% for hipe_graph_coloring_regalloc:
--export([is_fixed/2]).
-
-%% for hipe_ls_regalloc:
--export([args/2, is_arg/2, is_global/2, new_spill_index/2]).
--export([breadthorder/2, postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights
--export([branch_preds/2]).
-
-check_and_rewrite(CFG, Coloring, _) ->
- hipe_ppc_ra_postconditions:check_and_rewrite(CFG, Coloring, 'normal').
-
-reverse_postorder(CFG, _) ->
- hipe_ppc_cfg:reverse_postorder(CFG).
-
-non_alloc(CFG, no_context) ->
- non_alloc_1(hipe_ppc_registers:nr_args(), hipe_ppc_cfg:params(CFG)).
-
-%% same as hipe_ppc_frame:fix_formals/2
-non_alloc_1(0, Rest) -> Rest;
-non_alloc_1(N, [_|Rest]) -> non_alloc_1(N-1, Rest);
-non_alloc_1(_, []) -> [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- hipe_ppc_liveness_gpr:analyse(CFG).
-
-livein(Liveness,L,_) ->
- [X || X <- hipe_ppc_liveness_gpr:livein(Liveness,L),
- hipe_ppc:temp_is_allocatable(X)].
-
-liveout(BB_in_out_liveness,Label,_) ->
- [X || X <- hipe_ppc_liveness_gpr:liveout(BB_in_out_liveness,Label),
- hipe_ppc:temp_is_allocatable(X)].
-
-%% Registers stuff
-
-allocatable(no_context) ->
- hipe_ppc_registers:allocatable_gpr().
-
-all_precoloured(no_context) ->
- hipe_ppc_registers:all_precoloured().
-
-is_precoloured(Reg, _) ->
- hipe_ppc_registers:is_precoloured_gpr(Reg).
-
-is_fixed(R, _) ->
- hipe_ppc_registers:is_fixed(R).
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_ppc_cfg:labels(CFG).
-
-var_range(_CFG, _) ->
- hipe_gensym:var_range(ppc).
-
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(ppc),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG,L,_) ->
- hipe_ppc_cfg:bb(CFG,L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_ppc_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Instr,_) ->
- hipe_ppc_cfg:branch_preds(Instr).
-
-%% PowerPC stuff
-
-def_use(Instruction, Ctx) ->
- {defines(Instruction, Ctx), uses(Instruction, Ctx)}.
-
-uses(I, _) ->
- [X || X <- hipe_ppc_defuse:insn_use_gpr(I),
- hipe_ppc:temp_is_allocatable(X)].
-
-defines(I, _) ->
- [X || X <- hipe_ppc_defuse:insn_def_gpr(I),
- hipe_ppc:temp_is_allocatable(X)].
-
-defines_all_alloc(I, _) ->
- hipe_ppc_defuse:insn_defs_all_gpr(I).
-
-is_move(Instruction, _) ->
- case hipe_ppc:is_pseudo_move(Instruction) of
- true ->
- Dst = hipe_ppc:pseudo_move_dst(Instruction),
- case hipe_ppc:temp_is_allocatable(Dst) of
- false -> false;
- _ ->
- Src = hipe_ppc:pseudo_move_src(Instruction),
- hipe_ppc:temp_is_allocatable(Src)
- end;
- false -> false
- end.
-
-is_spill_move(Instruction, _) ->
- hipe_ppc:is_pseudo_spill_move(Instruction).
-
-reg_nr(Reg, _) ->
- hipe_ppc:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_ppc:mk_pseudo_move(Dst, Src).
-
-mk_goto(Label, _) ->
- hipe_ppc:mk_b_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- hipe_ppc_cfg:redirect_jmp(Jmp, ToOld, ToNew).
-
-new_label(_) ->
- hipe_gensym:get_next_label(ppc).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(ppc).
-
-update_reg_nr(Nr, Temp, _) ->
- hipe_ppc:mk_temp(Nr, hipe_ppc:temp_type(Temp)).
-
-subst_temps(SubstFun, Instr, _) ->
- hipe_ppc_subst:insn_temps(
- fun(Op) ->
- case hipe_ppc:temp_is_allocatable(Op)
- andalso hipe_ppc:temp_type(Op) =/= 'double'
- of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
-%%% Linear Scan stuff
-
-new_spill_index(SpillIndex, _) when is_integer(SpillIndex) ->
- SpillIndex+1.
-
-breadthorder(CFG, _) ->
- hipe_ppc_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_ppc_cfg:postorder(CFG).
-
-is_global(R, _) ->
- R =:= hipe_ppc_registers:temp1() orelse
- R =:= hipe_ppc_registers:temp2() orelse
- R =:= hipe_ppc_registers:temp3() orelse
- hipe_ppc_registers:is_fixed(R).
-
-is_arg(R, _) ->
- hipe_ppc_registers:is_arg(R).
-
-args(CFG, _) ->
- hipe_ppc_registers:args(hipe_ppc_cfg:arity(CFG)).
diff --git a/lib/hipe/regalloc/hipe_ppc_specific_fp.erl b/lib/hipe/regalloc/hipe_ppc_specific_fp.erl
deleted file mode 100644
index dcfdf6592c..0000000000
--- a/lib/hipe/regalloc/hipe_ppc_specific_fp.erl
+++ /dev/null
@@ -1,192 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_ppc_specific_fp).
-
-%% for hipe_coalescing_regalloc:
--export([number_of_temporaries/2
- ,analyze/2
- ,labels/2
- ,all_precoloured/1
- ,bb/3
- ,liveout/3
- ,reg_nr/2
- ,def_use/2
- ,is_move/2
- ,is_spill_move/2
- ,is_precoloured/2
- ,var_range/2
- ,allocatable/1
- ,non_alloc/2
- ,physical_name/2
- ,reverse_postorder/2
- ,livein/3
- ,uses/2
- ,defines/2
- ,defines_all_alloc/2
- ]).
-
-%% for hipe_graph_coloring_regalloc:
--export([is_fixed/2]).
-
-%% for hipe_ls_regalloc:
-%%-export([args/2, is_arg/2, is_global, new_spill_index/2]).
-%%-export([breadthorder/2, postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights
--export([branch_preds/2]).
-
-check_and_rewrite(CFG, Coloring, _) ->
- hipe_ppc_ra_postconditions_fp:check_and_rewrite(CFG, Coloring).
-
-reverse_postorder(CFG, _) ->
- hipe_ppc_cfg:reverse_postorder(CFG).
-
-non_alloc(_CFG, _) ->
- [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- hipe_ppc_liveness_fpr:analyse(CFG).
-
-livein(Liveness, L, _) ->
- hipe_ppc_liveness_fpr:livein(Liveness, L).
-
-liveout(BB_in_out_liveness, Label, _) ->
- hipe_ppc_liveness_fpr:liveout(BB_in_out_liveness, Label).
-
-%% Registers stuff
-
-allocatable(no_context) ->
- hipe_ppc_registers:allocatable_fpr().
-
-all_precoloured(Ctx) ->
- allocatable(Ctx).
-
-is_precoloured(Reg, _) ->
- hipe_ppc_registers:is_precoloured_fpr(Reg).
-
-is_fixed(_Reg, _) ->
- false.
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_ppc_cfg:labels(CFG).
-
-var_range(_CFG, _) ->
- hipe_gensym:var_range(ppc).
-
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(ppc),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG, L, _) ->
- hipe_ppc_cfg:bb(CFG, L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_ppc_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Instr,_) ->
- hipe_ppc_cfg:branch_preds(Instr).
-
-%% PowerPC stuff
-
-def_use(I, Ctx) ->
- {defines(I, Ctx), uses(I, Ctx)}.
-
-uses(I, _) ->
- hipe_ppc_defuse:insn_use_fpr(I).
-
-defines(I, _) ->
- hipe_ppc_defuse:insn_def_fpr(I).
-
-defines_all_alloc(I, _) ->
- hipe_ppc_defuse:insn_defs_all_fpr(I).
-
-is_move(I, _) ->
- hipe_ppc:is_pseudo_fmove(I).
-
-is_spill_move(I, _) ->
- hipe_ppc:is_pseudo_spill_fmove(I).
-
-reg_nr(Reg, _) ->
- hipe_ppc:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_ppc:mk_pseudo_fmove(Dst, Src).
-
-mk_goto(Label, _) ->
- hipe_ppc:mk_b_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- hipe_ppc_cfg:redirect_jmp(Jmp, ToOld, ToNew).
-
-new_label(_) ->
- hipe_gensym:get_next_label(ppc).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(ppc).
-
-update_reg_nr(Nr, _Temp, _) ->
- hipe_ppc:mk_temp(Nr, 'double').
-
-subst_temps(SubstFun, Instr, _) ->
- hipe_ppc_subst:insn_temps(
- fun(Op) ->
- case hipe_ppc:temp_is_allocatable(Op)
- andalso hipe_ppc:temp_type(Op) =:= 'double'
- of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
--ifdef(notdef).
-new_spill_index(SpillIndex, _) ->
- SpillIndex+1.
-
-breadthorder(CFG, _) ->
- hipe_ppc_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_ppc_cfg:postorder(CFG).
-
-is_global(_R, _) ->
- false.
-
-is_arg(_R, _) ->
- false.
-
-args(_CFG, _) ->
- [].
--endif.
diff --git a/lib/hipe/regalloc/hipe_range_split.erl b/lib/hipe/regalloc/hipe_range_split.erl
deleted file mode 100644
index 385df695f2..0000000000
--- a/lib/hipe/regalloc/hipe_range_split.erl
+++ /dev/null
@@ -1,1187 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% TEMPORARY LIVE RANGE SPLITTING PASS
-%%
-%% Live range splitting is useful to allow a register allocator to allocate a
-%% temporary to register for a part of its lifetime, even if it cannot be for
-%% the entirety. This improves register allocation quality, at the cost of
-%% making the allocation problem more time and memory intensive to solve.
-%%
-%% Optimal allocation can be achieved if all temporaries are split at every
-%% program point (between all instructions), but this makes register allocation
-%% infeasably slow in practice. Instead, this module uses heuristics to choose
-%% which temporaries should have their live ranges split, and at which points.
-%%
-%% The range splitter only considers temps which are live during a call
-%% instruction, since they're known to be spilled. The control-flow graph is
-%% partitioned at call instructions and splitting decisions are made separately
-%% for each partition. The register copy of a temp (if any) gets a separate name
-%% in each partition.
-%%
-%% There are three different ways the range splitter may choose to split a
-%% temporary in a program partition:
-%%
-%% * Mode1: Spill the temp before calls, and restore it after them
-%% * Mode2: Spill the temp after definitions, restore it after calls
-%% * Mode3: Spill the temp after definitions, restore it before uses
-%%
-%% To pick which of these should be used for each temp×partiton pair, the range
-%% splitter uses a cost function. The cost is simply the sum of the cost of all
-%% expected stack accesses, and the cost for an individual stack access is based
-%% on the probability weight of the basic block that it resides in. This biases
-%% the range splitter so that it attempts moving stack accesses from a functions
-%% hot path to the cold path.
-%%
-%% The heuristic has a couple of tuning knobs, adjusting its preference for
-%% different spilling modes, aggressiveness, and how much influence the basic
-%% block probability weights have.
-%%
-%% Edge case not handled: Call instructions directly defining a pseudo. In that
-%% case, if that pseudo has been selected for mode2 spills, no spill is inserted
-%% after the call.
--module(hipe_range_split).
-
--export([split/5]).
-
--compile(inline).
-
-%% -define(DO_ASSERT, 1).
-%% -define(DEBUG, 1).
--include("../main/hipe.hrl").
-
-%% Heuristic tuning constants
--define(DEFAULT_MIN_GAIN, 1.1). % option: range_split_min_gain
--define(DEFAULT_MODE1_FUDGE, 1.1). % option: range_split_mode1_fudge
--define(DEFAULT_WEIGHT_POWER, 2). % option: range_split_weight_power
--define(WEIGHT_CONST_FUN(Power), math:log(Power)/math:log(100)).
--define(WEIGHT_FUN(Wt, Const), math:pow(Wt, Const)).
--define(HEUR_MAX_TEMPS, 20000).
-
--type target_cfg() :: any().
--type target_instr() :: any().
--type target_temp() :: any().
--type liveness() :: any().
--type target_module() :: module().
--type target_context() :: any().
--type target() :: {target_module(), target_context()}.
--type liveset() :: ordsets:ordset(temp()).
--type temp() :: non_neg_integer().
--type label() :: non_neg_integer().
-
--spec split(target_cfg(), liveness(), target_module(), target_context(),
- comp_options())
- -> target_cfg().
-split(TCFG0, Liveness, TargetMod, TargetContext, Options) ->
- Target = {TargetMod, TargetContext},
- NoTemps = number_of_temporaries(TCFG0, Target),
- if NoTemps > ?HEUR_MAX_TEMPS ->
- ?debug_msg("~w: Too many temps (~w), falling back on restore_reuse.~n",
- [?MODULE, NoTemps]),
- hipe_restore_reuse:split(TCFG0, Liveness, TargetMod, TargetContext);
- true ->
- Wts = compute_weights(TCFG0, TargetMod, TargetContext, Options),
- {CFG0, Temps} = convert(TCFG0, Target),
- Avail = avail_analyse(TCFG0, Liveness, Target),
- Defs = def_analyse(CFG0, TCFG0),
- RDefs = rdef_analyse(CFG0),
- PLive = plive_analyse(CFG0),
- {CFG, DUCounts, Costs, DSets0} =
- scan(CFG0, Liveness, PLive, Wts, Defs, RDefs, Avail, Target),
- {DSets, _} = hipe_dsets:to_map(DSets0),
- Renames = decide(DUCounts, Costs, Target, Options),
- rewrite(CFG, TCFG0, Target, Liveness, PLive, Defs, Avail, DSets, Renames,
- Temps)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Internal program representation
-%%
-%% Second pass: Convert cfg to internal representation
-
--record(cfg, {
- rpo_labels :: [label()],
- bbs :: #{label() => bb()}
- }).
--type cfg() :: #cfg{}.
-
-cfg_bb(L, #cfg{bbs=BBS}) -> maps:get(L, BBS).
-
-cfg_postorder(#cfg{rpo_labels=RPO}) -> lists:reverse(RPO).
-
--record(bb, {
- code :: [code_elem()],
- %% If the last instruction of code defines all allocatable registers
- has_call :: boolean(),
- succ :: [label()]
- }).
--type bb() :: #bb{}.
--type code_elem() :: instr() | mode2_spills() | mode3_restores().
-
-bb_code(#bb{code=Code}) -> Code.
-bb_has_call(#bb{has_call=HasCall}) -> HasCall.
-bb_succ(#bb{succ=Succ}) -> Succ.
-
-bb_butlast(#bb{code=Code}) ->
- bb_butlast_1(Code).
-
-bb_butlast_1([_Last]) -> [];
-bb_butlast_1([I|Is]) -> [I|bb_butlast_1(Is)].
-
-bb_last(#bb{code=Code}) -> lists:last(Code).
-
--record(instr, {
- i :: target_instr(),
- def :: ordsets:ordset(temp()),
- use :: ordsets:ordset(temp())
- }).
--type instr() :: #instr{}.
-
--record(mode2_spills, {
- temps :: ordsets:ordset(temp())
- }).
--type mode2_spills() :: #mode2_spills{}.
-
--record(mode3_restores, {
- temps :: ordsets:ordset(temp())
- }).
--type mode3_restores() :: #mode3_restores{}.
-
--spec convert(target_cfg(), target()) -> {cfg(), temps()}.
-convert(CFG, Target) ->
- RPO = reverse_postorder(CFG, Target),
- {BBsList, Temps} = convert_bbs(RPO, CFG, Target, #{}, []),
- {#cfg{rpo_labels = RPO,
- bbs = maps:from_list(BBsList)},
- Temps}.
-
-convert_bbs([], _CFG, _Target, Temps, Acc) -> {Acc, Temps};
-convert_bbs([L|Ls], CFG, Target, Temps0, Acc) ->
- Succs = hipe_gen_cfg:succ(CFG, L),
- TBB = bb(CFG, L, Target),
- TCode = hipe_bb:code(TBB),
- {Code, Last, Temps} = convert_code(TCode, Target, Temps0, []),
- HasCall = defines_all_alloc(Last#instr.i, Target),
- BB = #bb{code = Code,
- has_call = HasCall,
- succ = Succs},
- convert_bbs(Ls, CFG, Target, Temps, [{L,BB}|Acc]).
-
-convert_code([], _Target, Temps, [Last|_]=Acc) ->
- {lists:reverse(Acc), Last, Temps};
-convert_code([TI|TIs], Target, Temps0, Acc) ->
- {TDef, TUse} = def_use(TI, Target),
- I = #instr{i = TI,
- def = ordsets:from_list(reg_names(TDef, Target)),
- use = ordsets:from_list(reg_names(TUse, Target))},
- Temps = add_temps(TUse, Target, add_temps(TDef, Target, Temps0)),
- convert_code(TIs, Target, Temps, [I|Acc]).
-
--type temps() :: #{temp() => target_temp()}.
-add_temps([], _Target, Temps) -> Temps;
-add_temps([T|Ts], Target, Temps) ->
- add_temps(Ts, Target, Temps#{reg_nr(T, Target) => T}).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fourth pass: P({DEF}) lattice fwd dataflow (for eliding stores at SPILL
-%% splits)
--type defsi() :: #{label() => defseti() | {call, defseti(), defseti()}}.
--type defs() :: #{label() => defsetf()}.
-
--spec def_analyse(cfg(), target_cfg()) -> defs().
-def_analyse(CFG = #cfg{rpo_labels = RPO}, TCFG) ->
- Defs0 = def_init(CFG),
- def_dataf(RPO, TCFG, Defs0).
-
--spec def_init(cfg()) -> defsi().
-def_init(#cfg{bbs = BBs}) ->
- maps:from_list(
- [begin
- {L, case HasCall of
- false -> def_init_scan(bb_code(BB), defseti_new());
- true ->
- {call, def_init_scan(bb_butlast(BB), defseti_new()),
- defseti_from_ordset((bb_last(BB))#instr.def)}
- end}
- end || {L, BB = #bb{has_call=HasCall}} <- maps:to_list(BBs)]).
-
-def_init_scan([], Defset) -> Defset;
-def_init_scan([#instr{def=Def}|Is], Defset0) ->
- Defset = defseti_add_ordset(Def, Defset0),
- def_init_scan(Is, Defset).
-
--spec def_dataf([label()], target_cfg(), defsi()) -> defs().
-def_dataf(Labels, TCFG, Defs0) ->
- case def_dataf_once(Labels, TCFG, Defs0, 0) of
- {Defs, 0} ->
- def_finalise(Defs);
- {Defs, _Changed} ->
- def_dataf(Labels, TCFG, Defs)
- end.
-
--spec def_finalise(defsi()) -> defs().
-def_finalise(Defs) ->
- maps:from_list([{K, defseti_finalise(BL)}
- || {K, {call, BL, _}} <- maps:to_list(Defs)]).
-
--spec def_dataf_once([label()], target_cfg(), defsi(), non_neg_integer())
- -> {defsi(), non_neg_integer()}.
-def_dataf_once([], _TCFG, Defs, Changed) -> {Defs, Changed};
-def_dataf_once([L|Ls], TCFG, Defs0, Changed0) ->
- AddPreds =
- fun(Defset1) ->
- lists:foldl(fun(P, Defset2) ->
- defseti_union(defout(P, Defs0), Defset2)
- end, Defset1, hipe_gen_cfg:pred(TCFG, L))
- end,
- Defset =
- case Defset0 = maps:get(L, Defs0) of
- {call, Butlast, Defout} -> {call, AddPreds(Butlast), Defout};
- _ -> AddPreds(Defset0)
- end,
- Changed = case Defset =:= Defset0 of
- true -> Changed0;
- false -> Changed0+1
- end,
- def_dataf_once(Ls, TCFG, Defs0#{L := Defset}, Changed).
-
--spec defout(label(), defsi()) -> defseti().
-defout(L, Defs) ->
- case maps:get(L, Defs) of
- {call, _DefButLast, Defout} -> Defout;
- Defout -> Defout
- end.
-
--spec defbutlast(label(), defs()) -> defsetf().
-defbutlast(L, Defs) -> maps:get(L, Defs).
-
--spec defseti_new() -> defseti().
--spec defseti_union(defseti(), defseti()) -> defseti().
--spec defseti_add_ordset(ordsets:ordset(temp()), defseti()) -> defseti().
--spec defseti_from_ordset(ordsets:ordset(temp())) -> defseti().
--spec defseti_finalise(defseti()) -> defsetf().
--spec defsetf_member(temp(), defsetf()) -> boolean().
--spec defsetf_intersect_ordset(ordsets:ordset(temp()), defsetf())
- -> ordsets:ordset(temp()).
-
--type defseti() :: bitord().
-defseti_new() -> bitord_new().
-defseti_union(A, B) -> bitord_union(A, B).
-defseti_add_ordset(OS, D) -> defseti_union(defseti_from_ordset(OS), D).
-defseti_from_ordset(OS) -> bitord_from_ordset(OS).
-defseti_finalise(D) -> bitarr_from_bitord(D).
-
--type defsetf() :: bitarr().
-defsetf_member(E, D) -> bitarr_get(E, D).
-
-defsetf_intersect_ordset([], _D) -> [];
-defsetf_intersect_ordset([E|Es], D) ->
- case bitarr_get(E, D) of
- true -> [E|defsetf_intersect_ordset(Es,D)];
- false -> defsetf_intersect_ordset(Es,D)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fifth pass: P({DEF}) lattice reverse dataflow (for eliding stores at defines
-%% in mode2)
--type rdefsi() :: #{label() =>
- {call, rdefseti(), [label()]}
- | {nocall, rdefseti(), rdefseti(), [label()]}}.
--type rdefs() :: #{label() => {final, rdefsetf(), [label()]}}.
-
--spec rdef_analyse(cfg()) -> rdefs().
-rdef_analyse(CFG = #cfg{rpo_labels=RPO}) ->
- Defs0 = rdef_init(CFG),
- PO = rdef_postorder(RPO, CFG, []),
- rdef_dataf(PO, Defs0).
-
-%% Filter out 'call' labels, since they don't change
--spec rdef_postorder([label()], cfg(), [label()]) -> [label()].
-rdef_postorder([], _CFG, Acc) -> Acc;
-rdef_postorder([L|Ls], CFG, Acc) ->
- case bb_has_call(cfg_bb(L, CFG)) of
- true -> rdef_postorder(Ls, CFG, Acc);
- false -> rdef_postorder(Ls, CFG, [L|Acc])
- end.
-
--spec rdef_init(cfg()) -> rdefsi().
-rdef_init(#cfg{bbs = BBs}) ->
- maps:from_list(
- [{L, case HasCall of
- true ->
- Defin = rdef_init_scan(bb_butlast(BB), rdefseti_empty()),
- {call, Defin, Succs};
- false ->
- Gen = rdef_init_scan(bb_code(BB), rdefseti_empty()),
- {nocall, Gen, rdefseti_top(), Succs}
- end}
- || {L, BB = #bb{has_call=HasCall, succ=Succs}} <- maps:to_list(BBs)]).
-
--spec rdef_init_scan([instr()], rdefseti()) -> rdefseti().
-rdef_init_scan([], Defset) -> Defset;
-rdef_init_scan([#instr{def=Def}|Is], Defset0) ->
- Defset = rdefseti_add_ordset(Def, Defset0),
- rdef_init_scan(Is, Defset).
-
--spec rdef_dataf([label()], rdefsi()) -> rdefs().
-rdef_dataf(Labels, Defs0) ->
- case rdef_dataf_once(Labels, Defs0, 0) of
- {Defs, 0} ->
- rdef_finalise(Defs);
- {Defs, _Changed} ->
- rdef_dataf(Labels, Defs)
- end.
-
--spec rdef_finalise(rdefsi()) -> rdefs().
-rdef_finalise(Defs) ->
- maps:map(fun(L, V) ->
- Succs = rsuccs_val(V),
- Defout0 = rdefout_intersect(L, Defs, rdefseti_top()),
- {final, rdefset_finalise(Defout0), Succs}
- end, Defs).
-
--spec rdef_dataf_once([label()], rdefsi(), non_neg_integer())
- -> {rdefsi(), non_neg_integer()}.
-rdef_dataf_once([], Defs, Changed) -> {Defs, Changed};
-rdef_dataf_once([L|Ls], Defs0, Changed0) ->
- #{L := {nocall, Gen, Defin0, Succs}} = Defs0,
- Defin = rdefseti_union(Gen, rdefout_intersect(L, Defs0, Defin0)),
- Defset = {nocall, Gen, Defin, Succs},
- Changed = case Defin =:= Defin0 of
- true -> Changed0;
- false -> Changed0+1
- end,
- rdef_dataf_once(Ls, Defs0#{L := Defset}, Changed).
-
--spec rdefin(label(), rdefsi()) -> rdefseti().
-rdefin(L, Defs) -> rdefin_val(maps:get(L, Defs)).
-rdefin_val({nocall, _Gen, Defin, _Succs}) -> Defin;
-rdefin_val({call, Defin, _Succs}) -> Defin.
-
--spec rsuccs(label(), rdefsi()) -> [label()].
-rsuccs(L, Defs) -> rsuccs_val(maps:get(L, Defs)).
-rsuccs_val({nocall, _Gen, _Defin, Succs}) -> Succs;
-rsuccs_val({call, _Defin, Succs}) -> Succs.
-
--spec rdefout(label(), rdefs()) -> rdefsetf().
-rdefout(L, Defs) ->
- #{L := {final, Defout, _Succs}} = Defs,
- Defout.
-
--spec rdefout_intersect(label(), rdefsi(), rdefseti()) -> rdefseti().
-rdefout_intersect(L, Defs, Init) ->
- lists:foldl(fun(S, Acc) ->
- rdefseti_intersect(rdefin(S, Defs), Acc)
- end, Init, rsuccs(L, Defs)).
-
--type rdefseti() :: bitord() | top.
-rdefseti_top() -> top.
-rdefseti_empty() -> bitord_new().
--spec rdefseti_from_ordset(ordsets:ordset(temp())) -> rdefseti().
-rdefseti_from_ordset(OS) -> bitord_from_ordset(OS).
-
--spec rdefseti_add_ordset(ordsets:ordset(temp()), rdefseti()) -> rdefseti().
-rdefseti_add_ordset(_, top) -> top; % Should never happen in rdef_dataf
-rdefseti_add_ordset(OS, D) -> rdefseti_union(rdefseti_from_ordset(OS), D).
-
--spec rdefseti_union(rdefseti(), rdefseti()) -> rdefseti().
-rdefseti_union(top, _) -> top;
-rdefseti_union(_, top) -> top;
-rdefseti_union(A, B) -> bitord_union(A, B).
-
--spec rdefseti_intersect(rdefseti(), rdefseti()) -> rdefseti().
-rdefseti_intersect(top, D) -> D;
-rdefseti_intersect(D, top) -> D;
-rdefseti_intersect(A, B) -> bitord_intersect(A, B).
-
--type rdefsetf() :: {arr, bitarr()} | top.
--spec rdefset_finalise(rdefseti()) -> rdefsetf().
-rdefset_finalise(top) -> top;
-rdefset_finalise(Ord) -> {arr, bitarr_from_bitord(Ord)}.
-
-%% rdefsetf_top() -> top.
-rdefsetf_empty() -> {arr, bitarr_new()}.
-
--spec rdefsetf_add_ordset(ordsets:ordset(temp()), rdefsetf()) -> rdefsetf().
-rdefsetf_add_ordset(_, top) -> top;
-rdefsetf_add_ordset(OS, {arr, Arr}) ->
- {arr, lists:foldl(fun bitarr_set/2, Arr, OS)}.
-
--spec rdef_step(instr(), rdefsetf()) -> rdefsetf().
-rdef_step(#instr{def=Def}, Defset) ->
- %% ?ASSERT(not defines_all_alloc(I, Target)),
- rdefsetf_add_ordset(Def, Defset).
-
--spec ordset_subtract_rdefsetf(ordsets:ordset(temp()), rdefsetf())
- -> ordsets:ordset(temp()).
-ordset_subtract_rdefsetf(_, top) -> [];
-ordset_subtract_rdefsetf(OS, {arr, Arr}) ->
- %% Lazy implementation; could do better if OS can grow
- lists:filter(fun(E) -> not bitarr_get(E, Arr) end, OS).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Integer sets represented as bit sets
-%%
-%% Two representations; bitord() and bitarr()
--define(LIMB_IX_BITS, 11).
--define(LIMB_BITS, (1 bsl ?LIMB_IX_BITS)).
--define(LIMB_IX(Index), (Index bsr ?LIMB_IX_BITS)).
--define(BIT_IX(Index), (Index band (?LIMB_BITS - 1))).
--define(BIT_MASK(Index), (1 bsl ?BIT_IX(Index))).
-
-%% bitord(): fast at union/2 and can be compared for equality with '=:='
--type bitord() :: orddict:orddict(non_neg_integer(), 0..((1 bsl ?LIMB_BITS)-1)).
-
--spec bitord_new() -> bitord().
-bitord_new() -> [].
-
--spec bitord_union(bitord(), bitord()) -> bitord().
-bitord_union(Lhs, Rhs) ->
- orddict:merge(fun(_, L, R) -> L bor R end, Lhs, Rhs).
-
--spec bitord_intersect(bitord(), bitord()) -> bitord().
-bitord_intersect([], _) -> [];
-bitord_intersect(_, []) -> [];
-bitord_intersect([{K, L}|Ls], [{K, R}|Rs]) ->
- [{K, L band R} | bitord_intersect(Ls, Rs)];
-bitord_intersect([{LK, _}|Ls], [{RK, _}|_]=Rs) when LK < RK ->
- bitord_intersect(Ls, Rs);
-bitord_intersect([{LK, _}|_]=Ls, [{RK, _}|Rs]) when LK > RK ->
- bitord_intersect(Ls, Rs).
-
--spec bitord_from_ordset(ordsets:ordset(non_neg_integer())) -> bitord().
-bitord_from_ordset([]) -> [];
-bitord_from_ordset([B|Bs]) ->
- bitord_from_ordset_1(Bs, ?LIMB_IX(B), ?BIT_MASK(B)).
-
-bitord_from_ordset_1([B|Bs], Key, Val) when Key =:= ?LIMB_IX(B) ->
- bitord_from_ordset_1(Bs, Key, Val bor ?BIT_MASK(B));
-bitord_from_ordset_1([B|Bs], Key, Val) ->
- [{Key,Val} | bitord_from_ordset_1(Bs, ?LIMB_IX(B), ?BIT_MASK(B))];
-bitord_from_ordset_1([], Key, Val) -> [{Key, Val}].
-
-%% bitarr(): fast (enough) at get/2
--type bitarr() :: array:array(0..((1 bsl ?LIMB_BITS)-1)).
-
--spec bitarr_new() -> bitarr().
-bitarr_new() -> array:new({default, 0}).
-
--spec bitarr_get(non_neg_integer(), bitarr()) -> boolean().
-bitarr_get(Index, Array) ->
- Limb = array:get(?LIMB_IX(Index), Array),
- 0 =/= (Limb band ?BIT_MASK(Index)).
-
--spec bitarr_set(non_neg_integer(), bitarr()) -> bitarr().
-bitarr_set(Index, Array) ->
- Limb0 = array:get(?LIMB_IX(Index), Array),
- Limb = Limb0 bor ?BIT_MASK(Index),
- array:set(?LIMB_IX(Index), Limb, Array).
-
--spec bitarr_from_bitord(bitord()) -> bitarr().
-bitarr_from_bitord(Ord) ->
- array:from_orddict(Ord, 0).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Sixth pass: Partition-local liveness analysis
-%%
-%% As temps are not spilled when exiting a partition in mode2, only
-%% partition-local uses need to be considered when deciding which temps need
-%% restoring at partition entry.
-
--type plive() :: #{label() =>
- {call, liveset(), [label()]}
- | {nocall, {liveset(), liveset()}, liveset(), [label()]}}.
-
--spec plive_analyse(cfg()) -> plive().
-plive_analyse(CFG) ->
- Defs0 = plive_init(CFG),
- PO = cfg_postorder(CFG),
- plive_dataf(PO, Defs0).
-
--spec plive_init(cfg()) -> plive().
-plive_init(#cfg{bbs = BBs}) ->
- maps:from_list(
- [begin
- {L, case HasCall of
- true ->
- {Gen, _} = plive_init_scan(bb_code(BB)),
- {call, Gen, Succs};
- false ->
- GenKill = plive_init_scan(bb_code(BB)),
- {nocall, GenKill, liveset_empty(), Succs}
- end}
- end || {L, BB = #bb{has_call=HasCall, succ=Succs}} <- maps:to_list(BBs)]).
-
--spec plive_init_scan([instr()]) -> {liveset(), liveset()}.
-plive_init_scan([]) -> {liveset_empty(), liveset_empty()};
-plive_init_scan([#instr{def=InstrKill, use=InstrGen}|Is]) ->
- {Gen0, Kill0} = plive_init_scan(Is),
- Gen1 = liveset_subtract(Gen0, InstrKill),
- Gen = liveset_union(Gen1, InstrGen),
- Kill1 = liveset_union(Kill0, InstrKill),
- Kill = liveset_subtract(Kill1, InstrGen),
- {Gen, Kill}.
-
--spec plive_dataf([label()], plive()) -> plive().
-plive_dataf(Labels, PLive0) ->
- case plive_dataf_once(Labels, PLive0, 0) of
- {PLive, 0} -> PLive;
- {PLive, _Changed} ->
- plive_dataf(Labels, PLive)
- end.
-
--spec plive_dataf_once([label()], plive(), non_neg_integer()) ->
- {plive(), non_neg_integer()}.
-plive_dataf_once([], PLive, Changed) -> {PLive, Changed};
-plive_dataf_once([L|Ls], PLive0, Changed0) ->
- Liveset =
- case Liveset0 = maps:get(L, PLive0) of
- {call, Livein, Succs} ->
- {call, Livein, Succs};
- {nocall, {Gen, Kill} = GenKill, _OldLivein, Succs} ->
- Liveout = pliveout(L, PLive0),
- Livein = liveset_union(Gen, liveset_subtract(Liveout, Kill)),
- {nocall, GenKill, Livein, Succs}
- end,
- Changed = case Liveset =:= Liveset0 of
- true -> Changed0;
- false -> Changed0+1
- end,
- plive_dataf_once(Ls, PLive0#{L := Liveset}, Changed).
-
--spec pliveout(label(), plive()) -> liveset().
-pliveout(L, PLive) ->
- liveset_union([plivein(S, PLive) || S <- psuccs(L, PLive)]).
-
--spec psuccs(label(), plive()) -> [label()].
-psuccs(L, PLive) -> psuccs_val(maps:get(L, PLive)).
-psuccs_val({call, _Livein, Succs}) -> Succs;
-psuccs_val({nocall, _GenKill, _Livein, Succs}) -> Succs.
-
--spec plivein(label(), plive()) -> liveset().
-plivein(L, PLive) -> plivein_val(maps:get(L, PLive)).
-plivein_val({call, Livein, _Succs}) -> Livein;
-plivein_val({nocall, _GenKill, Livein, _Succs}) -> Livein.
-
-liveset_empty() -> ordsets:new().
-liveset_subtract(A, B) -> ordsets:subtract(A, B).
-liveset_union(A, B) -> ordsets:union(A, B).
-liveset_union(LivesetList) -> ordsets:union(LivesetList).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Third pass: Compute dataflow analyses required for placing mode3
-%% spills/restores.
-%% Reuse analysis implementation in hipe_restore_reuse.
-%% XXX: hipe_restore_reuse has it's own "rdef"; we would like to reuse that one
-%% too.
--type avail() :: hipe_restore_reuse:avail().
-
--spec avail_analyse(target_cfg(), liveness(), target()) -> avail().
-avail_analyse(CFG, Liveness, Target) ->
- hipe_restore_reuse:analyse(CFG, Liveness, Target).
-
--spec mode3_split_in_block(label(), avail()) -> ordsets:ordset(temp()).
-mode3_split_in_block(L, Avail) ->
- hipe_restore_reuse:split_in_block(L, Avail).
-
--spec mode3_block_renameset(label(), avail()) -> ordsets:ordset(temp()).
-mode3_block_renameset(L, Avail) ->
- hipe_restore_reuse:renamed_in_block(L, Avail).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Seventh pass
-%%
-%% Compute program space partitioning, collect information required by the
-%% heuristic.
--type part_key() :: label().
--type part_dsets() :: hipe_dsets:dsets(part_key()).
--type part_dsets_map() :: #{part_key() => part_key()}.
--type ducounts() :: #{part_key() => ducount()}.
-
--spec scan(cfg(), liveness(), plive(), weights(), defs(), rdefs(), avail(),
- target()) -> {cfg(), ducounts(), costs(), part_dsets()}.
-scan(CFG0, Liveness, PLive, Weights, Defs, RDefs, Avail, Target) ->
- #cfg{rpo_labels = Labels, bbs = BBs0} = CFG0,
- CFG = CFG0#cfg{bbs=#{}}, % kill reference
- DSets0 = hipe_dsets:new(Labels),
- Costs0 = costs_new(),
- {BBs, DUCounts0, Costs1, DSets1} =
- scan_bbs(maps:to_list(BBs0), Liveness, PLive, Weights, Defs, RDefs, Avail,
- Target, #{}, Costs0, DSets0, []),
- {RLList, DSets2} = hipe_dsets:to_rllist(DSets1),
- {Costs, DSets} = costs_map_roots(DSets2, Costs1),
- DUCounts = collect_ducounts(RLList, DUCounts0, #{}),
- {CFG#cfg{bbs=maps:from_list(BBs)}, DUCounts, Costs, DSets}.
-
--spec collect_ducounts([{label(), [label()]}], ducounts(), ducounts())
- -> ducounts().
-collect_ducounts([], _, Acc) -> Acc;
-collect_ducounts([{R,Ls}|RLs], DUCounts, Acc) ->
- DUCount = lists:foldl(
- fun(Key, FAcc) ->
- ducount_merge(maps:get(Key, DUCounts, ducount_new()), FAcc)
- end, ducount_new(), Ls),
- collect_ducounts(RLs, DUCounts, Acc#{R => DUCount}).
-
--spec scan_bbs([{label(), bb()}], liveness(), plive(), weights(), defs(),
- rdefs(), avail(), target(), ducounts(), costs(), part_dsets(),
- [{label(), bb()}])
- -> {[{label(), bb()}], ducounts(), costs(), part_dsets()}.
-scan_bbs([], _Liveness, _PLive, _Weights, _Defs, _RDefs, _Avail, _Target,
- DUCounts, Costs, DSets, Acc) ->
- {Acc, DUCounts, Costs, DSets};
-scan_bbs([{L,BB}|BBs], Liveness, PLive, Weights, Defs, RDefs, Avail, Target,
- DUCounts0, Costs0, DSets0, Acc) ->
- Wt = weight(L, Weights),
- {DSets, Costs5, EntryCode, ExitCode, RDefout, Liveout} =
- case bb_has_call(BB) of
- false ->
- DSets1 = lists:foldl(fun(S, DS) -> hipe_dsets:union(L, S, DS) end,
- DSets0, bb_succ(BB)),
- {DSets1, Costs0, bb_code(BB), [], rdefout(L, RDefs),
- liveout(Liveness, L, Target)};
- true ->
- LastI = #instr{def=LastDef} = bb_last(BB),
- LiveBefore = ordsets:subtract(liveout(Liveness, L, Target), LastDef),
- %% We can omit the spill of a temp that has not been defined since the
- %% last time it was spilled
- SpillSet = defsetf_intersect_ordset(LiveBefore, defbutlast(L, Defs)),
- Costs1 = costs_insert(exit, L, Wt, SpillSet, Costs0),
- Costs4 = lists:foldl(fun({S, BranchWt}, Costs2) ->
- SLivein = livein(Liveness, S, Target),
- SPLivein = plivein(S, PLive),
- SWt = weight_scaled(L, BranchWt, Weights),
- Costs3 = costs_insert(entry1, S, SWt, SLivein, Costs2),
- costs_insert(entry2, S, SWt, SPLivein, Costs3)
- end, Costs1, branch_preds(LastI#instr.i, Target)),
- {DSets0, Costs4, bb_butlast(BB), [LastI], rdefsetf_empty(), LiveBefore}
- end,
- Mode3Splits = mode3_split_in_block(L, Avail),
- {RevEntryCode, Restored} = scan_bb_fwd(EntryCode, Mode3Splits, [], []),
- {Code, DUCount, Mode2Spills} =
- scan_bb(RevEntryCode, Wt, RDefout, Liveout, ducount_new(), [], ExitCode),
- DUCounts = DUCounts0#{L => DUCount},
- M2SpillSet = ordsets:from_list(Mode2Spills),
- Costs6 = costs_insert(spill, L, Wt, M2SpillSet, Costs5),
- Mode3Renames = mode3_block_renameset(L, Avail),
- Costs7 = costs_insert(restore, L, Wt, ordsets:intersection(M2SpillSet, Mode3Renames), Costs6),
- Costs8 = costs_insert(restore, L, Wt, ordsets:from_list(Restored), Costs7),
- Costs = add_unsplit_mode3_costs(DUCount, Mode3Renames, L, Costs8),
- scan_bbs(BBs, Liveness, PLive, Weights, Defs, RDefs, Avail, Target, DUCounts,
- Costs, DSets, [{L,BB#bb{code=Code}}|Acc]).
-
--spec add_unsplit_mode3_costs(ducount(), ordsets:ordset(temp()), label(), costs())
- -> costs().
-add_unsplit_mode3_costs(DUCount, Mode3Renames, L, Costs) ->
- Unsplit = orddict_without_ordset(Mode3Renames,
- orddict:from_list(ducount_to_list(DUCount))),
- add_unsplit_mode3_costs_1(Unsplit, L, Costs).
-
--spec add_unsplit_mode3_costs_1([{temp(),float()}], label(), costs())
- -> costs().
-add_unsplit_mode3_costs_1([], _L, Costs) -> Costs;
-add_unsplit_mode3_costs_1([{T,C}|Cs], L, Costs) ->
- add_unsplit_mode3_costs_1(Cs, L, costs_insert(restore, L, C, [T], Costs)).
-
-%% @doc Returns a new orddict without keys in Set and their associated values.
--spec orddict_without_ordset(ordsets:ordset(K), orddict:orddict(K, V))
- -> orddict:orddict(K, V).
-orddict_without_ordset([S|Ss], [{K,_}|_]=Dict) when S < K ->
- orddict_without_ordset(Ss, Dict);
-orddict_without_ordset([S|_]=Set, [D={K,_}|Ds]) when S > K ->
- [D|orddict_without_ordset(Set, Ds)];
-orddict_without_ordset([_S|Ss], [{_K,_}|Ds]) -> % _S == _K
- orddict_without_ordset(Ss, Ds);
-orddict_without_ordset(_, []) -> [];
-orddict_without_ordset([], Dict) -> Dict.
-
-%% Scans the code forward, collecting and inserting mode3 restores
--spec scan_bb_fwd([instr()], ordsets:ordset(temp()), ordsets:ordset(temp()),
- [code_elem()])
- -> {[code_elem()], ordsets:ordset(temp())}.
-scan_bb_fwd([], [], Restored, Acc) -> {Acc, Restored};
-scan_bb_fwd([I|Is], SplitHere0, Restored0, Acc0) ->
- #instr{def=Def, use=Use} = I,
- {ToRestore, SplitHere1} =
- lists:partition(fun(R) -> lists:member(R, Use) end, SplitHere0),
- SplitHere = lists:filter(fun(R) -> not lists:member(R, Def) end, SplitHere1),
- Acc =
- case ToRestore of
- [] -> [I | Acc0];
- _ -> [I, #mode3_restores{temps=ToRestore} | Acc0]
- end,
- scan_bb_fwd(Is, SplitHere, ToRestore ++ Restored0, Acc).
-
-%% Scans the code backwards, collecting def/use counts and mode2 spills
--spec scan_bb([code_elem()], float(), rdefsetf(), liveset(), ducount(),
- [temp()], [code_elem()])
- -> {[code_elem()], ducount(), [temp()]}.
-scan_bb([], _Wt, _RDefout, _Liveout, DUCount, Spills, Acc) ->
- {Acc, DUCount, Spills};
-scan_bb([I=#mode3_restores{}|Is], Wt, RDefout, Liveout, DUCount, Spills, Acc) ->
- scan_bb(Is, Wt, RDefout, Liveout, DUCount, Spills, [I|Acc]);
-scan_bb([I|Is], Wt, RDefout, Liveout, DUCount0, Spills0, Acc0) ->
- #instr{def=Def,use=Use} = I,
- DUCount = ducount_add(Use, Wt, ducount_add(Def, Wt, DUCount0)),
- Livein = liveness_step(I, Liveout),
- RDefin = rdef_step(I, RDefout),
- %% The temps that would be spilled after I in mode 2
- NewSpills = ordset_subtract_rdefsetf(
- ordsets:intersection(Def, Liveout),
- RDefout),
- ?ASSERT(NewSpills =:= (NewSpills -- Spills0)),
- Spills = NewSpills ++ Spills0,
- Acc1 = case NewSpills of
- [] -> Acc0;
- _ -> [#mode2_spills{temps=NewSpills}|Acc0]
- end,
- scan_bb(Is, Wt, RDefin, Livein, DUCount, Spills, [I|Acc1]).
-
--spec liveness_step(instr(), liveset()) -> liveset().
-liveness_step(#instr{def=Def, use=Use}, Liveout) ->
- ordsets:union(Use, ordsets:subtract(Liveout, Def)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% First pass: compute basic-block weighting
-
--type weights() :: no_bb_weights
- | {hipe_bb_weights:bb_weights(), float()}.
-
--spec weight(label(), weights()) -> float().
-weight(L, Weights) -> weight_scaled(L, 1.0, Weights).
-
--spec compute_weights(target_cfg(), target_module(), target_context(),
- comp_options()) -> weights().
-compute_weights(CFG, TargetMod, TargetContext, Options) ->
- case proplists:get_bool(range_split_weights, Options) of
- false -> no_bb_weights;
- true ->
- {hipe_bb_weights:compute(CFG, TargetMod, TargetContext),
- ?WEIGHT_CONST_FUN(proplists:get_value(range_split_weight_power,
- Options, ?DEFAULT_WEIGHT_POWER))}
- end.
-
--spec weight_scaled(label(), float(), weights()) -> float().
-weight_scaled(_L, _Scale, no_bb_weights) -> 1.0;
-weight_scaled(L, Scale, {Weights, Const}) ->
- Wt0 = hipe_bb_weights:weight(L, Weights) * Scale,
- Wt = erlang:min(erlang:max(Wt0, 0.0000000000000000001), 10000.0),
- ?WEIGHT_FUN(Wt, Const).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Heuristic splitting decision.
-%%
-%% Decide which temps to split, in which parts, and pick new names for them.
--type spill_mode() :: mode1 % Spill temps at partition exits
- | mode2 % Spill temps at definitions
- | mode3.% Spill temps at definitions, restore temps at uses
--type ren() :: #{temp() => {spill_mode(), temp()}}.
--type renames() :: #{label() => ren()}.
-
--record(heur_par, {
- mode1_fudge :: float(),
- min_gain :: float()
- }).
--type heur_par() :: #heur_par{}.
-
--spec decide(ducounts(), costs(), target(), comp_options()) -> renames().
-decide(DUCounts, Costs, Target, Options) ->
- Par = #heur_par{
- mode1_fudge = proplists:get_value(range_split_mode1_fudge, Options,
- ?DEFAULT_MODE1_FUDGE),
- min_gain = proplists:get_value(range_split_min_gain, Options,
- ?DEFAULT_MIN_GAIN)},
- decide_parts(maps:to_list(DUCounts), Costs, Target, Par, #{}).
-
--spec decide_parts([{part_key(), ducount()}], costs(), target(),
- heur_par(), renames())
- -> renames().
-decide_parts([], _Costs, _Target, _Par, Acc) -> Acc;
-decide_parts([{Part,DUCount}|Ps], Costs, Target, Par, Acc) ->
- Spills = decide_temps(ducount_to_list(DUCount), Part, Costs, Target, Par,
- #{}),
- decide_parts(Ps, Costs, Target, Par, Acc#{Part => Spills}).
-
--spec decide_temps([{temp(), float()}], part_key(), costs(), target(),
- heur_par(), ren())
- -> ren().
-decide_temps([], _Part, _Costs, _Target, _Par, Acc) -> Acc;
-decide_temps([{Temp, SpillGain}|Ts], Part, Costs, Target, Par, Acc0) ->
- SpillCost1 = costs_query(Temp, entry1, Part, Costs)
- + costs_query(Temp, exit, Part, Costs),
- SpillCost2 = costs_query(Temp, entry2, Part, Costs)
- + costs_query(Temp, spill, Part, Costs),
- SpillCost3 = costs_query(Temp, restore, Part, Costs),
- Acc =
- %% SpillCost1 =:= 0.0 usually means the temp is local to the partition;
- %% hence no need to split it
- case (SpillCost1 =/= 0.0) %% maps:is_key(Temp, S)
- andalso (not is_precoloured(Temp, Target))
- andalso ((Par#heur_par.min_gain*SpillCost1 < SpillGain)
- orelse (Par#heur_par.min_gain*SpillCost2 < SpillGain)
- orelse (Par#heur_par.min_gain*SpillCost3 < SpillGain))
- of
- false -> Acc0;
- true ->
- Mode =
- if Par#heur_par.mode1_fudge*SpillCost1 < SpillCost2,
- Par#heur_par.mode1_fudge*SpillCost1 < SpillCost3 ->
- mode1;
- SpillCost2 < SpillCost3 ->
- mode2;
- true ->
- mode3
- end,
- Acc0#{Temp => {Mode, new_reg_nr(Target)}}
- end,
- decide_temps(Ts, Part, Costs, Target, Par, Acc).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Eighth pass: Rewrite program performing range splitting.
-
--spec rewrite(cfg(), target_cfg(), target(), liveness(), plive(), defs(),
- avail(), part_dsets_map(), renames(), temps())
- -> target_cfg().
-rewrite(#cfg{bbs=BBs}, TCFG, Target, Liveness, PLive, Defs, Avail, DSets,
- Renames, Temps) ->
- rewrite_bbs(maps:to_list(BBs), Target, Liveness, PLive, Defs, Avail, DSets,
- Renames, Temps, TCFG).
-
--spec rewrite_bbs([{label(), bb()}], target(), liveness(), plive(), defs(),
- avail(), part_dsets_map(), renames(), temps(), target_cfg())
- -> target_cfg().
-rewrite_bbs([], _Target, _Liveness, _PLive, _Defs, _Avail, _DSets, _Renames,
- _Temps, TCFG) ->
- TCFG;
-rewrite_bbs([{L,BB}|BBs], Target, Liveness, PLive, Defs, Avail, DSets, Renames,
- Temps, TCFG0) ->
- Code0Rev = lists:reverse(bb_code(BB)),
- EntryRen = maps:get(maps:get(L,DSets), Renames),
- M3Ren = mode3_block_renameset(L, Avail),
- SubstFun = rewrite_subst_fun(Target, EntryRen, M3Ren),
- Fun = fun(I) -> subst_temps(SubstFun, I, Target) end,
- {Code, TCFG} =
- case bb_has_call(BB) of
- false ->
- Code1 = rewrite_instrs(Code0Rev, Fun, EntryRen, M3Ren, Temps, Target,
- []),
- {Code1, TCFG0};
- true ->
- CallI0 = hd(Code0Rev),
- Succ = bb_succ(BB),
- {CallTI, TCFG1} = inject_restores(Succ, Target, Liveness, PLive, DSets,
- Renames, Temps, CallI0#instr.i, TCFG0),
- Liveout1 = liveness_step(CallI0, liveout(Liveness, L, Target)),
- Defout = defbutlast(L, Defs),
- SpillMap = mk_spillmap(EntryRen, Liveout1, Defout, Temps, Target),
- Code1 = rewrite_instrs(tl(Code0Rev), Fun, EntryRen, M3Ren, Temps,
- Target, []),
- Code2 = lift_spills(lists:reverse(Code1), Target, SpillMap, [CallTI]),
- {Code2, TCFG1}
- end,
- TBB = hipe_bb:code_update(bb(TCFG, L, Target), Code),
- rewrite_bbs(BBs, Target, Liveness, PLive, Defs, Avail, DSets, Renames, Temps,
- update_bb(TCFG, L, TBB, Target)).
-
--spec rewrite_instrs([code_elem()], rewrite_fun(), ren(),
- ordsets:ordset(temp()), temps(), target(),
- [target_instr()])
- -> [target_instr()].
-rewrite_instrs([], _Fun, _Ren, _M3Ren, _Temps, _Target, Acc) -> Acc;
-rewrite_instrs([I|Is], Fun, Ren, M3Ren, Temps, Target, Acc0) ->
- Acc =
- case I of
- #instr{i=TI} -> [Fun(TI)|Acc0];
- #mode2_spills{temps=Mode2Spills} ->
- add_mode2_spills(Mode2Spills, Target, Ren, M3Ren, Temps, Acc0);
- #mode3_restores{temps=Mode3Restores} ->
- add_mode3_restores(Mode3Restores, Target, Ren, Temps, Acc0)
- end,
- rewrite_instrs(Is, Fun, Ren, M3Ren, Temps, Target, Acc).
-
--spec add_mode2_spills(ordsets:ordset(temp()), target(), ren(),
- ordsets:ordset(temp()), temps(), [target_instr()])
- -> [target_instr()].
-add_mode2_spills([], _Target, _Ren, _M3Ren, _Temps, Acc) -> Acc;
-add_mode2_spills([R|Rs], Target, Ren, M3Ren, Temps, Acc0) ->
- Acc =
- case Ren of
- #{R := {Mode, NewName}} when Mode =:= mode2; Mode =:= mode3 ->
- case Mode =/= mode3 orelse lists:member(R, M3Ren) of
- false -> Acc0;
- true ->
- #{R := T} = Temps,
- SpillInstr = mk_move(update_reg_nr(NewName, T, Target), T, Target),
- [SpillInstr|Acc0]
- end;
- #{} ->
- Acc0
- end,
- add_mode2_spills(Rs, Target, Ren, M3Ren, Temps, Acc).
-
--spec add_mode3_restores(ordsets:ordset(temp()), target(), ren(), temps(),
- [target_instr()])
- -> [target_instr()].
-add_mode3_restores([], _Target, _Ren, _Temps, Acc) -> Acc;
-add_mode3_restores([R|Rs], Target, Ren, Temps, Acc) ->
- case Ren of
- #{R := {mode3, NewName}} ->
- #{R := T} = Temps,
- RestoreInstr = mk_move(T, update_reg_nr(NewName, T, Target), Target),
- add_mode3_restores(Rs, Target, Ren, Temps, [RestoreInstr|Acc]);
- #{} ->
- add_mode3_restores(Rs, Target, Ren, Temps, Acc)
- end.
-
--type rewrite_fun() :: fun((target_instr()) -> target_instr()).
--type subst_fun() :: fun((target_temp()) -> target_temp()).
--spec rewrite_subst_fun(target(), ren(), ordsets:ordset(temp())) -> subst_fun().
-rewrite_subst_fun(Target, Ren, M3Ren) ->
- fun(Temp) ->
- Reg = reg_nr(Temp, Target),
- case Ren of
- #{Reg := {Mode, NewName}} ->
- case Mode =/= mode3 orelse lists:member(Reg, M3Ren) of
- false -> Temp;
- true -> update_reg_nr(NewName, Temp, Target)
- end;
- #{} -> Temp
- end
- end.
-
--type spillmap() :: [{temp(), target_instr()}].
--spec mk_spillmap(ren(), liveset(), defsetf(), temps(), target())
- -> spillmap().
-mk_spillmap(Ren, Livein, Defout, Temps, Target) ->
- [begin
- Temp = maps:get(Reg, Temps),
- {NewName, mk_move(update_reg_nr(NewName, Temp, Target), Temp, Target)}
- end || {Reg, {mode1, NewName}} <- maps:to_list(Ren),
- lists:member(Reg, Livein), defsetf_member(Reg, Defout)].
-
--spec mk_restores(ren(), liveset(), liveset(), temps(), target())
- -> [target_instr()].
-mk_restores(Ren, Livein, PLivein, Temps, Target) ->
- [begin
- Temp = maps:get(Reg, Temps),
- mk_move(Temp, update_reg_nr(NewName, Temp, Target), Target)
- end || {Reg, {Mode, NewName}} <- maps:to_list(Ren),
- ( (Mode =:= mode1 andalso lists:member(Reg, Livein ))
- orelse (Mode =:= mode2 andalso lists:member(Reg, PLivein)))].
-
--spec inject_restores([label()], target(), liveness(), plive(),
- part_dsets_map(), renames(), temps(), target_instr(),
- target_cfg())
- -> {target_instr(), target_cfg()}.
-inject_restores([], _Target, _Liveness, _PLive, _DSets, _Renames, _Temps, CFTI,
- TCFG) ->
- {CFTI, TCFG};
-inject_restores([L|Ls], Target, Liveness, PLive, DSets, Renames, Temps, CFTI0,
- TCFG0) ->
- Ren = maps:get(maps:get(L,DSets), Renames),
- Livein = livein(Liveness, L, Target),
- PLivein = plivein(L, PLive),
- {CFTI, TCFG} =
- case mk_restores(Ren, Livein, PLivein, Temps, Target) of
- [] -> {CFTI0, TCFG0}; % optimisation
- Restores ->
- RestBBLbl = new_label(Target),
- Code = Restores ++ [mk_goto(L, Target)],
- CFTI1 = redirect_jmp(CFTI0, L, RestBBLbl, Target),
- TCFG1 = update_bb(TCFG0, RestBBLbl, hipe_bb:mk_bb(Code), Target),
- {CFTI1, TCFG1}
- end,
- inject_restores(Ls, Target, Liveness, PLive, DSets, Renames, Temps, CFTI,
- TCFG).
-
-%% Heuristic. Move spills up until we meet the edge of the BB or a definition of
-%% that temp.
--spec lift_spills([target_instr()], target(), spillmap(), [target_instr()])
- -> [target_instr()].
-lift_spills([], _Target, SpillMap, Acc) ->
- [SpillI || {_, SpillI} <- SpillMap] ++ Acc;
-lift_spills([I|Is], Target, SpillMap0, Acc) ->
- Def = reg_defines(I, Target),
- {Spills0, SpillMap} =
- lists:partition(fun({Reg,_}) -> lists:member(Reg, Def) end, SpillMap0),
- Spills = [SpillI || {_, SpillI} <- Spills0],
- lift_spills(Is, Target, SpillMap, [I|Spills ++ Acc]).
-
-reg_defines(I, Target) ->
- reg_names(defines(I,Target), Target).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Costs ADT
-%%
-%% Keeps track of cumulative cost of spilling temps in particular partitions
-%% using particular spill modes.
--type cost_map() :: #{[part_key()|temp()] => float()}.
--type cost_key() :: entry1 | entry2 | exit | spill | restore.
--record(costs, {entry1 = #{} :: cost_map()
- ,entry2 = #{} :: cost_map()
- ,exit = #{} :: cost_map()
- ,spill = #{} :: cost_map()
- ,restore = #{} :: cost_map()
- }).
--type costs() :: #costs{}.
-
--spec costs_new() -> costs().
-costs_new() -> #costs{}.
-
--spec costs_insert(cost_key(), part_key(), float(), liveset(), costs())
- -> costs().
-costs_insert(entry1, A, Weight, Liveset, Costs=#costs{entry1=Entry1}) ->
- Costs#costs{entry1=costs_insert_1(A, Weight, Liveset, Entry1)};
-costs_insert(entry2, A, Weight, Liveset, Costs=#costs{entry2=Entry2}) ->
- Costs#costs{entry2=costs_insert_1(A, Weight, Liveset, Entry2)};
-costs_insert(exit, A, Weight, Liveset, Costs=#costs{exit=Exit}) ->
- Costs#costs{exit=costs_insert_1(A, Weight, Liveset, Exit)};
-costs_insert(spill, A, Weight, Liveset, Costs=#costs{spill=Spill}) ->
- Costs#costs{spill=costs_insert_1(A, Weight, Liveset, Spill)};
-costs_insert(restore, A, Weight, Liveset, Costs=#costs{restore=Restore}) ->
- Costs#costs{restore=costs_insert_1(A, Weight, Liveset, Restore)}.
-
-costs_insert_1(A, Weight, Liveset, CostMap0) when is_float(Weight) ->
- lists:foldl(fun(Live, CostMap1) ->
- map_update_counter([A|Live], Weight, CostMap1)
- end, CostMap0, Liveset).
-
--spec costs_map_roots(part_dsets(), costs()) -> {costs(), part_dsets()}.
-costs_map_roots(DSets0, Costs) ->
- {Entry1, DSets1} = costs_map_roots_1(DSets0, Costs#costs.entry1),
- {Entry2, DSets2} = costs_map_roots_1(DSets1, Costs#costs.entry2),
- {Exit, DSets3} = costs_map_roots_1(DSets2, Costs#costs.exit),
- {Spill, DSets4} = costs_map_roots_1(DSets3, Costs#costs.spill),
- {Restore, DSets} = costs_map_roots_1(DSets4, Costs#costs.restore),
- {#costs{entry1=Entry1,entry2=Entry2,exit=Exit,spill=Spill,restore=Restore},
- DSets}.
-
-costs_map_roots_1(DSets0, CostMap) ->
- {NewEs, DSets} = lists:mapfoldl(fun({[A|T], Wt}, DSets1) ->
- {AR, DSets2} = hipe_dsets:find(A, DSets1),
- {{[AR|T], Wt}, DSets2}
- end, DSets0, maps:to_list(CostMap)),
- {maps_from_list_merge(NewEs, fun erlang:'+'/2, #{}), DSets}.
-
-maps_from_list_merge([], _MF, Acc) -> Acc;
-maps_from_list_merge([{K,V}|Ps], MF, Acc) ->
- maps_from_list_merge(Ps, MF, case Acc of
- #{K := OV} -> Acc#{K := MF(V, OV)};
- #{} -> Acc#{K => V}
- end).
-
--spec costs_query(temp(), cost_key(), part_key(), costs()) -> float().
-costs_query(Temp, entry1, Part, #costs{entry1=Entry1}) ->
- costs_query_1(Temp, Part, Entry1);
-costs_query(Temp, entry2, Part, #costs{entry2=Entry2}) ->
- costs_query_1(Temp, Part, Entry2);
-costs_query(Temp, exit, Part, #costs{exit=Exit}) ->
- costs_query_1(Temp, Part, Exit);
-costs_query(Temp, spill, Part, #costs{spill=Spill}) ->
- costs_query_1(Temp, Part, Spill);
-costs_query(Temp, restore, Part, #costs{restore=Restore}) ->
- costs_query_1(Temp, Part, Restore).
-
-costs_query_1(Temp, Part, CostMap) ->
- Key = [Part|Temp],
- case CostMap of
- #{Key := Wt} -> Wt;
- #{} -> 0.0
- end.
-
--spec map_update_counter(Key, number(), #{Key => number(), OK => OV})
- -> #{Key := number(), OK => OV}.
-map_update_counter(Key, Incr, Map) ->
- case Map of
- #{Key := Orig} -> Map#{Key := Orig + Incr};
- #{} -> Map#{Key => Incr}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Def and use counting ADT
--type ducount() :: #{temp() => float()}.
-
--spec ducount_new() -> ducount().
-ducount_new() -> #{}.
-
--spec ducount_add([temp()], float(), ducount()) -> ducount().
-ducount_add([], _Weight, DUCount) -> DUCount;
-ducount_add([T|Ts], Weight, DUCount0) ->
- DUCount =
- case DUCount0 of
- #{T := Count} -> DUCount0#{T := Count + Weight};
- #{} -> DUCount0#{T => Weight}
- end,
- ducount_add(Ts, Weight, DUCount).
-
-ducount_to_list(DUCount) -> maps:to_list(DUCount).
-
--spec ducount_merge(ducount(), ducount()) -> ducount().
-ducount_merge(DCA, DCB) when map_size(DCA) < map_size(DCB) ->
- ducount_merge_1(ducount_to_list(DCA), DCB);
-ducount_merge(DCA, DCB) when map_size(DCA) >= map_size(DCB) ->
- ducount_merge_1(ducount_to_list(DCB), DCA).
-
-ducount_merge_1([], DUCount) -> DUCount;
-ducount_merge_1([{T,AC}|Ts], DUCount0) ->
- DUCount =
- case DUCount0 of
- #{T := BC} -> DUCount0#{T := AC + BC};
- #{} -> DUCount0#{T => AC}
- end,
- ducount_merge_1(Ts, DUCount).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Target module interface functions
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(TGT_IFACE_0(N), N( {M,C}) -> M:N( C)).
--define(TGT_IFACE_1(N), N(A1, {M,C}) -> M:N(A1, C)).
--define(TGT_IFACE_2(N), N(A1,A2, {M,C}) -> M:N(A1,A2, C)).
--define(TGT_IFACE_3(N), N(A1,A2,A3,{M,C}) -> M:N(A1,A2,A3,C)).
-
-?TGT_IFACE_2(bb).
-?TGT_IFACE_1(def_use).
-?TGT_IFACE_1(defines).
-?TGT_IFACE_1(defines_all_alloc).
-?TGT_IFACE_1(is_precoloured).
-?TGT_IFACE_1(mk_goto).
-?TGT_IFACE_2(mk_move).
-?TGT_IFACE_0(new_label).
-?TGT_IFACE_0(new_reg_nr).
-?TGT_IFACE_1(number_of_temporaries).
-?TGT_IFACE_3(redirect_jmp).
-?TGT_IFACE_1(reg_nr).
-?TGT_IFACE_1(reverse_postorder).
-?TGT_IFACE_2(subst_temps).
-?TGT_IFACE_3(update_bb).
-?TGT_IFACE_2(update_reg_nr).
-
-branch_preds(Instr, {TgtMod,TgtCtx}) ->
- merge_sorted_preds(lists:keysort(1, TgtMod:branch_preds(Instr, TgtCtx))).
-
-livein(Liveness, L, Target={TgtMod,TgtCtx}) ->
- ordsets:from_list(reg_names(TgtMod:livein(Liveness, L, TgtCtx), Target)).
-
-liveout(Liveness, L, Target={TgtMod,TgtCtx}) ->
- ordsets:from_list(reg_names(TgtMod:liveout(Liveness, L, TgtCtx), Target)).
-
-merge_sorted_preds([]) -> [];
-merge_sorted_preds([{L, P1}, {L, P2}|LPs]) ->
- merge_sorted_preds([{L, P1+P2}|LPs]);
-merge_sorted_preds([LP|LPs]) -> [LP|merge_sorted_preds(LPs)].
-
-reg_names(Regs, {TgtMod,TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
diff --git a/lib/hipe/regalloc/hipe_reg_worklists.erl b/lib/hipe/regalloc/hipe_reg_worklists.erl
deleted file mode 100644
index 415f1d6122..0000000000
--- a/lib/hipe/regalloc/hipe_reg_worklists.erl
+++ /dev/null
@@ -1,358 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%----------------------------------------------------------------------
-%%% File : hipe_reg_worklists.erl
-%%% Author : Andreas Wallin <d96awa@csd.uu.se>
-%%% Purpose : Represents sets of nodes/temporaries that we are
-%%% working on, such as simplify and spill sets.
-%%% Created : 3 Feb 2000 by Andreas Wallin <d96awa@csd.uu.se>
-%%% Modified: Spring 2005 by NilsOla Linnermark <nilsola@abc.se>
-%%% to suit the optimistic coalesching allocator
-%%%----------------------------------------------------------------------
-
--module(hipe_reg_worklists).
--author(['Andreas Wallin', 'Thorild Selén']).
--export([new/6, % only used by optimistic allocator
- new/7,
- simplify/1,
- spill/1,
- freeze/1,
- stack/1,
- add_simplify/2,
- add_freeze/2,
- add_coalesced/2,
- add_coalesced/3, % only used by optimistic allocator
- add_spill/2,
- push_stack/3,
- remove_simplify/2,
- remove_spill/2,
- remove_freeze/2,
- is_empty_simplify/1,
- is_empty_spill/1,
- is_empty_freeze/1,
- member_freeze/2,
- member_coalesced_to/2, % only used by optimistic allocator
- member_stack_or_coalesced/2,
- non_stacked_or_coalesced_nodes/2,
- transfer_freeze_simplify/2,
- transfer_freeze_spill/2
- ]).
--ifdef(DEBUG_PRINTOUTS).
--export([print_memberships/1]).
--endif.
-
--record(worklists,
- {simplify, % Low-degree nodes (if coalescing non move-related)
- stack, % Stack of removed low-degree nodes, with adjacency lists
- membership, % Mapping from temp to which set it is in
- coalesced_to, % if the node is coalesced to (only used by optimistic allocator)
- spill, % Significant-degree nodes
- freeze % Low-degree move-related nodes
- }).
-
-%%-ifndef(DEBUG).
-%%-define(DEBUG,true).
-%%-endif.
--include("../main/hipe.hrl").
-
-%%%----------------------------------------------------------------------
-%% Function: new
-%%
-%% Description: Constructor for worklists structure
-%%
-%% Parameters:
-%% IG -- Interference graph
-%% Target -- Target module name
-%% CFG -- Target-specific CFG
-%% Move_sets -- Move information
-%% K -- Number of registers
-%%
-%% Returns:
-%% A new worklists data structure
-%%
-%%%----------------------------------------------------------------------
-
-%% only used by optimistic allocator
-new(IG, TargetMod, TargetCtx, CFG, K, No_temporaries) ->
- CoalescedTo = hipe_bifs:array(No_temporaries, 'none'),
- init(initial(TargetMod, TargetCtx, CFG), K, IG,
- empty(No_temporaries, CoalescedTo)).
-
-new(IG, TargetMod, TargetCtx, CFG, Move_sets, K, No_temporaries) ->
- init(initial(TargetMod, TargetCtx, CFG), K, IG, Move_sets,
- empty(No_temporaries, [])).
-
-initial(TargetMod, TargetCtx, CFG) ->
- {Min_temporary, Max_temporary} = TargetMod:var_range(CFG, TargetCtx),
- NonAlloc = TargetMod:non_alloc(CFG, TargetCtx),
- non_precoloured(TargetMod, TargetCtx, Min_temporary, Max_temporary, [])
- -- [TargetMod:reg_nr(X, TargetCtx) || X <- NonAlloc].
-
-non_precoloured(TargetMod, TargetCtx, Current, Max_temporary, Initial) ->
- if Current > Max_temporary ->
- Initial;
- true ->
- NewInitial =
- case TargetMod:is_precoloured(Current, TargetCtx) of
- true -> Initial;
- false -> [Current|Initial]
- end,
- non_precoloured(TargetMod, TargetCtx, Current+1, Max_temporary, NewInitial)
- end.
-
-%% construct an empty initialized worklists data structure
-empty(No_temporaries, CoalescedTo) ->
- #worklists{
- membership = hipe_bifs:array(No_temporaries, 'none'),
- coalesced_to = CoalescedTo, % only used by optimistic allocator
- simplify = ordsets:new(),
- stack = [],
- spill = ordsets:new(),
- freeze = ordsets:new()
- }.
-
-%% Selectors for worklists record
-
-simplify(Worklists) -> Worklists#worklists.simplify.
-spill(Worklists) -> Worklists#worklists.spill.
-freeze(Worklists) -> Worklists#worklists.freeze.
-stack(Worklists) -> Worklists#worklists.stack.
-
-%% Updating worklists records
-
-set_simplify(Simplify, Worklists) ->
- Worklists#worklists{simplify = Simplify}.
-set_spill(Spill, Worklists) ->
- Worklists#worklists{spill = Spill}.
-set_freeze(Freeze, Worklists) ->
- Worklists#worklists{freeze = Freeze}.
-
-
-%%----------------------------------------------------------------------
-%% Function: init
-%%
-%% Description: Initializes worklists
-%%
-%% Parameters:
-%% Initials -- Not precoloured temporaries
-%% K -- Number of registers
-%% IG -- Interference graph
-%% Move_sets -- Move information
-%% Worklists -- (Empty) worklists structure
-%%
-%% Returns:
-%% Initialized worklists structure
-%%
-%%----------------------------------------------------------------------
-
-init([], _, _, Worklists) -> Worklists;
-init([Initial|Initials], K, IG, Worklists) ->
- case hipe_ig:is_trivially_colourable(Initial, K, IG) of
- false ->
- New_worklists = add_spill(Initial, Worklists),
- init(Initials, K, IG, New_worklists);
- _ ->
- New_worklists = add_simplify(Initial, Worklists),
- init(Initials, K, IG, New_worklists)
- end.
-
-init([], _, _, _, Worklists) -> Worklists;
-init([Initial|Initials], K, IG, Move_sets, Worklists) ->
- case hipe_ig:is_trivially_colourable(Initial, K, IG) of
- false ->
- New_worklists = add_spill(Initial, Worklists),
- init(Initials, K, IG, Move_sets, New_worklists);
- _ ->
- case hipe_moves:move_related(Initial, Move_sets) of
- true ->
- New_worklists = add_freeze(Initial, Worklists),
- init(Initials, K, IG, Move_sets, New_worklists);
- _ ->
- New_worklists = add_simplify(Initial, Worklists),
- init(Initials, K, IG, Move_sets, New_worklists)
- end
- end.
-
-%%%----------------------------------------------------------------------
-%% Function: is_empty
-%%
-%% Description: Tests if the selected worklist if empty or not.
-%%
-%% Parameters:
-%% Worklists -- A worklists data structure
-%%
-%% Returns:
-%% true -- If the worklist was empty
-%% false -- otherwise
-%%
-%%%----------------------------------------------------------------------
-
-is_empty_simplify(Worklists) ->
- simplify(Worklists) =:= [].
-
-is_empty_spill(Worklists) ->
- spill(Worklists) =:= [].
-
-is_empty_freeze(Worklists) ->
- freeze(Worklists) =:= [].
-
-%%%----------------------------------------------------------------------
-%% Function: add
-%%
-%% Description: Adds one element to one of the worklists.
-%%
-%% Parameters:
-%% Element -- An element you want to add to the
-%% selected worklist. The element should
-%% be a node/temporary.
-%% Worklists -- A worklists data structure
-%%
-%% Returns:
-%% An worklists data-structure that have Element in selected
-%% worklist.
-%%
-%%%----------------------------------------------------------------------
-add_coalesced(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'stack_or_coalesced'),
- Worklists.
-
-add_coalesced(From, To, Worklists) -> % only used by optimistic allocator
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, From, 'stack_or_coalesced'),
- Coalesced_to = Worklists#worklists.coalesced_to,
- hipe_bifs:array_update(Coalesced_to, To, 'coalesced_to'),
- Worklists.
-
-add_simplify(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'simplify'),
- Simplify = ordsets:add_element(Element, simplify(Worklists)),
- set_simplify(Simplify, Worklists).
-
-add_spill(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'spill'),
- Spill = ordsets:add_element(Element, spill(Worklists)),
- set_spill(Spill, Worklists).
-
-add_freeze(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'freeze'),
- Freeze = ordsets:add_element(Element, freeze(Worklists)),
- set_freeze(Freeze, Worklists).
-
-push_stack(Node, AdjList, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Node, 'stack_or_coalesced'),
- Stack = Worklists#worklists.stack,
- Worklists#worklists{stack = [{Node,AdjList}|Stack]}.
-
-%%%----------------------------------------------------------------------
-%% Function: remove
-%%
-%% Description: Removes one element to one of the worklists.
-%%
-%% Parameters:
-%% Element -- An element you want to remove from the
-%% selected worklist. The element should
-%% be a node/temporary.
-%% Worklists -- A worklists data structure
-%%
-%% Returns:
-%% A worklists data-structure that don't have Element in selected
-%% worklist.
-%%
-%%%----------------------------------------------------------------------
-remove_simplify(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'none'),
- Simplify = ordsets:del_element(Element, simplify(Worklists)),
- set_simplify(Simplify, Worklists).
-
-remove_spill(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'none'),
- Spill = ordsets:del_element(Element, spill(Worklists)),
- set_spill(Spill, Worklists).
-
-remove_freeze(Element, Worklists) ->
- Membership = Worklists#worklists.membership,
- hipe_bifs:array_update(Membership, Element, 'none'),
- Freeze = ordsets:del_element(Element, freeze(Worklists)),
- set_freeze(Freeze, Worklists).
-
-%%%----------------------------------------------------------------------
-%% Function: transfer
-%%
-%% Description: Moves element from one worklist to another.
-%%
-%%%----------------------------------------------------------------------
-transfer_freeze_simplify(Element, Worklists) ->
- add_simplify(Element, remove_freeze(Element, Worklists)).
-
-transfer_freeze_spill(Element, Worklists) ->
- add_spill(Element, remove_freeze(Element, Worklists)).
-
-%%%----------------------------------------------------------------------
-%% Function: member
-%%
-%% Description: Checks if one element if member of selected worklist.
-%%
-%% Parameters:
-%% Element -- Element you want to know if it's a
-%% member of selected worklist.
-%% Worklists -- A worklists data structure
-%%
-%% Returns:
-%% true -- if Element is a member of selected worklist
-%% false -- Otherwise
-%%
-%%%----------------------------------------------------------------------
-
-member_coalesced_to(Element, Worklists) -> % only used by optimistic allocator
- hipe_bifs:array_sub(Worklists#worklists.coalesced_to, Element) =:= 'coalesced_to'.
-
-member_freeze(Element, Worklists) ->
- hipe_bifs:array_sub(Worklists#worklists.membership, Element) =:= 'freeze'.
-
-member_stack_or_coalesced(Element, Worklists) ->
- hipe_bifs:array_sub(Worklists#worklists.membership, Element) =:= 'stack_or_coalesced'.
-
-non_stacked_or_coalesced_nodes(Nodes, Worklists) ->
- Membership = Worklists#worklists.membership,
- [Node || Node <- Nodes,
- hipe_bifs:array_sub(Membership, Node) =/= 'stack_or_coalesced'].
-
-%%%----------------------------------------------------------------------
-%% Print functions - only used for debugging
-
--ifdef(DEBUG_PRINTOUTS).
-print_memberships(Worklists) ->
- ?debug_msg("Worklist memeberships:\n", []),
- Membership = Worklists#worklists.membership,
- NrElems = hipe_bifs:array_length(Membership),
- Coalesced_to = Worklists#worklists.coalesced_to,
- print_membership(NrElems, Membership, Coalesced_to).
-
-print_membership(0, _, _) ->
- true;
-print_membership(Element, Membership, Coalesced_to) ->
- NextElement = Element - 1,
- ?debug_msg("worklist ~w ~w ~w\n",
- [NextElement, hipe_bifs:array_sub(Membership, NextElement),
- hipe_bifs:array_sub(Coalesced_to, NextElement)]),
- print_membership(NextElement, Membership, Coalesced_to).
--endif.
diff --git a/lib/hipe/regalloc/hipe_regalloc_loop.erl b/lib/hipe/regalloc/hipe_regalloc_loop.erl
deleted file mode 100644
index 29ef3adcc2..0000000000
--- a/lib/hipe/regalloc/hipe_regalloc_loop.erl
+++ /dev/null
@@ -1,117 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Common wrapper for graph_coloring and coalescing regallocs.
-
--module(hipe_regalloc_loop).
--export([ra/7, ra_fp/6]).
-
-%%-define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.
--include("../main/hipe.hrl").
-
-ra(CFG, Liveness0, SpillIndex, Options, RegAllocMod, TargetMod, TargetCtx) ->
- {NewCFG, Liveness, Coloring, _NewSpillIndex} =
- ra_common(CFG, Liveness0, SpillIndex, Options, RegAllocMod, TargetMod,
- TargetCtx),
- {NewCFG, Liveness, Coloring}.
-
-ra_fp(CFG, Liveness, Options, RegAllocMod, TargetMod, TargetCtx) ->
- ra_common(CFG, Liveness, 0, Options, RegAllocMod, TargetMod, TargetCtx).
-
-ra_common(CFG0, Liveness0, SpillIndex, Options, RegAllocMod, TargetMod,
- TargetCtx) ->
- ?inc_counter(ra_calls_counter, 1),
- {CFG1, Liveness1} =
- do_range_split(CFG0, Liveness0, TargetMod, TargetCtx, Options),
- SpillLimit0 = TargetMod:number_of_temporaries(CFG1, TargetCtx),
- {Coloring, _, CFG, Liveness} =
- call_allocator_initial(CFG1, Liveness1, SpillLimit0, SpillIndex, Options,
- RegAllocMod, TargetMod, TargetCtx),
- %% The first iteration, the hipe_regalloc_prepass may create new temps, these
- %% should not end up above SpillLimit.
- SpillLimit = TargetMod:number_of_temporaries(CFG, TargetCtx),
- alloc(Coloring, CFG, Liveness, SpillLimit, SpillIndex, Options,
- RegAllocMod, TargetMod, TargetCtx).
-
-alloc(Coloring, CFG0, Liveness, SpillLimit, SpillIndex, Options,
- RegAllocMod, TargetMod, TargetCtx) ->
- ?inc_counter(ra_iteration_counter, 1),
- {CFG, DidSpill} = TargetMod:check_and_rewrite(CFG0, Coloring, TargetCtx),
- case DidSpill of
- false -> %% No new temps, we are done.
- ?add_spills(Options, _NewSpillIndex),
- TempMap = hipe_temp_map:cols2tuple(Coloring, TargetMod, TargetCtx),
- {TempMap2, NewSpillIndex2} =
- hipe_spillmin:stackalloc(CFG0, Liveness, [], SpillIndex, Options,
- TargetMod, TargetCtx, TempMap),
- Coloring2 =
- hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), TempMap2),
- %% case proplists:get_bool(verbose_spills, Options) of
- %% true ->
- %% ?msg("Num spill slots used: ~p~n", [NewSpillIndex2-SpillIndex]);
- %% false ->
- %% ok
- %% end,
- {CFG, Liveness, Coloring2, NewSpillIndex2};
- _ ->
- %% Since SpillLimit is used as a low-water-mark
- %% the list of temps not to spill is uninteresting.
- {NewColoring, _NewSpillIndex} =
- call_allocator(CFG, Liveness, SpillLimit, SpillIndex, Options,
- RegAllocMod, TargetMod, TargetCtx),
- alloc(NewColoring, CFG, Liveness, SpillLimit, SpillIndex, Options,
- RegAllocMod, TargetMod, TargetCtx)
- end.
-
-call_allocator_initial(CFG, Liveness, SpillLimit, SpillIndex, Options,
- RegAllocMod, TargetMod, TargetCtx) ->
- case proplists:get_bool(ra_prespill, Options) of
- true ->
- hipe_regalloc_prepass:regalloc_initial(
- RegAllocMod, CFG, Liveness, SpillIndex, SpillLimit, TargetMod,
- TargetCtx, Options);
- false ->
- {C, SI} = RegAllocMod:regalloc(CFG, Liveness, SpillIndex, SpillLimit,
- TargetMod, TargetCtx, Options),
- {C, SI, CFG, Liveness}
- end.
-
-call_allocator(CFG, Liveness, SpillLimit, SpillIndex, Options, RegAllocMod,
- TargetMod, TargetCtx) ->
- case proplists:get_bool(ra_prespill, Options) of
- true ->
- hipe_regalloc_prepass:regalloc(
- RegAllocMod, CFG, Liveness, SpillIndex, SpillLimit, TargetMod,
- TargetCtx, Options);
- false ->
- RegAllocMod:regalloc(CFG, Liveness, SpillIndex, SpillLimit, TargetMod,
- TargetCtx, Options)
- end.
-
-do_range_split(CFG0, Liveness0, TgtMod, TgtCtx, Options) ->
- {CFG2, Liveness1} =
- case proplists:get_bool(ra_restore_reuse, Options) of
- true ->
- CFG1 = hipe_restore_reuse:split(CFG0, Liveness0, TgtMod, TgtCtx),
- {CFG1, TgtMod:analyze(CFG1, TgtCtx)};
- false ->
- {CFG0, Liveness0}
- end,
- case proplists:get_bool(ra_range_split, Options) of
- true ->
- CFG3 = hipe_range_split:split(CFG2, Liveness1, TgtMod, TgtCtx, Options),
- {CFG3, TgtMod:analyze(CFG3, TgtCtx)};
- false ->
- {CFG2, Liveness1}
- end.
diff --git a/lib/hipe/regalloc/hipe_regalloc_prepass.erl b/lib/hipe/regalloc/hipe_regalloc_prepass.erl
deleted file mode 100644
index 5024840237..0000000000
--- a/lib/hipe/regalloc/hipe_regalloc_prepass.erl
+++ /dev/null
@@ -1,953 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% PREPASS FOR ITERATED REGISTER ALLOCATORS
-%%
-%% Implements a trivial partial but optimal fast register allocator to be used
-%% as the first pass of the register allocation loop.
-%%
-%% The idea is to drastically reduce the number of temporaries, so as to speed
-%% up the real register allocators.
-%%
-%% * Spills trivially unallocatable temps
-%% This relies on the fact that calls intentionally clobber all registers.
-%% Since this is the case, any temp that is alive over a call can't possibly
-%% be allocated to anything but a spill slot.
-%%
-%% * Partitions the program at points where no pseudos that were not spiled are
-%% live, and then do register allocation on these partitions independently.
-%% These program points are commonly, but not exclusively, the call
-%% instructions.
-%%
-%% TODO
-%% * This module seems very successful at finding every single spill; register
-%% allocation performance should be improved if we short-circuit the first
-%% hipe_regalloc_loop iteration, skipping directly to rewrite without ever
-%% calling RegAllocMod.
--module(hipe_regalloc_prepass).
--export([regalloc/8, regalloc_initial/8]).
-
--ifndef(DEBUG).
--compile(inline).
--endif.
-
-%%-define(DO_ASSERT, 1).
--include("../main/hipe.hrl").
-
-%%% TUNABLES
-
-%% Partitions with fewer than ?TUNE_TOO_FEW_BBS basic block halves are merged
-%% together before register allocation.
--define(TUNE_TOO_FEW_BBS, 256).
-
-%% Ignore the ra_partitioned option (and do whole function RA instead) when
-%% there are fewer than ?TUNE_MIN_SPLIT_BBS basic blocks.
--define(TUNE_MIN_SPLIT_BBS, 384).
-
-%% We present a "pseudo-target" to the register allocator we wrap.
--export([analyze/2,
- all_precoloured/1,
- allocatable/1,
- args/2,
- bb/3,
- def_use/2,
- defines/2,
- is_fixed/2, % used by hipe_graph_coloring_regalloc
- is_global/2,
- is_move/2,
- is_precoloured/2,
- labels/2,
- livein/3,
- liveout/3,
- non_alloc/2,
- number_of_temporaries/2,
- physical_name/2,
- postorder/2,
- reg_nr/2,
- uses/2,
- var_range/2,
- reverse_postorder/2]).
-
--record(prepass_ctx,
- {target_mod :: module()
- ,target_ctx :: target_context()
- ,sub :: sub_map() % Translates temp numbers found in CFG and understood by
- % Target to temp numbers passed to RegAllocMod.
- ,inv :: inv_map() % Translates temp numbers passed to RegAllocMod
- % to temp numbers found in CFG and understood by
- % Target
- ,max_phys :: temp() % Exclusive upper bound on physical registers
- }).
-
--record(cfg,
- {cfg :: target_cfg()
- ,bbs :: transformed_bbs()
- ,max_reg :: temp() % Exclusive upper bound on temp numbers
- ,rpostorder :: undefined % Only precomputed with partitioned cfg
- | [label()]
- }).
-
--type bb() :: hipe_bb:bb(). % containing instr()
--type liveset() :: ordsets:ordset(temp()).
--record(transformed_bb,
- {bb :: bb()
- ,livein :: liveset()
- ,liveout :: liveset()
- }).
--type transformed_bb() :: #transformed_bb{}.
--type transformed_bbs() :: #{label() => transformed_bb()}.
-
--record(instr,
- {defuse :: {[temp()], [temp()]}
- ,is_move :: boolean()
- }).
--type instr() :: #instr{}.
-
--type target_cfg() :: any().
--type target_instr() :: any().
--type target_temp() :: any().
--type target_reg() :: non_neg_integer().
--type target_liveness() :: any().
--type target_liveset() :: ordsets:ordset(target_reg()).
--type target_context() :: any().
--type spillno() :: non_neg_integer().
--type temp() :: non_neg_integer().
--type label() :: non_neg_integer().
-
--spec regalloc(module(), target_cfg(), target_liveness(), spillno(), spillno(),
- module(), target_context(), proplists:proplist())
- -> {hipe_map(), spillno()}.
-regalloc(RegAllocMod, CFG, Liveness, SpillIndex0, SpillLimit, TargetMod,
- TargetCtx, Options) ->
- {Coloring, SpillIndex, same} =
- regalloc_1(RegAllocMod, CFG, SpillIndex0, SpillLimit, TargetMod,
- TargetCtx, Options, Liveness),
- {Coloring, SpillIndex}.
-
-%% regalloc_initial/7 is allowed to introduce new temporaries, unlike
-%% regalloc/7.
-%% In order for regalloc/7 to never introduce temporaries, regalloc/7 must never
-%% choose to do split allocation unless regalloc_initial/7 does. This is the
-%% reason that the splitting heuristic is solely based on the number of basic
-%% blocks, which does not change during the register allocation loop.
--spec regalloc_initial(module(), target_cfg(), target_liveness(), spillno(),
- spillno(), module(), target_context(),
- proplists:proplist())
- -> {hipe_map(), spillno(), target_cfg(),
- target_liveness()}.
-regalloc_initial(RegAllocMod, CFG0, Liveness0, SpillIndex0, SpillLimit,
- TargetMod, TargetCtx, Options) ->
- {Coloring, SpillIndex, NewCFG} =
- regalloc_1(RegAllocMod, CFG0, SpillIndex0, SpillLimit, TargetMod, TargetCtx,
- Options, Liveness0),
- {CFG, Liveness} =
- case NewCFG of
- same -> {CFG0, Liveness0};
- {rewritten, CFG1} -> {CFG1, TargetMod:analyze(CFG1, TargetCtx)}
- end,
- {Coloring, SpillIndex, CFG, Liveness}.
-
-regalloc_1(RegAllocMod, CFG0, SpillIndex0, SpillLimit, TargetMod, TargetCtx,
- Options, Liveness) ->
- {ScanBBs, Seen, SpillMap, SpillIndex1} =
- scan_cfg(CFG0, Liveness, SpillIndex0, TargetMod, TargetCtx),
-
- {PartColoring, SpillIndex, NewCFG} =
- case proplists:get_bool(ra_partitioned, Options)
- andalso length(TargetMod:labels(CFG0, TargetCtx)) > ?TUNE_MIN_SPLIT_BBS
- of
- true ->
- regalloc_partitioned(SpillMap, SpillIndex1, SpillLimit, ScanBBs,
- CFG0, TargetMod, TargetCtx, RegAllocMod, Options);
- _ ->
- regalloc_whole(Seen, SpillMap, SpillIndex1, SpillLimit, ScanBBs,
- CFG0, TargetMod, TargetCtx, RegAllocMod, Options)
- end,
-
- SpillColors = [{T, {spill, S}} || {T, S} <- maps:to_list(SpillMap)],
- Coloring = SpillColors ++ PartColoring,
-
- ?ASSERT(begin
- AllPrecoloured = TargetMod:all_precoloured(TargetCtx),
- MaxPhys = lists:max(AllPrecoloured) + 1,
- Unused = unused(live_pseudos(Seen, SpillMap, MaxPhys),
- SpillMap, CFG0, TargetMod, TargetCtx),
- unused_unused(Unused, CFG0, TargetMod, TargetCtx)
- end),
- ?ASSERT(begin
- CFG =
- case NewCFG of
- same -> CFG0;
- {rewritten, CFG1} -> CFG1
- end,
- check_coloring(Coloring, CFG, TargetMod, TargetCtx)
- end), % Sanity-check
- ?ASSERT(just_as_good_as(RegAllocMod, CFG, Liveness, SpillIndex0, SpillLimit,
- TargetMod, TargetCtx, Options, SpillMap, Coloring,
- Unused)),
- {Coloring, SpillIndex, NewCFG}.
-
-regalloc_whole(Seen, SpillMap, SpillIndex0, SpillLimit, ScanBBs,
- CFG, TargetMod, TargetCtx, RegAllocMod, Options) ->
- AllPrecoloured = TargetMod:all_precoloured(TargetCtx),
- MaxPhys = lists:max(AllPrecoloured) + 1,
- LivePseudos = live_pseudos(Seen, SpillMap, MaxPhys),
- {SubMap, InvMap, MaxPhys, MaxR, SubSpillLimit} =
- number_and_map(AllPrecoloured, LivePseudos, SpillLimit),
- BBs = transform_whole_cfg(ScanBBs, SubMap),
- SubMod = #cfg{cfg=CFG, bbs=BBs, max_reg=MaxR},
- SubContext = #prepass_ctx{target_mod=TargetMod, target_ctx=TargetCtx,
- max_phys=MaxPhys, inv=InvMap, sub=SubMap},
- {SubColoring, SpillIndex} =
- RegAllocMod:regalloc(SubMod, SubMod, SpillIndex0, SubSpillLimit, ?MODULE,
- SubContext, Options),
- ?ASSERT(check_coloring(SubColoring, SubMod, ?MODULE, SubContext)),
- {translate_coloring(SubColoring, InvMap), SpillIndex, same}.
-
-regalloc_partitioned(SpillMap, SpillIndex0, SpillLimit, ScanBBs,
- CFG, TargetMod, TargetCtx, RegAllocMod, Options) ->
- AllPrecoloured = TargetMod:all_precoloured(TargetCtx),
- MaxPhys = lists:max(AllPrecoloured) + 1,
-
- DSets0 = initial_dsets(CFG, TargetMod, TargetCtx),
- PartBBList = part_cfg(ScanBBs, SpillMap, MaxPhys),
- DSets1 = join_whole_blocks(PartBBList, DSets0),
- {PartBBsRLList, DSets2} = merge_small_parts(DSets1),
- {PartBBs, DSets3} = merge_pointless_splits(PartBBList, ScanBBs, DSets2),
- SeenMap = collect_seenmap(PartBBsRLList, PartBBs),
- {RPostMap, _DSets4} = part_order(TargetMod:reverse_postorder(CFG, TargetCtx),
- DSets3),
-
- {Allocations, SpillIndex} =
- lists:mapfoldl(
- fun({Root, Elems}, SpillIndex1) ->
- #{Root := Seen} = SeenMap,
- #{Root := RPost} = RPostMap,
- LivePseudos = live_pseudos(Seen, SpillMap, MaxPhys),
- {SubMap, InvMap, MaxPhys, MaxR, SubSpillLimit} =
- number_and_map(AllPrecoloured, LivePseudos, SpillLimit),
- BBs = transform_cfg(Elems, PartBBs, SubMap),
- SubMod = #cfg{cfg=CFG, bbs=BBs, max_reg=MaxR, rpostorder=RPost},
- SubContext = #prepass_ctx{target_mod=TargetMod, target_ctx=TargetCtx,
- max_phys=MaxPhys, inv=InvMap, sub=SubMap},
- {SubColoring, SpillIndex2} =
- RegAllocMod:regalloc(SubMod, SubMod, SpillIndex1, SubSpillLimit,
- ?MODULE, SubContext, Options),
- ?ASSERT(check_coloring(SubColoring, SubMod, ?MODULE, SubContext)),
- {{translate_coloring(SubColoring, InvMap), Elems}, SpillIndex2}
- end, SpillIndex0, PartBBsRLList),
- {Coloring, NewCFG} =
- combine_allocations(Allocations, MaxPhys, PartBBs, TargetMod, TargetCtx,
- CFG),
- {Coloring, SpillIndex, NewCFG}.
-
--spec number_and_map([target_reg()], target_liveset(), target_reg())
- -> {sub_map(), inv_map(), temp(), temp(), temp()}.
-number_and_map(Phys, Pseud, SpillLimit) ->
- MaxPhys = lists:max(Phys) + 1,
- ?ASSERT(Pseud =:= [] orelse lists:min(Pseud) >= MaxPhys),
- NrPseuds = length(Pseud),
- MaxR = MaxPhys+NrPseuds,
- PseudNrs = lists:zip(Pseud, lists:seq(MaxPhys, MaxR-1)),
- MapList = lists:zip(Phys, Phys) % Physicals are identity-mapped
- ++ PseudNrs,
- ?ASSERT(MapList =:= lists:ukeysort(1, MapList)),
- SubMap = {s,maps:from_list(MapList)},
- InvMap = {i,maps:from_list([{Fake, Real} || {Real, Fake} <- MapList])},
- SubSpillLimit = translate_spill_limit(MapList, SpillLimit),
- {SubMap, InvMap, MaxPhys, MaxR, SubSpillLimit}.
-
--spec translate_spill_limit([{target_reg(), temp()}], target_reg()) -> temp().
-translate_spill_limit([{Real,Fake}], SpillLimit) when Real < SpillLimit ->
- Fake + 1;
-translate_spill_limit([{Real,_}|Ps], SpillLimit) when Real < SpillLimit ->
- translate_spill_limit(Ps, SpillLimit);
-translate_spill_limit([{Real,Fake}|_], SpillLimit) when Real >= SpillLimit ->
- Fake.
-
--spec live_pseudos(seen(), spill_map(), target_reg()) -> target_liveset().
-live_pseudos(Seen, SpillMap, MaxPhys) ->
- %% When SpillMap is much larger than Seen (which is typical in the partitioned
- %% case), it is much more efficient doing it like this than making an ordset
- %% of the spills and subtracting.
- ordsets:from_list(
- lists:filter(fun(R) -> R >= MaxPhys andalso not maps:is_key(R, SpillMap)
- end, maps:keys(Seen))).
-
--spec translate_coloring(hipe_map(), inv_map()) -> hipe_map().
-translate_coloring(SubColoring, InvMap) ->
- lists:map(fun({T, P}) -> {imap_get(T, InvMap), P} end, SubColoring).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% First pass
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Spill trivially unallocatable temps, create internal target-independent
-%% program representation, and collect a set of all used temps.
--record(spill_state,
- {map :: spill_map()
- ,ix :: spillno()
- }).
--type spill_state() :: #spill_state{}.
--type spill_map() :: #{target_reg() => spillno()}.
-
--spec scan_cfg(target_cfg(), target_liveness(), spillno(), module(),
- target_context())
- -> {scan_bbs()
- ,seen()
- ,spill_map()
- ,spillno()
- }.
-scan_cfg(CFG, Liveness, SpillIndex0, TgtMod, TgtCtx) ->
- State0 = #spill_state{map=#{}, ix=SpillIndex0},
- {BBs, Seen, #spill_state{map=Spill, ix=SpillIndex}} =
- scan_bbs(TgtMod:labels(CFG,TgtCtx), CFG, Liveness, #{}, State0, #{}, TgtMod,
- TgtCtx),
- {BBs, Seen, Spill, SpillIndex}.
-
--type seen() :: #{target_reg() => []}. % set
--type scan_bb() :: {[instr()], target_liveset(), target_liveset()}.
--type scan_bbs() :: #{label() => scan_bb()}.
-
--spec scan_bbs([label()], target_cfg(), target_liveness(), seen(),
- spill_state(), scan_bbs(), module(), target_context())
- -> {scan_bbs(), seen(), spill_state()}.
-scan_bbs([], _CFG, _Liveness, Seen, State, BBs, _TgtMod, _TgtCtx) ->
- {BBs, Seen, State};
-scan_bbs([L|Ls], CFG, Liveness, Seen0, State0, BBs, TgtMod, TgtCtx) ->
- Liveout = t_liveout(Liveness, L, TgtMod, TgtCtx),
- {Code, Livein, Seen, State} =
- scan_bb(lists:reverse(hipe_bb:code(TgtMod:bb(CFG, L, TgtCtx))), Liveout,
- Seen0, State0, [], TgtMod, TgtCtx),
- BB = {Code, Livein, Liveout},
- scan_bbs(Ls, CFG, Liveness, Seen, State, BBs#{L=>BB}, TgtMod, TgtCtx).
-
--spec scan_bb([target_instr()], target_liveset(), seen(), spill_state(),
- [instr()], module(), target_context())
- -> {[instr()]
- ,target_liveset()
- ,seen()
- ,spill_state()
- }.
-scan_bb([], Live, Seen, State, IAcc, _TgtMod, _TgtCtx) ->
- {IAcc, Live, Seen, State};
-scan_bb([I|Is], Live0, Seen0, State0, IAcc0, TgtMod, TgtCtx) ->
- {TDef, TUse} = TgtMod:def_use(I,TgtCtx),
- ?ASSERT(TDef =:= TgtMod:defines(I,TgtCtx)),
- ?ASSERT(TUse =:= TgtMod:uses(I,TgtCtx)),
- Def = ordsets:from_list(reg_names(TDef, TgtMod, TgtCtx)),
- Use = ordsets:from_list(reg_names(TUse, TgtMod, TgtCtx)),
- Live = ordsets:union(Use, ToSpill = ordsets:subtract(Live0, Def)),
- Seen = add_seen(Def, add_seen(Use, Seen0)),
- NewI = #instr{defuse={Def, Use}, is_move=TgtMod:is_move(I,TgtCtx)},
- IAcc = [NewI|IAcc0],
- State =
- case TgtMod:defines_all_alloc(I,TgtCtx) of
- false -> State0;
- true -> spill_all(ToSpill, TgtMod, TgtCtx, State0)
- end,
- %% We can drop "no-ops" here; where (if anywhere) is it worth it?
- scan_bb(Is, Live, Seen, State, IAcc, TgtMod, TgtCtx).
-
--spec t_liveout(target_liveness(), label(), module(), target_context()) ->
- target_liveset().
-t_liveout(Liveness, L, TgtMod, TgtCtx) ->
- %% FIXME: unnecessary sort; liveout is sorted, reg_names(...) should be sorted
- %% or consist of a few sorted subsequences (per type)
- ordsets:from_list(reg_names(TgtMod:liveout(Liveness, L, TgtCtx), TgtMod,
- TgtCtx)).
-
--spec reg_names([target_temp()], module(), target_context()) -> [target_reg()].
-reg_names(Regs, TgtMod, TgtCtx) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
--spec add_seen([target_reg()], seen()) -> seen().
-add_seen([], Seen) -> Seen;
-add_seen([R|Rs], Seen) -> add_seen(Rs, Seen#{R=>[]}).
-
--spec spill_all([target_reg()], module(), target_context(), spill_state()) ->
- spill_state().
-spill_all([], _TgtMod, _TgtCtx, State) -> State;
-spill_all([R|Rs], TgtMod, TgtCtx, State=#spill_state{map=Map, ix=Ix}) ->
- case TgtMod:is_precoloured(R,TgtCtx) or maps:is_key(R, Map) of
- true -> spill_all(Rs, TgtMod, TgtCtx, State);
- false -> spill_all(Rs, TgtMod, TgtCtx,
- State#spill_state{map=Map#{R=>Ix}, ix=Ix+1})
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Second pass (without split)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Rewrite CFG to the new temp names.
--spec transform_whole_cfg(scan_bbs(), sub_map()) -> transformed_bbs().
-transform_whole_cfg(BBs0, SubMap) ->
- maps:map(fun(_, BB) -> transform_whole_bb(BB, SubMap) end, BBs0).
-
--spec transform_whole_bb(scan_bb(), sub_map()) -> transformed_bb().
-transform_whole_bb({Code, Livein, Liveout}, SubMap) ->
- #transformed_bb{
- bb=hipe_bb:mk_bb([I#instr{defuse={smap_get_all_partial(Def, SubMap),
- smap_get_all_partial(Use, SubMap)}}
- || I = #instr{defuse={Def,Use}} <- Code])
- %% Assume mapping preserves monotonicity
- ,livein=smap_get_all_partial(Livein, SubMap)
- ,liveout=smap_get_all_partial(Liveout, SubMap)
- }.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Second pass (with split)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Discover program partitioning
-%% Regretfully, this needs to be a separate pass, as having the global live set
-%% is crucial to get a useful partitioning.
-
-%% Single-block parts are merged if there are multiple in a single block, as it
-%% is judged to not be beneficial to make them too small.
-
--type part_bb_part() :: {[instr()], target_liveset(), target_liveset()}.
--type part_bb() :: {single, part_bb_part()}
- | {split, part_bb_part(), part_bb_part()}.
--type part_bb_list() :: [{label(), part_bb()}].
--type part_bbs() :: #{label() => part_bb()}.
--type part_bb_sofar() :: single
- | {split, [instr()], target_liveset()}. % , target_liveset()
-
--spec part_cfg(scan_bbs(), spill_map(), target_reg()) -> part_bb_list().
-part_cfg(ScanBBs, SpillMap, MaxPhys) ->
- Liveset = mk_part_liveset(SpillMap, MaxPhys),
- lists:map(fun(BB) -> part_bb(BB, Liveset) end, maps:to_list(ScanBBs)).
-
--spec part_bb({label(), scan_bb()}, part_liveset()) -> {label(), part_bb()}.
-part_bb({L, BB0={Code0, Livein, Liveout}}, Liveset) ->
- {Sofar, NewCode} = part_bb_1(lists:reverse(Code0), Liveset, Liveout, []),
- BB = case Sofar of
- single ->
- ?ASSERT(Code0 =:= NewCode),
- {single, BB0};
- {split, ExitCode, ExitLivein = EntryLiveout} ->
- {split, {NewCode, Livein, EntryLiveout},
- {ExitCode, ExitLivein, Liveout}}
- end,
- {L, BB}.
-
--spec part_bb_1([instr()], part_liveset(), target_liveset(), [instr()])
- -> {part_bb_sofar(), [instr()]}.
-part_bb_1([], _Liveset, _Livein, IAcc) -> {single, IAcc};
-part_bb_1([I=#instr{defuse={Def,Use}}|Is], Liveset, Live0, IAcc0) ->
- Live = ordsets:union(Use, ordsets:subtract(Live0, Def)),
- IAcc = [I|IAcc0],
- case part_none_live(Live, Liveset) of
- false -> part_bb_1(Is, Liveset, Live, IAcc);
- %% One split point will suffice
- true -> {{split, IAcc, Live}, lists:reverse(Is)}
- end.
-
--spec part_none_live(target_liveset(), part_liveset()) -> boolean().
-part_none_live(Live, Liveset) ->
- not lists:any(fun(R) -> part_liveset_is_live(R, Liveset) end, Live).
-
--type part_liveset() :: {spill_map(), target_reg()}.
-
--spec mk_part_liveset(spill_map(), target_reg()) -> part_liveset().
-mk_part_liveset(SpillMap, MaxPhys) -> {SpillMap, MaxPhys}.
-
--spec part_liveset_is_live(target_reg(), part_liveset()) -> boolean().
-part_liveset_is_live(R, {SpillMap, MaxPhys}) when is_integer(R) ->
- R >= MaxPhys andalso not maps:is_key(R, SpillMap).
-
-%% @doc Merges split blocks where entry and exit belong to the same DSet.
-%% Does not change DSets
--spec merge_pointless_splits(part_bb_list(), scan_bbs(), bb_dsets())
- -> {part_bbs(), bb_dsets()}.
-merge_pointless_splits(PartBBList0, ScanBBs, DSets0) ->
- {PartBBList, DSets} =
- merge_pointless_splits_1(PartBBList0, ScanBBs, DSets0, []),
- {maps:from_list(PartBBList), DSets}.
-
--spec merge_pointless_splits_1(
- part_bb_list(), scan_bbs(), bb_dsets(), part_bb_list())
- -> {part_bb_list(), bb_dsets()}.
-merge_pointless_splits_1([], _ScanBBs, DSets, Acc) -> {Acc, DSets};
-merge_pointless_splits_1([P={_,{single,_}}|Ps], ScanBBs, DSets, Acc) ->
- merge_pointless_splits_1(Ps, ScanBBs, DSets, [P|Acc]);
-merge_pointless_splits_1([P0={L,{split,_,_}}|Ps], ScanBBs, DSets0, Acc) ->
- {EntryRoot, DSets1} = hipe_dsets:find({entry,L}, DSets0),
- {ExitRoot, DSets} = hipe_dsets:find({exit,L}, DSets1),
- case EntryRoot =:= ExitRoot of
- false -> merge_pointless_splits_1(Ps, ScanBBs, DSets, [P0|Acc]);
- true ->
- %% Reuse the code list from ScanBBs rather than concatenating the split
- %% parts
- #{L := BB} = ScanBBs,
- ?ASSERT(begin
- {L,{split,{_EntryCode,_,_},{_ExitCode,_,_}}}=P0, % [_|
- {_Code,_,_}=BB,
- _Code =:= (_EntryCode ++ _ExitCode)
- end),
- merge_pointless_splits_1(Ps, ScanBBs, DSets, [{L,{single, BB}}|Acc])
- end.
-
--spec merge_small_parts(bb_dsets()) -> {bb_dsets_rllist(), bb_dsets()}.
-merge_small_parts(DSets0) ->
- {RLList, DSets1} = hipe_dsets:to_rllist(DSets0),
- RLLList = [{R, length(Elems), Elems} || {R, Elems} <- RLList],
- merge_small_parts_1(RLLList, DSets1, []).
-
--spec merge_small_parts_1(
- [{bb_dset_key(), non_neg_integer(), [bb_dset_key()]}],
- bb_dsets(), bb_dsets_rllist()
- ) -> {bb_dsets_rllist(), bb_dsets()}.
-merge_small_parts_1([], DSets, Acc) -> {Acc, DSets};
-merge_small_parts_1([{R, _, Es}], DSets, Acc) -> {[{R, Es}|Acc], DSets};
-merge_small_parts_1([{R, L, Es}|Ps], DSets, Acc) when L >= ?TUNE_TOO_FEW_BBS ->
- merge_small_parts_1(Ps, DSets, [{R,Es}|Acc]);
-merge_small_parts_1([Fst,{R, L, Es}|Ps], DSets, Acc)
- when L >= ?TUNE_TOO_FEW_BBS ->
- merge_small_parts_1([Fst|Ps], DSets, [{R,Es}|Acc]);
-merge_small_parts_1([{R1,L1,Es1},{R2,L2,Es2}|Ps], DSets0, Acc) ->
- ?ASSERT(L1 < ?TUNE_TOO_FEW_BBS andalso L2 < ?TUNE_TOO_FEW_BBS),
- DSets1 = hipe_dsets:union(R1, R2, DSets0),
- {R, DSets} = hipe_dsets:find(R1, DSets1),
- merge_small_parts_1([{R,L2+L1,Es2++Es1}|Ps], DSets, Acc).
-
-%% @doc Partition an ordering over BBs into subsequences for the dsets that
-%% contain them.
-%% Does not change dsets.
--spec part_order([label()], bb_dsets())
- -> {#{bb_dset_key() => [label()]}, bb_dsets()}.
-part_order(Lbs, DSets) -> part_order(Lbs, DSets, #{}).
-
-part_order([], DSets, Acc) -> {Acc, DSets};
-part_order([L|Ls], DSets0, Acc0) ->
- {EntryRoot, DSets1} = hipe_dsets:find({entry,L}, DSets0),
- {ExitRoot, DSets2} = hipe_dsets:find({exit,L}, DSets1),
- Acc1 = map_append(EntryRoot, L, Acc0),
- %% Only include the label once if both entry and exit is in same partition
- Acc2 = case EntryRoot =:= ExitRoot of
- true -> Acc1;
- false -> map_append(ExitRoot, L, Acc1)
- end,
- part_order(Ls, DSets2, Acc2).
-
-map_append(Key, Elem, Map) ->
- case Map of
- #{Key := List} -> Map#{Key := [Elem|List]};
- #{} -> Map#{Key => [Elem]}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Interference graph partitioning
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% We partition the program
-
-%% The algorithm considers two kinds of components; those that are local to a
-%% basic block, and those that are not. The key is that any basic block belongs
-%% to at most two non-local components; one from the beginning to the first
-%% split point, and one from the end to the last split point.
-
--type bb_dset_key() :: {entry | exit, label()}.
--type bb_dsets() :: hipe_dsets:dsets(bb_dset_key()).
--type bb_dsets_rllist() :: [{bb_dset_key(), [bb_dset_key()]}].
-
--spec initial_dsets(target_cfg(), module(), target_context()) -> bb_dsets().
-initial_dsets(CFG, TgtMod, TgtCtx) ->
- Labels = TgtMod:labels(CFG, TgtCtx),
- DSets0 = hipe_dsets:new(lists:append([[{entry,L},{exit,L}] || L <- Labels])),
- Edges = lists:append([[{L, S} || S <- hipe_gen_cfg:succ(CFG, L)]
- || L <- Labels]),
- lists:foldl(fun({X, Y}, DS) -> hipe_dsets:union({exit,X}, {entry,Y}, DS) end,
- DSets0, Edges).
-
--spec join_whole_blocks(part_bb_list(), bb_dsets()) -> bb_dsets().
-join_whole_blocks(PartBBList, DSets0) ->
- lists:foldl(fun({L, {single, _}}, DS) ->
- hipe_dsets:union({entry,L}, {exit,L}, DS);
- ({_, {split, _, _}}, DS) -> DS
- end, DSets0, PartBBList).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Third pass
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Collect all referenced temps in each partition.
-
-%% Note: The temps could be collected during the partition pass for each
-%% half-bb, and then combined here. Would that be beneficial?
-
-collect_seenmap(PartBBsRLList, PartBBs) ->
- collect_seenmap(PartBBsRLList, #{}, PartBBs).
-
-collect_seenmap([], Acc, _PartBBs) -> Acc;
-collect_seenmap([{R,Elems}|Ps], Acc, PartBBs) ->
- Seen = collect_seen_part(Elems, #{}, PartBBs),
- collect_seenmap(Ps, Acc#{R => Seen}, PartBBs).
-
-collect_seen_part([], Acc, _PartBBs) -> Acc;
-collect_seen_part([{Half,L}|Es], Acc0, PartBBs) ->
- BB = maps:get(L, PartBBs),
- Code = case {Half, BB} of
- {entry, {single, {C,_,_}}} -> C;
- {entry, {split, {C,_,_}, _}} -> C;
- {exit, {split, _, {C,_,_}}} -> C;
- {exit, {single, _}} -> [] % Ignore; was collected by its entry half
- end,
- Acc = collect_seen_code(Code, Acc0),
- collect_seen_part(Es, Acc, PartBBs).
-
-collect_seen_code([], Acc) -> Acc;
-collect_seen_code([#instr{defuse={Def,Use}}|Is], Acc) ->
- collect_seen_code(Is, add_seen(Def, add_seen(Use, Acc))).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fourth pass
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Rewrite CFG to the new temp names.
--spec transform_cfg([bb_dset_key()], part_bbs(), sub_map()) -> transformed_bbs().
-
-transform_cfg(Elems, PartBBs, SubMap) ->
- transform_cfg(Elems, PartBBs, SubMap, #{}).
-
-transform_cfg([], _PartBBs, _SubMap, Acc) -> Acc;
-transform_cfg([{Half,L}|Es], PartBBs, SubMap, Acc0) ->
- #{L := PBB} = PartBBs,
- Acc = case {Half, PBB} of
- {entry, {single,BB}} -> Acc0#{L=>transform_bb(BB, SubMap)};
- {entry, {split,BB,_}} -> Acc0#{L=>transform_bb(BB, SubMap)};
- {exit, {split,_,BB}} -> Acc0#{L=>transform_bb(BB, SubMap)};
- {exit, {single, _}} -> Acc0 % Was included by the entry half
- end,
- transform_cfg(Es, PartBBs, SubMap, Acc).
-
--spec transform_bb(part_bb_part(), sub_map()) -> transformed_bb().
-transform_bb(BB, SubMap) ->
- %% For now, part_bb_part() and split_bb() share representation
- transform_whole_bb(BB, SubMap).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fifth pass
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Combine colorings and substitute temps in actual cfg if there were
-%% collisions.
-
-%% A temp can sometimes appear in more than one partition. For example, defining
-%% an unused value. If these are found by combine_allocations, we have to
-%% rename this temp in one of the partitions on the real cfg.
-%%
-%% We optimistically assume that there will be no such collisions, and when
-%% there are, we fix them up as they're found.
-
--spec combine_allocations([{hipe_map(), [bb_dset_key()]}], target_reg(),
- part_bbs(), module(), target_context(), target_cfg())
- -> {hipe_map(), same | {rewritten, target_cfg()}}.
-combine_allocations([{A,_}|As], MaxPhys, PartBBs, TgtMod, TgtCtx, CFG) ->
- {Phys, Pseuds} = lists:partition(fun({R,_}) -> R < MaxPhys end, A),
- {Seen, _, []} = partition_by_seen(Pseuds, #{}, [], []),
- combine_allocations(As, MaxPhys, PartBBs, TgtMod, TgtCtx, Phys, Seen, Pseuds,
- {same, CFG}).
-
--spec combine_allocations([{hipe_map(), [bb_dset_key()]}], target_reg(),
- part_bbs(), module(), target_context(), hipe_map(),
- seen(), hipe_map(), {same|rewritten, target_cfg()})
- -> {hipe_map(), same | {rewritten, target_cfg()}}.
-combine_allocations([], _MaxPhys, _PartBBs, _TgtMod, _TgtCtx, Phys, _Seen,
- Pseuds, CFGT) ->
- {Phys ++ Pseuds, case CFGT of
- {same, _} -> same;
- {rewritten, _} -> CFGT
- end};
-combine_allocations([{A,PartElems}|As], MaxPhys, PartBBs, TgtMod, TgtCtx, Phys,
- Seen0, Acc, CFGT={_,CFG0}) ->
- {Phys, Pseuds0} = lists:partition(fun({R,_}) -> R < MaxPhys end, A),
- {Seen, Pseuds, Collisions} = partition_by_seen(Pseuds0, Seen0, [], []),
- case Collisions of
- [] -> combine_allocations(As, MaxPhys, PartBBs, TgtMod, TgtCtx, Phys, Seen,
- Pseuds++Acc, CFGT);
- _ ->
- %% There were collisions; rename all the temp numbers in Collisions
- {CFG, Renamed} = rename(Collisions, PartElems, PartBBs, TgtMod, TgtCtx,
- CFG0),
- combine_allocations(As, MaxPhys, PartBBs, TgtMod, TgtCtx, Phys, Seen,
- Pseuds++Renamed++Acc, {rewritten,CFG})
- end.
-
-%% @doc Partitions a coloring on whether the registers are in the Seen set,
-%% adding any new registers to the set.
--spec partition_by_seen(hipe_map(), seen(), hipe_map(), hipe_map())
- -> {seen(), hipe_map(), hipe_map()}.
-partition_by_seen([], Seen, Acc, Collisions) -> {Seen, Acc, Collisions};
-partition_by_seen([C={R,_}|Cs], Seen, Acc, Colls) ->
- case Seen of
- #{R := _} -> partition_by_seen(Cs, Seen, Acc, [C|Colls]);
- #{} -> partition_by_seen(Cs, Seen#{R => []}, [C|Acc], Colls)
- end.
-
--spec rename(hipe_map(), [bb_dset_key()], part_bbs(), module(),
- target_context(), target_cfg())
- -> {target_cfg(), hipe_map()}.
-rename(CollisionList, PartElems, PartBBs, TgtMod, TgtCtx, CFG0) ->
- {Map, Renamed} = new_names(CollisionList, TgtMod, TgtCtx, #{}, []),
- Fun = fun(I) ->
- TgtMod:subst_temps(
- fun(Temp) ->
- N = TgtMod:reg_nr(Temp, TgtCtx),
- case Map of
- #{N := Subst} -> TgtMod:update_reg_nr(Subst, Temp, TgtCtx);
- #{} -> Temp
- end
- end, I, TgtCtx)
- end,
- {rename_1(PartElems, PartBBs, TgtMod, TgtCtx, Fun, CFG0), Renamed}.
-
--type rename_map() :: #{target_reg() => target_reg()}.
--type rename_fun() :: fun((target_instr()) -> target_instr()).
-
--spec new_names(hipe_map(), module(), target_context(), rename_map(),
- hipe_map())
- -> {rename_map(), hipe_map()}.
-new_names([], _TgtMod, _TgtCtx, Map, Renamed) -> {Map, Renamed};
-new_names([{R,C}|As], TgtMod, TgtCtx, Map, Renamed) ->
- Subst = TgtMod:new_reg_nr(TgtCtx),
- new_names(As, TgtMod, TgtCtx, Map#{R => Subst}, [{Subst, C} | Renamed]).
-
-%% @doc Maps over all instructions in a partition on the original CFG.
--spec rename_1([bb_dset_key()], part_bbs(), module(), target_context(),
- rename_fun(), target_cfg()) -> target_cfg().
-rename_1([], _PartBBs, _TgtMod, _TgtCtx, _Fun, CFG) -> CFG;
-rename_1([{Half,L}|Es], PartBBs, TgtMod, TgtCtx, Fun, CFG0) ->
- Code0 = hipe_bb:code(BB = TgtMod:bb(CFG0, L, TgtCtx)),
- Code = case {Half, maps:get(L, PartBBs)} of
- {entry, {single,_}} -> lists:map(Fun, Code0);
- {entry, {split,PBBP,_}} ->
- map_start(Fun, part_bb_part_len(PBBP), Code0);
- {exit, {split,_,PBBP}} ->
- map_end(Fun, part_bb_part_len(PBBP), Code0);
- {exit, {single, _}} -> Code0
- end,
- CFG = TgtMod:update_bb(CFG0, L, hipe_bb:code_update(BB, Code), TgtCtx),
- rename_1(Es, PartBBs, TgtMod, TgtCtx, Fun, CFG).
-
--spec part_bb_part_len(part_bb_part()) -> non_neg_integer().
-part_bb_part_len({Code, _Livein, _Liveout}) -> length(Code).
-
-%% @doc Map the first N elements of a list
--spec map_start(fun((X) -> Y), non_neg_integer(), [X]) -> [X|Y].
-map_start(_Fun, 0, List) -> List;
-map_start(Fun, N, [E|Es]) ->
- [Fun(E)|map_start(Fun, N-1, Es)].
-
-%% @doc Map the last N elements of a list
--spec map_end(fun((X) -> Y), non_neg_integer(), [X]) -> [X|Y].
-map_end(Fun, N, List) ->
- map_end(Fun, N, length(List), List).
-
-map_end(Fun, N, Len, [E|Es]) when Len > N -> [E|map_end(Fun, N, Len-1, Es)];
-map_end(Fun, N, Len, List) when Len =:= N -> lists:map(Fun, List).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Temp map ADT
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--type sub_map() :: {s,#{target_reg() => temp()}}.
--type inv_map() :: {i,#{temp() => target_reg()}}.
-
--spec smap_get(target_reg(), sub_map()) -> temp().
-smap_get(Temp, {s,Map}) when is_integer(Temp) -> maps:get(Temp, Map).
-
--spec imap_get(temp(), inv_map()) -> target_reg().
-imap_get(Temp, {i,Map}) when is_integer(Temp) -> maps:get(Temp, Map).
-
--spec smap_get_all_partial([target_reg()], sub_map()) -> [temp()].
-smap_get_all_partial([], _) -> [];
-smap_get_all_partial([T|Ts], SMap={s,Map}) when is_integer(T) ->
- case Map of
- #{T := R} -> [R|smap_get_all_partial(Ts, SMap)];
- #{} -> smap_get_all_partial(Ts, SMap)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Validation
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--ifdef(DO_ASSERT).
-%%%%%%%%%%%%%%%%%%%%
-%% Check that the coloring is correct (if the IG is correct):
-%%
-
-%% Define these as 'ok' or 'report(X,Y)' depending on how much output you want.
--define(report0(X,Y), ?IF_DEBUG_LEVEL(0,?msg(X, Y),ok)).
--define(report(X,Y), ?IF_DEBUG_LEVEL(1,?msg(X, Y),ok)).
--define(report2(X,Y), ?IF_DEBUG_LEVEL(2,?msg(X, Y),ok)).
--define(report3(X,Y), ?IF_DEBUG_LEVEL(3,?msg(X, Y),ok)).
-
-check_coloring(Coloring, CFG, TgtMod, TgtCtx) ->
- ?report0("checking coloring ~p~n",[Coloring]),
- IG = hipe_ig:build(CFG, TgtMod:analyze(CFG,TgtCtx), TgtMod, TgtCtx),
- check_cols(hipe_vectors:list(hipe_ig:adj_list(IG)),
- init_coloring(Coloring, TgtMod, TgtCtx)).
-
-init_coloring(Xs, TgtMod, TgtCtx) ->
- hipe_temp_map:cols2tuple(Xs, TgtMod, TgtCtx).
-
-check_color_of(X, Cols) ->
- case hipe_temp_map:find(X, Cols) of
- unknown ->
- uncolored;
- C ->
- C
- end.
-
-check_cols([], _Cols) ->
- ?report("coloring valid~n",[]),
- true;
-check_cols([{X,Neighbours}|Xs], Cols) ->
- Cs = [{N, check_color_of(N, Cols)} || N <- Neighbours],
- C = check_color_of(X, Cols),
- case valid_coloring(X, C, Cs) of
- yes ->
- check_cols(Xs, Cols);
- {no,Invalids} ->
- ?msg("node ~p has same color (~p) as ~p~n", [X,C,Invalids]),
- check_cols(Xs, Cols) andalso false
- end.
-
-valid_coloring(_X, _C, []) ->
- yes;
-valid_coloring(X, C, [{Y,C}|Ys]) ->
- case valid_coloring(X, C, Ys) of
- yes -> {no, [Y]};
- {no,Zs} -> {no, [Y|Zs]}
- end;
-valid_coloring(X, C, [_|Ys]) ->
- valid_coloring(X, C, Ys).
-
-unused_unused(Unused, CFG, TgtMod, TgtCtx) ->
- IG = hipe_ig:build(CFG, TgtMod:analyze(CFG,TgtCtx), TgtMod, TgtCtx),
- lists:all(fun(R) -> case hipe_ig:get_node_degree(R, IG) of
- 0 -> true;
- Deg ->
- ?msg("Temp ~w is in unused but has degree ~w~n",
- [R, Deg]),
- false
- end end, Unused).
-
-%%%%%%%%%%%%%%%%%%%%
-%% Check that no register allocation opportunities were missed due to ?MODULE
-%%
-just_as_good_as(RegAllocMod, CFG, Liveness, SpillIndex0, SpillLimit, TgtMod,
- TgtCtx, Options, SpillMap, Coloring, Unused) ->
- {CheckColoring, _} =
- RegAllocMod:regalloc(CFG, Liveness, SpillIndex0, SpillLimit, TgtMod, TgtCtx,
- Options),
- Now = lists:sort([{R,Kind} || {R,{Kind,_}} <- Coloring,
- not ordsets:is_element(R, Unused)]),
- Check = lists:sort([{R,Kind} || {R,{Kind,_}} <- CheckColoring,
- not ordsets:is_element(R, Unused)]),
- CheckMap = maps:from_list(Check),
- SaneSpills = all_spills_sane_1(CheckColoring, SpillMap),
- case SaneSpills
- andalso lists:all(fun({R, spill}) -> maps:get(R, CheckMap) =:= spill;
- ({_,reg}) -> true
- end, Now)
- of
- true -> true;
- false ->
- {NowRegs, _} = _NowCount = count(Now),
- {CheckRegs, _} = _CheckCount = count(Check),
- {M,F,A} = element(2, element(3, CFG)),
- io:fwrite(standard_error, "Colorings differ (~w, ~w)!~n"
- "MFA: ~w:~w/~w~n"
- "Unused: ~w~n"
- "Now:~w~nCorrect:~w~n",
- [TgtMod, RegAllocMod,
- M,F,A,
- Unused,
- Now -- Check, Check -- Now]),
- SaneSpills andalso NowRegs >= CheckRegs
- end.
-
-count(C) -> {length([[] || {_, reg} <- C]),
- length([[] || {_, spill} <- C])}.
-
-unused(LivePseudos, SpillMap, CFG, TgtMod, TgtCtx) ->
- {TMin, TMax} = TgtMod:var_range(CFG,TgtCtx),
- SpillOSet = ordsets:from_list(maps:keys(SpillMap)),
- PhysOSet = ordsets:from_list(TgtMod:all_precoloured(TgtCtx)),
- Used = ordsets:union(LivePseudos, ordsets:union(PhysOSet, SpillOSet)),
- ordsets:subtract(lists:seq(TMin, TMax), Used).
-
-%% Check that no temp that we wrote off was actually allocatable.
-all_spills_sane_1(_, Empty) when map_size(Empty) =:= 0 -> true;
-all_spills_sane_1([], _Nonempty) -> false;
-all_spills_sane_1([{T, {reg, _}}|Cs], SpillMap) ->
- not maps:is_key(T, SpillMap) andalso all_spills_sane_1(Cs, SpillMap);
-all_spills_sane_1([{T, {spill, _}}|Cs], SpillMap) ->
- all_spills_sane_1(Cs, maps:remove(T, SpillMap)).
-
--endif. % DO_ASSERT
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Pseudo-target interface
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-analyze(Cfg, _ModRec) -> Cfg.
-bb(Cfg=#cfg{bbs=BBs}, Ix, _ModRec) ->
- case BBs of
- #{Ix := #transformed_bb{bb=BB}} -> BB;
- _ -> error(badarg, [Cfg, Ix])
- end.
-args(Arity, #prepass_ctx{target_mod=TgtMod, target_ctx=TgtCtx, sub=SubM}) ->
- smap_get(TgtMod:args(Arity,TgtCtx), SubM).
-labels(#cfg{bbs=BBs}, _ModRec) -> maps:keys(BBs).
-livein(#cfg{bbs=BBs}, Lb, _SubMod) ->
- #{Lb := #transformed_bb{livein=Livein}} = BBs,
- Livein.
-liveout(#cfg{bbs=BBs}, Lb, _SubMod) ->
- #{Lb := #transformed_bb{liveout=Liveout}} = BBs,
- Liveout.
-uses(I, MR) -> element(2, def_use(I, MR)).
-defines(I, MR) -> element(1, def_use(I, MR)).
-def_use(#instr{defuse=DefUse}, _ModRec) -> DefUse.
-is_move(#instr{is_move=IM}, _ModRec) -> IM.
-is_fixed(Reg, #prepass_ctx{target_mod=TgtMod,target_ctx=TgtCtx,inv=InvM}) ->
- TgtMod:is_fixed(imap_get(Reg, InvM),TgtCtx). % XXX: Is this hot?
-is_global(Reg, #prepass_ctx{target_mod=TgtMod,target_ctx=TgtCtx,
- max_phys=MaxPhys}) when Reg < MaxPhys ->
- TgtMod:is_global(Reg,TgtCtx). % assume id-map
-is_precoloured(Reg, #prepass_ctx{max_phys=MaxPhys}) -> Reg < MaxPhys.
-reg_nr(Reg, _ModRec) -> Reg. % After mapping (naturally)
-non_alloc(#cfg{cfg=CFG}, #prepass_ctx{target_mod=TgtMod,target_ctx=TgtCtx,
- sub=SubM}) ->
- smap_get_all_partial(reg_names(TgtMod:non_alloc(CFG,TgtCtx), TgtMod, TgtCtx),
- SubM).
-number_of_temporaries(#cfg{max_reg=MaxR}, _ModRec) -> MaxR.
-allocatable(#prepass_ctx{target_mod=TgtMod, target_ctx=TgtCtx}) ->
- TgtMod:allocatable(TgtCtx). % assume id-map
-physical_name(Reg, _ModRec) -> Reg.
-all_precoloured(#prepass_ctx{target_mod=TgtMod, target_ctx=TgtCtx}) ->
- TgtMod:all_precoloured(TgtCtx). % dito
-var_range(#cfg{cfg=_CFG, max_reg=MaxReg},
- #prepass_ctx{target_mod=_TgtMod, target_ctx=_TgtCtx}) ->
- ?ASSERT(begin {TgtMin, _} = _TgtMod:var_range(_CFG,_TgtCtx),
- TgtMin =:= 0
- end),
- {0, MaxReg-1}.
-
-postorder(#cfg{cfg=CFG,rpostorder=undefined},
- #prepass_ctx{target_mod=TgtMod,target_ctx=TgtCtx}) ->
- TgtMod:postorder(CFG,TgtCtx);
-postorder(#cfg{rpostorder=Labels}, _ModRec) when is_list(Labels) ->
- lists:reverse(Labels).
-
-reverse_postorder(#cfg{cfg=CFG,rpostorder=undefined},
- #prepass_ctx{target_mod=TgtMod,target_ctx=TgtCtx}) ->
- TgtMod:reverse_postorder(CFG,TgtCtx);
-reverse_postorder(#cfg{rpostorder=Labels}, _ModRec) when is_list(Labels) ->
- Labels.
diff --git a/lib/hipe/regalloc/hipe_restore_reuse.erl b/lib/hipe/regalloc/hipe_restore_reuse.erl
deleted file mode 100644
index 2158bd185e..0000000000
--- a/lib/hipe/regalloc/hipe_restore_reuse.erl
+++ /dev/null
@@ -1,516 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% RESTORE REUSE LIVE RANGE SPLITTING PASS
-%%
-%% This is a simple live range splitter that tries to avoid sequences where a
-%% temporary is accessed on stack multiple times by keeping a copy of that temp
-%% around in a register.
-%%
-%% At any point where a temporary that is expected to be spilled (see uses of
-%% spills_add_list/2) is defined or used, this pass considers that temporary
-%% "available".
-%%
-%% Limitations:
-%% * If a live range part starts with several different restores, this module
-%% will introduce a new temp number for each of them, and later be forced to
-%% generate phi blocks. It would be more efficient to introduce just a
-%% single temp number. That would also remove the need for the phi blocks.
-%% * If a live range part ends in a definition, that definition should just
-%% define the base temp rather than the substitution, since some CISC
-%% targets might be able to inline the memory access in the instruction.
--module(hipe_restore_reuse).
-
--export([split/4]).
-
-%% Exports for hipe_range_split, which uses restore_reuse as one possible spill
-%% "mode"
--export([analyse/3
- ,renamed_in_block/2
- ,split_in_block/2
- ]).
--export_type([avail/0]).
-
--compile(inline).
-
-%% -define(DO_ASSERT, 1).
--include("../main/hipe.hrl").
-
--type target_cfg() :: any().
--type liveness() :: any().
--type target_module() :: module().
--type target_context() :: any().
--type target() :: {target_module(), target_context()}.
--type label() :: non_neg_integer().
--type reg() :: non_neg_integer().
--type instr() :: any().
--type temp() :: any().
-
--spec split(target_cfg(), liveness(), target_module(), target_context())
- -> target_cfg().
-split(CFG, Liveness, TargetMod, TargetContext) ->
- Target = {TargetMod, TargetContext},
- Avail = analyse(CFG, Liveness, Target),
- rewrite(CFG, Target, Avail).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--opaque avail() :: #{label() => avail_bb()}.
-
--record(avail_bb, {
- %% Blocks where HasCall is true are considered to have too high
- %% register pressure to support a register copy of a temp
- has_call :: boolean(),
- %% AvailOut: Temps that can be split (are available)
- out :: availset(),
- %% Gen: AvailOut generated locally
- gen :: availset(),
- %% WantIn: Temps that are split
- want :: regset(),
- %% Self: Temps with avail-want pairs locally
- self :: regset(),
- %% DefIn: Temps shadowed by later def in same live range part
- defin :: regset(),
- pred :: [label()],
- succ :: [label()]
- }).
--type avail_bb() :: #avail_bb{}.
-
-avail_get(L, Avail) -> maps:get(L, Avail).
-avail_set(L, Val, Avail) -> maps:put(L, Val, Avail).
-avail_has_call(L, Avail) -> (avail_get(L, Avail))#avail_bb.has_call.
-avail_out(L, Avail) -> (avail_get(L, Avail))#avail_bb.out.
-avail_self(L, Avail) -> (avail_get(L, Avail))#avail_bb.self.
-avail_pred(L, Avail) -> (avail_get(L, Avail))#avail_bb.pred.
-avail_succ(L, Avail) -> (avail_get(L, Avail))#avail_bb.succ.
-
-avail_in(L, Avail) ->
- case avail_pred(L, Avail) of
- [] -> availset_empty(); % entry
- Pred ->
- lists:foldl(fun(P, ASet) ->
- availset_intersect(avail_out(P, Avail), ASet)
- end, availset_top(), Pred)
- end.
-
-want_in(L, Avail) -> (avail_get(L, Avail))#avail_bb.want.
-want_out(L, Avail) ->
- lists:foldl(fun(S, Set) ->
- ordsets:union(want_in(S, Avail), Set)
- end, ordsets:new(), avail_succ(L, Avail)).
-
-def_in(L, Avail) -> (avail_get(L, Avail))#avail_bb.defin.
-def_out(L, Avail) ->
- case avail_succ(L, Avail) of
- [] -> ordsets:new(); % entry
- Succ ->
- ordsets:intersection([def_in(S, Avail) || S <- Succ])
- end.
-
--type regset() :: ordsets:ordset(reg()).
--type availset() :: top | regset().
-availset_empty() -> [].
-availset_top() -> top.
-availset_intersect(top, B) -> B;
-availset_intersect(A, top) -> A;
-availset_intersect(A, B) -> ordsets:intersection(A, B).
-availset_union(top, _) -> top;
-availset_union(_, top) -> top;
-availset_union(A, B) -> ordsets:union(A, B).
-ordset_intersect_availset(OS, top) -> OS;
-ordset_intersect_availset(OS, AS) -> ordsets:intersection(OS, AS).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Analysis pass
-%%
-%% The analysis pass collects the set of temps we're interested in splitting
-%% (Spills), and computes three dataflow analyses for this subset of temps.
-%%
-%% Avail, which is the set of temps which are available in register from a
-%% previous (potential) spill or restore without going through a HasCall
-%% block.
-%% Want, which is a liveness analysis for the subset of temps used by an
-%% instruction that are also in Avail at that point. In other words, Want is
-%% the set of temps that are split (has a register copy) at a particular
-%% point.
-%% Def, which are the temps that are already going to be spilled later, and so
-%% need not be spilled when they're defined.
-%%
-%% Lastly, it computes the set Self for each block, which is the temps that have
-%% avail-want pairs in the same block, and so should be split in that block even
-%% if they're not in WantIn for the block.
-
--spec analyse(target_cfg(), liveness(), target()) -> avail().
-analyse(CFG, Liveness, Target) ->
- Avail0 = analyse_init(CFG, Liveness, Target),
- RPO = reverse_postorder(CFG, Target),
- AvailLs = [L || L <- RPO, not avail_has_call(L, Avail0)],
- Avail1 = avail_dataf(AvailLs, Avail0),
- Avail2 = analyse_filter_want(maps:keys(Avail1), Avail1),
- PO = lists:reverse(RPO),
- want_dataf(PO, Avail2).
-
--spec analyse_init(target_cfg(), liveness(), target()) -> avail().
-analyse_init(CFG, Liveness, Target) ->
- analyse_init(labels(CFG, Target), CFG, Liveness, Target, #{}, []).
-
--spec analyse_init([label()], target_cfg(), liveness(), target(), spillset(),
- [{label(), avail_bb()}])
- -> avail().
-analyse_init([], _CFG, _Liveness, Target, Spills0, Acc) ->
- %% Precoloured temps can't be spilled
- Spills = spills_filter(fun(R) -> not is_precoloured(R, Target) end, Spills0),
- analyse_init_1(Acc, Spills, []);
-analyse_init([L|Ls], CFG, Liveness, Target, Spills0, Acc) ->
- {DefIn, Gen, Self, Want, HasCall0} =
- analyse_scan(hipe_bb:code(bb(CFG, L, Target)), Target,
- ordsets:new(), ordsets:new(), ordsets:new(),
- ordsets:new()),
- {Spills, Out, HasCall} =
- case HasCall0 of
- false -> {Spills0, availset_top(), false};
- {true, CallDefs} ->
- Spill = ordsets:subtract(liveout(Liveness, L, Target), CallDefs),
- {spills_add_list(Spill, Spills0), Gen, true}
- end,
- Pred = hipe_gen_cfg:pred(CFG, L),
- Succ = hipe_gen_cfg:succ(CFG, L),
- Val = #avail_bb{gen=Gen, want=Want, self=Self, out=Out, has_call=HasCall,
- pred=Pred, succ=Succ, defin=DefIn},
- analyse_init(Ls, CFG, Liveness, Target, Spills, [{L, Val} | Acc]).
-
--spec analyse_init_1([{label(), avail_bb()}], spillset(),
- [{label(), avail_bb()}])
- -> avail().
-analyse_init_1([], _Spills, Acc) -> maps:from_list(Acc);
-analyse_init_1([{L, Val0}|Vs], Spills, Acc) ->
- #avail_bb{out=Out,gen=Gen,want=Want,self=Self} = Val0,
- Val = Val0#avail_bb{
- out = spills_filter_availset(Out, Spills),
- gen = spills_filter_availset(Gen, Spills),
- want = spills_filter_availset(Want, Spills),
- self = spills_filter_availset(Self, Spills)},
- analyse_init_1(Vs, Spills, [{L, Val} | Acc]).
-
--type spillset() :: #{reg() => []}.
--spec spills_add_list([reg()], spillset()) -> spillset().
-spills_add_list([], Spills) -> Spills;
-spills_add_list([R|Rs], Spills) -> spills_add_list(Rs, Spills#{R => []}).
-
--spec spills_filter_availset(availset(), spillset()) -> availset().
-spills_filter_availset([E|Es], Spills) ->
- case Spills of
- #{E := _} -> [E|spills_filter_availset(Es, Spills)];
- #{} -> spills_filter_availset(Es, Spills)
- end;
-spills_filter_availset([], _) -> [];
-spills_filter_availset(top, _) -> top.
-
-spills_filter(Fun, Spills) -> maps:filter(fun(K, _) -> Fun(K) end, Spills).
-
--spec analyse_scan([instr()], target(), Defset, Gen, Self, Want)
- -> {Defset, Gen, Self, Want, HasCall} when
- HasCall :: false | {true, regset()},
- Defset :: regset(),
- Gen :: availset(),
- Self :: regset(),
- Want :: regset().
-analyse_scan([], _Target, Defs, Gen, Self, Want) ->
- {Defs, Gen, Self, Want, false};
-analyse_scan([I|Is], Target, Defs0, Gen0, Self0, Want0) ->
- {DefL, UseL} = reg_def_use(I, Target),
- Use = ordsets:from_list(UseL),
- Def = ordsets:from_list(DefL),
- Self = ordsets:union(ordsets:intersection(Use, Gen0), Self0),
- Want = ordsets:union(ordsets:subtract(Use, Defs0), Want0),
- Defs = ordsets:union(Def, Defs0),
- case defines_all_alloc(I, Target) of
- true ->
- [] = Is, %assertion
- {Defs, ordsets:new(), Self, Want, {true, Def}};
- false ->
- Gen = ordsets:union(ordsets:union(Def, Use), Gen0),
- analyse_scan(Is, Target, Defs, Gen, Self, Want)
- end.
-
--spec avail_dataf([label()], avail()) -> avail().
-avail_dataf(RPO, Avail0) ->
- case avail_dataf_once(RPO, Avail0, 0) of
- {Avail, 0} -> Avail;
- {Avail, _Changed} ->
- avail_dataf(RPO, Avail)
- end.
-
--spec avail_dataf_once([label()], avail(), non_neg_integer())
- -> {avail(), non_neg_integer()}.
-avail_dataf_once([], Avail, Changed) -> {Avail, Changed};
-avail_dataf_once([L|Ls], Avail0, Changed0) ->
- ABB = #avail_bb{out=OldOut, gen=Gen} = avail_get(L, Avail0),
- In = avail_in(L, Avail0),
- {Changed, Avail} =
- case availset_union(In, Gen) of
- OldOut -> {Changed0, Avail0};
- Out -> {Changed0+1, avail_set(L, ABB#avail_bb{out=Out}, Avail0)}
- end,
- avail_dataf_once(Ls, Avail, Changed).
-
--spec analyse_filter_want([label()], avail()) -> avail().
-analyse_filter_want([], Avail) -> Avail;
-analyse_filter_want([L|Ls], Avail0) ->
- ABB = #avail_bb{want=Want0, defin=DefIn0} = avail_get(L, Avail0),
- In = avail_in(L, Avail0),
- Want = ordset_intersect_availset(Want0, In),
- DefIn = ordset_intersect_availset(DefIn0, In),
- Avail = avail_set(L, ABB#avail_bb{want=Want, defin=DefIn}, Avail0),
- analyse_filter_want(Ls, Avail).
-
--spec want_dataf([label()], avail()) -> avail().
-want_dataf(PO, Avail0) ->
- case want_dataf_once(PO, Avail0, 0) of
- {Avail, 0} -> Avail;
- {Avail, _Changed} ->
- want_dataf(PO, Avail)
- end.
-
--spec want_dataf_once([label()], avail(), non_neg_integer())
- -> {avail(), non_neg_integer()}.
-want_dataf_once([], Avail, Changed) -> {Avail, Changed};
-want_dataf_once([L|Ls], Avail0, Changed0) ->
- ABB0 = #avail_bb{want=OldIn,defin=OldDef} = avail_get(L, Avail0),
- AvailIn = avail_in(L, Avail0),
- Out = want_out(L, Avail0),
- DefOut = def_out(L, Avail0),
- {Changed, Avail} =
- case {ordsets:union(ordset_intersect_availset(Out, AvailIn), OldIn),
- ordsets:union(ordset_intersect_availset(DefOut, AvailIn), OldDef)}
- of
- {OldIn, OldDef} -> {Changed0, Avail0};
- {In, DefIn} ->
- ABB = ABB0#avail_bb{want=In,defin=DefIn},
- {Changed0+1, avail_set(L, ABB, Avail0)}
- end,
- want_dataf_once(Ls, Avail, Changed).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Rewrite pass
--type subst_dict() :: orddict:orddict(reg(), reg()).
--type input() :: #{label() => subst_dict()}.
-
--spec rewrite(target_cfg(), target(), avail()) -> target_cfg().
-rewrite(CFG, Target, Avail) ->
- RPO = reverse_postorder(CFG, Target),
- rewrite(RPO, Target, Avail, #{}, CFG).
-
--spec rewrite([label()], target(), avail(), input(), target_cfg())
- -> target_cfg().
-rewrite([], _Target, _Avail, _Input, CFG) -> CFG;
-rewrite([L|Ls], Target, Avail, Input0, CFG0) ->
- SplitHere = split_in_block(L, Avail),
- {Input1, LInput} =
- case Input0 of
- #{L := LInput0} -> {Input0, LInput0};
- #{} -> {Input0#{L => []}, []} % entry block
- end,
- ?ASSERT([] =:= [X || X <- SplitHere, orddict:is_key(X, LInput)]),
- ?ASSERT(want_in(L, Avail) =:= orddict:fetch_keys(LInput)),
- {CFG1, LOutput} =
- case {SplitHere, LInput} of
- {[], []} -> % optimisation (rewrite will do nothing, so skip it)
- {CFG0, LInput};
- _ ->
- Code0 = hipe_bb:code(BB=bb(CFG0, L, Target)),
- DefOut = def_out(L, Avail),
- {Code, LOutput0, _DefIn} =
- rewrite_instrs(Code0, Target, LInput, DefOut, SplitHere),
- {update_bb(CFG0, L, hipe_bb:code_update(BB, Code), Target), LOutput0}
- end,
- {Input, CFG} = rewrite_succs(avail_succ(L, Avail), Target, L, LOutput, Avail,
- Input1, CFG1),
- rewrite(Ls, Target, Avail, Input, CFG).
-
--spec renamed_in_block(label(), avail()) -> ordsets:ordset(reg()).
-renamed_in_block(L, Avail) ->
- ordsets:union([avail_self(L, Avail), want_in(L, Avail),
- want_out(L, Avail)]).
-
--spec split_in_block(label(), avail()) -> ordsets:ordset(reg()).
-split_in_block(L, Avail) ->
- ordsets:subtract(ordsets:union(avail_self(L, Avail), want_out(L, Avail)),
- want_in(L, Avail)).
-
--spec rewrite_instrs([instr()], target(), subst_dict(), regset(), [reg()])
- -> {[instr()], subst_dict(), regset()}.
-rewrite_instrs([], _Target, Output, DefOut, []) ->
- {[], Output, DefOut};
-rewrite_instrs([I|Is], Target, Input0, BBDefOut, SplitHere0) ->
- {TDef, TUse} = def_use(I, Target),
- {Def, Use} = {reg_names(TDef, Target), reg_names(TUse, Target)},
- %% Restores are generated in forward order by picking temps from SplitHere as
- %% they're used or defined. After the last instruction, all temps have been
- %% picked.
- {ISplits, SplitHere} =
- lists:partition(fun(R) ->
- lists:member(R, Def) orelse lists:member(R, Use)
- end, SplitHere0),
- {Input, Restores} =
- case ISplits of
- [] -> {Input0, []};
- _ ->
- make_splits(ISplits, Target, TDef, TUse, Input0, [])
- end,
- %% Here's the recursive call
- {Acc0, Output, DefOut} =
- rewrite_instrs(Is, Target, Input, BBDefOut, SplitHere),
- %% From here we're processing instructions in reverse order, because to avoid
- %% redundant spills we need to walk the 'def' dataflow, which is in reverse.
- SubstFun = fun(Temp) ->
- case orddict:find(reg_nr(Temp, Target), Input) of
- {ok, NewTemp} -> NewTemp;
- error -> Temp
- end
- end,
- Acc1 = insert_spills(TDef, Target, Input, DefOut, Acc0),
- Acc = Restores ++ [subst_temps(SubstFun, I, Target) | Acc1],
- DefIn = ordsets:union(DefOut, ordsets:from_list(Def)),
- {Acc, Output, DefIn}.
-
--spec make_splits([reg()], target(), [temp()], [temp()], subst_dict(),
- [instr()])
- -> {subst_dict(), [instr()]}.
-make_splits([], _Target, _TDef, _TUse, Input, Acc) ->
- {Input, Acc};
-make_splits([S|Ss], Target, TDef, TUse, Input0, Acc0) ->
- SubstReg = new_reg_nr(Target),
- {Acc, Subst} =
- case find_reg_temp(S, TUse, Target) of
- error ->
- {ok, Temp} = find_reg_temp(S, TDef, Target),
- {Acc0, update_reg_nr(SubstReg, Temp, Target)};
- {ok, Temp} ->
- Subst0 = update_reg_nr(SubstReg, Temp, Target),
- Acc1 = [mk_move(Temp, Subst0, Target) | Acc0],
- {Acc1, Subst0}
- end,
- Input = orddict:store(S, Subst, Input0),
- make_splits(Ss, Target, TDef, TUse, Input, Acc).
-
--spec find_reg_temp(reg(), [temp()], target()) -> error | {ok, temp()}.
-find_reg_temp(_Reg, [], _Target) -> error;
-find_reg_temp(Reg, [T|Ts], Target) ->
- case reg_nr(T, Target) of
- Reg -> {ok, T};
- _ -> find_reg_temp(Reg, Ts, Target)
- end.
-
--spec insert_spills([temp()], target(), subst_dict(), regset(), [instr()])
- -> [instr()].
-insert_spills([], _Target, _Input, _DefOut, Acc) -> Acc;
-insert_spills([T|Ts], Target, Input, DefOut, Acc0) ->
- R = reg_nr(T, Target),
- Acc =
- case orddict:find(R, Input) of
- error -> Acc0;
- {ok, Subst} ->
- case lists:member(R, DefOut) of
- true -> Acc0;
- false -> [mk_move(Subst, T, Target) | Acc0]
- end
- end,
- insert_spills(Ts, Target, Input, DefOut, Acc).
-
--spec rewrite_succs([label()], target(), label(), subst_dict(), avail(),
- input(), target_cfg()) -> {input(), target_cfg()}.
-rewrite_succs([], _Target, _P, _POutput, _Avail, Input, CFG) -> {Input, CFG};
-rewrite_succs([L|Ls], Target, P, POutput, Avail, Input0, CFG0) ->
- NewLInput = orddict_with_ordset(want_in(L, Avail), POutput),
- {Input, CFG} =
- case Input0 of
- #{L := LInput} ->
- CFG2 =
- case required_phi_moves(LInput, NewLInput) of
- [] -> CFG0;
- ReqMovs ->
- PhiLb = new_label(Target),
- Code = [mk_move(S,D,Target) || {S,D} <- ReqMovs]
- ++ [mk_goto(L, Target)],
- PhiBB = hipe_bb:mk_bb(Code),
- CFG1 = update_bb(CFG0, PhiLb, PhiBB, Target),
- bb_redirect_jmp(L, PhiLb, P, CFG1, Target)
- end,
- {Input0, CFG2};
- #{} ->
- {Input0#{L => NewLInput}, CFG0}
- end,
- rewrite_succs(Ls, Target, P, POutput, Avail, Input, CFG).
-
--spec bb_redirect_jmp(label(), label(), label(), target_cfg(), target())
- -> target_cfg().
-bb_redirect_jmp(From, To, Lb, CFG, Target) ->
- BB0 = bb(CFG, Lb, Target),
- Last = redirect_jmp(hipe_bb:last(BB0), From, To, Target),
- BB = hipe_bb:code_update(BB0, hipe_bb:butlast(BB0) ++ [Last]),
- update_bb(CFG, Lb, BB, Target).
-
--spec required_phi_moves(subst_dict(), subst_dict()) -> [{reg(), reg()}].
-required_phi_moves([], []) -> [];
-required_phi_moves([P|Is], [P|Os]) -> required_phi_moves(Is, Os);
-required_phi_moves([{K, In}|Is], [{K, Out}|Os]) ->
- [{Out, In}|required_phi_moves(Is, Os)].
-
-%% @doc Returns a new orddict with the keys in Set and their associated values.
--spec orddict_with_ordset(ordsets:ordset(K), orddict:orddict(K, V))
- -> orddict:orddict(K, V).
-orddict_with_ordset([S|Ss], [{K, _}|_]=Dict) when S < K ->
- orddict_with_ordset(Ss, Dict);
-orddict_with_ordset([S|_]=Set, [{K, _}|Ds]) when S > K ->
- orddict_with_ordset(Set, Ds);
-orddict_with_ordset([_S|Ss], [{_K, _}=P|Ds]) -> % _S == _K
- [P|orddict_with_ordset(Ss, Ds)];
-orddict_with_ordset([], _) -> [];
-orddict_with_ordset(_, []) -> [].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Target module interface functions
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(TGT_IFACE_0(N), N( {M,C}) -> M:N( C)).
--define(TGT_IFACE_1(N), N(A1, {M,C}) -> M:N(A1, C)).
--define(TGT_IFACE_2(N), N(A1,A2, {M,C}) -> M:N(A1,A2, C)).
--define(TGT_IFACE_3(N), N(A1,A2,A3,{M,C}) -> M:N(A1,A2,A3,C)).
-
-?TGT_IFACE_2(bb).
-?TGT_IFACE_1(def_use).
-?TGT_IFACE_1(defines_all_alloc).
-?TGT_IFACE_1(is_precoloured).
-?TGT_IFACE_1(labels).
-?TGT_IFACE_1(mk_goto).
-?TGT_IFACE_2(mk_move).
-?TGT_IFACE_0(new_label).
-?TGT_IFACE_0(new_reg_nr).
-?TGT_IFACE_3(redirect_jmp).
-?TGT_IFACE_1(reg_nr).
-?TGT_IFACE_1(reverse_postorder).
-?TGT_IFACE_2(subst_temps).
-?TGT_IFACE_3(update_bb).
-?TGT_IFACE_2(update_reg_nr).
-
-liveout(Liveness, L, Target={TgtMod,TgtCtx}) ->
- ordsets:from_list(reg_names(TgtMod:liveout(Liveness, L, TgtCtx), Target)).
-
-reg_names(Regs, {TgtMod,TgtCtx}) ->
- [TgtMod:reg_nr(X,TgtCtx) || X <- Regs].
-
-reg_def_use(I, Target) ->
- {TDef, TUse} = def_use(I, Target),
- {reg_names(TDef, Target), reg_names(TUse, Target)}.
diff --git a/lib/hipe/regalloc/hipe_sparc_specific.erl b/lib/hipe/regalloc/hipe_sparc_specific.erl
deleted file mode 100644
index 78b6379eba..0000000000
--- a/lib/hipe/regalloc/hipe_sparc_specific.erl
+++ /dev/null
@@ -1,214 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_specific).
-
-%% for hipe_coalescing_regalloc:
--export([number_of_temporaries/2
- ,analyze/2
- ,labels/2
- ,all_precoloured/1
- ,bb/3
- ,liveout/3
- ,reg_nr/2
- ,def_use/2
- ,is_move/2
- ,is_spill_move/2
- ,is_precoloured/2
- ,var_range/2
- ,allocatable/1
- ,non_alloc/2
- ,physical_name/2
- ,reverse_postorder/2
- ,livein/3
- ,uses/2
- ,defines/2
- ,defines_all_alloc/2
- ]).
-
-%% for hipe_graph_coloring_regalloc:
--export([is_fixed/2]).
-
-%% for hipe_ls_regalloc:
--export([args/2, is_arg/2, is_global/2, new_spill_index/2]).
--export([breadthorder/2, postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights, hipe_range_split
--export([branch_preds/2]).
-
-check_and_rewrite(CFG, Coloring, no_context) ->
- hipe_sparc_ra_postconditions:check_and_rewrite(CFG, Coloring, 'normal').
-
-reverse_postorder(CFG, _) ->
- hipe_sparc_cfg:reverse_postorder(CFG).
-
-non_alloc(CFG, no_context) ->
- non_alloc_1(hipe_sparc_registers:nr_args(), hipe_sparc_cfg:params(CFG)).
-
-%% same as hipe_sparc_frame:fix_formals/2
-non_alloc_1(0, Rest) -> Rest;
-non_alloc_1(N, [_|Rest]) -> non_alloc_1(N-1, Rest);
-non_alloc_1(_, []) -> [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- hipe_sparc_liveness_gpr:analyse(CFG).
-
-livein(Liveness,L,_) ->
- [X || X <- hipe_sparc_liveness_gpr:livein(Liveness,L),
- hipe_sparc:temp_is_allocatable(X)].
-
-liveout(BB_in_out_liveness,Label,_) ->
- [X || X <- hipe_sparc_liveness_gpr:liveout(BB_in_out_liveness,Label),
- hipe_sparc:temp_is_allocatable(X)].
-
-%% Registers stuff
-
-allocatable(no_context) ->
- hipe_sparc_registers:allocatable_gpr().
-
-all_precoloured(no_context) ->
- hipe_sparc_registers:all_precoloured().
-
-is_precoloured(Reg, _) ->
- hipe_sparc_registers:is_precoloured_gpr(Reg).
-
-is_fixed(R, _) ->
- hipe_sparc_registers:is_fixed(R).
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_sparc_cfg:labels(CFG).
-
-var_range(_CFG, _) ->
- hipe_gensym:var_range(sparc).
-
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(sparc),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG,L,_) ->
- hipe_sparc_cfg:bb(CFG,L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_sparc_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Branch,_) ->
- hipe_sparc_cfg:branch_preds(Branch).
-
-%% SPARC stuff
-
-def_use(Instruction, Ctx) ->
- {defines(Instruction, Ctx), uses(Instruction, Ctx)}.
-
-uses(I, _) ->
- [X || X <- hipe_sparc_defuse:insn_use_gpr(I),
- hipe_sparc:temp_is_allocatable(X)].
-
-defines(I, _) ->
- [X || X <- hipe_sparc_defuse:insn_def_gpr(I),
- hipe_sparc:temp_is_allocatable(X)].
-
-defines_all_alloc(I, _) ->
- hipe_sparc_defuse:insn_defs_all_gpr(I).
-
-is_move(Instruction, _) ->
- case hipe_sparc:is_pseudo_move(Instruction) of
- true ->
- Dst = hipe_sparc:pseudo_move_dst(Instruction),
- case hipe_sparc:temp_is_allocatable(Dst) of
- false -> false;
- _ ->
- Src = hipe_sparc:pseudo_move_src(Instruction),
- hipe_sparc:temp_is_allocatable(Src)
- end;
- false -> false
- end.
-
-is_spill_move(Instruction, _) ->
- hipe_sparc:is_pseudo_spill_move(Instruction).
-
-reg_nr(Reg, _) ->
- hipe_sparc:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_sparc:mk_pseudo_move(Src, Dst).
-
-mk_goto(Label, _) ->
- hipe_sparc:mk_b_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- hipe_sparc_cfg:redirect_jmp(Jmp, ToOld, ToNew).
-
-new_label(_) ->
- hipe_gensym:get_next_label(sparc).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(sparc).
-
-update_reg_nr(Nr, Temp, _) ->
- hipe_sparc:mk_temp(Nr, hipe_sparc:temp_type(Temp)).
-
-subst_temps(SubstFun, Instr, _) ->
- hipe_sparc_subst:insn_temps(
- fun(Op) ->
- case hipe_sparc:temp_is_allocatable(Op)
- andalso hipe_sparc:temp_type(Op) =/= 'double'
- of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
-%%% Linear Scan stuff
-
-new_spill_index(SpillIndex, _) when is_integer(SpillIndex) ->
- SpillIndex+1.
-
-breadthorder(CFG, _) ->
- hipe_sparc_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_sparc_cfg:postorder(CFG).
-
-is_global(R, _) ->
- R =:= hipe_sparc_registers:temp1() orelse
- R =:= hipe_sparc_registers:temp2() orelse
- R =:= hipe_sparc_registers:temp3() orelse
- hipe_sparc_registers:is_fixed(R).
-
-is_arg(R, _) ->
- hipe_sparc_registers:is_arg(R).
-
-args(CFG, _) ->
- hipe_sparc_registers:args(hipe_sparc_cfg:arity(CFG)).
diff --git a/lib/hipe/regalloc/hipe_sparc_specific_fp.erl b/lib/hipe/regalloc/hipe_sparc_specific_fp.erl
deleted file mode 100644
index 485fdc212a..0000000000
--- a/lib/hipe/regalloc/hipe_sparc_specific_fp.erl
+++ /dev/null
@@ -1,192 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_specific_fp).
-
-%% for hipe_coalescing_regalloc:
--export([number_of_temporaries/2
- ,analyze/2
- ,labels/2
- ,all_precoloured/1
- ,bb/3
- ,liveout/3
- ,reg_nr/2
- ,def_use/2
- ,is_move/2
- ,is_spill_move/2
- ,is_precoloured/2
- ,var_range/2
- ,allocatable/1
- ,non_alloc/2
- ,physical_name/2
- ,reverse_postorder/2
- ,livein/3
- ,uses/2
- ,defines/2
- ,defines_all_alloc/2
- ]).
-
-%% for hipe_graph_coloring_regalloc:
--export([is_fixed/2]).
-
-%% for hipe_ls_regalloc:
-%%-export([args/2, is_arg/2, is_global, new_spill_index/2]).
-%%-export([breadthorder/2, postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights, hipe_range_split
--export([branch_preds/2]).
-
-check_and_rewrite(CFG, Coloring, no_context) ->
- hipe_sparc_ra_postconditions_fp:check_and_rewrite(CFG, Coloring).
-
-reverse_postorder(CFG, _) ->
- hipe_sparc_cfg:reverse_postorder(CFG).
-
-non_alloc(_CFG, _) ->
- [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- hipe_sparc_liveness_fpr:analyse(CFG).
-
-livein(Liveness, L, _) ->
- hipe_sparc_liveness_fpr:livein(Liveness, L).
-
-liveout(BB_in_out_liveness, Label, _) ->
- hipe_sparc_liveness_fpr:liveout(BB_in_out_liveness, Label).
-
-%% Registers stuff
-
-allocatable(no_context) ->
- hipe_sparc_registers:allocatable_fpr().
-
-all_precoloured(Ctx) ->
- allocatable(Ctx).
-
-is_precoloured(Reg, _) ->
- hipe_sparc_registers:is_precoloured_fpr(Reg).
-
-is_fixed(_Reg, _) ->
- false.
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_sparc_cfg:labels(CFG).
-
-var_range(_CFG, _) ->
- hipe_gensym:var_range(sparc).
-
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(sparc),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG, L, _) ->
- hipe_sparc_cfg:bb(CFG, L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_sparc_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Branch,_) ->
- hipe_sparc_cfg:branch_preds(Branch).
-
-%% SPARC stuff
-
-def_use(I, Ctx) ->
- {defines(I,Ctx), uses(I,Ctx)}.
-
-uses(I, _) ->
- hipe_sparc_defuse:insn_use_fpr(I).
-
-defines(I, _) ->
- hipe_sparc_defuse:insn_def_fpr(I).
-
-defines_all_alloc(I, _) ->
- hipe_sparc_defuse:insn_defs_all_fpr(I).
-
-is_move(I, _) ->
- hipe_sparc:is_pseudo_fmove(I).
-
-is_spill_move(I, _) ->
- hipe_sparc:is_pseudo_spill_fmove(I).
-
-reg_nr(Reg, _) ->
- hipe_sparc:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_sparc:mk_pseudo_fmove(Src, Dst).
-
-mk_goto(Label, _) ->
- hipe_sparc:mk_b_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- hipe_sparc_cfg:redirect_jmp(Jmp, ToOld, ToNew).
-
-new_label(_) ->
- hipe_gensym:get_next_label(sparc).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(sparc).
-
-update_reg_nr(Nr, _Temp, _) ->
- hipe_sparc:mk_temp(Nr, 'double').
-
-subst_temps(SubstFun, Instr, _) ->
- hipe_sparc_subst:insn_temps(
- fun(Op) ->
- case hipe_sparc:temp_is_allocatable(Op)
- andalso hipe_sparc:temp_type(Op) =:= 'double'
- of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
--ifdef(notdef).
-new_spill_index(SpillIndex, _)->
- SpillIndex+1.
-
-breadthorder(CFG, _) ->
- hipe_sparc_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_sparc_cfg:postorder(CFG).
-
-is_global(_R, _) ->
- false.
-
-is_arg(_R, _) ->
- false.
-
-args(_CFG, _) ->
- [].
--endif.
diff --git a/lib/hipe/regalloc/hipe_spillcost.erl b/lib/hipe/regalloc/hipe_spillcost.erl
deleted file mode 100644
index 906cdac1aa..0000000000
--- a/lib/hipe/regalloc/hipe_spillcost.erl
+++ /dev/null
@@ -1,95 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_spillcost).
-
--export([new/1,
- inc_costs/2,
- ref_in_bb/2,
- spill_cost/2]).
-%% The following is exported only for debugging purposes.
--ifdef(DEBUG_PRINTOUTS).
--export([nr_of_use/2]).
--endif.
-
-%%----------------------------------------------------------------------------
-
--include("hipe_spillcost.hrl").
-
-%%----------------------------------------------------------------------------
-
--spec new(non_neg_integer()) -> #spill_cost{}.
-
-new(NrTemps) ->
- #spill_cost{uses = hipe_bifs:array(NrTemps, 0),
- bb_uses = hipe_bifs:array(NrTemps, 0)}.
-
-%%----------------------------------------------------------------------------
-%% Function: inc_costs
-%%
-%% Description: Registers usage of a list of temporaries (for spill_cost)
-%%----------------------------------------------------------------------------
-
--spec inc_costs([non_neg_integer()], #spill_cost{}) -> #spill_cost{}.
-
-inc_costs(Temps, SC) ->
- Uses = SC#spill_cost.uses,
- lists:foreach(fun (T) -> inc_use(T, Uses) end, Temps),
- SC. % updated via side-effects
-
-inc_use(Temp, Uses) ->
- hipe_bifs:array_update(Uses, Temp, get_uses(Temp, Uses) + 1).
-
-nr_of_use(Temp, SC) ->
- get_uses(Temp, SC#spill_cost.uses).
-
-get_uses(Temp, Uses) ->
- hipe_bifs:array_sub(Uses, Temp).
-
-%%----------------------------------------------------------------------------
-%% Function: ref_in_bb
-%%
-%% Description: Registers that a set of temporaries are used in one basic
-%% block; should be done exactly once per basic block
-%%----------------------------------------------------------------------------
-
--spec ref_in_bb([non_neg_integer()], #spill_cost{}) -> #spill_cost{}.
-
-ref_in_bb(Temps, SC) ->
- BBUses = SC#spill_cost.bb_uses,
- lists:foreach(fun (T) -> inc_bb_use(T, BBUses) end, Temps),
- SC. % updated via side-effects
-
-inc_bb_use(Temp, BBUses) ->
- hipe_bifs:array_update(BBUses, Temp, get_bb_uses(Temp, BBUses) + 1).
-
-bb_use(Temp, SC) ->
- get_bb_uses(Temp, SC#spill_cost.bb_uses).
-
-get_bb_uses(Temp, BBUses) ->
- hipe_bifs:array_sub(BBUses, Temp).
-
-%%----------------------------------------------------------------------------
-%% Function: spill_cost
-%%
-%% Description: Computes a spill cost for a temporary
-%%
-%% Returns:
-%% Spill cost (a real number -- higher means worse to spill)
-%%----------------------------------------------------------------------------
-
--spec spill_cost(non_neg_integer(), #spill_cost{}) -> float().
-
-spill_cost(Temp, SC) ->
- nr_of_use(Temp, SC) / bb_use(Temp, SC).
diff --git a/lib/hipe/regalloc/hipe_spillcost.hrl b/lib/hipe/regalloc/hipe_spillcost.hrl
deleted file mode 100644
index b1e84cee16..0000000000
--- a/lib/hipe/regalloc/hipe_spillcost.hrl
+++ /dev/null
@@ -1,20 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--type hipe_array() :: integer().
-
--record(spill_cost,
- {uses :: hipe_array(), % number of uses of each temp
- bb_uses :: hipe_array() % number of basic blocks each temp occurs in
- }).
diff --git a/lib/hipe/regalloc/hipe_temp_map.erl b/lib/hipe/regalloc/hipe_temp_map.erl
deleted file mode 100644
index 58145efb3e..0000000000
--- a/lib/hipe/regalloc/hipe_temp_map.erl
+++ /dev/null
@@ -1,120 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ===========================================================================
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ===========================================================================
-%% Module : hipe_temp_map
-%% Purpose :
-%% Notes :
-%% History : * 2001-07-24 Erik Johansson (happi@it.uu.se): Created.
-%% ===========================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_temp_map).
-
--export([cols2tuple/3, find/2, is_spilled/2, to_substlist/1]).
-
--include("../main/hipe.hrl").
-
--type target_context() :: any().
-
-%%----------------------------------------------------------------------------
-%% Convert a list of [{R0, C1}, {R1, C2}, ...] to a temp_map
-%% (Currently implemented as a tuple) tuple {C1, C2, ...}.
-%%
-%% The indices (Ri) must be unique but do not have to be sorted and
-%% they can be sparse.
-%% Note that the first allowed index is 0 -- this will be mapped to
-%% element 1
-%%----------------------------------------------------------------------------
-
--spec cols2tuple(hipe_map(), module(), target_context()) -> hipe_temp_map().
-
-cols2tuple(Map, TgtMod, TgtCtx) ->
- SortedMap = lists:keysort(1, Map),
- cols2tuple(0, SortedMap, [], TgtMod, TgtCtx).
-
-%% sorted_cols2tuple(Map, TgtMod, TgtCtx) ->
-%% ?ASSERT(Map =:= lists:keysort(1, Map)),
-%% cols2tuple(0, Map, [], TgtMod, TgtCtx).
-
-%% Build a dense mapping
-cols2tuple(_, [], Vs, _, _) ->
- %% Done reverse the list and convert to tuple.
- list_to_tuple(lists:reverse(Vs));
-cols2tuple(N, [{R, C}|Ms], Vs, TgtMod, TgtCtx) when N =:= R ->
- %% N makes sure the mapping is dense. N is he next key.
- cols2tuple(N+1, Ms, [C|Vs], TgtMod, TgtCtx);
-cols2tuple(N, SourceMapping=[{R,_}|_], Vs, TgtMod, TgtCtx) when N < R ->
- %% The source was sparse, make up some placeholders...
- Val =
- case TgtMod:is_precoloured(N, TgtCtx) of
- %% If it is precoloured, we know what to map it to.
- true -> {reg, N};
- false -> unknown
- end,
- cols2tuple(N+1, SourceMapping, [Val|Vs], TgtMod, TgtCtx).
-
-%%
-%% True if temp Temp is spilled.
-%%
--spec is_spilled(non_neg_integer(), hipe_temp_map()) -> boolean().
-
-is_spilled(Temp, Map) ->
- case find(Temp, Map) of
- {reg, _R} -> false;
- {fp_reg, _R}-> false;
- {spill, _N} -> true;
- unknown -> false
- end.
-
-%% %% True if temp Temp is allocated to a reg.
-%% in_reg(Temp, Map) ->
-%% case element(Temp+1, Map) of
-%% {reg, _R} -> true;
-%% {fp_reg, _R}-> false;
-%% {spill, _N} -> false;
-%% unknown -> false
-%% end.
-%%
-%% %% True if temp Temp is allocated to a fp_reg.
-%% in_fp_reg(Temp, Map) ->
-%% case element(Temp+1, Map) of
-%% {fp_reg, _R} -> true;
-%% {reg, _R} -> false;
-%% {spill, _N} -> false;
-%% unknown -> false
-%% end.
-
-%% Returns the inf temp Temp is mapped to.
-find(Temp, Map) when Temp < tuple_size(Map) -> element(Temp+1, Map);
-find(_, Map) when is_tuple(Map) -> unknown. % consistency with cols2tuple/3
-
-
-%%
-%% Converts a temp_map tuple back to a (sorted) key-list.
-%%
--spec to_substlist(hipe_temp_map()) -> hipe_map().
-
-to_substlist(Map) ->
- T = tuple_to_list(Map),
- mapping(T, 0).
-
-mapping([R|Rs], Temp) ->
- [{Temp, R}| mapping(Rs, Temp+1)];
-mapping([], _) ->
- [].
diff --git a/lib/hipe/regalloc/hipe_x86_specific.erl b/lib/hipe/regalloc/hipe_x86_specific.erl
deleted file mode 100644
index dacfb71b00..0000000000
--- a/lib/hipe/regalloc/hipe_x86_specific.erl
+++ /dev/null
@@ -1,259 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_SPECIFIC, hipe_amd64_specific).
--define(HIPE_X86_RA_POSTCONDITIONS, hipe_amd64_ra_postconditions).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
--define(HIPE_X86_DEFUSE, hipe_amd64_defuse).
--define(HIPE_X86_SUBST, hipe_amd64_subst).
--else.
--define(HIPE_X86_SPECIFIC, hipe_x86_specific).
--define(HIPE_X86_RA_POSTCONDITIONS, hipe_x86_ra_postconditions).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_LIVENESS, hipe_x86_liveness).
--define(HIPE_X86_DEFUSE, hipe_x86_defuse).
--define(HIPE_X86_SUBST, hipe_x86_subst).
--endif.
-
--module(?HIPE_X86_SPECIFIC).
-
--export([number_of_temporaries/2]).
-
-%% The following exports are used as M:F(...) calls from other modules;
-%% e.g. hipe_x86_ra_ls.
--export([analyze/2,
- bb/3,
- args/2,
- labels/2,
- livein/3,
- liveout/3,
- uses/2,
- defines/2,
- defines_all_alloc/2,
- def_use/2,
- is_arg/2, % used by hipe_ls_regalloc
- is_move/2,
- is_spill_move/2,
- is_fixed/2, % used by hipe_graph_coloring_regalloc
- is_global/2,
- is_precoloured/2,
- reg_nr/2,
- non_alloc/2,
- allocatable/1,
- physical_name/2,
- all_precoloured/1,
- new_spill_index/2, % used by hipe_ls_regalloc
- var_range/2,
- breadthorder/2,
- postorder/2,
- reverse_postorder/2]).
-
-%% callbacks for hipe_regalloc_loop
--export([check_and_rewrite/3]).
-
-%% callbacks for hipe_regalloc_prepass, hipe_range_split
--export([mk_move/3,
- mk_goto/2,
- redirect_jmp/4,
- new_label/1,
- new_reg_nr/1,
- update_reg_nr/3,
- update_bb/4,
- subst_temps/3]).
-
-%% callbacks for hipe_bb_weights
--export([branch_preds/2]).
-
-check_and_rewrite(CFG, Coloring, _) ->
- ?HIPE_X86_RA_POSTCONDITIONS:check_and_rewrite(CFG, Coloring, 'normal').
-
-reverse_postorder(CFG, _) ->
- hipe_x86_cfg:reverse_postorder(CFG).
-
-breadthorder(CFG, _) ->
- hipe_x86_cfg:breadthorder(CFG).
-
-postorder(CFG, _) ->
- hipe_x86_cfg:postorder(CFG).
-
-%% Globally defined registers for linear scan
-is_global(R, _) ->
- ?HIPE_X86_REGISTERS:temp1() =:= R orelse
- ?HIPE_X86_REGISTERS:temp0() =:= R orelse
- ?HIPE_X86_REGISTERS:is_fixed(R).
-
-is_fixed(R, _) ->
- ?HIPE_X86_REGISTERS:is_fixed(R).
-
-is_arg(R, _) ->
- ?HIPE_X86_REGISTERS:is_arg(R).
-
-args(CFG, _) ->
- ?HIPE_X86_REGISTERS:args(hipe_x86_cfg:arity(CFG)).
-
-non_alloc(CFG, _) ->
- non_alloc_1(?HIPE_X86_REGISTERS:nr_args(), hipe_x86_cfg:params(CFG)).
-
-%% same as hipe_x86_frame:fix_formals/2
-non_alloc_1(0, Rest) -> Rest;
-non_alloc_1(N, [_|Rest]) -> non_alloc_1(N-1, Rest);
-non_alloc_1(_, []) -> [].
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- ?HIPE_X86_LIVENESS:analyze(CFG).
-
-livein(Liveness,L,_) ->
- [X || X <- ?HIPE_X86_LIVENESS:livein(Liveness,L),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:fcalls(),
- hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:heap_limit(),
- hipe_x86:temp_type(X) =/= 'double'].
-
-liveout(BB_in_out_liveness,Label,_) ->
- [X || X <- ?HIPE_X86_LIVENESS:liveout(BB_in_out_liveness,Label),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:fcalls(),
- hipe_x86:temp_reg(X) =/= ?HIPE_X86_REGISTERS:heap_limit(),
- hipe_x86:temp_type(X) =/= 'double'].
-
-%% Registers stuff
-
-allocatable(_) ->
- ?HIPE_X86_REGISTERS:allocatable().
-
-all_precoloured(_) ->
- ?HIPE_X86_REGISTERS:all_precoloured().
-
-is_precoloured(Reg,_) ->
- ?HIPE_X86_REGISTERS:is_precoloured(Reg).
-
-physical_name(Reg,_) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG,_) ->
- hipe_x86_cfg:labels(CFG).
-
-var_range(_CFG,_) ->
- hipe_gensym:var_range(x86).
-
-number_of_temporaries(_CFG,_) ->
- Highest_temporary = hipe_gensym:get_var(x86),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG,L,_) ->
- hipe_x86_cfg:bb(CFG,L).
-
-update_bb(CFG,L,BB,_) ->
- hipe_x86_cfg:bb_add(CFG,L,BB).
-
-branch_preds(Instr,_) ->
- hipe_x86_cfg:branch_preds(Instr).
-
-%% X86 stuff
-
-def_use(Instruction,_) ->
- {[X || X <- ?HIPE_X86_DEFUSE:insn_def(Instruction),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =/= 'double'],
- [X || X <- ?HIPE_X86_DEFUSE:insn_use(Instruction),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =/= 'double']
- }.
-
-uses(I,_) ->
- [X || X <- ?HIPE_X86_DEFUSE:insn_use(I),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =/= 'double'].
-
-defines(I,_) ->
- [X || X <- ?HIPE_X86_DEFUSE:insn_def(I),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =/= 'double'].
-
-defines_all_alloc(I,_) -> ?HIPE_X86_DEFUSE:insn_defs_all(I).
-
-is_move(Instruction,_) ->
- case hipe_x86:is_move(Instruction) of
- true ->
- Src = hipe_x86:move_src(Instruction),
- Dst = hipe_x86:move_dst(Instruction),
- case hipe_x86:is_temp(Src) of
- true ->
- case hipe_x86:temp_is_allocatable(Src) of
- true ->
- case hipe_x86:is_temp(Dst) of
- true ->
- hipe_x86:temp_is_allocatable(Dst);
- false -> false
- end;
- false -> false
- end;
- false -> false
- end;
- false -> false
- end.
-
-is_spill_move(Instruction,_) ->
- hipe_x86:is_pseudo_spill_move(Instruction).
-
-reg_nr(Reg,_) ->
- hipe_x86:temp_reg(Reg).
-
-mk_move(Src, Dst, _) ->
- hipe_x86:mk_move(Src, Dst).
-
-mk_goto(Label, _) ->
- hipe_x86:mk_jmp_label(Label).
-
-redirect_jmp(Jmp, ToOld, ToNew, _) when is_integer(ToOld), is_integer(ToNew) ->
- Ref = make_ref(),
- put(Ref, false),
- I = hipe_x86_subst:insn_lbls(
- fun(Tgt) ->
- if Tgt =:= ToOld -> put(Ref, true), ToNew;
- is_integer(Tgt) -> Tgt
- end
- end, Jmp),
- true = erase(Ref), % Assert that something was rewritten
- I.
-
-new_label(_) ->
- hipe_gensym:get_next_label(x86).
-
-new_reg_nr(_) ->
- hipe_gensym:get_next_var(x86).
-
-update_reg_nr(Nr, Temp, _) ->
- hipe_x86:mk_temp(Nr, hipe_x86:temp_type(Temp)).
-
-subst_temps(SubstFun, Instr, _) ->
- ?HIPE_X86_SUBST:insn_temps(
- fun(Op) ->
- case hipe_x86:temp_is_allocatable(Op)
- andalso hipe_x86:temp_type(Op) =/= 'double'
- of
- true -> SubstFun(Op);
- false -> Op
- end
- end, Instr).
-
-new_spill_index(SpillIndex, _) when is_integer(SpillIndex) ->
- SpillIndex+1.
diff --git a/lib/hipe/regalloc/hipe_x86_specific_x87.erl b/lib/hipe/regalloc/hipe_x86_specific_x87.erl
deleted file mode 100644
index 3fe49e1f00..0000000000
--- a/lib/hipe/regalloc/hipe_x86_specific_x87.erl
+++ /dev/null
@@ -1,172 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_SPECIFIC_X87, hipe_amd64_specific_x87).
--define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_DEFUSE, hipe_amd64_defuse).
--else.
--define(HIPE_X86_SPECIFIC_X87, hipe_x86_specific_x87).
--define(HIPE_X86_LIVENESS, hipe_x86_liveness).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_DEFUSE, hipe_x86_defuse).
--endif.
-
--module(?HIPE_X86_SPECIFIC_X87).
--export([allocatable/2,
- is_precoloured/2,
- %% var_range/2,
- %% def_use/2,
- %% is_fixed/2,
- is_arg/2,
- %% non_alloc/2,
- new_spill_index/2,
- number_of_temporaries/2
- ]).
-
-%% The following exports are used as M:F(...) calls from other modules;
-%% e.g. hipe_x86_ra_ls.
--export([analyze/2,
- bb/3,
- args/2,
- labels/2,
- livein/3,
- liveout/3,
- uses/2,
- defines/2,
- defines_all_alloc/2,
- is_spill_move/2,
- is_global/2,
- reg_nr/2,
- physical_name/2,
- breadthorder/2,
- postorder/2,
- reverse_postorder/2]).
-
-%% callbacks for hipe_x86_ra_ls
--export([check_and_rewrite/4]).
-
-%% Rewrite happens in hipe_x86_ra_finalise:finalise/4
-check_and_rewrite(CFG, _Coloring, 'linearscan', _) ->
- {CFG, false}.
-
-breadthorder(CFG, _) ->
- hipe_x86_cfg:breadthorder(CFG).
-postorder(CFG, _) ->
- hipe_x86_cfg:postorder(CFG).
-reverse_postorder(CFG, _) ->
- hipe_x86_cfg:reverse_postorder(CFG).
-
-is_global(_, _) ->
- false.
-
--ifdef(notdef).
-is_fixed(_, _) ->
- false.
--endif.
-
-is_arg(_, _) ->
- false.
-
-args(_, _) ->
- [].
-
--ifdef(notdef).
-non_alloc(_, _) ->
- [].
--endif.
-
-%% Liveness stuff
-
-analyze(CFG, _) ->
- ?HIPE_X86_LIVENESS:analyze(CFG).
-
-livein(Liveness,L,_) ->
- [X || X <- ?HIPE_X86_LIVENESS:livein(Liveness,L),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'].
-
-liveout(BB_in_out_liveness,Label,_) ->
- [X || X <- ?HIPE_X86_LIVENESS:liveout(BB_in_out_liveness,Label),
- hipe_x86:temp_is_allocatable(X),
- hipe_x86:temp_type(X) =:= 'double'].
-
-%% Registers stuff
-
-allocatable('linearscan', _) ->
- ?HIPE_X86_REGISTERS:allocatable_x87().
-
-is_precoloured(Reg, _) ->
- ?HIPE_X86_REGISTERS:is_precoloured_x87(Reg).
-
-physical_name(Reg, _) ->
- Reg.
-
-%% CFG stuff
-
-labels(CFG, _) ->
- hipe_x86_cfg:labels(CFG).
-
--ifdef(notdef).
-var_range(_CFG, _) ->
- {Min,Max} = hipe_gensym:var_range(x86),
- %% io:format("Var_range: ~w\n",[{Min,Max}]),
- {Min,Max}.
--endif.
-
-number_of_temporaries(_CFG, _) ->
- Highest_temporary = hipe_gensym:get_var(x86),
- %% Since we can have temps from 0 to Max adjust by +1.
- Highest_temporary + 1.
-
-bb(CFG,L,_) ->
- hipe_x86_cfg:bb(CFG,L).
-
-%% X86 stuff
-
--ifdef(notdef).
-def_use(Instruction, _) ->
- {[X || X <- ?HIPE_X86_DEFUSE:insn_def(Instruction),
- hipe_x86:temp_is_allocatable(X),
- temp_is_double(X)],
- [X || X <- ?HIPE_X86_DEFUSE:insn_use(Instruction),
- hipe_x86:temp_is_allocatable(X),
- temp_is_double(X)]
- }.
--endif.
-
-uses(I, _) ->
- [X || X <- ?HIPE_X86_DEFUSE:insn_use(I),
- hipe_x86:temp_is_allocatable(X),
- temp_is_double(X)].
-
-defines(I, _) ->
- [X || X <- ?HIPE_X86_DEFUSE:insn_def(I),
- hipe_x86:temp_is_allocatable(X),
- temp_is_double(X)].
-
-defines_all_alloc(I, _) -> hipe_amd64_defuse:insn_defs_all(I).
-
-is_spill_move(I, _) ->
- hipe_x86:is_pseudo_spill_fmove(I).
-
-temp_is_double(Temp) ->
- hipe_x86:temp_type(Temp) =:= 'double'.
-
-reg_nr(Reg, _) ->
- hipe_x86:temp_reg(Reg).
-
-new_spill_index(SpillIndex, _) ->
- SpillIndex+1.
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
deleted file mode 100644
index 67485875a6..0000000000
--- a/lib/hipe/rtl/Makefile
+++ /dev/null
@@ -1,182 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2020. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-ifdef HIPE_ENABLED
-HIPE_MODULES = hipe_rtl hipe_rtl_cfg \
- hipe_rtl_liveness \
- hipe_icode2rtl hipe_rtl_mk_switch \
- hipe_rtl_primops \
- hipe_rtl_varmap hipe_rtl_exceptions \
- hipe_rtl_binary_match hipe_rtl_binary_construct \
- hipe_rtl_arith_32 hipe_rtl_arith_64 \
- hipe_rtl_ssa hipe_rtl_ssa_const_prop \
- hipe_rtl_cleanup_const hipe_rtl_symbolic hipe_rtl_lcm \
- hipe_rtl_ssapre hipe_rtl_binary hipe_rtl_ssa_avail_expr \
- hipe_rtl_arch hipe_tagscheme hipe_rtl_verify_gcsafe
-else
-HIPE_MODULES =
-endif
-
-MODULES = $(HIPE_MODULES)
-
-HRL_FILES= hipe_literals.hrl
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-# APP_FILE=
-# App_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS: Please keep +inline below
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_export_vars
-ifneq ($(NATIVE_LIBS_ENABLED),yes)
-ERL_COMPILE_FLAGS += -Werror
-endif
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-clean:
- rm -f hipe_literals.hrl
- rm -f $(TARGET_FILES)
- rm -f core erl_crash.dump
-
-distclean: clean
-realclean: clean
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/rtl"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/rtl"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-
-ifeq ($(TYPE),debug)
-TYPE_STR=.debug
-else
-TYPE_STR=
-endif
-
-FLAVOR=$(DEFAULT_FLAVOR)
-
-ifeq ($(FLAVOR),plain)
-FLAVOR_STR=
-else
-FLAVOR_STR=.smp
-endif
-
-ifeq ($(XCOMP),yes)
-MKLIT_FLAGS= -x
-else
-MKLIT_FLAGS=
-endif
-
-
-HIPE_MKLITERALS=$(ERL_TOP)/bin/$(TARGET)/hipe_mkliterals$(TYPE_STR)$(FLAVOR_STR)
-
-
-hipe_literals.hrl: $(HIPE_MKLITERALS)
- $(gen_verbose)$(HIPE_MKLITERALS) $(MKLIT_FLAGS) -e > hipe_literals.hrl
-
-# Need to generate hipe.hrl from one and only one target in one and only
-# one makefile; otherwise, clearmake will force rebuilds of hipe over and
-# over again.
-../main/hipe.hrl: ../vsn.mk ../main/hipe.hrl.src
- $(V_at)(cd ../main && $(MAKE) hipe.hrl)
-
-# 2012-02-24. Please keep these dependencies up to date. They tend to rot.
-# grep ^-include *.erl says a lot, but you need to dig further, e.g:
-# grep ^-include ../flow/*.{hrl,inc}
-$(EBIN)/hipe_icode2rtl.beam: \
- ../main/hipe.hrl ../icode/hipe_icode.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_arch.beam: hipe_literals.hrl
-$(EBIN)/hipe_rtl_arith_32.beam: ../main/hipe.hrl hipe_rtl_arith.inc
-$(EBIN)/hipe_rtl_arith_64.beam: ../main/hipe.hrl hipe_rtl_arith.inc
-$(EBIN)/hipe_rtl_binary_construct.beam: \
- ../main/hipe.hrl hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_binary_match.beam: hipe_literals.hrl
-$(EBIN)/hipe_rtl_cfg.beam: \
- ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc
-$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl
-$(EBIN)/hipe_rtl.beam: ../main/hipe.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_exceptions.beam: ../main/hipe.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_lcm.beam: ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl
-$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc
-$(EBIN)/hipe_rtl_mk_switch.beam: ../main/hipe.hrl
-$(EBIN)/hipe_rtl_primops.beam: ../main/hipe.hrl \
- ../icode/hipe_icode_primops.hrl hipe_rtl.hrl hipe_literals.hrl
-$(EBIN)/hipe_rtl_ssa_avail_expr.beam: ../main/hipe.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_ssa_const_prop.beam: ../main/hipe.hrl hipe_rtl.hrl \
- ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc
-$(EBIN)/hipe_rtl_ssa.beam: hipe_rtl.hrl \
- ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc ../ssa/hipe_ssa.inc
-$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl hipe_rtl.hrl
-$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl \
- ../icode/hipe_icode_primops.hrl
-$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl \
- ../misc/hipe_consttab.hrl ../icode/hipe_icode.hrl
-$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
deleted file mode 100644
index 1ab41f4deb..0000000000
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ /dev/null
@@ -1,727 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%=======================================================================
-%% File : hipe_icode2rtl.erl
-%% Author(s) : Erik Johansson
-%% Description : Translates Icode to RTL
-%%=======================================================================
-%% TODO: Better handling of switches...
-
--module(hipe_icode2rtl).
-
--export([translate/2]).
--export([translate_instrs/4]). %% used in hipe_rtl_mk_switch
-
-%%-------------------------------------------------------------------------
-
-%% -define(DEBUG,1). % used by hipe.hrl below
-
--include("../main/hipe.hrl").
--include("../icode/hipe_icode.hrl").
--include("hipe_literals.hrl").
-
-%%-------------------------------------------------------------------------
-
-%% @spec translate(IcodeRecord::#icode{}, Options::options()) -> term()
-%%
-%% options() = [option()]
-%% option() = term()
-%%
-%% @doc Translates a linear form of Icode for a single function to a
-%% linear form of RTL-code.
-%%
-translate(IcodeRecord = #icode{}, Options) ->
- ?IF_DEBUG_LEVEL(2, put(hipe_mfa, hipe_icode:icode_fun(IcodeRecord)), ok),
- %% hipe_icode_pp:pp(Fun),
-
- %% Initialize gensym and varmap
- {Args, VarMap} = hipe_rtl_varmap:init(IcodeRecord),
- %% Get the name and other info of the function to translate.
- MFA = hipe_icode:icode_fun(IcodeRecord),
- ConstTab = hipe_consttab:new(), % hipe_icode:icode_data(IcodeRecord),
- %% io:format("~w\n", [ConstTab]),
- Icode = hipe_icode:icode_code(IcodeRecord),
- IsClosure = hipe_icode:icode_is_closure(IcodeRecord),
- IsLeaf = hipe_icode:icode_is_leaf(IcodeRecord),
- IcodeInfo = hipe_icode:icode_info(IcodeRecord),
-
- %% Translate Icode instructions to RTL instructions
- ?opt_start_timer("Icode to nested RTL"),
- {Code, _VarMap1, ConstTab1} =
- translate_instrs(Icode, VarMap, ConstTab, Options),
- ?opt_stop_timer("Icode to nested RTL"),
- %% We build the code as list of lists of...
- %% in order to avoid appends.
- ?opt_start_timer("Flatten RTL"),
- Code1 = lists:flatten(Code),
- ?opt_stop_timer("Flatten RTL"),
- %% Build the RTL structure.
- Rtl = hipe_rtl:mk_rtl(MFA,
- Args,
- IsClosure,
- IsLeaf,
- Code1,
- ConstTab1,
- {1, hipe_gensym:get_var(rtl)},
- {1, hipe_gensym:get_label(rtl)}),
- %% hipe_rtl:pp(Rtl),
- %% Propagate info from Icode to RTL.
- hipe_rtl:rtl_info_update(Rtl, IcodeInfo).
-
-%%-------------------------------------------------------------------------
-
-%%
-%% @doc Translates a list of Icode instructions to a list of RTL instructions.
-%%
-translate_instrs(Is, VarMap, ConstTab, Options) ->
- translate_instrs(Is, VarMap, [], ConstTab, Options).
-
-translate_instrs([], VarMap, RTL_Code, ConstTab, _Options) ->
- {RTL_Code, VarMap, ConstTab};
-translate_instrs([I|Is], VarMap, AccCode, ConstTab, Options) ->
- %% Translate one instruction.
- {Code, VarMap0, ConstTab0} =
- translate_instruction(I, VarMap, ConstTab, Options),
- %% ?IF_DEBUG_LEVEL(3,?msg(" To Instr: ~w~n",[Code]),no_debug),
- ?IF_DEBUG(?when_option(rtl_show_translation, Options,
- ?msg(" To Instr: ~w~n", [Code])), ok),
- translate_instrs(Is, VarMap0, [AccCode,Code], ConstTab0, Options).
-
-%%
-%% @doc Translates an Icode instruction to one or more RTL instructions.
-%%
-
-translate_instruction(I, VarMap, ConstTab, Options) ->
- %% ?IF_DEBUG_LEVEL(3,?msg("From Instr: ~w~n",[I]),no_debug),
- ?IF_DEBUG(?when_option(rtl_show_translation, Options,
- ?msg("From Instr: ~w~n", [I])), ok),
- case I of
- #icode_call{} ->
- gen_call(I, VarMap, ConstTab);
- #icode_comment{} ->
- {hipe_rtl:mk_comment(hipe_icode:comment_text(I)), VarMap, ConstTab};
- #icode_enter{} ->
- gen_enter(I, VarMap, ConstTab);
- #icode_fail{} ->
- gen_fail(I, VarMap, ConstTab);
- #icode_goto{} ->
- gen_goto(I, VarMap, ConstTab);
- #icode_if{} ->
- gen_if(I, VarMap, ConstTab);
- #icode_label{} ->
- gen_label(I, VarMap, ConstTab);
- #icode_move{} ->
- gen_move(I, VarMap, ConstTab);
- #icode_begin_handler{} ->
- hipe_rtl_exceptions:gen_begin_handler(I, VarMap, ConstTab);
- #icode_return{} ->
- gen_return(I, VarMap, ConstTab);
- #icode_switch_val{} ->
- gen_switch_val(I, VarMap, ConstTab, Options);
- #icode_switch_tuple_arity{} ->
- gen_switch_tuple(I, VarMap, ConstTab, Options);
- #icode_type{} ->
- gen_type(I, VarMap, ConstTab);
- X ->
- exit({?MODULE,{"unknown Icode instruction",X}})
- end.
-
-%%-------------------------------------------------------------------------
-
-%%
-%% CALL
-%%
-
-gen_call(I, VarMap, ConstTab) ->
- Fun = hipe_icode:call_fun(I),
- {Dst, VarMap0} = hipe_rtl_varmap:ivs2rvs(hipe_icode:call_dstlist(I), VarMap),
- Fail = hipe_icode:call_fail_label(I),
-
- {Args, VarMap1, ConstTab1, InitCode} =
- args_to_vars(hipe_icode:call_args(I), VarMap0, ConstTab),
-
- IsGuard = hipe_icode:call_in_guard(I),
-
- {FailLblName, VarMap3} =
- case Fail of
- [] -> %% Not in a catch
- {[], VarMap1};
- _ ->
- {FLbl, VarMap2} =
- hipe_rtl_varmap:icode_label2rtl_label(Fail, VarMap1),
- {hipe_rtl:label_name(FLbl), VarMap2}
- end,
-
- {ContLblName, ContLbl, VarMap4} =
- case hipe_icode:call_continuation(I) of
- [] -> %% This call does not end a BB.
- CLbl = hipe_rtl:mk_new_label(),
- {hipe_rtl:label_name(CLbl), CLbl, VarMap3};
- Cont ->
- {CLbl, NewVarMap} =
- hipe_rtl_varmap:icode_label2rtl_label(Cont, VarMap3),
- {hipe_rtl:label_name(CLbl), [], NewVarMap}
- end,
-
- {Code, ConstTab2} =
- case hipe_icode:call_type(I) of
- primop ->
- hipe_rtl_primops:gen_primop(
- {Fun, Dst, Args, ContLblName, FailLblName},
- IsGuard, ConstTab1);
- Type ->
- Call = gen_call_1(Fun, Dst, Args, IsGuard, ContLblName,
- FailLblName, Type),
- {Call, ConstTab1}
- end,
- {[InitCode,Code,ContLbl], VarMap4, ConstTab2}.
-
-%% This catches those standard functions that we inline expand
-
-gen_call_1(Fun={_M,_F,_A}, Dst, Args, IsGuard, Cont, Fail, Type) ->
- case hipe_rtl_primops:gen_call_builtin(Fun, Dst, Args, IsGuard, Cont,
- Fail) of
- [] ->
- hipe_rtl:mk_call(Dst, Fun, Args, Cont, Fail, conv_call_type(Type));
- Code ->
- Code
- end.
-
-conv_call_type(remote) -> remote;
-conv_call_type(local) -> not_remote.
-
-%% --------------------------------------------------------------------
-
-%%
-%% ENTER
-%%
-
-gen_enter(I, VarMap, ConstTab) ->
- Fun = hipe_icode:enter_fun(I),
- {Args, VarMap1, ConstTab1, InitCode} =
- args_to_vars(hipe_icode:enter_args(I), VarMap, ConstTab),
- {Code1, ConstTab2} =
- case hipe_icode:enter_type(I) of
- primop ->
- IsGuard = false, % enter cannot happen in a guard
- hipe_rtl_primops:gen_enter_primop({Fun, Args}, IsGuard, ConstTab1);
- Type ->
- Call = gen_enter_1(Fun, Args, Type),
- {Call, ConstTab1}
- end,
- {[InitCode,Code1], VarMap1, ConstTab2}.
-
-%% This catches those standard functions that we inline expand
-
-gen_enter_1(Fun, Args, Type) ->
- case hipe_rtl_primops:gen_enter_builtin(Fun, Args) of
- [] ->
- hipe_rtl:mk_enter(Fun, Args, conv_call_type(Type));
- Code ->
- Code
- end.
-
-%% --------------------------------------------------------------------
-
-%%
-%% FAIL
-%%
-
-gen_fail(I, VarMap, ConstTab) ->
- Fail = hipe_icode:fail_label(I),
- {Label, VarMap0} =
- if Fail =:= [] ->
- %% not in a catch
- {[], VarMap};
- true ->
- {Lbl, Map} = hipe_rtl_varmap:icode_label2rtl_label(Fail, VarMap),
- {hipe_rtl:label_name(Lbl), Map}
- end,
- {Args, VarMap1, ConstTab1, InitCode} =
- args_to_vars(hipe_icode:fail_args(I), VarMap0, ConstTab),
- Class = hipe_icode:fail_class(I),
- FailCode = hipe_rtl_exceptions:gen_fail(Class, Args, Label),
- {[InitCode, FailCode], VarMap1, ConstTab1}.
-
-%% --------------------------------------------------------------------
-
-%%
-%% GOTO
-%%
-
-gen_goto(I, VarMap, ConstTab) ->
- {Label, Map0} =
- hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:goto_label(I), VarMap),
- {hipe_rtl:mk_goto(hipe_rtl:label_name(Label)), Map0, ConstTab}.
-
-%% --------------------------------------------------------------------
-
-%%
-%% IF
-%%
-
-gen_if(I, VarMap, ConstTab) ->
- {Args, VarMap1, ConstTab1, InitCode} =
- args_to_vars(hipe_icode:if_args(I), VarMap, ConstTab),
- {TrueLbl, VarMap2} =
- hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:if_true_label(I), VarMap1),
- {FalseLbl, VarMap3} =
- hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:if_false_label(I),VarMap2),
- CondCode =
- gen_cond(hipe_icode:if_op(I),
- Args,
- hipe_rtl:label_name(TrueLbl),
- hipe_rtl:label_name(FalseLbl),
- hipe_icode:if_pred(I)),
- {[InitCode,CondCode], VarMap3, ConstTab1}.
-
-
-%% --------------------------------------------------------------------
-
-%%
-%% LABEL
-%%
-
-gen_label(I, VarMap, ConstTab) ->
- LabelName = hipe_icode:label_name(I),
- {NewLabel,Map0} = hipe_rtl_varmap:icode_label2rtl_label(LabelName, VarMap),
- {NewLabel,Map0,ConstTab}.
-
-%% --------------------------------------------------------------------
-
-%%
-%% MOVE
-%%
-
-gen_move(I, VarMap, ConstTab) ->
- MovedSrc = hipe_icode:move_src(I),
- {Dst, VarMap0} =
- hipe_rtl_varmap:icode_var2rtl_var(hipe_icode:move_dst(I), VarMap),
- case hipe_icode:is_const(MovedSrc) of
- true ->
- {Code, NewConstMap} = gen_const_move(Dst, MovedSrc, ConstTab),
- {[Code], VarMap0, NewConstMap};
- false ->
- {Src, VarMap1} = hipe_rtl_varmap:icode_var2rtl_var(MovedSrc, VarMap0),
- Code =
- case hipe_icode:is_fvar(MovedSrc) of
- true ->
- hipe_rtl:mk_fmove(Dst, Src);
- false -> % It is a var or reg
- hipe_rtl:mk_move(Dst, Src)
- end,
- {[Code], VarMap1, ConstTab}
- end.
-
-%% --------------------------------------------------------------------
-
-%%
-%% RETURN
-%%
-
-gen_return(I, VarMap, ConstTab) ->
- {RetVars, VarMap0, ConstTab0, Code} =
- args_to_vars(hipe_icode:return_vars(I), VarMap, ConstTab),
- {Code ++ [hipe_rtl:mk_return(RetVars)], VarMap0, ConstTab0}.
-
-%% --------------------------------------------------------------------
-
-%%
-%% SWITCH
-%%
-
-%%
-%% Rewrite switch_val to the equivalent Icode if-then-else sequence,
-%% then translate that sequence instead.
-%% Doing this at the RTL level would generate the exact same code,
-%% but would also require _a_lot_ more work.
-%% (Don't believe me? Try it. I did, and threw the code away in disgust.
-%% The main ugliness comes from (1) maintaining ConstTab for the constants
-%% that may be added there [switch_val is not limited to immediates!],
-%% (2) maintaining Map for the translated labels, and (3) expanding
-%% equality tests to eq-or-call-primop-exact_eqeq_2.)
-%%
-%% TODO:
-%% - separate immediate and non-immediate cases,
-%% and translate each list separately
-%%
--ifdef(usesjumptable).
--define(uumess,?msg("~w Use jtab: ~w\n",
- [Options,proplists:get_bool(use_jumptable, Options)])).
--else.
--define(uumess,ok).
--endif.
-
-gen_switch_val(I, VarMap, ConstTab, Options) ->
- %% If you want to see whether jumptables are used or not...
- ?uumess,
- hipe_rtl_mk_switch:gen_switch_val(I, VarMap, ConstTab, Options).
-
-gen_switch_tuple(I, Map, ConstTab, Options) ->
- hipe_rtl_mk_switch:gen_switch_tuple(I, Map, ConstTab, Options).
-
-%% --------------------------------------------------------------------
-
-%%
-%% TYPE
-%%
-
-gen_type(I, VarMap, ConstTab) ->
- {Vars, Map0, NewConstTab, Code1} =
- args_to_vars(hipe_icode:type_args(I), VarMap, ConstTab),
- {TrueLbl, Map1} =
- hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:type_true_label(I), Map0),
- {FalseLbl, Map2} =
- hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:type_false_label(I), Map1),
- {Code2, NewConstTab1} = gen_type_test(Vars, hipe_icode:type_test(I),
- hipe_rtl:label_name(TrueLbl),
- hipe_rtl:label_name(FalseLbl),
- hipe_icode:type_pred(I),
- NewConstTab),
- {Code1 ++ Code2, Map2, NewConstTab1}.
-
-%% --------------------------------------------------------------------
-
-%%
-%% Generate code for a type test. If X is not of type Type then goto Label.
-%%
-
-gen_type_test([X], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
- case Type of
- atom ->
- {hipe_tagscheme:test_atom(X, TrueLbl, FalseLbl, Pred), ConstTab};
- bignum ->
- {hipe_tagscheme:test_bignum(X, TrueLbl, FalseLbl, Pred), ConstTab};
- binary ->
- {hipe_tagscheme:test_binary(X, TrueLbl, FalseLbl, Pred), ConstTab};
- bitstr ->
- {hipe_tagscheme:test_bitstr(X, TrueLbl, FalseLbl, Pred), ConstTab};
- boolean ->
- TmpT = hipe_rtl:mk_new_var(),
- TmpF = hipe_rtl:mk_new_var(),
- Lbl = hipe_rtl:mk_new_label(),
- {[hipe_rtl:mk_load_atom(TmpT, true),
- hipe_rtl:mk_branch(X, eq, TmpT, TrueLbl,hipe_rtl:label_name(Lbl),Pred),
- Lbl,
- hipe_rtl:mk_load_atom(TmpF, false),
- hipe_rtl:mk_branch(X, eq, TmpF, TrueLbl, FalseLbl, Pred)], ConstTab};
- cons ->
- {hipe_tagscheme:test_cons(X, TrueLbl, FalseLbl, Pred), ConstTab};
- fixnum ->
- {hipe_tagscheme:test_fixnum(X, TrueLbl, FalseLbl, Pred), ConstTab};
- float ->
- {hipe_tagscheme:test_flonum(X, TrueLbl, FalseLbl, Pred), ConstTab};
- function ->
- {hipe_tagscheme:test_fun(X, TrueLbl, FalseLbl, Pred), ConstTab};
- integer ->
- {hipe_tagscheme:test_integer(X, TrueLbl, FalseLbl, Pred), ConstTab};
- list ->
- {hipe_tagscheme:test_list(X, TrueLbl, FalseLbl, Pred), ConstTab};
- map ->
- {hipe_tagscheme:test_map(X, TrueLbl, FalseLbl, Pred), ConstTab};
- nil ->
- {hipe_tagscheme:test_nil(X, TrueLbl, FalseLbl, Pred), ConstTab};
- number ->
- {hipe_tagscheme:test_number(X, TrueLbl, FalseLbl, Pred), ConstTab};
- pid ->
- {hipe_tagscheme:test_any_pid(X, TrueLbl, FalseLbl, Pred), ConstTab};
- port ->
- {hipe_tagscheme:test_any_port(X, TrueLbl, FalseLbl, Pred), ConstTab};
- reference ->
- {hipe_tagscheme:test_ref(X, TrueLbl, FalseLbl, Pred), ConstTab};
- tuple ->
- {hipe_tagscheme:test_tuple(X, TrueLbl, FalseLbl, Pred), ConstTab};
- {atom, Atom} ->
- Tmp = hipe_rtl:mk_new_var(),
- {[hipe_rtl:mk_load_atom(Tmp, Atom),
- hipe_rtl:mk_branch(X, eq, Tmp, TrueLbl, FalseLbl, Pred)], ConstTab};
- {integer, N} when is_integer(N) ->
- %% XXX: warning, does not work for bignums
- case hipe_tagscheme:is_fixnum(N) of
- true ->
- Int = hipe_tagscheme:mk_fixnum(N),
- {hipe_rtl:mk_branch(X, eq, hipe_rtl:mk_imm(Int),
- TrueLbl, FalseLbl, Pred),
- ConstTab};
- false ->
- BignumLbl = hipe_rtl:mk_new_label(),
- RetLbl = hipe_rtl:mk_new_label(),
- BigN = hipe_rtl:mk_new_var(),
- Tmp = hipe_rtl:mk_new_var(),
- {BigCode,NewConstTab} = gen_big_move(BigN, N, ConstTab),
- {[hipe_tagscheme:test_fixnum(X, FalseLbl,
- hipe_rtl:label_name(BignumLbl),1-Pred),
- BignumLbl, BigCode]
- ++
- [hipe_rtl:mk_call([Tmp], op_exact_eqeq_2 , [X,BigN],
- hipe_rtl:label_name(RetLbl),[],not_remote),
- RetLbl,
- hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)],
- NewConstTab}
- end;
- {record, A, S} ->
- TupleLbl = hipe_rtl:mk_new_label(),
- TupleLblName = hipe_rtl:label_name(TupleLbl),
- AtomLab = hipe_rtl:mk_new_label(),
- AtomLabName = hipe_rtl:label_name(AtomLab),
- TagVar = hipe_rtl:mk_new_var(),
- TmpAtomVar = hipe_rtl:mk_new_var(),
- {UntagCode, ConstTab1} =
- hipe_rtl_primops:gen_primop({{unsafe_element,1},[TagVar],[X],
- AtomLabName,[]},
- false, ConstTab),
- Code =
- hipe_tagscheme:test_tuple_N(X, S, TupleLblName, FalseLbl, Pred) ++
- [TupleLbl|UntagCode] ++
- [AtomLab,
- hipe_rtl:mk_load_atom(TmpAtomVar, A),
- hipe_rtl:mk_branch(TagVar, eq, TmpAtomVar, TrueLbl, FalseLbl, Pred)],
- {Code,
- ConstTab1};
- {tuple, N} ->
- {hipe_tagscheme:test_tuple_N(X, N, TrueLbl, FalseLbl, Pred), ConstTab};
- Other ->
- exit({?MODULE,{"unknown type",Other}})
- end;
-gen_type_test(Z = [X,Y], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
- case Type of
- function2 ->
- {hipe_tagscheme:test_fun2(X, Y, TrueLbl, FalseLbl, Pred), ConstTab};
- fixnum ->
- {hipe_tagscheme:test_fixnums(Z, TrueLbl, FalseLbl, Pred), ConstTab};
- Other ->
- exit({?MODULE,{"unknown type",Other}})
- end;
-gen_type_test(X, Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
- case Type of
- fixnum ->
- {hipe_tagscheme:test_fixnums(X, TrueLbl, FalseLbl, Pred), ConstTab};
- Other ->
- exit({?MODULE,{"type cannot have several arguments",Other}})
- end.
-
-
-%% --------------------------------------------------------------------
-%%
-%% Generate code for the if-conditional.
-%%
-
-gen_cond(CondOp, Args, TrueLbl, FalseLbl, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- GenLbl = hipe_rtl:mk_new_label(),
- TestRetLbl = hipe_rtl:mk_new_label(),
- TestRetName = hipe_rtl:label_name(TestRetLbl),
-
- case CondOp of
- 'fixnum_eq' ->
- [Arg1, Arg2] = Args,
- [hipe_rtl:mk_branch(Arg1, eq, Arg2, TrueLbl,
- FalseLbl, Pred)];
- '=:=' ->
- [Arg1, Arg2] = Args,
- TypeTestLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_branch(Arg1, eq, Arg2, TrueLbl,
- hipe_rtl:label_name(TypeTestLbl), Pred),
- TypeTestLbl,
- hipe_tagscheme:test_either_immed(Arg1, Arg2, FalseLbl,
- hipe_rtl:label_name(GenLbl)),
- GenLbl,
- hipe_rtl:mk_call([Tmp], op_exact_eqeq_2, Args,
- TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- 'fixnum_neq' ->
- [Arg1, Arg2] = Args,
- [hipe_rtl:mk_branch(Arg1, eq, Arg2, FalseLbl,
- TrueLbl, 1-Pred)];
- '=/=' ->
- [Arg1, Arg2] = Args,
- TypeTestLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_branch(Arg1, eq, Arg2, FalseLbl,
- hipe_rtl:label_name(TypeTestLbl), 1-Pred),
- TypeTestLbl,
- hipe_tagscheme:test_either_immed(Arg1, Arg2, TrueLbl,
- hipe_rtl:label_name(GenLbl)),
- GenLbl,
- hipe_rtl:mk_call([Tmp], op_exact_eqeq_2, Args,
- TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
- FalseLbl, TrueLbl, Pred)];
- '==' ->
- [Arg1, Arg2] = Args,
- [hipe_rtl:mk_branch(Arg1, eq, Arg2,
- TrueLbl, hipe_rtl:label_name(GenLbl), Pred),
- GenLbl,
- hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- '/=' ->
- [Arg1, Arg2] = Args,
- [hipe_rtl:mk_branch(Arg1, eq, Arg2,
- FalseLbl, hipe_rtl:label_name(GenLbl), 1-Pred),
- GenLbl,
- hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- 'fixnum_gt' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_gt(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
- 'fixnum_ge' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_ge(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
- 'fixnum_lt' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_lt(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
- 'fixnum_le' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_le(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
- '>' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenLbl)),
- hipe_tagscheme:fixnum_gt(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
- GenLbl,
- hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, gt, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- '<' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenLbl)),
- hipe_tagscheme:fixnum_lt(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
- GenLbl,
- hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, lt, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- '>=' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenLbl)),
- hipe_tagscheme:fixnum_ge(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
- GenLbl,
- hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, ge, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- '=<' ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenLbl)),
- hipe_tagscheme:fixnum_le(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
- GenLbl,
- hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, le, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)];
- _Other ->
- [hipe_rtl:mk_call([Tmp], CondOp, Args, TestRetName, [], not_remote),
- TestRetLbl,
- hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
- TrueLbl, FalseLbl, Pred)]
- end.
-
-%% --------------------------------------------------------------------
-%%
-%% Translate a list argument list of icode vars to rtl vars. Also
-%% handles constants in arguments.
-%%
-
-args_to_vars([Arg|Args],VarMap, ConstTab) ->
- {Vars, VarMap1, ConstTab1, Code} =
- args_to_vars(Args, VarMap, ConstTab),
- case hipe_icode:is_variable(Arg) of
- true ->
- {Var, VarMap2} = hipe_rtl_varmap:icode_var2rtl_var(Arg, VarMap1),
- {[Var|Vars], VarMap2, ConstTab1, Code};
- false ->
- case type_of_const(Arg) of
- big ->
- ConstVal = hipe_icode:const_value(Arg),
- {ConstTab2, Label} = hipe_consttab:insert_term(ConstTab1, ConstVal),
- NewArg = hipe_rtl:mk_const_label(Label),
- {[NewArg|Vars], VarMap1, ConstTab2, Code};
- fixnum ->
- ConstVal = hipe_icode:const_value(Arg),
- NewArg = hipe_rtl:mk_imm(tagged_val_of(ConstVal)),
- {[NewArg|Vars], VarMap1, ConstTab1, Code};
- nil ->
- NewArg = hipe_rtl:mk_imm(tagged_val_of([])),
- {[NewArg|Vars], VarMap1, ConstTab1, Code};
- _ ->
- Var = hipe_rtl:mk_new_var(),
- {Code2, ConstTab2} = gen_const_move(Var, Arg, ConstTab1),
- {[Var|Vars], VarMap1, ConstTab2, [Code2,Code]}
- end
- end;
-args_to_vars([], VarMap, ConstTab) ->
- {[], VarMap, ConstTab, []}.
-
-%% --------------------------------------------------------------------
-
-%%
-%% Translate a move where the source is a constant
-%%
-
-gen_const_move(Dst, Const, ConstTab) ->
- ConstVal = hipe_icode:const_value(Const),
- case type_of_const(Const) of
- %% const_fun ->
- %% gen_fun_move(Dst, ConstVal, ConstTab);
- nil ->
- Src = hipe_rtl:mk_imm(tagged_val_of([])),
- {hipe_rtl:mk_move(Dst, Src), ConstTab};
- fixnum ->
- Src = hipe_rtl:mk_imm(tagged_val_of(ConstVal)),
- {hipe_rtl:mk_move(Dst, Src), ConstTab};
- atom ->
- {hipe_rtl:mk_load_atom(Dst, ConstVal), ConstTab};
- big ->
- gen_big_move(Dst, ConstVal, ConstTab)
- end.
-
-%% gen_fun_move(Dst, Fun, ConstTab) ->
-%% ?WARNING_MSG("Funmove ~w! -- NYI\n", [Fun]),
-%% {NewTab, Label} = hipe_consttab:insert_fun(ConstTab, Fun),
-%% {hipe_rtl:mk_load_address(Dst, Label, constant), NewTab}.
-
-gen_big_move(Dst, Big, ConstTab) ->
- {NewTab, Label} = hipe_consttab:insert_term(ConstTab, Big),
- {hipe_rtl:mk_move(Dst, hipe_rtl:mk_const_label(Label)),
- NewTab}.
-
-type_of_const(Const) ->
- case hipe_icode:const_value(Const) of
- [] ->
- nil;
- X when is_integer(X) ->
- case hipe_tagscheme:is_fixnum(X) of
- true -> fixnum;
- false -> big
- end;
- A when is_atom(A) ->
- atom;
- _ ->
- big
- end.
-
-tagged_val_of([]) -> hipe_tagscheme:mk_nil();
-tagged_val_of(X) when is_integer(X) -> hipe_tagscheme:mk_fixnum(X).
diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl
deleted file mode 100644
index 33027f3259..0000000000
--- a/lib/hipe/rtl/hipe_rtl.erl
+++ /dev/null
@@ -1,1804 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% @doc
-%%
-%% Provides an abstract datatype for HiPE's RTL (Register Transfer Language).
-%%
-%% <h3> RTL - Register Transfer Language </h3>
-%%
-%% Consists of the instructions:
-%% <ul>
-%% <li> {alu, Dst, Src1, Op, Src2} </li>
-%% <li> {alub, Dst, Src1, Op, Src2, RelOp, TrueLabel, FalseLabel, P} </li>
-%% <li> {branch, Src1, Src2, RelOp, TrueLabel, FalseLabel, P} </li>
-%% <li> {call, DsListt, Fun, ArgList, Type, Continuation, FailContinuation, NormalContinuation}
-%% Type is one of {local, remote, primop, closure} </li>
-%% <li> {comment, Text} </li>
-%% <li> {enter, Fun, ArgList, Type}
-%% Type is one of {local, remote, primop, closure} </li>
-%% <li> {fconv, Dst, Src} </li>
-%% <li> {fload, Dst, Src, Offset} </li>
-%% <li> {fmove, Dst, Src} </li>
-%% <li> {fp, Dst, Src1, Op, Src2} </li>
-%% <li> {fp_unop, Dst, Src, Op} </li>
-%% <li> {fstore, Base, Offset, Src} </li>
-%% <li> {gctest, Words} </li>
-%% <li> {goto, Label} </li>
-%% <li> {goto_index, Block, Index, LabelList} </li>
-%% <li> {label, Name} </li>
-%% <li> {load, Dst, Src, Offset, Size, Sign} </li>
-%% <li> {load_address, Dst, Addr, Type} </li>
-%% <li> {load_atom, Dst, Atom} </li>
-%% <li> {load_word_index, Dst, Block, Index} </li>
-%% <li> {move, Dst, Src} </li>
-%% <li> {multimove, [Dst1, ..., DstN], [Src1, ..., SrcN]} </li>
-%% <li> {phi, Dst, Id, [Src1, ..., SrcN]} </li>
-%% <li> {return, VarList} </li>
-%% <li> {store, Base, Offset, Src, Size} </li>
-%% <li> {switch, Src1, Labels, SortedBy} </li>
-%% </ul>
-%%
-%% There are three kinds of 'registers' in RTL.
-%% <ol>
-%% <li> Variables containing tagged data that are traced by the GC. </li>
-%% <li> Registers that are ignored by the GC. </li>
-%% <li> Floating point registers. </li>
-%% </ol>
-%% These registers all share the same namespace.
-%%
-%% IMPORTANT:
-%%
-%% The variables contain tagged Erlang terms, the registers
-%% contain untagged values (that can be all sorts of things) and
-%% the floating point registers contain untagged floating point
-%% values. This means that the different kinds of 'registers' are
-%% incompatible and CANNOT be assigned to each other unless the
-%% proper conversions are made.
-%%
-%% When performing optimizations, it is reasonably safe to move
-%% values stored in variables. However, when moving around untagged
-%% values from either registers or floating point registers make
-%% sure you know what you are doing.
-%%
-%% Example 1: A register might contain the untagged pointer to
-%% something on the heap. If this value is moved across
-%% a program point where a garbage collection might
-%% occur, the pointer can be invalid. If you are lucky
-%% you will end up with a segmentation fault; if unlucky,
-%% you will be stuck on a wild goose chase.
-%%
-%% Example 2: Floating point arithmetic instructions must occur in
-%% a floating point block. Otherwise, exceptions can be
-%% masked.
-%%
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl).
--include("../main/hipe.hrl").
-
--export([mk_rtl/8,
- rtl_fun/1,
- rtl_params/1,
- rtl_is_closure/1,
- rtl_is_leaf/1,
- rtl_code/1,
- rtl_code_update/2,
- rtl_data/1,
- %% rtl_data_update/2,
- %% rtl_var_range/1,
- %% rtl_var_range_update/2,
- rtl_label_range/1,
- %% rtl_label_range_update/2,
- rtl_info/1,
- rtl_info_update/2]).
-
--export([mk_move/2,
- move_dst/1,
- move_src/1,
- %% move_src_update/2,
- %% is_move/1,
-
- mk_multimove/2,
- multimove_dstlist/1,
- multimove_srclist/1,
- %% multimove_srclist_update/2,
- %% is_multimove/1,
-
- mk_phi/1,
- phi_dst/1,
- phi_id/1,
- phi_arg/2,
- phi_arglist/1,
- is_phi/1,
- phi_enter_pred/3,
- phi_remove_pred/2,
-
- mk_alu/4,
- alu_dst/1,
- alu_src1/1,
- alu_src1_update/2,
- alu_src2/1,
- alu_src2_update/2,
- alu_op/1,
- %% is_alu_op/1,
- is_shift_op/1,
-
- mk_load/3,
- mk_load/5,
- load_dst/1,
- load_src/1,
- load_offset/1,
- load_size/1,
- load_sign/1,
-
- mk_load_atom/2,
- load_atom_dst/1,
- load_atom_atom/1,
-
- mk_load_word_index/3,
- load_word_index_dst/1,
- %% load_word_index_index/1,
- %% load_word_index_block/1,
-
- mk_goto_index/3,
- goto_index_index/1,
- %% goto_index_block/1,
- goto_index_labels/1,
-
- mk_load_address/3,
- load_address_dst/1,
- %% load_address_dst_update/2,
- load_address_addr/1,
- load_address_addr_update/2,
- load_address_type/1,
- %% load_address_type_update/2,
-
- mk_store/3,
- mk_store/4,
- store_base/1,
- store_src/1,
- store_offset/1,
- store_size/1,
-
- mk_label/1,
- mk_new_label/0,
- label_name/1,
- is_label/1,
-
- mk_branch/5,
- mk_branch/6,
- mk_branch/7,
- %% is_branch/1,
- %% branch_true_label_update/2,
- %% branch_false_label_update/2,
-
- mk_alub/7,
- mk_alub/8,
- alub_has_dst/1,
- alub_dst/1,
- alub_src1/1,
- alub_op/1,
- alub_src2/1,
- alub_cond/1,
- alub_true_label/1,
- %% alub_true_label_update/2,
- alub_false_label/1,
- %% alub_false_label_update/2,
- alub_pred/1,
- %% is_alub/1,
-
- mk_switch/2,
- %% mk_switch/3,
- mk_sorted_switch/3,
- switch_src/1,
- %% switch_src_update/2,
- switch_labels/1,
- %% switch_labels_update/2,
- switch_sort_order/1,
- %% switch_sort_order_update/2,
-
- mk_goto/1,
- goto_label/1,
- is_goto/1,
- %% goto_label_update/2,
-
- mk_call/6,
- mk_call/7,
- call_fun/1,
- call_dstlist/1,
- call_dstlist_update/2,
- call_arglist/1,
- call_continuation/1,
- call_fail/1,
- call_type/1,
- call_normal/1,
- call_normal_update/2,
- %% call_continuation_update/2,
- call_fail_update/2,
- is_call/1,
-
- mk_enter/3,
- enter_fun/1,
- enter_arglist/1,
- enter_type/1,
-
- mk_return/1,
- return_varlist/1,
-
- mk_gctest/1,
- gctest_words/1,
-
- mk_comment/1,
- comment_text/1,
- is_comment/1,
-
- mk_fload/3,
- fload_dst/1,
- fload_src/1,
- %% fload_src_update/2,
- fload_offset/1,
- %% fload_offset_update/2,
-
- mk_fstore/3,
- fstore_base/1,
- fstore_src/1,
- fstore_offset/1,
-
- mk_fp/4,
- fp_dst/1,
- fp_src1/1,
- %% fp_src1_update/2,
- fp_src2/1,
- %% fp_src2_update/2,
- fp_op/1,
-
- mk_fp_unop/3,
- fp_unop_dst/1,
- fp_unop_src/1,
- %% fp_unop_src_update/2,
- fp_unop_op/1,
-
- mk_fmove/2,
- fmove_dst/1,
- fmove_src/1,
- %% fmove_src_update/2,
- %% is_fmove/1,
-
- mk_fconv/2,
- fconv_dst/1,
- fconv_src/1,
- %% fconv_src_update/2,
- %% is_fconv/1,
-
- mk_var/1,
- mk_var/2,
- mk_new_var/0,
- is_var/1,
- var_index/1,
- var_liveness/1,
- var_liveness_update/2,
-
- %% change_vars_to_regs/1,
-
- mk_fixnumop/3,
- fixnumop_dst/1,
- fixnumop_src/1,
- fixnumop_type/1,
-
- mk_reg/1, % assumes non gc-safe
- mk_reg_gcsafe/1,
- mk_new_reg/0, % assumes non gc-safe
- mk_new_reg_gcsafe/0,
- is_reg/1,
- reg_index/1,
- reg_is_gcsafe/1,
-
- %% mk_fpreg/1,
- mk_new_fpreg/0,
- is_fpreg/1,
- fpreg_index/1,
-
- mk_imm/1,
- is_imm/1,
- imm_value/1,
-
- mk_const_label/1,
- const_label_label/1,
- is_const_label/1,
-
- args/1,
- uses/1,
- %% subst/2,
- subst_uses/2,
- subst_defines/2,
- defines/1,
- redirect_jmp/3,
- is_safe/1,
- reduce_unused/1,
- %% highest_var/1,
- pp/1,
- pp/2,
- pp_block/1,
-
- %% FIXME _dst_update command. Ok to export these?
- alu_dst_update/2,
- fconv_dst_update/2,
- fload_dst_update/2,
- %% fmove_dst_update/2,
- fp_dst_update/2,
- fp_unop_dst_update/2,
- load_dst_update/2,
- load_address_dst_update/2,
- load_atom_dst_update/2,
- load_word_index_dst_update/2,
- %% move_dst_update/2,
- fixnumop_dst_update/2,
- pp_instr/2,
- %% Uber hack!
- pp_var/2,
- pp_reg/2,
- pp_arg/2,
- phi_arglist_update/2,
- phi_redirect_pred/3]).
-
--export([subst_uses_llvm/2]).
-
--export_type([alub_cond/0, rtl/0]).
-
-%%
-%% RTL
-%%
-
--record(rtl, {'fun', %% Name of the function (MFA)
- arglist, %% List of argument names (formals)
- is_closure, %% True if this is code for a closure.
- is_leaf, %% True if this is a leaf function.
- code, %% Linear list of RTL-instructions.
- data, %% Data segment
- var_range, %% {Min,Max} First and last name used for
- %% regs, fpregs, or vars.
- %% (they use a common namespace)
- label_range, %% {Min,Max} First and last name used for labels
- info=[] %% A keylist with arbitrary information.
- }).
--opaque rtl() :: #rtl{}.
-
-mk_rtl(Fun, ArgList, Closure, Leaf, Code, Data, VarRange, LabelRange) ->
- #rtl{'fun'=Fun, arglist=ArgList, code=Code,
- data=Data, is_closure=Closure, is_leaf=Leaf,
- var_range=VarRange, label_range=LabelRange}.
-rtl_fun(#rtl{'fun'=Fun}) -> Fun.
-rtl_params(#rtl{arglist=ArgList}) -> ArgList.
-rtl_is_closure(#rtl{is_closure=Closure}) -> Closure.
-rtl_is_leaf(#rtl{is_leaf=Leaf}) -> Leaf.
-rtl_code(#rtl{code=Code}) -> Code.
-rtl_code_update(Rtl, Code) -> Rtl#rtl{code=Code}.
-rtl_data(#rtl{data=Data}) -> Data.
-%% rtl_data_update(Rtl, Data) -> Rtl#rtl{data=Data}.
-%% rtl_var_range(#rtl{var_range=VarRange}) -> VarRange.
-%% rtl_var_range_update(Rtl, VarRange) -> Rtl#rtl{var_range=VarRange}.
-rtl_label_range(#rtl{label_range=LabelRange}) -> LabelRange.
-%% rtl_label_range_update(Rtl, LabelRange) -> Rtl#rtl{label_range=LabelRange}.
-rtl_info(#rtl{info=Info}) -> Info.
-rtl_info_update(Rtl, Info) -> Rtl#rtl{info=Info}.
-
-%%-----------------------------------------------------------------------------
-
--include("hipe_rtl.hrl").
-
-%%-----------------------------------------------------------------------------
-
-%%
-%% move
-%%
-
-mk_move(Dst, Src) ->
- false = is_fpreg(Dst), false = is_fpreg(Src),
- #move{dst=Dst, src=Src}.
-move_dst(#move{dst=Dst}) -> Dst.
-move_dst_update(M, NewDst) -> false = is_fpreg(NewDst), M#move{dst=NewDst}.
-move_src(#move{src=Src}) -> Src.
-move_src_update(M, NewSrc) -> false = is_fpreg(NewSrc), M#move{src=NewSrc}.
-%% is_move(#move{}) -> true;
-%% is_move(_) -> false.
-
-%%
-%% multimove
-%%
-
-mk_multimove(DstList, SrcList) ->
- case length(DstList) =:= length(SrcList) of
- true -> true;
- false ->
- exit({?MODULE,mk_multimove,
- {"different arities",{dstlist,DstList},{srclist,SrcList}}})
- end,
- #multimove{dstlist=DstList, srclist=SrcList}.
-multimove_dstlist(#multimove{dstlist=DstList}) -> DstList.
-multimove_dstlist_update(M, NewDstList) -> M#multimove{dstlist=NewDstList}.
-multimove_srclist(#multimove{srclist=SrcList}) -> SrcList.
-multimove_srclist_update(M, NewSrcList) -> M#multimove{srclist=NewSrcList}.
-%% is_multimove(#multimove{}) -> true;
-%% is_multimove(_) -> false.
-
-%%
-%% phi
-%%
-
-%% The id field is not entirely redundant. It is used in mappings
-%% in the SSA pass since the dst field can change.
-mk_phi(Var) -> #phi{dst = Var, id = Var, arglist = []}.
-%% mk_phi(Var, ArgList) -> #phi{dst = Var, id = Var, arglist = ArgList}.
-phi_dst(#phi{dst=Dst}) -> Dst.
-phi_dst_update(Phi, NewDst) -> Phi#phi{dst = NewDst}.
-phi_id(#phi{id=Id}) -> Id.
-phi_args(Phi) -> [X || {_,X} <- phi_arglist(Phi)].
-phi_arg(Phi, Pred) ->
- case lists:keyfind(Pred, 1, phi_arglist(Phi)) of
- false ->
- exit({?MODULE,phi_arg,{"Uknown Phi predecessor",Phi,{pred,Pred}}});
- {_, Var} -> Var
- end.
-phi_arglist(#phi{arglist=ArgList}) -> ArgList.
-phi_arglist_update(P,NewArgList) ->P#phi{arglist=NewArgList}.
-is_phi(#phi{}) -> true;
-is_phi(_) -> false.
-phi_enter_pred(Phi, Pred, Var) ->
- Phi#phi{arglist=[{Pred,Var}|lists:keydelete(Pred, 1, phi_arglist(Phi))]}.
-phi_remove_pred(Phi, Pred) ->
- NewArgList = lists:keydelete(Pred, 1, phi_arglist(Phi)),
- case NewArgList of
- [Arg] -> %% the phi should be turned into a move instruction
- {_Label,Var} = Arg,
- Dst = phi_dst(Phi),
- case {is_fpreg(Dst), is_fpreg(Var)} of
- {true, true} -> mk_fmove(Dst, Var);
- {false, false} -> mk_move(Dst, Var)
- end;
- %% io:format("~nPhi (~w) turned into move (~w) when removing pred ~w~n",[Phi,Move,Pred]),
- [_|_] ->
- Phi#phi{arglist=NewArgList}
- end.
-phi_argvar_subst(Phi, Subst) ->
- NewArgList = [{Pred,subst1(Subst, Var)} || {Pred,Var} <- phi_arglist(Phi)],
- Phi#phi{arglist=NewArgList}.
-phi_redirect_pred(P, OldPred, NewPred)->
- Subst = [{OldPred, NewPred}],
- NewArgList = [{subst1(Subst, Pred), Var} || {Pred,Var} <- phi_arglist(P)],
- P#phi{arglist=NewArgList}.
-
-
-%%
-%% alu
-%%
-
-mk_alu(Dst, Src1, Op, Src2) ->
- #alu{dst=Dst, src1=Src1, op=Op, src2=Src2}.
-alu_dst(#alu{dst=Dst}) -> Dst.
-alu_dst_update(Alu, NewDst) -> Alu#alu{dst=NewDst}.
-alu_src1(#alu{src1=Src1}) -> Src1.
-alu_src1_update(Alu, NewSrc) -> Alu#alu{src1=NewSrc}.
-alu_src2(#alu{src2=Src2}) -> Src2.
-alu_src2_update(Alu, NewSrc) -> Alu#alu{src2=NewSrc}.
-alu_op(#alu{op=Op}) -> Op.
-
-%%
-%% load
-%%
-
-mk_load(Dst, Src, Offset) -> mk_load(Dst, Src, Offset, word, unsigned).
-mk_load(Dst, Src, Offset, Size, Sign) ->
- ?ASSERT((Sign =:= unsigned) orelse (Sign =:= signed)),
- ?ASSERT((Size =:= word) orelse (Size =:= int32) orelse
- (Size =:= int16) orelse (Size =:= byte)),
- #load{dst=Dst, src=Src, offset=Offset, size=Size, sign=Sign}.
-load_dst(#load{dst=Dst}) -> Dst.
-load_dst_update(L, NewDst) -> L#load{dst=NewDst}.
-load_src(#load{src=Src}) -> Src.
-load_src_update(L, NewSrc) -> L#load{src=NewSrc}.
-load_offset(#load{offset=Offset}) -> Offset.
-load_offset_update(L, NewOffset) -> L#load{offset=NewOffset}.
-load_size(#load{size=Size}) -> Size.
-load_sign(#load{sign=Sign}) -> Sign.
-
-%%
-%% load_atom
-%%
-
-mk_load_atom(Dst, Atom) -> #load_atom{dst=Dst,atom=Atom}.
-load_atom_dst(#load_atom{dst=Dst}) -> Dst.
-load_atom_dst_update(L, NewDst) -> L#load_atom{dst=NewDst}.
-load_atom_atom(#load_atom{atom=Atom}) -> Atom.
-
-mk_load_word_index(Dst, Block, Index) ->
- #load_word_index{dst=Dst, block=Block, index=Index}.
-load_word_index_dst(#load_word_index{dst=Dst}) -> Dst.
-load_word_index_dst_update(L, NewDst) -> L#load_word_index{dst=NewDst}.
-load_word_index_block(#load_word_index{block=Block}) -> Block.
-load_word_index_index(#load_word_index{index=Index}) -> Index.
-
-mk_goto_index(Block, Index, Labels) ->
- #goto_index{block=Block, index=Index, labels=Labels}.
-goto_index_block(#goto_index{block=Block}) -> Block.
-goto_index_index(#goto_index{index=Index}) -> Index.
-goto_index_labels(#goto_index{labels=Labels}) -> Labels.
-
-%%
-%% load_address
-%%
-
-mk_load_address(Dst, Addr, Type) ->
- #load_address{dst=Dst, addr=Addr, type=Type}.
-load_address_dst(#load_address{dst=Dst}) -> Dst.
-load_address_dst_update(LA, NewDst) -> LA#load_address{dst=NewDst}.
-load_address_addr(#load_address{addr=Addr}) -> Addr.
-load_address_addr_update(LoadAddress, NewAdr) ->
- LoadAddress#load_address{addr=NewAdr}.
-load_address_type(#load_address{type=Type}) -> Type.
-%% load_address_type_update(LA, NewType) -> LA#load_address{type=NewType}.
-
-%%
-%% store
-%%
-
-mk_store(Base, Offset, Src) -> mk_store(Base, Offset, Src, word).
-mk_store(Base, Offset, Src, Size) ->
- ?ASSERT((Size =:= word) orelse (Size =:= int32) orelse
- (Size =:= int16) orelse (Size =:= byte)),
- #store{base=Base, src=Src, offset=Offset, size=Size}.
-store_base(#store{base=Base}) -> Base.
-store_base_update(S, NewBase) -> S#store{base=NewBase}.
-store_offset(#store{offset=Offset}) -> Offset.
-store_offset_update(S, NewOffset) -> S#store{offset=NewOffset}.
-store_src(#store{src=Src}) -> Src.
-store_src_update(S, NewSrc) -> S#store{src=NewSrc}.
-store_size(#store{size=Size}) -> Size.
-
-%%
-%% label
-%%
-
-mk_label(Name) -> #label{name=Name}.
-mk_new_label() -> mk_label(hipe_gensym:get_next_label(rtl)).
-label_name(#label{name=Name}) -> Name.
-is_label(#label{}) -> true;
-is_label(_) -> false.
-
-%%
-%% alub
-%%
-
--type alub_cond() :: 'eq' | 'ne' | 'ge' | 'geu' | 'gt' | 'gtu' | 'le'
- | 'leu' | 'lt' | 'ltu' | 'overflow' | 'not_overflow'.
-
-mk_branch(Src1, Cond, Src2, True, False) ->
- mk_branch(Src1, Cond, Src2, True, False, 0.5).
-mk_branch(Src1, Cond, Src2, True, False, P) ->
- mk_branch(Src1, 'sub', Src2, Cond, True, False, P).
-mk_branch(Src1, Op, Src2, Cond, True, False, P) ->
- mk_alub([], Src1, Op, Src2, Cond, True, False, P).
-
-mk_alub(Dst, Src1, Op, Src2, Cond, True, False) ->
- mk_alub(Dst, Src1, Op, Src2, Cond, True, False, 0.5).
-mk_alub(Dst, Src1, Op, Src2, Cond, True, False, P) ->
- #alub{dst=Dst, src1=Src1, op=Op, src2=Src2, 'cond'=Cond,
- true_label=True, false_label=False, p=P}.
-alub_has_dst(#alub{dst=Dst}) -> Dst =/= [].
-alub_dst(#alub{dst=Dst}) -> Dst.
-alub_dst_update(A, NewDst) -> A#alub{dst=NewDst}.
-alub_src1(#alub{src1=Src1}) -> Src1.
-alub_src1_update(A, NewSrc) -> A#alub{src1=NewSrc}.
-alub_op(#alub{op=Op}) -> Op.
-alub_src2(#alub{src2=Src2}) -> Src2.
-alub_src2_update(A, NewSrc) -> A#alub{src2=NewSrc}.
-alub_cond(#alub{'cond'=Cond}) -> Cond.
-alub_true_label(#alub{true_label=TrueLbl}) -> TrueLbl.
-alub_true_label_update(A, NewTrue) -> A#alub{true_label=NewTrue}.
-alub_false_label(#alub{false_label=FalseLbl}) -> FalseLbl.
-alub_false_label_update(A, NewFalse) -> A#alub{false_label=NewFalse}.
-alub_pred(#alub{p=P}) -> P.
-
-%%
-%% switch
-%%
-
-mk_switch(Src, Labels) -> #switch{src=Src, labels=Labels}.
-mk_sorted_switch(Src, Labels, Order) ->
- #switch{src=Src, labels=Labels, sorted_by=Order}.
-switch_src(#switch{src=Src}) -> Src.
-switch_src_update(I, N) -> I#switch{src=N}.
-switch_labels(#switch{labels=Labels}) -> Labels.
-switch_labels_update(I,N) -> I#switch{labels=N}.
-switch_sort_order(#switch{sorted_by=Order}) -> Order.
-%% switch_sort_order_update(I,N) -> I#switch{sorted_by=N}.
-
-%%
-%% goto
-%%
-
-mk_goto(Label) -> #goto{label=Label}.
-goto_label(#goto{label=Label}) -> Label.
-goto_label_update(I, NewLabel) ->
- I#goto{label=NewLabel}.
-is_goto(#goto{}) -> true;
-is_goto(_) -> false.
-
-%%
-%% call
-%%
-
-%% LLVM: Call with normal continuation
-mk_call(DstList, Fun, ArgList, Continuation, FailContinuation,
- NormalContinuation, Type) ->
- case Type of
- remote -> ok;
- not_remote -> ok
- end,
- #call{dstlist=DstList, 'fun'=Fun, arglist=ArgList, type=Type,
- continuation=Continuation, failcontinuation=FailContinuation,
- normalcontinuation=NormalContinuation}.
-
-mk_call(DstList, Fun, ArgList, Continuation, FailContinuation, Type) ->
- case Type of
- remote -> ok;
- not_remote -> ok
- end,
- #call{dstlist=DstList, 'fun'=Fun, arglist=ArgList, type=Type,
- continuation=Continuation,
- failcontinuation=FailContinuation}.
-
-call_normal(#call{normalcontinuation=NormalContinuation}) -> NormalContinuation.
-call_normal_update(C, NewNormalContinuation) ->
- C#call{normalcontinuation=NewNormalContinuation}.
-call_dstlist(#call{dstlist=DstList}) -> DstList.
-call_dstlist_update(C, NewDstList) -> C#call{dstlist=NewDstList}.
-call_fun(#call{'fun'=Fun}) -> Fun.
-call_fun_update(C, F) -> C#call{'fun'=F}.
-call_arglist(#call{arglist=ArgList}) -> ArgList.
-call_arglist_update(C, NewArgList) -> C#call{arglist=NewArgList}.
-call_continuation(#call{continuation=Continuation}) -> Continuation.
-call_fail(#call{failcontinuation=FailContinuation}) -> FailContinuation.
-call_type(#call{type=Type}) -> Type.
-call_continuation_update(C, NewCont) -> C#call{continuation=NewCont}.
-call_fail_update(C, NewCont) -> C#call{failcontinuation=NewCont}.
-is_call(#call{}) -> true;
-is_call(_) -> false.
-call_is_known(C) ->
- Fun = call_fun(C),
- call_or_enter_fun_is_known(Fun).
-
-call_or_enter_fun_is_known(Fun) ->
- case is_atom(Fun) of
- true -> true; %% make the expected common case fast
- false ->
- case is_reg(Fun) of
- true -> false;
- false ->
- case is_var(Fun) of
- true -> false;
- false ->
- case Fun of
- {M,F,A} when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
- true;
- {F,A} when is_atom(F), is_integer(A), A >= 0 ->
- true;
- _ -> %% colored versions of rtl_reg or rtl_var (used in SSA)
- false
- end
- end
- end
- end.
-
-%%
-%% enter
-%%
-
-mk_enter(Fun, ArgList, Type) ->
- case Type of
- remote -> ok;
- not_remote -> ok % {local,primop,closure,pointer}
- end,
- #enter{'fun'=Fun, arglist=ArgList, type=Type}.
-enter_fun(#enter{'fun'=Fun}) -> Fun.
-enter_fun_update(I, F) -> I#enter{'fun' = F}.
-enter_arglist(#enter{arglist=ArgList}) -> ArgList.
-enter_arglist_update(E, NewArgList) -> E#enter{arglist=NewArgList}.
-enter_type(#enter{type=Type}) -> Type.
-enter_is_known(E) ->
- Fun = enter_fun(E),
- call_or_enter_fun_is_known(Fun).
-
-%%
-%% return
-%%
-
-mk_return(VarList) -> #return{varlist=VarList}.
-return_varlist(#return{varlist=VarList}) -> VarList.
-return_varlist_update(R, NewVarList) -> R#return{varlist=NewVarList}.
-
-%%
-%% gctests
-%%
-
-mk_gctest(Words) when is_integer(Words) -> #gctest{words=mk_imm(Words)};
-mk_gctest(Reg) -> #gctest{words=Reg}. % This handles rtl_regs and rtl_vars
-gctest_words(#gctest{words=Words}) -> Words.
-gctest_words_update(S, NewWords) -> S#gctest{words=NewWords}.
-
-
-%%
-%% fixnumop
-%%
-
-mk_fixnumop(Dst, Src, Type) ->
- #fixnumop{dst=Dst, src=Src, type=Type}.
-fixnumop_dst(#fixnumop{dst=Dst}) -> Dst.
-fixnumop_dst_update(S, Dst) -> S#fixnumop{dst=Dst}.
-fixnumop_src(#fixnumop{src=Src}) -> Src.
-fixnumop_src_update(S, Src) -> S#fixnumop{src=Src}.
-fixnumop_type(#fixnumop{type=Type}) -> Type.
-
-%%
-%% comments
-%%
-
-mk_comment(Text) -> #comment{text=Text}.
-comment_text(#comment{text=Text}) -> Text.
-is_comment(#comment{}) -> true;
-is_comment(_) -> false.
-
-%%-------------------------------------------------------------------------
-%% Floating point stuff.
-%%-------------------------------------------------------------------------
-
-%%
-%% fload
-%%
-
-mk_fload(Dst, Src, Offset) -> #fload{dst=Dst, src=Src, offset=Offset}.
-fload_dst(#fload{dst=Dst}) -> Dst.
-fload_dst_update(L, NewDst) -> L#fload{dst=NewDst}.
-fload_src(#fload{src=Src}) -> Src.
-fload_src_update(L, NewSrc) -> L#fload{src=NewSrc}.
-fload_offset(#fload{offset=Offset}) -> Offset.
-fload_offset_update(L, NewOffset) -> L#fload{offset=NewOffset}.
-
-%%
-%% fstore
-%%
-
-mk_fstore(Base, Offset, Src) ->
- #fstore{base=Base, offset=Offset, src=Src}.
-fstore_base(#fstore{base=Base}) -> Base.
-fstore_base_update(F, NewBase) -> F#fstore{base=NewBase}.
-fstore_offset(#fstore{offset=Offset}) -> Offset.
-fstore_offset_update(F, NewOff) -> F#fstore{offset=NewOff}.
-fstore_src(#fstore{src=Src}) -> Src.
-fstore_src_update(F, NewSrc) -> F#fstore{src=NewSrc}.
-
-%%
-%% fp
-%%
-
-
-mk_fp(Dst, Src1, Op, Src2) ->
- [#fp{dst=Dst, src1=Src1, op=Op, src2=Src2}
- | hipe_rtl_arch:mk_fp_check_result(Dst)].
-
-fp_dst(#fp{dst=Dst}) -> Dst.
-fp_dst_update(Fp, NewDst) -> Fp#fp{dst=NewDst}.
-fp_src1(#fp{src1=Src1}) -> Src1.
-fp_src1_update(Fp, NewSrc) -> Fp#fp{src1=NewSrc}.
-fp_src2(#fp{src2=Src2}) -> Src2.
-fp_src2_update(Fp, NewSrc) -> Fp#fp{src2=NewSrc}.
-fp_op(#fp{op=Op}) -> Op.
-
-%%
-%% fp_unop
-%%
-
-mk_fp_unop(Dst, Src, Op) ->
- #fp_unop{dst=Dst, src=Src, op=Op}.
-fp_unop_dst(#fp_unop{dst=Dst}) -> Dst.
-fp_unop_dst_update(Fp, NewDst) -> Fp#fp_unop{dst=NewDst}.
-fp_unop_src(#fp_unop{src=Src}) -> Src.
-fp_unop_src_update(Fp, NewSrc) -> Fp#fp_unop{src=NewSrc}.
-fp_unop_op(#fp_unop{op=Op}) -> Op.
-
-%%
-%% fmove
-%%
-
-mk_fmove(X, Y) -> true = is_fpreg(X), true = is_fpreg(Y), #fmove{dst=X, src=Y}.
-fmove_dst(#fmove{dst=Dst}) -> Dst.
-fmove_dst_update(M, NewDst) -> true = is_fpreg(NewDst), M#fmove{dst=NewDst}.
-fmove_src(#fmove{src=Src}) -> Src.
-fmove_src_update(M, NewSrc) -> true = is_fpreg(NewSrc), M#fmove{src=NewSrc}.
-
-%%
-%% fconv
-%%
-
-mk_fconv(X, Y) -> #fconv{dst=X, src=Y}.
-fconv_dst(#fconv{dst=Dst}) -> Dst.
-fconv_dst_update(C, NewDst) -> C#fconv{dst=NewDst}.
-fconv_src(#fconv{src=Src}) -> Src.
-fconv_src_update(C, NewSrc) -> C#fconv{src=NewSrc}.
-
-%%
-%% The values
-%%
-%% change_vars_to_regs(Vars) ->
-%% change_vars_to_regs(Vars, []).
-%% change_vars_to_regs([Var|Rest], Acc) ->
-%% change_vars_to_regs(Rest,[change_var_to_reg(Var)|Acc]);
-%% change_vars_to_regs([], Acc) ->
-%% lists:reverse(Acc).
-%%
-%% change_var_to_reg(Var) ->
-%% mk_reg(var_index(Var)).
-
--record(rtl_reg, {index :: integer(),
- is_gc_safe :: boolean()}).
-
-mk_reg(Num, IsGcSafe) when is_integer(Num), Num >= 0 ->
- #rtl_reg{index=Num,is_gc_safe=IsGcSafe}.
-mk_reg(Num) -> mk_reg(Num, false).
-mk_reg_gcsafe(Num) -> mk_reg(Num, true).
-mk_new_reg() -> mk_reg(hipe_gensym:get_next_var(rtl), false).
-mk_new_reg_gcsafe() -> mk_reg(hipe_gensym:get_next_var(rtl), true).
-reg_index(#rtl_reg{index=Index}) -> Index.
-reg_is_gcsafe(#rtl_reg{is_gc_safe=IsGcSafe}) -> IsGcSafe.
-is_reg(#rtl_reg{}) -> true;
-is_reg(_) -> false.
-
--record(rtl_var, {index :: non_neg_integer(), liveness=live :: dead | live}).
-
-mk_var(Num) when is_integer(Num), Num >= 0 -> #rtl_var{index=Num}.
-mk_var(Num, Liveness) when is_integer(Num), Num>=0 -> #rtl_var{index=Num, liveness=Liveness}.
-mk_new_var() -> mk_var(hipe_gensym:get_next_var(rtl)).
-var_index(#rtl_var{index=Index}) -> Index.
-var_liveness(#rtl_var{liveness=Liveness}) -> Liveness.
-var_liveness_update(RtlVar, Liveness) -> RtlVar#rtl_var{liveness=Liveness}.
-is_var(#rtl_var{}) -> true;
-is_var(_) -> false.
-
--record(rtl_fpreg, {index :: non_neg_integer()}).
-
-mk_fpreg(Num) when is_integer(Num), Num >= 0 -> #rtl_fpreg{index=Num}.
-mk_new_fpreg() -> mk_fpreg(hipe_gensym:get_next_var(rtl)).
-fpreg_index(#rtl_fpreg{index=Index}) -> Index.
-is_fpreg(#rtl_fpreg{}) -> true;
-is_fpreg(_) -> false.
-
--record(rtl_imm, {value}).
-
-mk_imm(Value) -> #rtl_imm{value=Value}.
-imm_value(#rtl_imm{value=Value}) -> Value.
-is_imm(#rtl_imm{}) -> true;
-is_imm(_) -> false.
-
--record(rtl_const_lbl, {label}).
-
-mk_const_label(Label) -> #rtl_const_lbl{label=Label}.
-const_label_label(#rtl_const_lbl{label=Label}) -> Label.
-is_const_label(#rtl_const_lbl{}) -> true;
-is_const_label(_) -> false.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Utilities - no representation visible below this point
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%
-%% @doc Returns the list of variables, constant labels and immediates
-%% an RTL instruction uses.
-%%
-
-uses(I) ->
- remove_imms_and_const_lbls(args(I)).
-
-%%
-%% @doc Returns the list of variables an RTL instruction uses.
-%%
-
-args(I) ->
- case I of
- #alu{} -> [alu_src1(I), alu_src2(I)];
- #alub{} -> [alub_src1(I), alub_src2(I)];
- #call{} ->
- Args = call_arglist(I) ++ hipe_rtl_arch:call_used(),
- case call_is_known(I) of
- false -> [call_fun(I) | Args];
- true -> Args
- end;
- #comment{} -> [];
- #enter{} ->
- Args = enter_arglist(I) ++ hipe_rtl_arch:tailcall_used(),
- case enter_is_known(I) of
- false -> [enter_fun(I) | Args];
- true -> Args
- end;
- #fconv{} -> [fconv_src(I)];
- #fixnumop{} -> [fixnumop_src(I)];
- #fload{} -> [fload_src(I), fload_offset(I)];
- #fmove{} -> [fmove_src(I)];
- #fp{} -> [fp_src1(I), fp_src2(I)];
- #fp_unop{} -> [fp_unop_src(I)];
- #fstore{} -> [fstore_base(I), fstore_offset(I), fstore_src(I)];
- #goto{} -> [];
- #goto_index{} -> [];
- #gctest{} -> [gctest_words(I)];
- #label{} -> [];
- #load{} -> [load_src(I), load_offset(I)];
- #load_address{} -> [];
- #load_atom{} -> [];
- #load_word_index{} -> [];
- #move{} -> [move_src(I)];
- #multimove{} -> multimove_srclist(I);
- #phi{} -> phi_args(I);
- #return{} -> return_varlist(I) ++ hipe_rtl_arch:return_used();
- #store{} -> [store_base(I), store_offset(I), store_src(I)];
- #switch{} -> [switch_src(I)]
- end.
-
-%%
-%% @doc Returns a list of variables that an RTL instruction defines.
-%%
-
-defines(Instr) ->
- Defs = case Instr of
- #alu{} -> [alu_dst(Instr)];
- #alub{dst=[]} -> [];
- #alub{} -> [alub_dst(Instr)];
- #call{} -> call_dstlist(Instr) ++ hipe_rtl_arch:call_defined();
- #comment{} -> [];
- #enter{} -> [];
- #fconv{} -> [fconv_dst(Instr)];
- #fixnumop{} -> [fixnumop_dst(Instr)];
- #fload{} -> [fload_dst(Instr)];
- #fmove{} -> [fmove_dst(Instr)];
- #fp{} -> [fp_dst(Instr)];
- #fp_unop{} -> [fp_unop_dst(Instr)];
- #fstore{} -> [];
- #gctest{} -> [];
- #goto{} -> [];
- #goto_index{} -> [];
- #label{} -> [];
- #load{} -> [load_dst(Instr)];
- #load_address{} -> [load_address_dst(Instr)];
- #load_atom{} -> [load_atom_dst(Instr)];
- #load_word_index{} -> [load_word_index_dst(Instr)];
- #move{} -> [move_dst(Instr)];
- #multimove{} -> multimove_dstlist(Instr);
- #phi{} -> [phi_dst(Instr)];
- #return{} -> [];
- #store{} -> [];
- #switch{} -> []
- end,
- remove_imms_and_const_lbls(Defs).
-
-%% @spec remove_imms_and_const_lbls([rtl_argument()]) -> [rtl_argument()]
-%%
-%% @doc Removes all RTL immediates and constant labels from a list of arguments.
-
-remove_imms_and_const_lbls([]) ->
- [];
-remove_imms_and_const_lbls([Arg|Args]) ->
- case is_imm(Arg) orelse is_const_label(Arg) of
- true -> remove_imms_and_const_lbls(Args);
- false -> [Arg | remove_imms_and_const_lbls(Args)]
- end.
-
-%%
-%% Substitution: replace occurrences of X by Y if {X,Y} is in Subst.
-%%
-%% subst(Subst, X) ->
-%% subst_defines(Subst, subst_uses(Subst,X)).
-
-subst_uses(Subst, I) ->
- case I of
- #alu{} ->
- I0 = alu_src1_update(I, subst1(Subst, alu_src1(I))),
- alu_src2_update(I0, subst1(Subst, alu_src2(I)));
- #alub{} ->
- I0 = alub_src1_update(I, subst1(Subst, alub_src1(I))),
- alub_src2_update(I0, subst1(Subst, alub_src2(I)));
- #call{} ->
- case call_is_known(I) of
- false ->
- I0 = call_fun_update(I, subst1(Subst, call_fun(I))),
- call_arglist_update(I0, subst_list(Subst, call_arglist(I0)));
- true ->
- call_arglist_update(I, subst_list(Subst, call_arglist(I)))
- end;
- #comment{} ->
- I;
- #enter{} ->
- case enter_is_known(I) of
- false ->
- I0 = enter_fun_update(I, subst1(Subst, enter_fun(I))),
- enter_arglist_update(I0, subst_list(Subst, enter_arglist(I0)));
- true ->
- enter_arglist_update(I, subst_list(Subst, enter_arglist(I)))
- end;
- #fconv{} ->
- fconv_src_update(I, subst1(Subst, fconv_src(I)));
- #fixnumop{} ->
- fixnumop_src_update(I, subst1(Subst, fixnumop_src(I)));
- #fload{} ->
- I0 = fload_src_update(I, subst1(Subst, fload_src(I))),
- fload_offset_update(I0, subst1(Subst, fload_offset(I)));
- #fmove{} ->
- fmove_src_update(I, subst1(Subst, fmove_src(I)));
- #fp{} ->
- I0 = fp_src1_update(I, subst1(Subst, fp_src1(I))),
- fp_src2_update(I0, subst1(Subst, fp_src2(I)));
- #fp_unop{} ->
- fp_unop_src_update(I, subst1(Subst, fp_unop_src(I)));
- #fstore{} ->
- I0 = fstore_src_update(I, subst1(Subst, fstore_src(I))),
- I1 = fstore_base_update(I0, subst1(Subst, fstore_base(I))),
- fstore_offset_update(I1, subst1(Subst, fstore_offset(I)));
- #goto{} ->
- I;
- #goto_index{} ->
- I;
- #gctest{} ->
- gctest_words_update(I, subst1(Subst, gctest_words(I)));
- #label{} ->
- I;
- #load{} ->
- I0 = load_src_update(I, subst1(Subst, load_src(I))),
- load_offset_update(I0, subst1(Subst, load_offset(I)));
- #load_address{} ->
- I;
- #load_atom{} ->
- I;
- #load_word_index{} ->
- I;
- #move{} ->
- move_src_update(I, subst1(Subst, move_src(I)));
- #multimove{} ->
- multimove_srclist_update(I, subst_list(Subst, multimove_srclist(I)));
- #phi{} ->
- phi_argvar_subst(I, Subst);
- #return{} ->
- return_varlist_update(I, subst_list(Subst, return_varlist(I)));
- #store{} ->
- I0 = store_src_update(I, subst1(Subst, store_src(I))),
- I1 = store_base_update(I0, subst1(Subst, store_base(I))),
- store_offset_update(I1, subst1(Subst, store_offset(I)));
- #switch{} ->
- switch_src_update(I, subst1(Subst, switch_src(I)))
- end.
-
-subst_uses_llvm(Subst, I) ->
- case I of
- #alu{} ->
- {NewSrc2, Subst1} = subst1_llvm(Subst, alu_src2(I)),
- {NewSrc1, _ } = subst1_llvm(Subst1, alu_src1(I)),
- I0 = alu_src1_update(I, NewSrc1),
- alu_src2_update(I0, NewSrc2);
- #alub{} ->
- {NewSrc2, Subst1} = subst1_llvm(Subst, alub_src2(I)),
- {NewSrc1, _ } = subst1_llvm(Subst1, alub_src1(I)),
- I0 = alub_src1_update(I, NewSrc1),
- alub_src2_update(I0, NewSrc2);
- #call{} ->
- case call_is_known(I) of
- false ->
- {NewFun, Subst1} = subst1_llvm(Subst, call_fun(I)),
- {NewArgList, _} = subst_list_llvm(Subst1, call_arglist(I)),
- I0 = call_fun_update(I, NewFun),
- call_arglist_update(I0, NewArgList);
- true ->
- {NewArgList, _} = subst_list_llvm(Subst, call_arglist(I)),
- call_arglist_update(I, NewArgList)
- end;
- #comment{} ->
- I;
- #enter{} ->
- case enter_is_known(I) of
- false ->
- {NewFun, Subst1} = subst1_llvm(Subst, enter_fun(I)),
- {NewArgList, _} = subst_list_llvm(Subst1, enter_arglist(I)),
- I0 = enter_fun_update(I, NewFun),
- enter_arglist_update(I0, NewArgList);
- true ->
- {NewArgList, _} = subst_list_llvm(Subst, enter_arglist(I)),
- enter_arglist_update(I, NewArgList)
- end;
- #fconv{} ->
- {NewSrc, _ } = subst1_llvm(Subst, fconv_src(I)),
- fconv_src_update(I, NewSrc);
- #fixnumop{} ->
- {NewSrc, _ } = subst1_llvm(Subst, fixnumop_src(I)),
- fixnumop_src_update(I, NewSrc);
- #fload{} ->
- {NewSrc, Subst1} = subst1_llvm(Subst, fload_src(I)),
- {NewOffset, _ } = subst1_llvm(Subst1, fload_offset(I)),
- I0 = fload_src_update(I, NewSrc),
- fload_offset_update(I0, NewOffset);
- #fmove{} ->
- {NewSrc, _ } = subst1_llvm(Subst, fmove_src(I)),
- fmove_src_update(I, NewSrc);
- #fp{} ->
- {NewSrc2, Subst1} = subst1_llvm(Subst, fp_src2(I)),
- {NewSrc1, _ } = subst1_llvm(Subst1, fp_src1(I)),
- I0 = fp_src1_update(I, NewSrc1),
- fp_src2_update(I0, NewSrc2);
- #fp_unop{} ->
- {NewSrc, _ } = subst1_llvm(Subst, fp_unop_src(I)),
- fp_unop_src_update(I, NewSrc);
- #fstore{} ->
- {NewSrc, Subst1} = subst1_llvm(Subst, fstore_src(I)),
- {NewBase, Subst2} = subst1_llvm(Subst1, fstore_base(I)),
- {NewOffset, _ } = subst1_llvm(Subst2, fstore_offset(I)),
- I0 = fstore_src_update(I, NewSrc),
- I1 = fstore_base_update(I0, NewBase),
- fstore_offset_update(I1, NewOffset);
- #goto{} ->
- I;
- #goto_index{} ->
- I;
- #gctest{} ->
- {NewWords, _ } = subst1_llvm(Subst, gctest_words(I)),
- gctest_words_update(I, NewWords);
- #label{} ->
- I;
- #load{} ->
- {NewSrc, Subst1} = subst1_llvm(Subst, load_src(I)),
- {NewOffset, _ } = subst1_llvm(Subst1, load_offset(I)),
- I0 = load_src_update(I, NewSrc),
- load_offset_update(I0, NewOffset);
- #load_address{} ->
- I;
- #load_atom{} ->
- I;
- #load_word_index{} ->
- I;
- #move{} ->
- {NewSrc, _ } = subst1_llvm(Subst, move_src(I)),
- move_src_update(I, NewSrc);
- #multimove{} ->
- {NewSrcList, _} = subst_list_llvm(Subst, multimove_srclist(I)),
- multimove_srclist_update(I, NewSrcList);
- #phi{} ->
- phi_argvar_subst(I, Subst);
- #return{} ->
- {NewVarList, _} = subst_list_llvm(Subst, return_varlist(I)),
- return_varlist_update(I, NewVarList);
- #store{} ->
- {NewSrc, Subst1} = subst1_llvm(Subst, store_src(I)),
- {NewBase, Subst2} = subst1_llvm(Subst1, store_base(I)),
- {NewOffset, _ } = subst1_llvm(Subst2, store_offset(I)),
- I0 = store_src_update(I, NewSrc),
- I1 = store_base_update(I0, NewBase),
- store_offset_update(I1, NewOffset);
- #switch{} ->
- {NewSrc, _ } = subst1_llvm(Subst, switch_src(I)),
- switch_src_update(I, NewSrc)
- end.
-
-subst_list_llvm(S,X) -> subst_list_llvm(S, lists:reverse(X), []).
-subst_list_llvm(S, [], Acc) -> {Acc, S};
-subst_list_llvm(S, [X|Xs], Acc) ->
- {NewX, RestS} = subst1_llvm(S, X),
- subst_list_llvm(RestS, Xs, [NewX|Acc]).
-
-subst1_llvm(A,B) -> subst1_llvm(A,B,[]).
-
-subst1_llvm([], X, Acc) -> {X, Acc};
-subst1_llvm([{X,Y}|Rs], X, Acc) -> {Y, Acc++Rs};
-subst1_llvm([R|Xs], X, Acc) -> subst1_llvm(Xs,X,[R|Acc]).
-
-subst_defines(Subst, I)->
- case I of
- #alu{} ->
- alu_dst_update(I, subst1(Subst, alu_dst(I)));
- #alub{dst=[]} ->
- I;
- #alub{} ->
- alub_dst_update(I, subst1(Subst, alub_dst(I)));
- #call{} ->
- call_dstlist_update(I, subst_list(Subst, call_dstlist(I)));
- #comment{} ->
- I;
- #enter{} ->
- I;
- #fconv{} ->
- fconv_dst_update(I, subst1(Subst, fconv_dst(I)));
- #fixnumop{} ->
- fixnumop_dst_update(I, subst1(Subst, fixnumop_dst(I)));
- #fload{} ->
- fload_dst_update(I, subst1(Subst, fload_dst(I)));
- #fmove{} ->
- fmove_dst_update(I, subst1(Subst, fmove_dst(I)));
- #fp{} ->
- fp_dst_update(I, subst1(Subst, fp_dst(I)));
- #fp_unop{} ->
- fp_unop_dst_update(I, subst1(Subst, fp_unop_dst(I)));
- #fstore{} ->
- I;
- #gctest{} ->
- I;
- #goto{} ->
- I;
- #goto_index{} ->
- I;
- #label{} ->
- I;
- #load{} ->
- load_dst_update(I, subst1(Subst, load_dst(I)));
- #load_address{} ->
- load_address_dst_update(I, subst1(Subst, load_address_dst(I)));
- #load_atom{} ->
- load_atom_dst_update(I, subst1(Subst, load_atom_dst(I)));
- #load_word_index{} ->
- load_word_index_dst_update(I, subst1(Subst, load_word_index_dst(I)));
- #move{} ->
- move_dst_update(I, subst1(Subst, move_dst(I)));
- #multimove{} ->
- multimove_dstlist_update(I, subst_list(Subst, multimove_dstlist(I)));
- #phi{} ->
- phi_dst_update(I, subst1(Subst, phi_dst(I)));
- #return{} ->
- I;
- #store{} ->
- I;
- #switch{} ->
- I
- end.
-
-subst_list(S, Xs) ->
- [subst1(S, X) || X <- Xs].
-
-subst1([], X) -> X;
-subst1([{X,Y}|_], X) -> Y;
-subst1([_|Xs], X) -> subst1(Xs,X).
-
-%% @spec is_safe(rtl_instruction()) -> boolean()
-%%
-%% @doc Succeeds if an RTL instruction is safe and can be deleted if the
-%% result is not used.
-
-is_safe(Instr) ->
- case Instr of
- #alu{} -> true;
- #alub{} -> false;
- #call{} -> false;
- #comment{} -> false;
- #enter{} -> false;
- #fconv{} -> true;
- #fixnumop{} -> true;
- #fload{} -> true;
- #fmove{} -> true;
- #fp{} -> false;
- #fp_unop{} -> false;
- #fstore{} -> false;
- #gctest{} -> false;
- #goto{} -> false;
- #goto_index{} -> false; % ???
- #label{} -> true;
- #load{} -> true;
- #load_address{} -> true;
- #load_atom{} -> true;
- #load_word_index{} -> true;
- #move{} -> true;
- #multimove{} -> true;
- #phi{} -> true;
- #return{} -> false;
- #store{} -> false;
- #switch{} -> false %% Maybe this is safe...
- end.
-
-%% @spec reduce_unused(rtl_instruction())
-%% -> false | [rtl_instruction()].
-%%
-%% @doc Produces a simplified instruction sequence that is equivalent to [Instr]
-%% under the assumption that all results of Instr are unused, or 'false' if
-%% there is no such sequence (other than [Instr] itself).
-
-reduce_unused(Instr) ->
- case Instr of
- #alub{dst=Dst} when Dst =/= [] ->
- [Instr#alub{dst=[]}];
- _ ->
- case is_safe(Instr) of
- true -> [];
- false -> false
- end
- end.
-
-%%
-%% True if argument is an alu-operator
-%%
-
-%% is_alu_op(add) -> true;
-%% is_alu_op(sub) -> true;
-%% is_alu_op('or') -> true;
-%% is_alu_op('and') -> true;
-%% is_alu_op('xor') -> true;
-%% is_alu_op(andnot) -> true;
-%% is_alu_op(sll) -> true;
-%% is_alu_op(srl) -> true;
-%% is_alu_op(sra) -> true;
-%% is_alu_op(_) -> false.
-
-%% @spec is_shift_op(rtl_operator()) -> boolean()
-%%
-%% @doc Succeeds if its argument is an RTL operator.
-is_shift_op(sll) -> true;
-is_shift_op(srl) -> true;
-is_shift_op(sra) -> true;
-is_shift_op(_) -> false.
-
-
-%%
-%% True if argument is an relational operator
-%%
-
-%% is_rel_op(eq) -> true;
-%% is_rel_op(ne) -> true;
-%% is_rel_op(gt) -> true;
-%% is_rel_op(gtu) -> true;
-%% is_rel_op(ge) -> true;
-%% is_rel_op(geu) -> true;
-%% is_rel_op(lt) -> true;
-%% is_rel_op(ltu) -> true;
-%% is_rel_op(le) -> true;
-%% is_rel_op(leu) -> true;
-%% is_rel_op(overflow) -> true;
-%% is_rel_op(not_overflow) -> true;
-%% is_rel_op(_) -> false.
-
-redirect_jmp(Jmp, ToOld, ToNew) ->
- %% OBS: In a jmp instruction more than one labels may be identical
- %% and thus need redirection!
- case Jmp of
- #switch{} ->
- NewLbls = [case Lbl =:= ToOld of
- true -> ToNew;
- false -> Lbl
- end || Lbl <- switch_labels(Jmp)],
- switch_labels_update(Jmp, NewLbls);
- #alub{} ->
- TmpJmp = case alub_true_label(Jmp) of
- ToOld -> alub_true_label_update(Jmp, ToNew);
- _ -> Jmp
- end,
- case alub_false_label(TmpJmp) of
- ToOld -> alub_false_label_update(TmpJmp, ToNew);
- _ -> TmpJmp
- end;
- #goto{} ->
- case goto_label(Jmp) of
- ToOld -> goto_label_update(Jmp, ToNew);
- _ -> Jmp
- end;
- #call{} ->
- TmpJmp = case call_continuation(Jmp) of
- ToOld -> call_continuation_update(Jmp, ToNew);
- _ -> Jmp
- end,
- case call_fail(TmpJmp) of
- ToOld -> call_fail_update(TmpJmp, ToNew);
- _ -> TmpJmp
- end;
- _ ->
- Jmp
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% highest_var(Code) ->
-%% highest_var(Code,0).
-%%
-%% highest_var([I|Is],Max) ->
-%% Defs = defines(I),
-%% Uses = uses(I),
-%% highest_var(Is,new_max(Defs++Uses,Max));
-%% highest_var([],Max) ->
-%% Max.
-%%
-%% new_max([V|Vs],Max) ->
-%% VName =
-%% case is_var(V) of
-%% true ->
-%% var_index(V);
-%% false ->
-%% case is_fpreg(V) of
-%% true ->
-%% fpreg_index(V);
-%% _ ->
-%% reg_index(V)
-%% end
-%% end,
-%% if VName > Max ->
-%% new_max(Vs, VName);
-%% true ->
-%% new_max(Vs, Max)
-%% end;
-%% new_max([],Max) ->
-%% Max.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% @doc Pretty-printer for RTL.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-pp(Rtl) ->
- pp(standard_io, Rtl).
-
-pp_block(Instrs) ->
- pp_instrs(standard_io, Instrs).
-
-pp(Dev, Rtl) ->
- io:format(Dev, "~w(", [rtl_fun(Rtl)]),
- pp_args(Dev, rtl_params(Rtl)),
- io:format(Dev, ") ->~n", []),
- case rtl_is_closure(Rtl) of
- true ->
- io:format(Dev, ";; Closure\n", []);
- false -> ok
- end,
- case rtl_is_leaf(Rtl) of
- true ->
- io:format(Dev, ";; Leaf function\n", []);
- false -> ok
- end,
- io:format(Dev, ";; Info: ~w\n", [rtl_info(Rtl)]),
- io:format(Dev, ".DataSegment\n", []),
- hipe_data_pp:pp(Dev, rtl_data(Rtl), rtl, ""),
- io:format(Dev, ".CodeSegment\n", []),
- pp_instrs(Dev, rtl_code(Rtl)).
-
-pp_instrs(_Dev, []) ->
- ok;
-pp_instrs(Dev, [I|Is]) ->
- try pp_instr(Dev, I)
- catch _:_ -> io:format("*** ~w ***\n", [I])
- end,
- pp_instrs(Dev, Is).
-
-pp_instr(Dev, I) ->
- case I of
- #phi{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, phi_dst(I)),
- io:format(Dev, " <- phi(", []),
- pp_phi_args(Dev, phi_arglist(I)),
- io:format(Dev, ")~n", []);
- #move{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, move_dst(I)),
- io:format(Dev, " <- ", []),
- pp_arg(Dev, move_src(I)),
- io:format(Dev, "~n", []);
- #multimove{} ->
- io:format(Dev, " ", []),
- pp_args(Dev, multimove_dstlist(I)),
- io:format(Dev, " <= ", []),
- pp_args(Dev, multimove_srclist(I)),
- io:format(Dev, "~n", []);
- #alu{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, alu_dst(I)),
- io:format(Dev, " <- ", []),
- pp_arg(Dev, alu_src1(I)),
- io:format(Dev, " ~w ", [alu_op(I)]),
- pp_arg(Dev, alu_src2(I)),
- io:format(Dev, "~n", []);
- #load{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, load_dst(I)),
- io:format(Dev, " <- [", []),
- pp_arg(Dev, load_src(I)),
- io:format(Dev, "+", []),
- pp_arg(Dev, load_offset(I)),
- io:format(Dev, "]", []),
- case load_sign(I) of
- signed -> io:format(Dev, " -signed",[]);
- _ -> ok
- end,
- case load_size(I) of
- byte -> io:format(Dev, " -byte",[]);
- int16 -> io:format(Dev, " -int16",[]);
- int32 -> io:format(Dev, " -int32",[]);
- _ -> ok
- end,
- io:format(Dev, "~n", []);
- #load_atom{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, load_atom_dst(I)),
- io:format(Dev, " <- atom_no(\'~s\')~n", [load_atom_atom(I)]);
- #load_word_index{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, load_word_index_dst(I)),
- io:format(Dev, " <- word_index_no( DL~p[~p] )~n",
- [load_word_index_block(I),load_word_index_index(I)]);
- #goto_index{} ->
- io:format(Dev, " ", []),
- io:format(Dev, "goto_index DL~p[~p]~n",
- [goto_index_block(I), goto_index_index(I)]);
- #load_address{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, load_address_dst(I)),
- case load_address_type(I) of
- constant ->
- io:format(Dev, " <- DL~p~n", [load_address_addr(I)]);
- closure ->
- io:format(Dev, " <- L~p [closure]~n", [load_address_addr(I)]);
- Type ->
- io:format(Dev, " <- L~p [~p]~n", [load_address_addr(I),Type])
- end;
- #store{} ->
- io:format(Dev, " [", []),
- pp_arg(Dev, store_base(I)),
- io:format(Dev, "+", []),
- pp_arg(Dev, store_offset(I)),
- io:format(Dev, "] <- ", []),
- pp_arg(Dev, store_src(I)),
- case store_size(I) of
- byte -> io:format(Dev, " -byte",[]);
- int16 -> io:format(Dev, " -int16",[]);
- int32 -> io:format(Dev, " -int32",[]);
- _ -> ok
- end,
- io:format(Dev, "~n", []);
- #label{} ->
- io:format(Dev, "L~w:~n", [label_name(I)]);
- #switch{} ->
- io:format(Dev, " switch (", []),
- pp_arg(Dev, switch_src(I)),
- io:format(Dev, ") <", []),
- pp_switch_labels(Dev, switch_labels(I)),
- io:format(Dev, ">\n", []);
- #alub{} ->
- io:format(Dev, " ", []),
- case alub_has_dst(I) of
- true -> pp_arg(Dev, alub_dst(I));
- false -> io:format(Dev, "_", [])
- end,
- io:format(Dev, " <- ", []),
- pp_arg(Dev, alub_src1(I)),
- io:format(Dev, " ~w ", [alub_op(I)]),
- pp_arg(Dev, alub_src2(I)),
- io:format(Dev, " if",[]),
- io:format(Dev, " ~w ", [alub_cond(I)]),
- io:format(Dev, "then L~w (~.2f) else L~w~n",
- [alub_true_label(I), alub_pred(I), alub_false_label(I)]);
- #goto{} ->
- io:format(Dev, " goto L~w~n", [goto_label(I)]);
- #call{} ->
- io:format(Dev, " ", []),
- pp_args(Dev, call_dstlist(I)),
- io:format(Dev, " <- ", []),
- case call_is_known(I) of
- true ->
- case call_fun(I) of
- F when is_atom(F) ->
- io:format(Dev, "~w(", [F]);
- {M,F,A} when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
- io:format(Dev, "~w:~w(", [M, F]);
- {F,A} when is_atom(F), is_integer(A), A >=0 ->
- io:format(Dev, "~w(", [F])
- end;
- false ->
- io:format(Dev, "(",[]),
- pp_arg(Dev, call_fun(I)),
- io:format(Dev, ")(",[])
- end,
- pp_args(Dev, call_arglist(I)),
- io:format(Dev, ")", []),
- case call_continuation(I) of
- [] -> true;
- CC ->
- io:format(Dev, " then L~w", [CC])
- end,
- case call_fail(I) of
- [] -> true;
- L ->
- io:format(Dev, " fail to L~w", [L])
- end,
- io:format(Dev, "~n", []);
- #enter{} ->
- io:format(Dev, " ", []),
- case enter_is_known(I) of
- true ->
- case enter_fun(I) of
- F when is_atom(F) ->
- io:format(Dev, "~w(", [F]);
- {M,F,A} when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
- io:format(Dev, "~w:~w(", [M, F]);
- {F,A} when is_atom(F), is_integer(A), A >= 0 ->
- io:format(Dev, "~w(", [F])
- end;
- false ->
- io:format(Dev, "(",[]),
- pp_arg(Dev, enter_fun(I)),
- io:format(Dev, ")(",[])
- end,
- pp_args(Dev, enter_arglist(I)),
- io:format(Dev, ")~n", []);
- #return{} ->
- io:format(Dev, " return(", []),
- pp_args(Dev, return_varlist(I)),
- io:format(Dev, ")~n", []);
- #comment{} ->
- io:format(Dev, " ;; ~p~n", [comment_text(I)]);
- #fixnumop{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, fixnumop_dst(I)),
- io:format(Dev, " <- ", []),
- case fixnumop_type(I) of
- tag ->
- io:format(Dev, "fixnum_tag(", []);
- untag ->
- io:format(Dev, "fixnum_untag(", [])
- end,
- pp_arg(Dev, fixnumop_src(I)),
- io:format(Dev, ")~n", []);
- #gctest{} ->
- io:format(Dev, " gctest(", []),
- pp_arg(Dev, gctest_words(I)),
- io:format(Dev, ")~n", []);
- %% Floating point handling instructions below
- #fload{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, fload_dst(I)),
- io:format(Dev, " <-f [", []),
- pp_arg(Dev, fload_src(I)),
- io:format(Dev, "+", []),
- pp_arg(Dev, fload_offset(I)),
- io:format(Dev, "]~n", []);
- #fstore{} ->
- io:format(Dev, " [", []),
- pp_arg(Dev, fstore_base(I)),
- io:format(Dev, "+", []),
- pp_arg(Dev, fstore_offset(I)),
- io:format(Dev, "] <- ", []),
- pp_arg(Dev, fstore_src(I)),
- io:format(Dev, "~n", []);
- #fp{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, fp_dst(I)),
- io:format(Dev, " <- ", []),
- pp_arg(Dev, fp_src1(I)),
- io:format(Dev, " ~w ", [fp_op(I)]),
- pp_arg(Dev, fp_src2(I)),
- io:format(Dev, "~n", []);
- #fp_unop{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, fp_unop_dst(I)),
- io:format(Dev, " <- ", []),
- io:format(Dev, " ~w ", [fp_unop_op(I)]),
- pp_arg(Dev, fp_unop_src(I)),
- io:format(Dev, "~n", []);
- #fmove{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, fmove_dst(I)),
- io:format(Dev, " <- ", []),
- pp_arg(Dev, fmove_src(I)),
- io:format(Dev, "~n", []);
- #fconv{} ->
- io:format(Dev, " ", []),
- pp_arg(Dev, fconv_dst(I)),
- io:format(Dev, " <-fconv ", []),
- pp_arg(Dev, fconv_src(I)),
- io:format(Dev, "~n", []);
- Other ->
- exit({?MODULE,pp_instr,{"unknown RTL instruction",Other}})
- end.
-
-pp_args(_Dev, []) ->
- ok;
-pp_args(Dev, [A]) ->
- pp_arg(Dev, A);
-pp_args(Dev, [A|As]) ->
- pp_arg(Dev, A),
- io:format(Dev, ", ", []),
- pp_args(Dev, As).
-
-pp_phi_args(_Dev, []) -> ok;
-pp_phi_args(Dev, [{Pred,A}]) ->
- io:format(Dev, "{~w, ", [Pred]),
- pp_arg(Dev, A),
- io:format(Dev, "}", []);
-pp_phi_args(Dev, [{Pred,A}|Args]) ->
- io:format(Dev, "{~w, ", [Pred]),
- pp_arg(Dev, A),
- io:format(Dev, "}, ", []),
- pp_phi_args(Dev, Args);
-pp_phi_args(Dev, Args) ->
- pp_args(Dev, Args).
-
-pp_hard_reg(Dev, N) ->
- io:format(Dev, "~s", [hipe_rtl_arch:reg_name(N)]).
-
-pp_reg(Dev, Arg) ->
- case hipe_rtl_arch:is_precoloured(Arg) of
- true ->
- pp_hard_reg(Dev, reg_index(Arg));
- false ->
- case reg_is_gcsafe(Arg) of
- true -> io:format(Dev, "rs~w", [reg_index(Arg)]);
- false -> io:format(Dev, "r~w", [reg_index(Arg)])
- end
- end.
-
-pp_var(Dev, Arg) ->
- case hipe_rtl_arch:is_precoloured(Arg) of
- true ->
- pp_hard_reg(Dev, var_index(Arg));
- false ->
- io:format(Dev, "v~w", [var_index(Arg)]),
- case var_liveness(Arg) of
- dead -> io:format(Dev, "(dead)", []);
- _ -> ok
- end
- end.
-
-pp_arg(Dev, A) ->
- case is_var(A) of
- true ->
- pp_var(Dev, A);
- false ->
- case is_reg(A) of
- true ->
- pp_reg(Dev, A);
- false ->
- case is_imm(A) of
- true ->
- io:format(Dev, "~w", [imm_value(A)]);
- false ->
- case is_fpreg(A) of
- true ->
- io:format(Dev, "f~w", [fpreg_index(A)]);
- false ->
- case is_const_label(A) of
- true ->
- io:format(Dev, "DL~w", [const_label_label(A)]);
- false ->
- exit({?MODULE,pp_arg,{"bad RTL arg",A}})
- end
- end
- end
- end
- end.
-
-pp_switch_labels(Dev,Lbls) ->
- pp_switch_labels(Dev,Lbls,1).
-
-pp_switch_labels(Dev, [L], _Pos) ->
- io:format(Dev, "L~w", [L]);
-pp_switch_labels(Dev, [L|Ls], Pos) ->
- io:format(Dev, "L~w, ", [L]),
- NewPos =
- case Pos of
- 5 -> io:format(Dev, "\n ",[]),
- 0;
- N -> N + 1
- end,
- pp_switch_labels(Dev, Ls, NewPos);
-pp_switch_labels(_Dev, [], _) ->
- ok.
diff --git a/lib/hipe/rtl/hipe_rtl.hrl b/lib/hipe/rtl/hipe_rtl.hrl
deleted file mode 100644
index 50059693aa..0000000000
--- a/lib/hipe/rtl/hipe_rtl.hrl
+++ /dev/null
@@ -1,56 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Provides abstract datatypes for HiPE's RTL (Register Transfer Language).
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%---------------------------------------------------------------------
-
--record(alu, {dst, src1, op, src2}).
--record(alub, {dst, src1, op, src2, 'cond', true_label, false_label, p}).
--record(call, {dstlist, 'fun', arglist, type, continuation,
- failcontinuation, normalcontinuation = []}).
--record(comment, {text}).
--record(enter, {'fun', arglist, type}).
--record(fconv, {dst, src}).
--record(fixnumop, {dst, src, type}).
--record(fload, {dst, src, offset}).
--record(fmove, {dst, src}).
--record(fp, {dst, src1, op, src2}).
--record(fp_unop, {dst, src, op}).
--record(fstore, {base, offset, src}).
--record(gctest, {words}).
--record(goto, {label}).
--record(goto_index, {block, index, labels}).
--record(label, {name}).
--record(load, {dst, src, offset, size, sign}).
--record(load_address, {dst, addr, type}).
--record(load_atom, {dst, atom}).
--record(load_word_index, {dst, block, index}).
--record(move, {dst, src}).
--record(multimove, {dstlist, srclist}).
--record(phi, {dst, id, arglist}).
--record(return, {varlist}).
--record(store, {base, offset, src, size}).
--record(switch, {src, labels, sorted_by=[]}).
-
-%%---------------------------------------------------------------------
-
-%% An efficient macro to convert byte sizes to bit sizes
--define(bytes_to_bits(Bytes), ((Bytes) bsl 3)). % (N * 8)
-
-%%---------------------------------------------------------------------
diff --git a/lib/hipe/rtl/hipe_rtl_arch.erl b/lib/hipe/rtl/hipe_rtl_arch.erl
deleted file mode 100644
index 65149ea7db..0000000000
--- a/lib/hipe/rtl/hipe_rtl_arch.erl
+++ /dev/null
@@ -1,677 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson.
-%%=====================================================================
-%% Filename : hipe_rtl_arch.erl
-%% History : * 2001-04-10 Erik Johansson (happi@it.uu.se): Created.
-%%=====================================================================
-%% @doc
-%%
-%% This module contains interface functions whose semantics and
-%% implementation depend on the target architecture.
-%%
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_arch).
-
--export([first_virtual_reg/0,
- heap_pointer/0,
- heap_limit/0,
- fcalls/0,
- reg_name/1,
- is_precoloured/1,
- call_defined/0,
- call_used/0,
- tailcall_used/0,
- return_used/0,
- live_at_return/0,
- endianess/0,
- load_big_2/4,
- load_little_2/4,
- load_big_4/4,
- load_little_4/4,
- %% store_4/3,
- eval_alu/3,
- %% eval_alub/4,
- eval_cond/3,
- eval_cond_bits/5,
- fwait/0,
- handle_fp_exception/0,
- pcb_load/2,
- pcb_load/3,
- pcb_store/2,
- pcb_store/3,
- pcb_address/2,
- call_bif/5,
- %% alignment/0,
- nr_of_return_regs/0,
- log2_word_size/0,
- word_size/0,
- mk_fp_check_result/1
- ]).
-
--include("hipe_literals.hrl").
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% ____________________________________________________________________
-%%
-%% ARCH-specific stuff
-%% ____________________________________________________________________
-%%
-%%
-%% XXX: x86 might not _have_ real registers for some of these things
-%%
-
-first_virtual_reg() ->
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_sparc_registers:first_virtual();
- powerpc ->
- hipe_ppc_registers:first_virtual();
- ppc64 ->
- hipe_ppc_registers:first_virtual();
- arm ->
- hipe_arm_registers:first_virtual();
- x86 ->
- hipe_x86_registers:first_virtual();
- amd64 ->
- hipe_amd64_registers:first_virtual()
- end.
-
-heap_pointer() -> % {GetHPInsn, HPReg, PutHPInsn}
- case get(hipe_target_arch) of
- ultrasparc ->
- heap_pointer_from_reg(hipe_sparc_registers:heap_pointer());
- powerpc ->
- heap_pointer_from_reg(hipe_ppc_registers:heap_pointer());
- ppc64 ->
- heap_pointer_from_reg(hipe_ppc_registers:heap_pointer());
- arm ->
- heap_pointer_from_reg(hipe_arm_registers:heap_pointer());
- x86 ->
- x86_heap_pointer();
- amd64 ->
- amd64_heap_pointer()
- end.
-
-heap_pointer_from_reg(Reg) ->
- {hipe_rtl:mk_comment('get_heap_pointer'),
- hipe_rtl:mk_reg(Reg),
- hipe_rtl:mk_comment('put_heap_pointer')}.
-
--ifdef(AMD64_HP_IN_REGISTER).
-amd64_heap_pointer() ->
- heap_pointer_from_reg(hipe_amd64_registers:heap_pointer()).
--else.
--define(HEAP_POINTER_FROM_PCB_NEEDED,1).
-amd64_heap_pointer() ->
- heap_pointer_from_pcb().
--endif.
-
--ifdef(X86_HP_IN_ESI).
-x86_heap_pointer() ->
- heap_pointer_from_reg(hipe_x86_registers:heap_pointer()).
--else.
--define(HEAP_POINTER_FROM_PCB_NEEDED,1).
-x86_heap_pointer() ->
- heap_pointer_from_pcb().
--endif.
-
--ifdef(HEAP_POINTER_FROM_PCB_NEEDED).
-heap_pointer_from_pcb() ->
- Reg = hipe_rtl:mk_new_reg(),
- {pcb_load(Reg, ?P_HP), Reg, pcb_store(?P_HP, Reg)}.
--endif.
-
-heap_limit() -> % {GetHLIMITInsn, HLIMITReg}
- case get(hipe_target_arch) of
- ultrasparc ->
- heap_limit_from_pcb();
- powerpc ->
- heap_limit_from_pcb();
- ppc64 ->
- heap_limit_from_pcb();
- arm ->
- heap_limit_from_pcb();
- x86 ->
- heap_limit_from_reg(hipe_x86_registers:heap_limit());
- amd64 ->
- heap_limit_from_reg(hipe_amd64_registers:heap_limit())
- end.
-
-heap_limit_from_reg(Reg) ->
- {hipe_rtl:mk_comment('get_heap_limit'),
- hipe_rtl:mk_reg(Reg)}.
-
-heap_limit_from_pcb() ->
- Reg = hipe_rtl:mk_new_reg(),
- {pcb_load(Reg, ?P_HP_LIMIT), Reg}.
-
-fcalls() -> % {GetFCallsInsn, FCallsReg, PutFCallsInsn}
- case get(hipe_target_arch) of
- ultrasparc ->
- fcalls_from_pcb();
- powerpc ->
- fcalls_from_pcb();
- ppc64 ->
- fcalls_from_pcb();
- arm ->
- fcalls_from_pcb();
- x86 ->
- fcalls_from_reg(hipe_x86_registers:fcalls());
- amd64 ->
- fcalls_from_reg(hipe_amd64_registers:fcalls())
- end.
-
-fcalls_from_reg(Reg) ->
- {hipe_rtl:mk_comment('get_fcalls'),
- hipe_rtl:mk_reg(Reg),
- hipe_rtl:mk_comment('put_fcalls')}.
-
-fcalls_from_pcb() ->
- Reg = hipe_rtl:mk_new_reg(),
- {pcb_load(Reg, ?P_FCALLS), Reg, pcb_store(?P_FCALLS, Reg)}.
-
-reg_name(Reg) ->
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_sparc_registers:reg_name_gpr(Reg);
- powerpc ->
- hipe_ppc_registers:reg_name_gpr(Reg);
- ppc64 ->
- hipe_ppc_registers:reg_name_gpr(Reg);
- arm ->
- hipe_arm_registers:reg_name_gpr(Reg);
- x86 ->
- hipe_x86_registers:reg_name(Reg);
- amd64 ->
- hipe_amd64_registers:reg_name(Reg)
- end.
-
-%% @spec is_precoloured(rtl_arg()) -> boolean()
-%%
-%% @doc Succeeds if Arg is mapped to a precoloured register in the target.
-%%
-is_precoloured(Arg) ->
- case hipe_rtl:is_reg(Arg) of
- true ->
- is_precolored_regnum(hipe_rtl:reg_index(Arg));
- false ->
- hipe_rtl:is_var(Arg) andalso
- is_precolored_regnum(hipe_rtl:var_index(Arg))
- end.
-
-is_precolored_regnum(RegNum) ->
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_sparc_registers:is_precoloured_gpr(RegNum);
- powerpc ->
- hipe_ppc_registers:is_precoloured_gpr(RegNum);
- ppc64 ->
- hipe_ppc_registers:is_precoloured_gpr(RegNum);
- arm ->
- hipe_arm_registers:is_precoloured_gpr(RegNum);
- x86 ->
- hipe_x86_registers:is_precoloured(RegNum);
- amd64 ->
- hipe_amd64_registers:is_precoloured(RegNum)
- end.
-
-call_defined() ->
- call_used().
-
-call_used() ->
- live_at_return().
-
-tailcall_used() ->
- call_used().
-
-return_used() ->
- tailcall_used().
-
-live_at_return() ->
- case get(hipe_target_arch) of
- ultrasparc ->
- ordsets:from_list([hipe_rtl:mk_reg(R)
- || {R,_} <- hipe_sparc_registers:live_at_return()]);
- powerpc ->
- ordsets:from_list([hipe_rtl:mk_reg(R)
- || {R,_} <- hipe_ppc_registers:live_at_return()]);
- ppc64 ->
- ordsets:from_list([hipe_rtl:mk_reg(R)
- || {R,_} <- hipe_ppc_registers:live_at_return()]);
- arm ->
- ordsets:from_list([hipe_rtl:mk_reg(R)
- || {R,_} <- hipe_arm_registers:live_at_return()]);
- x86 ->
- ordsets:from_list([hipe_rtl:mk_reg(R)
- || {R,_} <- hipe_x86_registers:live_at_return()]);
- amd64 ->
- ordsets:from_list([hipe_rtl:mk_reg(R)
- || {R,_} <- hipe_amd64_registers:live_at_return()])
- end.
-
-%% @spec word_size() -> integer()
-%%
-%% @doc Returns the target's word size.
-%%
-word_size() ->
- case get(hipe_target_arch) of
- ultrasparc -> 4;
- powerpc -> 4;
- ppc64 -> 8;
- arm -> 4;
- x86 -> 4;
- amd64 -> 8
- end.
-
-%% alignment() ->
-%% case get(hipe_target_arch) of
-%% ultrasparc -> 4;
-%% powerpc -> 4;
-%% arm -> 4;
-%% x86 -> 4;
-%% amd64 -> 8
-%% end.
-
-%% @spec log2_word_size() -> integer()
-%%
-%% @doc Returns log2 of the target's word size.
-%%
-log2_word_size() ->
- case get(hipe_target_arch) of
- ultrasparc -> 2;
- powerpc -> 2;
- ppc64 -> 3;
- arm -> 2;
- x86 -> 2;
- amd64 -> 3
- end.
-
-%% @spec endianess() -> big | little
-%%
-%% @doc Returns the target's endianess.
-%%
-endianess() ->
- case get(hipe_target_arch) of
- ultrasparc -> big;
- powerpc -> big;
- ppc64 -> big;
- x86 -> little;
- amd64 -> little;
- arm -> ?ARM_ENDIANESS
- end.
-
-%%%------------------------------------------------------------------------
-%%% Reading integers from binaries, in various sizes and endianesses.
-%%% Operand-sized alignment is NOT guaranteed, only byte alignment.
-%%%------------------------------------------------------------------------
-
-%%% Load a 2-byte big-endian integer from a binary.
-%%% Increment Offset by 2.
-load_big_2(Dst, Base, Offset, Signedness) ->
- case get(hipe_target_arch) of
- powerpc ->
- load_2_directly(Dst, Base, Offset, Signedness);
- ppc64 ->
- load_2_directly(Dst, Base, Offset, Signedness);
- %% Note: x86 could use a "load;xchgb" or "load;rol $8,<16-bit reg>"
- %% sequence here. This has been implemented, but unfortunately didn't
- %% make consistent improvements to our benchmarks.
- _ ->
- load_big_2_in_pieces(Dst, Base, Offset, Signedness)
- end.
-
-%%% Load a 2-byte little-endian integer from a binary.
-%%% Increment Offset by 2.
-load_little_2(Dst, Base, Offset, Signedness) ->
- case get(hipe_target_arch) of
- x86 ->
- load_2_directly(Dst, Base, Offset, Signedness);
- powerpc ->
- [hipe_rtl:mk_call([Dst], 'lhbrx', [Base,Offset], [], [], not_remote),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(2)) |
- case Signedness of
- unsigned -> [];
- signed -> [hipe_rtl:mk_call([Dst], 'extsh', [Dst], [], [], not_remote)]
- end];
- ppc64 ->
- [hipe_rtl:mk_call([Dst], 'lhbrx', [Base,Offset], [], [], not_remote),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(2)) |
- case Signedness of
- unsigned -> [];
- signed -> [hipe_rtl:mk_call([Dst], 'extsh', [Dst], [], [], not_remote)]
- end];
- _ ->
- load_little_2_in_pieces(Dst, Base, Offset, Signedness)
- end.
-
-load_2_directly(Dst, Base, Offset, Signedness) ->
- [hipe_rtl:mk_load(Dst, Base, Offset, int16, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(2))].
-
-load_big_2_in_pieces(Dst, Base, Offset, Signedness) ->
- Tmp1 = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
-
-load_little_2_in_pieces(Dst, Base, Offset, Signedness) ->
- Tmp1 = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
-
-%%% Load a 4-byte big-endian integer from a binary.
-%%% Increment Offset by 4.
-load_big_4(Dst, Base, Offset, Signedness) ->
- case get(hipe_target_arch) of
- powerpc ->
- load_4_directly(Dst, Base, Offset, Signedness);
- ppc64 ->
- load_4_directly(Dst, Base, Offset, Signedness);
- %% Note: x86 could use a "load;bswap" sequence here.
- %% This has been implemented, but unfortunately didn't
- %% make any noticeable improvements in our benchmarks.
- arm ->
- %% When loading 4 bytes into a 32-bit register, the
- %% signedness of the high-order byte doesn't matter.
- %% ARM prefers unsigned byte loads so we'll use that.
- load_big_4_in_pieces(Dst, Base, Offset, unsigned);
- _ ->
- load_big_4_in_pieces(Dst, Base, Offset, Signedness)
- end.
-
-%%% Load a 4-byte little-endian integer from a binary.
-%%% Increment Offset by 4.
-load_little_4(Dst, Base, Offset, Signedness) ->
- case get(hipe_target_arch) of
- x86 ->
- load_4_directly(Dst, Base, Offset, Signedness);
- powerpc ->
- [hipe_rtl:mk_call([Dst], 'lwbrx', [Base,Offset], [], [], not_remote),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))];
- ppc64 ->
- [hipe_rtl:mk_call([Dst], 'lwbrx', [Base,Offset], [], [], not_remote),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4)) |
- case Signedness of
- unsigned -> [];
- signed -> [hipe_rtl:mk_call([Dst], 'extsw', [Dst], [], [], not_remote)]
- end];
- arm ->
- %% When loading 4 bytes into a 32-bit register, the
- %% signedness of the high-order byte doesn't matter.
- %% ARM prefers unsigned byte loads so we'll use that.
- load_little_4_in_pieces(Dst, Base, Offset, unsigned);
- _ ->
- load_little_4_in_pieces(Dst, Base, Offset, Signedness)
- end.
-
-load_4_directly(Dst, Base, Offset, Signedness) ->
- [hipe_rtl:mk_load(Dst, Base, Offset, int32, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
-
-load_big_4_in_pieces(Dst, Base, Offset, Signedness) ->
- Tmp1 = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
-
-load_little_4_in_pieces(Dst, Base, Offset, Signedness) ->
- Tmp1 = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(16)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(24)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))].
-
--ifdef(STORE_4_NEEDED).
-store_4(Base, Offset, Src) ->
- case get(hipe_target_arch) of
- x86 ->
- store_4_directly(Base, Offset, Src);
- powerpc ->
- store_4_directly(Base, Offset, Src);
- ppc64 ->
- store_4_directly(Base, Offset, Src);
- arm ->
- store_big_4_in_pieces(Base, Offset, Src);
- ultrasparc ->
- store_big_4_in_pieces(Base, Offset, Src);
- amd64 ->
- store_4_directly(Base, Offset, Src)
- end.
-
-store_4_directly(Base, Offset, Src) ->
- [hipe_rtl:mk_store(Base, Offset, Src, int32),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
-
-store_big_4_in_pieces(Base, Offset, Src) ->
- [hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_store(Base, Offset, Src, byte),
- hipe_rtl:mk_alu(Offset, Offset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, Offset, Src, byte),
- hipe_rtl:mk_alu(Offset, Offset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, Offset, Src, byte),
- hipe_rtl:mk_alu(Offset, Offset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, Offset, Src, byte),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
--endif.
-
-%%----------------------------------------------------------------------
-%% Handling of arithmetic -- depends on the size of word.
-%%----------------------------------------------------------------------
-
-eval_alu(Op, Arg1, Arg2) ->
- %% io:format("Evaluated alu: ~w ~w ~w = ",[Arg1, Op, Arg2]),
- Res = case word_size() of
- 4 ->
- hipe_rtl_arith_32:eval_alu(Op, Arg1, Arg2);
- 8 ->
- hipe_rtl_arith_64:eval_alu(Op, Arg1, Arg2)
- end,
- %% io:format("~w~n ",[Res]),
- Res.
-
--ifdef(EVAL_ALUB_NEEDED).
-eval_alub(Op, Cond, Arg1, Arg2) ->
- %% io:format("Evaluated alub: ~w ~w ~w cond ~w = ",[Arg1, Op, Arg2, Cond]),
- Res = case word_size() of
- 4 ->
- hipe_rtl_arith_32:eval_alub(Op, Cond, Arg1, Arg2);
- 8 ->
- hipe_rtl_arith_64:eval_alub(Op, Cond, Arg1, Arg2)
- end,
- %% io:format("~w~n ",[Res]),
- Res.
--endif.
-
-eval_cond(Cond, Arg1, Arg2) ->
- %% io:format("Evaluated cond: ~w ~w ~w = ",[Arg1, Cond, Arg2]),
- Res = case word_size() of
- 4 ->
- hipe_rtl_arith_32:eval_cond(Cond, Arg1, Arg2);
- 8 ->
- hipe_rtl_arith_64:eval_cond(Cond, Arg1, Arg2)
- end,
- %% io:format("~w~n ",[Res]),
- Res.
-
-eval_cond_bits(Cond, N, Z, V, C) ->
- %% io:format("Evaluated cond: ~w ~w ~w = ",[Arg1, Cond, Arg2]),
- Res = case word_size() of
- 4 ->
- hipe_rtl_arith_32:eval_cond_bits(Cond, N, Z, V, C);
- 8 ->
- hipe_rtl_arith_64:eval_cond_bits(Cond, N, Z, V, C)
- end,
- %% io:format("~w~n ",[Res]),
- Res.
-
-%%----------------------------------------------------------------------
-
-fwait() ->
- case ?ERTS_NO_FPE_SIGNALS of
- 1 -> [];
- 0 -> fwait_real()
- end.
-
-fwait_real() ->
- case get(hipe_target_arch) of
- x86 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
- amd64 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
- arm -> [];
- powerpc -> [];
- ppc64 -> [];
- ultrasparc -> []
- end.
-
-%% @spec handle_fp_exception() -> [term()]
-%%
-%% @doc
-%% Returns RTL code to restore the FPU after a floating-point exception.
-%% @end
-handle_fp_exception() ->
- case ?ERTS_NO_FPE_SIGNALS of
- 1 -> [];
- 0 -> handle_real_fp_exception()
- end.
-
-handle_real_fp_exception() ->
- case get(hipe_target_arch) of
- x86 ->
- ContLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([], handle_fp_exception, [],
- hipe_rtl:label_name(ContLbl), [], not_remote),
- ContLbl];
- amd64 ->
- ContLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([], handle_fp_exception, [],
- hipe_rtl:label_name(ContLbl), [], not_remote),
- ContLbl];
- arm ->
- [];
- powerpc ->
- [];
- ppc64 ->
- [];
- ultrasparc ->
- []
- end.
-
-%%
-%% PCB accesses.
-%% Wrapped to avoid leaking the PCB pointer to the wrong places.
-%%
-
-pcb_load(Dst, Off) -> pcb_load(Dst, Off, word).
-
-pcb_load(Dst, Off, Size) ->
- hipe_rtl:mk_load(Dst, proc_pointer(), hipe_rtl:mk_imm(Off), Size, unsigned).
-
-pcb_store(Off, Src) -> pcb_store(Off, Src, word).
-
-pcb_store(Off, Src, Size) ->
- hipe_rtl:mk_store(proc_pointer(), hipe_rtl:mk_imm(Off), Src, Size).
-
-pcb_address(Dst, Off) ->
- hipe_rtl:mk_alu(Dst, proc_pointer(), 'add', hipe_rtl:mk_imm(Off)).
-
-proc_pointer() -> % must not be exported
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_rtl:mk_reg_gcsafe(hipe_sparc_registers:proc_pointer());
- powerpc ->
- hipe_rtl:mk_reg_gcsafe(hipe_ppc_registers:proc_pointer());
- ppc64 ->
- hipe_rtl:mk_reg_gcsafe(hipe_ppc_registers:proc_pointer());
- arm ->
- hipe_rtl:mk_reg_gcsafe(hipe_arm_registers:proc_pointer());
- x86 ->
- hipe_rtl:mk_reg_gcsafe(hipe_x86_registers:proc_pointer());
- amd64 ->
- hipe_rtl:mk_reg_gcsafe(hipe_amd64_registers:proc_pointer())
- end.
-
-%%
-%% Special BIF calls.
-%% Wrapped to avoid leaking the PCB pointer to the wrong places,
-%% and to allow ARCH-specific expansion.
-%%
-
-call_bif(Dst, Name, Args, Cont, Fail) ->
- hipe_rtl:mk_call(Dst, Name, Args, Cont, Fail, not_remote).
-
-nr_of_return_regs() ->
- case get(hipe_target_arch) of
- ultrasparc ->
- 1;
- %% hipe_sparc_registers:nr_rets();
- powerpc ->
- 1;
- ppc64 ->
- 1;
- %% hipe_ppc_registers:nr_rets();
- arm ->
- 1;
- x86 ->
- hipe_x86_registers:nr_rets();
- amd64 ->
- 1
- %% hipe_amd64_registers:nr_rets();
- end.
-
-
-mk_fp_check_result(Result) ->
- case ?ERTS_NO_FPE_SIGNALS of
- 0 ->
- [];
- 1 ->
- [hipe_rtl:mk_fstore(proc_pointer(),
- hipe_rtl:mk_imm(?P_FLOAT_RESULT),
- Result),
- hipe_rtl:mk_call([], emulate_fpe, [], [], [], not_remote)]
- end.
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
deleted file mode 100644
index 575f10b542..0000000000
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ /dev/null
@@ -1,171 +0,0 @@
-%% -*- Erlang -*-
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_rtl_arith.inc
-%% Created : Feb 2004
-%% Purpose : Implements arithmetic which is parameterized by the size
-%% of the word of the target architecture (given as defines).
-%%----------------------------------------------------------------------
-
-
-%% Returns a tuple
-%% {Res, Sign, Zero, Overflow, Carry}
-%% Res will be a number in the range
-%% MAX_UNSIGNED_INT >= Res >= 0
-%% The other four values are flags that are either true or false
-%%
-eval_alu(Op, Arg1, Arg2)
- when Arg1 =< ?MAX_UNSIGNED_INT,
- Arg1 >= ?MIN_SIGNED_INT,
- Arg2 =< ?MAX_UNSIGNED_INT,
- Arg2 >= ?MIN_SIGNED_INT ->
-
- Sign1 = sign_bit(Arg1),
- Sign2 = sign_bit(Arg2),
-
- case Op of
- 'sub' ->
- Res = (Arg1 - Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = (Sign1 andalso (not Sign2) andalso (not N))
- or
- ((not Sign1) andalso Sign2 andalso N),
- C = ((not Sign1) andalso Sign2)
- or
- (N andalso ((not Sign1) orelse Sign2)),
- {Res, N, Z, V, C};
- 'add' ->
- Res = (Arg1 + Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = (Sign1 andalso Sign2 andalso (not N))
- or
- ((not Sign1) andalso (not Sign2) andalso N),
- C = (Sign1 andalso Sign2)
- or
- ((not N) andalso (Sign1 orelse Sign2)),
- {Res, N, Z, V, C};
- 'mul' ->
- FullRes = Arg1 * Arg2,
- Res = FullRes band ?WORDMASK,
- ResHi = FullRes bsr ?BITS,
- N = sign_bit(Res),
- Z = zero(Res),
- V = (N andalso (ResHi =/= -1)) orelse ((not N) andalso (ResHi =/= 0)),
- C = V,
- {Res, N, Z, V, C};
- 'sra' ->
- Res = (Arg1 bsr Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = 0,
- C = 0,
- {Res, N, Z, V, C};
- 'srl' ->
- Res = (Arg1 bsr Arg2) band shiftmask(Arg2),
- N = sign_bit(Res),
- Z = zero(Res),
- V = 0,
- C = 0,
- {Res, N, Z, V, C};
- 'sll' ->
- Res = (Arg1 bsl Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = 0,
- C = 0,
- {Res, N, Z, V, C};
- 'or' ->
- Res = (Arg1 bor Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = 0,
- C = 0,
- {Res, N, Z, V, C};
- 'and' ->
- Res = (Arg1 band Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = 0,
- C = 0,
- {Res, N, Z, V, C};
- 'xor' ->
- Res = (Arg1 bxor Arg2) band ?WORDMASK,
- N = sign_bit(Res),
- Z = zero(Res),
- V = 0,
- C = 0,
- {Res, N, Z, V, C};
- Op ->
- ?EXIT({"unknown alu op", Op})
- end;
-eval_alu(Op, Arg1, Arg2) ->
- ?EXIT({argument_overflow, Op, Arg1, Arg2}).
-
-%% Björn & Bjarni:
-%% We need to be able to do evaluations based only on the bits, since
-%% there are cases where we can evaluate a subset of the bits, but
-%% cannot do a full eval-alub call (eg. a + 0 gives no carry)
-%%
--spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(),
- boolean(), boolean(), boolean()) -> boolean().
-
-eval_cond_bits(Cond, N, Z, V, C) ->
- case Cond of
- 'eq' ->
- Z;
- 'ne' ->
- not Z;
- 'gt' ->
- not (Z orelse (N xor V));
- 'gtu' ->
- not (C orelse Z);
- 'ge' ->
- not (N xor V);
- 'geu'->
- not C;
- 'lt' ->
- N xor V;
- 'ltu'->
- C;
- 'le' ->
- Z orelse (N xor V);
- 'leu'->
- C orelse Z;
- 'overflow' ->
- V;
- 'not_overflow' ->
- not V
- end.
-
-eval_alub(Op, Cond, Arg1, Arg2) ->
- {Res, N, Z, V, C} = eval_alu(Op, Arg1, Arg2),
- {Res, eval_cond_bits(Cond, N, Z, V, C)}.
-
-eval_cond(Cond, Arg1, Arg2) ->
- {_, Bool} = eval_alub('sub', Cond, Arg1, Arg2),
- Bool.
-
-sign_bit(Val) ->
- ((Val bsr ?SIGN_BIT) band 1) =:= 1.
-
-shiftmask(Arg) ->
- Setbits = ?BITS - Arg,
- (1 bsl Setbits) - 1.
-
-zero(Val) ->
- Val =:= 0.
diff --git a/lib/hipe/rtl/hipe_rtl_arith_32.erl b/lib/hipe/rtl/hipe_rtl_arith_32.erl
deleted file mode 100644
index 1f911642d5..0000000000
--- a/lib/hipe/rtl/hipe_rtl_arith_32.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2002 by Erik Johansson.
-%% ====================================================================
-%% Filename : hipe_rtl_arith_32.erl
-%% Module : hipe_rtl_arith_32
-%% Purpose : To implement 32-bit RTL-arithmetic
-%% Notes : The arithmetic works on 32-bit signed and unsigned
-%% integers.
-%% The implementation is taken from the implementation
-%% of arithmetic on SPARC.
-%% XXX: This code is seldom used, and hence also
-%% seldom tested.
-%% Look here for strange bugs appearing when
-%% turning on rtl_prop.
-%%
-%% History : * 2002-10-23 Erik Stenman (happi@it.uu.se): Created.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_arith_32).
-
--export([eval_alu/3, eval_alub/4, eval_cond/3, eval_cond_bits/5]).
-
--define(BITS, 32).
--define(SIGN_BIT, 31).
--define(WORDMASK, 16#ffffffff).
--define(MAX_SIGNED_INT, 16#7fffffff).
--define(MIN_SIGNED_INT, -16#80000000).
--define(MAX_UNSIGNED_INT, 16#ffffffff).
-
--include("../main/hipe.hrl"). %% for ?EXIT
-
--include("hipe_rtl_arith.inc").
diff --git a/lib/hipe/rtl/hipe_rtl_arith_64.erl b/lib/hipe/rtl/hipe_rtl_arith_64.erl
deleted file mode 100644
index 5fa067b98e..0000000000
--- a/lib/hipe/rtl/hipe_rtl_arith_64.erl
+++ /dev/null
@@ -1,33 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_rtl_arith_64.erl
-%% Created : Feb 2004
-%% Purpose : Implements arithmetic for 64-bit target architectures.
-%%----------------------------------------------------------------------
-
--module(hipe_rtl_arith_64).
--export([eval_alu/3, eval_alub/4, eval_cond/3, eval_cond_bits/5]).
-
--define(BITS, 64).
--define(SIGN_BIT, 63).
--define(WORDMASK, 16#ffffffffffffffff).
--define(MAX_SIGNED_INT, 16#7fffffffffffffff).
--define(MIN_SIGNED_INT, -16#8000000000000000).
--define(MAX_UNSIGNED_INT,16#ffffffffffffffff).
-
--include("../main/hipe.hrl"). %% for ?EXIT
-
--include("hipe_rtl_arith.inc").
diff --git a/lib/hipe/rtl/hipe_rtl_binary.erl b/lib/hipe/rtl/hipe_rtl_binary.erl
deleted file mode 100644
index c11f61d567..0000000000
--- a/lib/hipe/rtl/hipe_rtl_binary.erl
+++ /dev/null
@@ -1,225 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_rtl_binary.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Description :
-%%%
-%%% Created : 5 Mar 2007 by Per Gustafsson <pergu@it.uu.se>
-%%%-------------------------------------------------------------------
--module(hipe_rtl_binary).
-
--export([gen_rtl/7]).
-
--export([floorlog2/1, get_word_integer/4, make_size/3, make_size/4]).
-
-%%--------------------------------------------------------------------
-
--define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa
--define(BYTE_SIZE, 8).
-
-%%--------------------------------------------------------------------
-
-gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab) ->
- case type_of_operation(BsOP) of
- match ->
- {hipe_rtl_binary_match:gen_rtl(
- BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab};
- construct ->
- hipe_rtl_binary_construct:gen_rtl(
- BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab)
- end.
-
-type_of_operation({bs_start_match,_}) -> match;
-type_of_operation({{bs_start_match,_},_}) -> match;
-type_of_operation({bs_get_binary,_,_}) -> match;
-type_of_operation({bs_get_binary_all,_,_}) -> match;
-type_of_operation({bs_get_binary_all_2,_,_}) -> match;
-type_of_operation({bs_get_integer,_,_}) -> match;
-type_of_operation({bs_get_float,_,_}) -> match;
-type_of_operation({bs_skip_bits,_}) -> match;
-type_of_operation({bs_skip_bits_all,_,_}) -> match;
-type_of_operation({bs_test_tail,_}) -> match;
-type_of_operation({bs_restore,_}) -> match;
-type_of_operation({bs_save,_}) -> match;
-type_of_operation({bs_test_unit,_}) -> match;
-type_of_operation({bs_match_string,_,_}) -> match;
-type_of_operation(bs_context_to_binary) -> match;
-type_of_operation({bs_add,_}) -> construct;
-type_of_operation({bs_add,_,_}) -> construct;
-type_of_operation(bs_bits_to_bytes) -> construct;
-type_of_operation(bs_bits_to_bytes2) -> construct;
-type_of_operation({bs_init,_}) -> construct;
-type_of_operation({bs_init,_,_}) -> construct;
-type_of_operation({bs_init_bits,_}) -> construct;
-type_of_operation({bs_init_bits,_,_}) -> construct;
-type_of_operation({bs_put_binary,_,_}) -> construct;
-type_of_operation({bs_put_binary_all,_,_}) -> construct;
-type_of_operation({bs_put_float,_,_,_}) -> construct;
-type_of_operation({bs_put_integer,_,_,_}) -> construct;
-type_of_operation({bs_put_string,_,_}) -> construct;
-type_of_operation({unsafe_bs_put_integer,_,_,_}) -> construct;
-type_of_operation(bs_utf8_size) -> construct;
-type_of_operation(bs_put_utf8) -> construct;
-type_of_operation(bs_get_utf8) -> match;
-type_of_operation(bs_utf16_size) -> construct;
-type_of_operation({bs_put_utf16,_}) -> construct;
-type_of_operation({bs_get_utf16,_}) -> match;
-type_of_operation(bs_validate_unicode) -> construct;
-type_of_operation(bs_validate_unicode_retract) -> match;
-type_of_operation(bs_final) -> construct;
-type_of_operation({bs_append,_,_,_,_}) -> construct;
-type_of_operation({bs_private_append,_,_}) -> construct;
-type_of_operation(bs_init_writable) -> construct.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Small utility functions:
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-create_lbls(X) when X > 0 ->
- [hipe_rtl:mk_new_label()|create_lbls(X-1)];
-create_lbls(0) ->
- [].
-
-%%------------------------------------------------------------------------------
-%% Utilities used by both hipe_rtl_binary_construct and hipe_rtl_binary_match
-%%------------------------------------------------------------------------------
-
-get_word_integer(Var, Register, SystemLimitLblName, FalseLblName) ->
- case hipe_rtl:is_imm(Var) of
- true ->
- TaggedVal = hipe_rtl:imm_value(Var),
- true = hipe_tagscheme:is_fixnum(TaggedVal),
- Val = hipe_tagscheme:fixnum_val(TaggedVal),
- if Val < 0 -> [hipe_rtl:mk_goto(FalseLblName)];
- true -> [hipe_rtl:mk_move(Register, hipe_rtl:mk_imm(Val))]
- end;
- false ->
- [EndLbl] = create_lbls(1),
- EndName = hipe_rtl:label_name(EndLbl),
- get_word_integer(Var, Register,SystemLimitLblName, FalseLblName,
- EndName, EndName, [EndLbl])
- end.
-
-get_word_integer(Var, Register, SystemLimitLblName, FalseLblName, TrueLblName,
- BigLblName, Tail) ->
- [FixnumLbl, NotFixnumLbl, BignumLbl, SuccessLbl] = create_lbls(4),
- [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(FixnumLbl),
- hipe_rtl:label_name(NotFixnumLbl), 0.99),
- FixnumLbl,
- hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
- hipe_rtl:label_name(SuccessLbl), FalseLblName,
- 0.99),
- SuccessLbl,
- hipe_tagscheme:untag_fixnum(Register, Var),
- hipe_rtl:mk_goto(TrueLblName),
- NotFixnumLbl,
- hipe_tagscheme:test_pos_bignum_arity(Var, 1, hipe_rtl:label_name(BignumLbl),
- FalseLblName, SystemLimitLblName, 0.99),
- BignumLbl,
- hipe_tagscheme:unsafe_get_one_word_pos_bignum(Register, Var),
- hipe_rtl:mk_goto(BigLblName) | Tail].
-
-make_size(UnitImm, BitsVar, FailLblName) ->
- make_size(UnitImm, BitsVar, FailLblName, FailLblName).
-
-make_size(1, BitsVar, OverflowLblName, FalseLblName) ->
- DstReg = hipe_rtl:mk_new_reg_gcsafe(),
- {get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName), DstReg};
-make_size(?BYTE_SIZE, BitsVar, OverflowLblName, FalseLblName) ->
- DstReg = hipe_rtl:mk_new_reg_gcsafe(),
- [FixnumLbl, BignumLbl] = create_lbls(2),
- WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
- FixnumLblName = hipe_rtl:label_name(FixnumLbl),
- Tail = [BignumLbl,
- hipe_rtl:mk_branch(DstReg, 'ltu',
- hipe_rtl:mk_imm(1 bsl (WordBits - ?BYTE_SHIFT)),
- FixnumLblName, OverflowLblName, 0.99),
- FixnumLbl,
- hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
- Code = get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName,
- FixnumLblName, hipe_rtl:label_name(BignumLbl), Tail),
- {Code, DstReg};
-make_size(UnitImm, BitsVar, OverflowLblName, FalseLblName) ->
- DstReg = hipe_rtl:mk_new_reg_gcsafe(),
- UnitList = number2list(UnitImm),
- Code = multiply_code(UnitList, BitsVar, DstReg, OverflowLblName, FalseLblName),
- {Code, DstReg}.
-
-multiply_code(List=[Head|_Tail], Variable, Result, OverflowLblName,
- FalseLblName) ->
- Test = set_high(Head),
- Tmp1 = hipe_rtl:mk_new_reg(),
- SuccessLbl = hipe_rtl:mk_new_label(),
- Register = hipe_rtl:mk_new_reg(),
- Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))|
- get_word_integer(Variable, Register, OverflowLblName, FalseLblName)]
- ++
- [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test),
- eq, hipe_rtl:label_name(SuccessLbl),
- OverflowLblName, 0.99),
- SuccessLbl],
- multiply_code(List, Register, Result, OverflowLblName, Tmp1, Code).
-
-multiply_code([ShiftSize|Rest], Register, Result, OverflowLblName, Tmp1,
- OldCode) ->
- SuccessLbl = hipe_rtl:mk_new_label(),
- Code =
- OldCode ++
- [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
- hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow,
- hipe_rtl:label_name(SuccessLbl), OverflowLblName, 0.99),
- SuccessLbl],
- multiply_code(Rest, Register, Result, OverflowLblName, Tmp1, Code);
-multiply_code([], _Register, _Result, _OverflowLblName, _Tmp1, Code) ->
- Code.
-
-set_high(X) ->
- WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
- set_high(min(X, WordBits), WordBits, 0).
-
-set_high(0, _, Y) ->
- Y;
-set_high(X, WordBits, Y) ->
- set_high(X-1, WordBits, Y+(1 bsl (WordBits-X))).
-
-
-number2list(X) when is_integer(X), X >= 0 ->
- number2list(X, []).
-
-number2list(1, Acc) ->
- lists:reverse([0|Acc]);
-number2list(0, Acc) ->
- lists:reverse(Acc);
-number2list(X, Acc) ->
- F = floorlog2(X),
- number2list(X-(1 bsl F), [F|Acc]).
-
-floorlog2(X) ->
- %% Double-precision floats do not have enough precision to make floorlog2
- %% exact for integers larger than 2^47.
- Approx = round(math:log(X)/math:log(2)-0.5),
- floorlog2_refine(X, Approx).
-
-floorlog2_refine(X, Approx) ->
- if (1 bsl Approx) > X ->
- floorlog2_refine(X, Approx - 1);
- (1 bsl (Approx+1)) > X ->
- Approx;
- true ->
- floorlog2_refine(X, Approx + 1)
- end.
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
deleted file mode 100644
index 111dda3d82..0000000000
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ /dev/null
@@ -1,1227 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ====================================================================
-%% Module : hipe_rtl_binary_construct
-%% Purpose :
-%% Notes :
-%% History : Written mostly by Per Gustafsson
-%% ====================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_binary_construct).
-
--export([gen_rtl/7]).
-
--import(hipe_rtl_binary, [get_word_integer/4]).
-
-%%-------------------------------------------------------------------------
-
--include("../main/hipe.hrl").
--include("hipe_rtl.hrl").
--include("hipe_literals.hrl").
-
--define(BYTE_SHIFT, hipe_rtl:mk_imm(3)). %% Turn bits into bytes or vice versa
--define(LOW_BITS, hipe_rtl:mk_imm(7)). %% Three lowest bits set
--define(LOW_BITS_INT, 7).
--define(BYTE_SIZE, 8).
--define(MAX_BINSIZE, ((1 bsl ((hipe_rtl_arch:word_size()*?BYTE_SIZE)-3)) - 1)).
-
-%% -------------------------------------------------------------------------
-%% The code is generated as a list of lists, it will be flattened later.
-%%
-
-gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab) ->
- %%io:format("~w, ~w, ~w~n", [BsOP, Args, Dst]),
- case BsOP of
- {bs_put_string, String, SizeInBytes} ->
- [NewOffset] = get_real(Dst),
- [Base, Offset] = Args,
- put_string(NewOffset, ConstTab, String, SizeInBytes, Base, Offset,
- TrueLblName);
- _ ->
- Code =
- case BsOP of
- {bs_init, Size, _Flags} ->
- [] = Args,
- [Dst0, Base, Offset] = Dst,
- case is_illegal_const(Size bsl 3) of
- true ->
- hipe_rtl:mk_goto(SystemLimitLblName);
- false ->
- const_init2(Size, Dst0, Base, Offset, TrueLblName)
- end;
-
- {bs_init, _Flags} ->
- [Size] = Args,
- [Dst0, Base, Offset] = Dst,
- var_init2(Size, Dst0, Base, Offset, TrueLblName,
- SystemLimitLblName, FalseLblName);
-
- {bs_init_bits, Size, _Flags} ->
- [] = Args,
- [Dst0, Base, Offset] = Dst,
- case is_illegal_const(Size) of
- true ->
- hipe_rtl:mk_goto(SystemLimitLblName);
- false ->
- const_init_bits(Size, Dst0, Base, Offset, TrueLblName)
- end;
-
- {bs_init_bits, _Flags} ->
- [Size] = Args,
- [Dst0, Base, Offset] = Dst,
- var_init_bits(Size, Dst0, Base, Offset, TrueLblName,
- SystemLimitLblName, FalseLblName);
-
- {bs_put_binary_all, Unit, _Flags} ->
- [Src, Base, Offset] = Args,
- [NewOffset] = get_real(Dst),
- put_binary_all(NewOffset, Src, Base, Offset, Unit,
- TrueLblName, FalseLblName);
-
- {bs_put_binary, Size, _Flags} ->
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- [NewOffset] = get_real(Dst),
- case Args of
- [Src, Base, Offset] ->
- put_static_binary(NewOffset, Src, Size, Base, Offset,
- TrueLblName, FalseLblName);
- [Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} =
- hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
- FalseLblName),
- InCode = put_dynamic_binary(NewOffset, Src, SizeReg, Base,
- Offset, TrueLblName, FalseLblName),
- SizeCode ++ InCode
- end
- end;
-
- {bs_put_float, Size, Flags, ConstInfo} ->
- [NewOffset] = get_real(Dst),
- Aligned = aligned(Flags),
- LittleEndian = littleendian(Flags),
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- case Args of
- [Src, Base, Offset] ->
- CCode = static_float_c_code(NewOffset, Src, Base, Offset, Size, Flags,
- TrueLblName, FalseLblName),
- put_float(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
- LittleEndian, ConstInfo, TrueLblName);
- [Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} =
- hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
- FalseLblName),
- InCode = float_c_code(NewOffset, Src, Base, Offset, SizeReg,
- Flags, TrueLblName, FalseLblName),
- SizeCode ++ InCode
- end
- end;
-
- {unsafe_bs_put_integer, 0, _Flags, _ConstInfo} ->
- [NewOffset] = get_real(Dst),
- case Args of
- [_Src, _Base, Offset] ->
- [hipe_rtl:mk_move(NewOffset,Offset),
- hipe_rtl:mk_goto(TrueLblName)];
- [_Src, _Bits, _Base, Offset] ->
- [hipe_rtl:mk_move(NewOffset,Offset),
- hipe_rtl:mk_goto(TrueLblName)]
- end;
-
- {unsafe_bs_put_integer, Size, Flags, ConstInfo} ->
- do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, true,
- TrueLblName, FalseLblName, SystemLimitLblName);
-
- {bs_put_integer, Size, Flags, ConstInfo} ->
- do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, false,
- TrueLblName, FalseLblName, SystemLimitLblName);
-
- bs_utf8_size ->
- case Dst of
- [_DstVar] ->
- [_Arg] = Args,
- [hipe_rtl:mk_call(Dst, bs_utf8_size, Args,
- TrueLblName, [], not_remote)];
- [] ->
- [hipe_rtl:mk_goto(TrueLblName)]
- end;
-
- bs_put_utf8 ->
- [_Src, _Base, _Offset] = Args,
- [NewOffs] = get_real(Dst),
- RetLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([NewOffs], bs_put_utf8, Args,
- hipe_rtl:label_name(RetLbl), [], not_remote),
- RetLbl,
- hipe_rtl:mk_branch(NewOffs, ne, hipe_rtl:mk_imm(0),
- TrueLblName, FalseLblName, 0.99)];
-
- bs_utf16_size ->
- case Dst of
- [_DstVar] ->
- [_Arg] = Args,
- [hipe_rtl:mk_call(Dst, bs_utf16_size, Args,
- TrueLblName, [], not_remote)];
- [] ->
- [hipe_rtl:mk_goto(TrueLblName)]
- end;
-
- {bs_put_utf16, Flags} ->
- [_Src, _Base, _Offset] = Args,
- NewDsts = get_real(Dst),
- PrimOp = % workaround for bif/primop arity restrictions
- case littleendian(Flags) of
- false -> bs_put_utf16be;
- true -> bs_put_utf16le
- end,
- [hipe_rtl:mk_call(NewDsts, PrimOp, Args,
- TrueLblName, FalseLblName, not_remote)];
-
- bs_validate_unicode ->
- [_Arg] = Args,
- [IsUnicode] = create_regs(1),
- RetLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([IsUnicode], is_unicode, Args,
- hipe_rtl:label_name(RetLbl), [], not_remote),
- RetLbl,
- hipe_rtl:mk_branch(IsUnicode, ne, hipe_rtl:mk_imm(0),
- TrueLblName, FalseLblName, 0.99)];
-
- bs_final ->
- Zero = hipe_rtl:mk_imm(0),
- [Src, Offset] = Args,
- [BitSize, ByteSize] = create_regs(2),
- [ShortLbl, LongLbl] = create_lbls(2),
- case Dst of
- [DstVar] ->
- [hipe_rtl:mk_alub(BitSize, Offset, 'and', ?LOW_BITS, eq,
- hipe_rtl:label_name(ShortLbl),
- hipe_rtl:label_name(LongLbl)), ShortLbl,
- hipe_rtl:mk_move(DstVar, Src),
- hipe_rtl:mk_goto(TrueLblName),
- LongLbl,
- hipe_rtl:mk_alu(ByteSize, Offset, 'srl', ?BYTE_SHIFT),
- hipe_tagscheme:mk_sub_binary(DstVar, ByteSize,
- Zero, BitSize, Zero, Src),
- hipe_rtl:mk_goto(TrueLblName)];
- [] ->
- [hipe_rtl:mk_goto(TrueLblName)]
- end;
-
- bs_init_writable ->
- Zero = hipe_rtl:mk_imm(0),
- [Size] = Args,
- [DstVar] = Dst,
- [SizeReg] = create_regs(1),
- [Base] = create_unsafe_regs(1),
- [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE + ?SUB_BIN_WORDSIZE),
- get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
- allocate_writable(DstVar, Base, SizeReg, Zero, Zero),
- hipe_rtl:mk_goto(TrueLblName)];
-
- {bs_private_append, _U, _F} ->
- [Size, Bin] = Args,
- [DstVar, Base, Offset] = Dst,
- [ProcBin] = create_vars(1),
- [SubSize, SizeReg, EndSubSize, EndSubBitSize] = create_regs(4),
- SubBinSize = {sub_binary, binsize},
- [hipe_tagscheme:get_field_from_term({sub_binary, orig}, Bin, ProcBin),
- hipe_tagscheme:get_field_from_term(SubBinSize, Bin, SubSize),
- get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
- realloc_binary(SizeReg, ProcBin, Base),
- calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
- hipe_tagscheme:set_field_from_term(SubBinSize, Bin, EndSubSize),
- hipe_tagscheme:set_field_from_term({sub_binary, bitsize}, Bin, EndSubBitSize),
- hipe_rtl:mk_move(DstVar, Bin),
- hipe_rtl:mk_goto(TrueLblName)];
-
- {bs_append, _U, _F, Unit, _Bla} ->
- [Size, Bin] = Args,
- [DstVar, Base, Offset] = Dst,
- [ProcBin] = create_vars(1),
- [Flags, SizeReg, IsWritable, EndSubSize, EndSubBitSize] =
- create_regs(5),
- [ContLbl,ContLbl2,ContLbl3,ContLbl4,WritableLbl,NotWritableLbl] =
- Lbls = create_lbls(6),
- [ContLblName, ContLbl2Name, ContLbl3Name, ContLbl4Name,
- Writable, NotWritable] =
- [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
- Zero = hipe_rtl:mk_imm(0),
- SubIsWritable = {sub_binary, is_writable},
- [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE + ?PROC_BIN_WORDSIZE),
- get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
- hipe_tagscheme:test_bitstr(Bin, ContLblName, FalseLblName, 0.99),
- ContLbl,
- hipe_tagscheme:test_subbinary(Bin,ContLbl2Name, NotWritable),
- ContLbl2,
- hipe_tagscheme:get_field_from_term(SubIsWritable, Bin, IsWritable),
- hipe_rtl:mk_branch(IsWritable, 'ne', Zero,
- ContLbl3Name, NotWritable),
- ContLbl3,
- hipe_tagscheme:get_field_from_term({sub_binary, orig}, Bin, ProcBin),
- hipe_tagscheme:get_field_from_term({proc_bin, flags}, ProcBin, Flags),
- hipe_rtl:mk_alub(Flags, Flags, 'and',
- hipe_rtl:mk_imm(?PB_IS_WRITABLE),
- eq, NotWritable, ContLbl4Name, 0.01),
- ContLbl4,
- calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
- is_divisible(Offset, Unit, Writable, FalseLblName),
- WritableLbl,
- hipe_tagscheme:set_field_from_term(SubIsWritable, Bin, Zero),
- realloc_binary(SizeReg, ProcBin, Base),
- hipe_tagscheme:mk_sub_binary(DstVar, EndSubSize, Zero,
- EndSubBitSize, Zero,
- hipe_rtl:mk_imm(1), ProcBin),
- hipe_rtl:mk_goto(TrueLblName),
- NotWritableLbl,
- not_writable_code(Bin, SizeReg, DstVar, Base, Offset, Unit,
- TrueLblName, FalseLblName)]
- end,
- {Code, ConstTab}
- end.
-
-%% Common implementation of bs_put_integer and unsafe_bs_put_integer
-do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, SrcUnsafe,
- TrueLblName, FalseLblName, SystemLimitLblName) ->
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- Aligned = aligned(Flags),
- LittleEndian = littleendian(Flags),
- [NewOffset] = get_real(Dst),
- case ConstInfo of
- fail ->
- [hipe_rtl:mk_goto(FalseLblName)];
- _ ->
- case Args of
- [Src, Base, Offset] ->
- CCode = static_int_c_code(NewOffset, Src, Base, Offset, Size,
- Flags, TrueLblName, FalseLblName),
- put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
- LittleEndian, SrcUnsafe, TrueLblName);
- [Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} =
- hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
- FalseLblName),
- CCode = int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
- TrueLblName, FalseLblName),
- InCode = put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg,
- CCode, Aligned, LittleEndian, SrcUnsafe,
- TrueLblName),
- SizeCode ++ InCode
- end
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Code that is used in the append and init writeable functions
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-not_writable_code(Bin, SizeReg, Dst, Base, Offset, Unit,
- TrueLblName, FalseLblName) ->
- [SrcBase] = create_unsafe_regs(1),
- [SrcOffset, SrcSize, TotSize, TotBytes, UsedBytes] = create_regs(5),
- [IncLbl,AllLbl] = Lbls = create_lbls(2),
- [IncLblName,AllLblName] = get_label_names(Lbls),
- [get_base_offset_size(Bin, SrcBase, SrcOffset, SrcSize, FalseLblName),
- hipe_rtl:mk_alu(TotSize, SrcSize, add, SizeReg),
- hipe_rtl:mk_alu(TotBytes, TotSize, add, ?LOW_BITS),
- hipe_rtl:mk_alu(TotBytes, TotBytes, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(UsedBytes, TotBytes, sll, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_branch(UsedBytes, geu, hipe_rtl:mk_imm(256),
- AllLblName, IncLblName),
- IncLbl,
- hipe_rtl:mk_move(UsedBytes, hipe_rtl:mk_imm(256)),
- AllLbl,
- allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize),
- put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0), Unit,
- TrueLblName, FalseLblName)].
-
-allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
- Zero = hipe_rtl:mk_imm(0),
- [NextLbl] = create_lbls(1),
- [EndSubSize, EndSubBitSize] = create_regs(2),
- [ProcBin] = create_unsafe_regs(1),
- [hipe_rtl:mk_call([Base], bs_allocate, [UsedBytes],
- hipe_rtl:label_name(NextLbl), [], not_remote),
- NextLbl,
- hipe_tagscheme:create_refc_binary(Base, TotBytes,
- hipe_rtl:mk_imm(?PB_IS_WRITABLE bor
- ?PB_ACTIVE_WRITER),
- ProcBin),
- hipe_rtl:mk_alu(EndSubSize, TotSize, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(EndSubBitSize, TotSize, 'and', ?LOW_BITS),
- hipe_tagscheme:mk_sub_binary(Dst, EndSubSize, Zero, EndSubBitSize,
- Zero, hipe_rtl:mk_imm(1), ProcBin)].
-
-realloc_binary(SizeReg, ProcBin, Base) ->
- [NoReallocLbl, ReallocLbl, NextLbl, ContLbl] = Lbls = create_lbls(4),
- [NoReallocLblName, ReallocLblName, NextLblName, ContLblName] =
- [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
- [PBSize, Tmp, ByteSize, NewSize, Flags, ResultingSize, OrigSize,
- BinPointer] = create_regs(8),
- ProcBinSizeTag = {proc_bin, binsize},
- ProcBinFlagsTag = {proc_bin, flags},
- ProcBinValTag = {proc_bin, val},
- ProcBinBytesTag = {proc_bin, bytes},
- BinOrigSizeTag = {binary, orig_size},
- [hipe_tagscheme:get_field_from_term(ProcBinSizeTag, ProcBin, PBSize),
- hipe_rtl:mk_alu(Tmp, SizeReg, 'add', ?LOW_BITS),
- hipe_rtl:mk_alu(ByteSize, Tmp, 'srl', ?BYTE_SHIFT),
- hipe_rtl:mk_alu(ResultingSize, ByteSize, 'add', PBSize),
- hipe_tagscheme:set_field_from_term(ProcBinSizeTag, ProcBin, ResultingSize),
- hipe_tagscheme:get_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
- hipe_rtl:mk_alu(Flags, Flags, 'or', hipe_rtl:mk_imm(?PB_ACTIVE_WRITER)),
- hipe_tagscheme:set_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
- hipe_tagscheme:get_field_from_term(ProcBinValTag, ProcBin, BinPointer),
- hipe_tagscheme:get_field_from_pointer(BinOrigSizeTag, BinPointer, OrigSize),
- hipe_rtl:mk_branch(OrigSize, 'geu', ResultingSize, NoReallocLblName,
- ReallocLblName),
- NoReallocLbl,
- hipe_tagscheme:get_field_from_term(ProcBinBytesTag, ProcBin, Base),
- hipe_rtl:mk_goto(ContLblName),
- ReallocLbl,
- hipe_rtl:mk_alu(NewSize, ResultingSize, 'sll', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_call([BinPointer], bs_reallocate, [BinPointer, NewSize],
- NextLblName, [], not_remote),
- NextLbl,
- hipe_tagscheme:set_field_from_pointer(BinOrigSizeTag, BinPointer, NewSize),
- hipe_tagscheme:set_field_from_term(ProcBinValTag, ProcBin, BinPointer),
- hipe_tagscheme:extract_binary_bytes(BinPointer, Base),
- hipe_tagscheme:set_field_from_term(ProcBinBytesTag, ProcBin, Base),
- ContLbl].
-
-calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize) ->
- [SubSize, SubBitSize, EndSize] = create_regs(3),
- [hipe_tagscheme:get_field_from_term({sub_binary, binsize}, Bin, SubSize),
- hipe_tagscheme:get_field_from_term({sub_binary, bitsize}, Bin, SubBitSize),
- hipe_rtl:mk_alu(Offset, SubSize, 'sll', ?BYTE_SHIFT),
- hipe_rtl:mk_alu(Offset, Offset, 'add', SubBitSize),
- hipe_rtl:mk_alu(EndSize, Offset, 'add', SizeReg),
- hipe_rtl:mk_alu(EndSubSize, EndSize, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(EndSubBitSize, EndSize, 'and', ?LOW_BITS)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Code that is used to create calls to beam functions
-%%
-%% X_c_code/8, used for putting terms into binaries
-%%
-%% X_get_c_code/10, used for getting terms from binaries
-%%
-%% - gen_test_sideffect_bs_call/4 is used to make a C-call that might
-%% fail but doesn't return an erlang value.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-static_float_c_code(NewOffset, Src, Base, Offset, Size, Flags,
- TrueLblName, FalseLblName) ->
- [SizeReg] = create_regs(1),
- [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))|
- float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
- TrueLblName, FalseLblName)].
-
-float_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
- TrueLblName, FalseLblName) ->
- put_c_code(bs_put_small_float, NewOffset, Src, Base, Offset, SizeReg,
- Flags, TrueLblName, FalseLblName).
-
-static_int_c_code(NewOffset, Src, Base, Offset, Size, Flags,
- TrueLblName, FalseLblName) ->
- [SizeReg] = create_regs(1),
- [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))|
- int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
- TrueLblName, FalseLblName)].
-
-int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
- TrueLblName, FalseLblName) ->
- put_c_code(bs_put_big_integer, NewOffset, Src, Base, Offset, SizeReg,
- Flags, TrueLblName, FalseLblName).
-
-binary_c_code(NewOffset, Src, Base, Offset, Size, TrueLblName) ->
- PassedLbl = hipe_rtl:mk_new_label(),
- [SizeReg, FlagsReg] = create_regs(2),
- [hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_move(SizeReg, Size),
- hipe_rtl:mk_call([], bs_put_bits, [Src, SizeReg, Base, Offset, FlagsReg],
- hipe_rtl:label_name(PassedLbl), [], not_remote),
- PassedLbl,
- hipe_rtl:mk_alu(NewOffset, Offset, add, SizeReg),
- hipe_rtl:mk_goto(TrueLblName)].
-
-put_c_code(Func, NewOffset, Src, Base, Offset, SizeReg, Flags,
- TrueLblName, FalseLblName) ->
- PassedLbl = hipe_rtl:mk_new_label(),
- [FlagsReg] = create_regs(1),
- [hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
- gen_test_sideffect_bs_call(Func, [Src, SizeReg, Base, Offset, FlagsReg],
- hipe_rtl:label_name(PassedLbl), FalseLblName),
- PassedLbl,
- hipe_rtl:mk_alu(NewOffset, Offset, add, SizeReg),
- hipe_rtl:mk_goto(TrueLblName)].
-
-gen_test_sideffect_bs_call(Name, Args, TrueLblName, FalseLblName) ->
- [Tmp1] = create_regs(1),
- RetLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([Tmp1], Name, Args,
- hipe_rtl:label_name(RetLbl), [], not_remote),
- RetLbl,
- hipe_rtl:mk_branch(Tmp1, eq, hipe_rtl:mk_imm(0),
- FalseLblName, TrueLblName, 0.01)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Small utility functions:
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-create_regs(X) when X > 0 ->
- [hipe_rtl:mk_new_reg_gcsafe()|create_regs(X-1)];
-create_regs(0) ->
- [].
-
-create_unsafe_regs(X) when X > 0 ->
- [hipe_rtl:mk_new_reg()|create_unsafe_regs(X-1)];
-create_unsafe_regs(0) ->
- [].
-
-create_vars(X) when X > 0 ->
- [hipe_rtl:mk_new_var()|create_vars(X-1)];
-create_vars(0) ->
- [].
-
-create_lbls(X) when X > 0 ->
- [hipe_rtl:mk_new_label()|create_lbls(X-1)];
-create_lbls(0) ->
- [].
-
-get_label_names(Lbls) ->
- [hipe_rtl:label_name(Lbl) || Lbl <- Lbls].
-
-aligned(Flags) ->
- case Flags band ?BSF_ALIGNED of
- 1 -> true;
- 0 -> false
- end.
-
-littleendian(Flags) ->
- case Flags band 2 of
- 2 -> true;
- 0 -> false
- end.
-
-is_illegal_const(Const) ->
- Const >= (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)) orelse Const < 0.
-
-get_real(Dst) ->
- case Dst of
- [_NewOffset] -> Dst;
- [] -> create_regs(1)
- end.
-
-%%-----------------------------------------------------------------------------
-%% Help functions implementing the bs operations in rtl code.
-%%
-%% The following functions are called from the translation switch:
-%%
-%% - put_string/7 creates code to copy a string to a binary
-%% starting at base+offset and ending at base+newoffset
-%%
-%% - const_init2/6 initializes the creation of a binary of constant size
-%%
-%% - var_init2/6 initializes the creation of a binary of variable size
-%%
-%% - get_int_from_unaligned_bin/11 creates code to extract a fixed
-%% size integer from a binary or makes a c-call if it does not
-%% conform to some certain rules.
-%%
-%% - get_unknown_size_int/11 creates code to extract a variable size
-%% byte-aligned integer from a binary or makes a c-call if it
-%% does not conform to some certain rules.
-%%
-%% - skip_no_of_bits/5 creates code to skip a variable amount of bits
-%% in a binary.
-%%
-%% - load_match_buffer/7 reloads the C-matchbuffer to RTL registers.
-%%
-%% - expand_runtime/4 creates code that calculates a maximal heap need
-%% before a binary match
-%%-----------------------------------------------------------------------------
-
-put_string(NewOffset, ConstTab, String, SizeInBytes, Base, Offset, TLName) ->
- [StringBase] = create_regs(1),
- {NewTab, Lbl} = hipe_consttab:insert_block(ConstTab, byte, String),
- {[hipe_rtl:mk_load_address(StringBase, Lbl, constant)|
- copy_string(StringBase, SizeInBytes, Base, Offset, NewOffset, TLName)],
- NewTab}.
-
-const_init2(Size, Dst, Base, Offset, TrueLblName) ->
- Log2WordSize = hipe_rtl_arch:log2_word_size(),
- WordSize = hipe_rtl_arch:word_size(),
- NextLbl = hipe_rtl:mk_new_label(),
- case Size =< ?MAX_HEAP_BIN_SIZE of
- true ->
- [hipe_rtl:mk_gctest(((Size + 3*WordSize-1) bsr Log2WordSize)+?SUB_BIN_WORDSIZE),
- hipe_tagscheme:create_heap_binary(Base, Size, Dst),
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_goto(TrueLblName)];
- false ->
- ByteSize = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
- hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm(Size)),
- hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
- hipe_rtl:label_name(NextLbl), [], not_remote),
- NextLbl,
- hipe_tagscheme:create_refc_binary(Base, ByteSize, Dst),
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_goto(TrueLblName)]
- end.
-
-const_init_bits(Size, Dst, Base, Offset, TrueLblName) ->
- Log2WordSize = hipe_rtl_arch:log2_word_size(),
- WordSize = hipe_rtl_arch:word_size(),
- [NextLbl] = create_lbls(1),
- TmpDst = hipe_rtl:mk_new_var(),
- Zero = hipe_rtl:mk_imm(0),
- {ExtraSpace, SubBinCode} =
- case (Size rem ?BYTE_SIZE) =:= 0 of
- true ->
- {0, [hipe_rtl:mk_move(Dst, TmpDst)]};
- false ->
- {?SUB_BIN_WORDSIZE,
- hipe_tagscheme:mk_sub_binary(Dst, hipe_rtl:mk_imm(Size bsr 3), Zero,
- hipe_rtl:mk_imm(Size band ?LOW_BITS_INT),
- Zero, TmpDst)}
- end,
- BaseBinCode =
- case Size =< (?MAX_HEAP_BIN_SIZE * 8) of
- true ->
- ByteSize = (Size + 7) div 8,
- [hipe_rtl:mk_gctest(((ByteSize + 3*WordSize-1) bsr Log2WordSize) + ExtraSpace),
- hipe_tagscheme:create_heap_binary(Base, ByteSize, TmpDst),
- hipe_rtl:mk_move(Offset, Zero)];
- false ->
- ByteSize = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+ExtraSpace),
- hipe_rtl:mk_move(Offset, Zero),
- hipe_rtl:mk_move(ByteSize, hipe_rtl:mk_imm((Size+7) bsr 3)),
- hipe_rtl:mk_call([Base], bs_allocate, [ByteSize],
- hipe_rtl:label_name(NextLbl), [], not_remote),
- NextLbl,
- hipe_tagscheme:create_refc_binary(Base, ByteSize, TmpDst)]
- end,
- [BaseBinCode, SubBinCode, hipe_rtl:mk_goto(TrueLblName)].
-
-var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
- Log2WordSize = hipe_rtl_arch:log2_word_size(),
- WordSize = hipe_rtl_arch:word_size(),
- [ContLbl, HeapLbl, REFCLbl, NextLbl] = create_lbls(4),
- [USize, Tmp] = create_regs(2),
- [get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
- hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_BINSIZE),
- hipe_rtl:label_name(ContLbl),
- SystemLimitLblName),
- ContLbl,
- hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
- hipe_rtl:label_name(HeapLbl),
- hipe_rtl:label_name(REFCLbl)),
- HeapLbl,
- hipe_rtl:mk_alu(Tmp, USize, add, hipe_rtl:mk_imm(3*WordSize-1)),
- hipe_rtl:mk_alu(Tmp, Tmp, srl, hipe_rtl:mk_imm(Log2WordSize)),
- hipe_rtl:mk_alu(Tmp, Tmp, add, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
- hipe_rtl:mk_gctest(Tmp),
- hipe_tagscheme:create_heap_binary(Base, USize, Dst),
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_goto(TrueLblName),
- REFCLbl,
- hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE+?SUB_BIN_WORDSIZE),
- hipe_rtl:mk_call([Base], bs_allocate, [USize],
- hipe_rtl:label_name(NextLbl), [], not_remote),
- NextLbl,
- hipe_tagscheme:create_refc_binary(Base, USize, Dst),
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_goto(TrueLblName)].
-
-var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
- [HeapLbl, REFCLbl, NextLbl, NoSubLbl, SubLbl,
- NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(9),
- [USize, ByteSize, TotByteSize, OffsetBits] = create_regs(4),
- [TmpDst] = create_unsafe_regs(1),
- Log2WordSize = hipe_rtl_arch:log2_word_size(),
- WordSize = hipe_rtl_arch:word_size(),
- MaximumWords =
- erlang:max((?MAX_HEAP_BIN_SIZE + 3*WordSize) bsr Log2WordSize,
- ?PROC_BIN_WORDSIZE) + ?SUB_BIN_WORDSIZE,
- Zero = hipe_rtl:mk_imm(0),
- [hipe_rtl:mk_gctest(MaximumWords),
- get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
- hipe_rtl:mk_alu(ByteSize, USize, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alub(OffsetBits, USize, 'and', ?LOW_BITS, eq,
- hipe_rtl:label_name(NoSubLbl),
- hipe_rtl:label_name(SubLbl)),
- NoSubLbl,
- hipe_rtl:mk_move(TotByteSize, ByteSize),
- hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
- SubLbl,
- hipe_rtl:mk_alu(TotByteSize, ByteSize, 'add', hipe_rtl:mk_imm(1)),
- JoinLbl,
- hipe_rtl:mk_branch(TotByteSize, 'leu', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
- hipe_rtl:label_name(HeapLbl),
- hipe_rtl:label_name(REFCLbl)),
- HeapLbl,
- hipe_tagscheme:create_heap_binary(Base, TotByteSize, TmpDst),
- hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl2)),
- REFCLbl,
- hipe_rtl:mk_call([Base], bs_allocate, [TotByteSize],
- hipe_rtl:label_name(NextLbl), [], not_remote),
- NextLbl,
- hipe_tagscheme:create_refc_binary(Base, TotByteSize, TmpDst),
- JoinLbl2,
- hipe_rtl:mk_move(Offset, Zero),
- hipe_rtl:mk_branch(OffsetBits, 'eq', Zero,
- hipe_rtl:label_name(NoCreateSubBin),
- hipe_rtl:label_name(CreateSubBin)),
- CreateSubBin,
- hipe_tagscheme:mk_sub_binary(Dst, ByteSize, Zero, OffsetBits, Zero, TmpDst),
- hipe_rtl:mk_goto(TrueLblName),
- NoCreateSubBin,
- hipe_rtl:mk_move(Dst, TmpDst),
- hipe_rtl:mk_goto(TrueLblName)].
-
-put_binary_all(NewOffset, Src, Base, Offset, Unit, TLName, FLName) ->
- [SrcBase, SrcOffset, NumBits] = create_regs(3),
- [ContLbl] = create_lbls(1),
- CCode = binary_c_code(NewOffset, Src, Base, Offset, NumBits, TLName),
- AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, NumBits, Base, Offset,
- NewOffset, TLName),
- [get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName),
- is_divisible(NumBits, Unit, hipe_rtl:label_name(ContLbl), FLName),
- ContLbl
- |test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode)].
-
-test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode) ->
- [Tmp] = create_regs(1),
- [AlignedLbl, CLbl] = create_lbls(2),
- [hipe_rtl:mk_alu(Tmp, SrcOffset, 'or', NumBits),
- hipe_rtl:mk_alu(Tmp, Tmp, 'or', Offset),
- hipe_rtl:mk_branch(Tmp, 'and', ?LOW_BITS, 'eq',
- hipe_rtl:label_name(AlignedLbl),
- hipe_rtl:label_name(CLbl), 0.5),
- AlignedLbl,
- AlignedCode,
- CLbl,
- CCode].
-
-put_static_binary(NewOffset, Src, Size, Base, Offset, TLName, FLName) ->
- [SrcBase] = create_unsafe_regs(1),
- [SrcOffset, SrcSize] = create_regs(2),
- case Size of
- 0 ->
- get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
- [hipe_rtl:mk_move(NewOffset, Offset),
- hipe_rtl:mk_goto(TLName)];
- _ ->
- SizeImm = hipe_rtl:mk_imm(Size),
- CCode = binary_c_code(NewOffset, Src, Base, Offset, SizeImm, TLName),
- AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, SizeImm, Base,
- Offset, NewOffset, TLName),
- get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
- small_check(SizeImm, SrcSize, FLName) ++
- test_alignment(SrcOffset, SizeImm, Offset, AlignedCode, CCode)
- end.
-
-put_dynamic_binary(NewOffset, Src, SizeReg, Base, Offset, TLName, FLName) ->
- [SrcBase] = create_unsafe_regs(1),
- [SrcOffset, SrcSize] = create_regs(2),
- CCode = binary_c_code(NewOffset, Src, Base, Offset, SizeReg, TLName),
- AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, SizeReg, Base, Offset,
- NewOffset, TLName),
- get_base_offset_size(Src, SrcBase, SrcOffset, SrcSize, FLName) ++
- small_check(SizeReg, SrcSize, FLName) ++
- test_alignment(SrcOffset, SizeReg, Offset, AlignedCode, CCode).
-
-put_float(NewOffset, Src, Base, Offset, 64, CCode, Aligned, LittleEndian,
- ConstInfo, TrueLblName) ->
- [CLbl] = create_lbls(1),
- case {Aligned, LittleEndian} of
- {true, false} ->
- copy_float_big(Base, Offset, NewOffset, Src,
- hipe_rtl:label_name(CLbl), TrueLblName, ConstInfo) ++
- [CLbl|CCode];
- {true, true} ->
- copy_float_little(Base, Offset, NewOffset, Src,
- hipe_rtl:label_name(CLbl), TrueLblName, ConstInfo) ++
- [CLbl|CCode];
- {false, _} ->
- CCode
- end;
-put_float(_NewOffset, _Src, _Base, _Offset, _Size, CCode, _Aligned,
- _LittleEndian, _ConstInfo, _TrueLblName) ->
- CCode.
-
-put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
- LittleEndian, SrcUnsafe, TrueLblName) ->
- {Init, End, UntaggedSrc} = make_init_end(Src, CCode, SrcUnsafe, TrueLblName),
- case {Aligned, LittleEndian} of
- {true, true} ->
- Init ++
- copy_int_little(Base, Offset, NewOffset, Size, UntaggedSrc) ++
- End;
- {true, false} ->
- Init ++
- copy_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
- End;
- {false, true} ->
- CCode;
- {false, false} ->
- Init ++
- copy_offset_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
- End
- end.
-
-put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
- LittleEndian, SrcUnsafe, TrueLblName) ->
- {Init, End, UntaggedSrc} = make_init_end(Src, CCode, SrcUnsafe, TrueLblName),
- case Aligned of
- true ->
- case LittleEndian of
- true ->
- Init ++
- copy_int_little(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
- End;
- false ->
- Init ++
- copy_int_big(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
- End
- end;
- false ->
- CCode
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Help functions used by the above
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-make_init_end(Src, CCode, false, TrueLblName) ->
- [CLbl, SuccessLbl] = create_lbls(2),
- [UntaggedSrc] = create_regs(1),
- Init = [hipe_tagscheme:test_fixnum(Src, hipe_rtl:label_name(SuccessLbl),
- hipe_rtl:label_name(CLbl), 0.99),
- SuccessLbl,
- hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
- End = [hipe_rtl:mk_goto(TrueLblName), CLbl| CCode],
- {Init, End, UntaggedSrc};
-make_init_end(Src, _CCode, true, TrueLblName) ->
- [UntaggedSrc] = create_regs(1),
- Init = [hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
- End = [hipe_rtl:mk_goto(TrueLblName)],
- {Init, End, UntaggedSrc}.
-
-get_base_offset_size(Binary, SrcBase, SrcOffset, SrcSize, FLName) ->
- [JoinLbl, EndLbl, SuccessLbl, SubLbl, OtherLbl, HeapLbl, REFCLbl] =
- Lbls = create_lbls(7),
- [JoinLblName, EndLblName, SuccessLblName, SubLblName,
- OtherLblName, HeapLblName, REFCLblName] = get_label_names(Lbls),
- [BitSize, BitOffset] = create_regs(2),
- [Orig] = create_vars(1),
- [hipe_tagscheme:test_bitstr(Binary, SuccessLblName, FLName, 0.99),
- SuccessLbl,
- hipe_tagscheme:get_field_from_term({sub_binary,binsize}, Binary, SrcSize),
- hipe_rtl:mk_alu(SrcSize, SrcSize, sll, ?BYTE_SHIFT),
- hipe_tagscheme:test_subbinary(Binary, SubLblName, OtherLblName),
- SubLbl,
- hipe_tagscheme:get_field_from_term({sub_binary,bitsize}, Binary, BitSize),
- hipe_tagscheme:get_field_from_term({sub_binary,offset}, Binary, SrcOffset),
- hipe_rtl:mk_alu(SrcSize, SrcSize, add, BitSize),
- hipe_tagscheme:get_field_from_term({sub_binary,bitoffset}, Binary, BitOffset),
- hipe_rtl:mk_alu(SrcOffset, SrcOffset, sll, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(SrcOffset, SrcOffset, add, BitOffset),
- hipe_tagscheme:get_field_from_term({sub_binary,orig}, Binary, Orig),
- hipe_rtl:mk_goto(JoinLblName),
- OtherLbl,
- hipe_rtl:mk_move(SrcOffset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_move(Orig, Binary),
- JoinLbl,
- hipe_tagscheme:test_heap_binary(Orig, HeapLblName, REFCLblName),
- HeapLbl,
- hipe_tagscheme:get_field_addr_from_term({heap_bin, {data, 0}}, Orig, SrcBase),
- hipe_rtl:mk_goto(EndLblName),
- REFCLbl,
- hipe_tagscheme:get_field_from_term({proc_bin,bytes}, Orig, SrcBase),
- EndLbl].
-
-copy_aligned_bytes(CopyBase, CopyOffset, Size, Base, Offset, NewOffset, TrueLblName) ->
- [BaseDst, BaseSrc] = create_unsafe_regs(2),
- [Iter, Extra, BothOffset] = create_regs(3),
- initializations(BaseSrc, BaseDst, BothOffset, CopyOffset, Offset, CopyBase, Base) ++
- [hipe_rtl:mk_alu(Extra, Size, 'and', ?LOW_BITS),
- hipe_rtl:mk_alu(Iter, Size, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)] ++
- easy_loop(BaseSrc, BaseDst, BothOffset, Iter, Extra, TrueLblName).
-
-copy_string(StringBase, StringSize, BinBase, BinOffset, NewOffset, TrueLblName) ->
- [TmpOffset,BothOffset,InitOffs] = create_regs(3),
- [NewBinBase] = create_unsafe_regs(1),
- [EasyLbl, HardLbl] = create_lbls(2),
- [hipe_rtl:mk_alu(TmpOffset, BinOffset, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(NewBinBase, BinBase, add, TmpOffset),
- hipe_rtl:mk_move(BothOffset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_alub(InitOffs, BinOffset, 'and', ?LOW_BITS, eq,
- hipe_rtl:label_name(EasyLbl), hipe_rtl:label_name(HardLbl)),
- EasyLbl,
- hipe_rtl:mk_alu(NewOffset, BinOffset, add,
- hipe_rtl:mk_imm(?bytes_to_bits(StringSize)))] ++
- easy_loop(StringBase, NewBinBase, BothOffset,
- hipe_rtl:mk_imm(StringSize), hipe_rtl:mk_imm(0), TrueLblName) ++
- [HardLbl,
- hipe_rtl:mk_alu(NewOffset, BinOffset, add,
- hipe_rtl:mk_imm(?bytes_to_bits(StringSize)))] ++
- hard_loop(StringBase, NewBinBase, BothOffset, hipe_rtl:mk_imm(StringSize),
- InitOffs, TrueLblName).
-
-small_check(SizeVar, CopySize, FalseLblName) ->
- SuccessLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_branch(SizeVar, leu, CopySize,
- hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl].
-
-easy_loop(BaseSrc, BaseDst, BothOffset, Iterations, Extra, TrueLblName) ->
- [Tmp1, Shift] = create_regs(2),
- [LoopLbl, TopLbl, EndLbl, ExtraLbl] = create_lbls(4),
- [TopLbl,
- hipe_rtl:mk_branch(BothOffset, ne, Iterations, hipe_rtl:label_name(LoopLbl),
- hipe_rtl:label_name(EndLbl), 0.99),
- LoopLbl,
- hipe_rtl:mk_load(Tmp1, BaseSrc, BothOffset, byte, unsigned),
- hipe_rtl:mk_store(BaseDst, BothOffset, Tmp1, byte),
- hipe_rtl:mk_alu(BothOffset, BothOffset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(TopLbl)),
- EndLbl,
- hipe_rtl:mk_branch(Extra, eq, hipe_rtl:mk_imm(0), TrueLblName,
- hipe_rtl:label_name(ExtraLbl)),
- ExtraLbl,
- hipe_rtl:mk_load(Tmp1, BaseSrc, BothOffset, byte, unsigned),
- hipe_rtl:mk_alu(Shift, hipe_rtl:mk_imm(?BYTE_SIZE), sub, Extra),
- hipe_rtl:mk_alu(Tmp1, Tmp1, srl, Shift),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, Shift),
- hipe_rtl:mk_store(BaseDst, BothOffset, Tmp1, byte),
- hipe_rtl:mk_goto(TrueLblName)].
-
-hard_loop(BaseSrc, BaseDst, BothOffset, Iterations,
- InitOffset, TrueLblName) ->
- [Tmp1, Tmp2, OldByte, NewByte, SaveByte] = create_regs(5),
- [LoopLbl, EndLbl, TopLbl] = create_lbls(3),
- [hipe_rtl:mk_load(OldByte, BaseDst, BothOffset, byte, unsigned),
- hipe_rtl:mk_alu(Tmp1, hipe_rtl:mk_imm(?BYTE_SIZE), sub, InitOffset),
- TopLbl,
- hipe_rtl:mk_branch(BothOffset, ne, Iterations,
- hipe_rtl:label_name(LoopLbl),
- hipe_rtl:label_name(EndLbl)),
- LoopLbl,
- hipe_rtl:mk_load(NewByte, BaseSrc, BothOffset, byte, unsigned),
- hipe_rtl:mk_alu(Tmp2, NewByte, srl, InitOffset),
- hipe_rtl:mk_alu(SaveByte, OldByte, 'or', Tmp2),
- hipe_rtl:mk_store(BaseDst, BothOffset, SaveByte, byte),
- hipe_rtl:mk_alu(OldByte, NewByte, sll, Tmp1),
- hipe_rtl:mk_alu(BothOffset, BothOffset, 'add', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(TopLbl)),
- EndLbl,
- hipe_rtl:mk_store(BaseDst, BothOffset, OldByte, byte),
- hipe_rtl:mk_goto(TrueLblName)].
-
-initializations(BaseTmp1, BaseTmp2, BothOffset, CopyOffset, Offset, CopyBase, Base) ->
- [OffsetTmp1,OffsetTmp2] = create_regs(2),
- [hipe_rtl:mk_alu(OffsetTmp1, CopyOffset, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(OffsetTmp2, Offset, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(BaseTmp1, CopyBase, add, OffsetTmp1),
- hipe_rtl:mk_alu(BaseTmp2, Base, add, OffsetTmp2),
- hipe_rtl:mk_move(BothOffset, hipe_rtl:mk_imm(0))].
-
-copy_int_little(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
- [Tmp2,TmpOffset] = create_regs(2),
- ByteSize = Size div ?BYTE_SIZE,
- [hipe_rtl:mk_alu(TmpOffset, Offset, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(Tmp2, hipe_rtl:mk_imm(ByteSize), 'add', TmpOffset)] ++
-
- little_loop(Tmp1, Tmp2, TmpOffset, Base) ++
-
- case Size band 7 of
- 0 ->
- [hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))];
- Bits ->
- [hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(?BYTE_SIZE-Bits)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))]
- end;
-copy_int_little(Base, Offset, NewOffset, Size, Tmp1) ->
- [Tmp2, Tmp3, Tmp4, TmpOffset] = create_regs(4),
- [hipe_rtl:mk_alu(Tmp2, Size, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(TmpOffset, Offset, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(Tmp3, Tmp2, 'add', TmpOffset)] ++
-
- little_loop(Tmp1, Tmp3, TmpOffset, Base) ++
-
- [hipe_rtl:mk_alu(Tmp4, Size, 'and', ?LOW_BITS),
- hipe_rtl:mk_alu(Tmp4, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp4),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, Tmp4),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)].
-
-little_loop(Tmp1, Tmp3, TmpOffset, Base) ->
- [BranchLbl, BodyLbl, EndLbl] = create_lbls(3),
- [BranchLbl,
- hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3,
- hipe_rtl:label_name(BodyLbl),
- hipe_rtl:label_name(EndLbl)),
- BodyLbl,
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
- EndLbl].
-
-big_loop(Tmp1, Tmp3, TmpOffset, Base) ->
- [BranchLbl, BodyLbl, EndLbl] = create_lbls(3),
- [BranchLbl,
- hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3,
- hipe_rtl:label_name(BodyLbl),
- hipe_rtl:label_name(EndLbl)),
- BodyLbl,
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
- EndLbl].
-
-copy_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
- [hipe_rtl:mk_move(NewOffset, Offset)];
-copy_int_big(Base, Offset, NewOffset, ?BYTE_SIZE, Tmp1) ->
- TmpOffset = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(8))];
-copy_int_big(Base, Offset, NewOffset, 2*?BYTE_SIZE, Tmp1) ->
- TmpOffset = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(16))];
-copy_int_big(Base, Offset, NewOffset, 3*?BYTE_SIZE, Tmp1) ->
- TmpOffset = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_alu(TmpOffset, Offset, srl, hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, add, hipe_rtl:mk_imm(2)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, add, hipe_rtl:mk_imm(24))];
-copy_int_big(Base, Offset,NewOffset, 4*?BYTE_SIZE, Tmp1) ->
- copy_big_word(Base, Offset, NewOffset, Tmp1);
-copy_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
- [OldOffset, TmpOffset, Bits] = create_regs(3),
- ByteSize = (Size + 7) div ?BYTE_SIZE,
- case Size band 7 of
- 0 ->
- [hipe_rtl:mk_alu(OldOffset, Offset, sra, hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(TmpOffset, OldOffset, add, hipe_rtl:mk_imm(ByteSize))];
- Rest ->
- [hipe_rtl:mk_alu(OldOffset, Offset, sra, hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(TmpOffset, OldOffset, add, hipe_rtl:mk_imm(ByteSize-1)),
- hipe_rtl:mk_alu(Bits, Tmp1, sll, hipe_rtl:mk_imm(?BYTE_SIZE-Rest)),
- hipe_rtl:mk_store(Base, TmpOffset, Bits, byte),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sra, hipe_rtl:mk_imm(Rest))]
- end ++
- big_loop(Tmp1, OldOffset, TmpOffset, Base) ++
- [hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size))];
-copy_int_big(Base, Offset, NewOffset, Size, Tmp1) ->
- Tmp2 = hipe_rtl:mk_new_reg(),
- Tmp3 = hipe_rtl:mk_new_reg(),
- Tmp4 = hipe_rtl:mk_new_reg(),
- Tmp5 = hipe_rtl:mk_new_reg(),
- Tmp6 = hipe_rtl:mk_new_reg(),
- TmpOffset = hipe_rtl:mk_new_reg(),
- EvenLbl = hipe_rtl:mk_new_label(),
- OddLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_alu(Tmp2, Size, 'srl', hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(Tmp3, Offset, 'srl', hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(TmpOffset, Tmp2, 'add', Tmp3),
- hipe_rtl:mk_alub(Tmp4, Size, 'and', hipe_rtl:mk_imm(7), 'eq',
- hipe_rtl:label_name(EvenLbl), hipe_rtl:label_name(OddLbl)),
- OddLbl,
- hipe_rtl:mk_alu(Tmp6, hipe_rtl:mk_imm(8), 'sub', Tmp4),
- hipe_rtl:mk_alu(Tmp5, Tmp1, 'sll', Tmp6),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp5, byte),
- EvenLbl,
- hipe_rtl:mk_alu(Tmp1, Tmp1, srl, Tmp4)] ++
- big_loop(Tmp1, Tmp3, TmpOffset, Base) ++
- [hipe_rtl:mk_alu(NewOffset, Offset, 'add', Size)].
-
-copy_big_word(Base, Offset, NewOffset, Word) ->
- TmpOffset = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
-
-copy_little_word(Base, Offset, NewOffset, Word) ->
- TmpOffset = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_alu(TmpOffset, Offset, 'srl', ?BYTE_SHIFT),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'add', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Word, Word, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
-
-copy_offset_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
- [hipe_rtl:mk_move(NewOffset, Offset)];
-copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1)
- when is_integer(Size), Size > 0 ->
- Tmp2 = hipe_rtl:mk_new_reg(),
- Tmp3 = hipe_rtl:mk_new_reg(),
- Tmp4 = hipe_rtl:mk_new_reg(),
- Tmp5 = hipe_rtl:mk_new_reg(),
- Tmp6 = hipe_rtl:mk_new_reg(),
- Tmp7 = hipe_rtl:mk_new_reg(),
- Tmp8 = hipe_rtl:mk_new_reg(),
- Tmp9 = hipe_rtl:mk_new_reg(),
- OldByte = hipe_rtl:mk_new_reg(),
- TmpOffset = hipe_rtl:mk_new_reg(),
- BranchLbl = hipe_rtl:mk_new_label(),
- BodyLbl = hipe_rtl:mk_new_label(),
- EndLbl = hipe_rtl:mk_new_label(),
- NextLbl = hipe_rtl:mk_new_label(),
- WordSize = hipe_rtl_arch:word_size(),
- [hipe_rtl:mk_alu(Tmp2, Offset, 'and', ?LOW_BITS),
- hipe_rtl:mk_alu(Tmp3, Offset, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(Size)),
- hipe_rtl:mk_alu(Tmp9, NewOffset, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(TmpOffset, Tmp9, srl, ?BYTE_SHIFT),
- hipe_rtl:mk_alu(Tmp4, NewOffset, 'and', ?LOW_BITS),
- hipe_rtl:mk_alu(Tmp6, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp4),
- hipe_rtl:mk_alu(Tmp6, Tmp6, 'and', ?LOW_BITS),
- hipe_rtl:mk_alu(Tmp4, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp6),
- hipe_rtl:mk_move(Tmp5, Tmp1),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sll', Tmp6),
- hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3, hipe_rtl:label_name(NextLbl),
- hipe_rtl:label_name(EndLbl)),
- NextLbl,
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_move(Tmp1, Tmp5),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', Tmp4),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
- BranchLbl,
- hipe_rtl:mk_branch(TmpOffset, 'ne', Tmp3, hipe_rtl:label_name(BodyLbl),
- hipe_rtl:label_name(EndLbl)),
- BodyLbl,
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sra', hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(BranchLbl)),
- EndLbl,
- hipe_rtl:mk_load(OldByte, Base, TmpOffset, byte, unsigned),
- hipe_rtl:mk_alu(Tmp8, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', Tmp2),
- hipe_rtl:mk_alu(OldByte, OldByte, 'srl', Tmp8),
- hipe_rtl:mk_alu(OldByte, OldByte, 'sll', Tmp8),
- hipe_rtl:mk_alu(Tmp7, Tmp2, 'add',
- hipe_rtl:mk_imm(?bytes_to_bits(WordSize-1))),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'sll', Tmp7),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'srl', Tmp7),
- hipe_rtl:mk_alu(Tmp1, Tmp1, 'or', OldByte),
- hipe_rtl:mk_store(Base, TmpOffset, Tmp1, byte)].
-
-copy_float_little(_Base, _Offset, _NewOffset, _Src, FalseLblName, _TrueLblName, fail) ->
- [hipe_rtl:mk_goto(FalseLblName)];
-copy_float_little(Base, Offset, NewOffset, Src, _FalseLblName, TrueLblName, pass) ->
- FloatLo = hipe_rtl:mk_new_reg(),
- FloatHi = hipe_rtl:mk_new_reg(),
- TmpOffset = hipe_rtl:mk_new_reg(),
- hipe_tagscheme:unsafe_load_float(FloatLo, FloatHi, Src) ++
- copy_little_word(Base, Offset, TmpOffset, FloatLo) ++
- copy_little_word(Base, TmpOffset, NewOffset, FloatHi) ++
- [hipe_rtl:mk_goto(TrueLblName)];
-copy_float_little(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
- SuccessLbl = hipe_rtl:mk_new_label(),
- hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
- [SuccessLbl|copy_float_little(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
-
-copy_float_big(_Base, _Offset, _NewOffset, _Src, FalseLblName, _TrueLblName, fail) ->
- [hipe_rtl:mk_goto(FalseLblName)];
-copy_float_big(Base, Offset, NewOffset, Src, _FalseLblName, TrueLblName,pass) ->
- FloatLo = hipe_rtl:mk_new_reg(),
- FloatHi = hipe_rtl:mk_new_reg(),
- TmpOffset = hipe_rtl:mk_new_reg(),
- hipe_tagscheme:unsafe_load_float(FloatLo, FloatHi, Src) ++
- copy_big_word(Base, Offset, TmpOffset, FloatHi) ++
- copy_big_word(Base, TmpOffset, NewOffset, FloatLo) ++
- [hipe_rtl:mk_goto(TrueLblName)];
-copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
- SuccessLbl = hipe_rtl:mk_new_label(),
- hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
- [SuccessLbl|copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
-
-is_divisible(_Dividend, 1, SuccLbl, _FailLbl) ->
- [hipe_rtl:mk_goto(SuccLbl)];
-is_divisible(Dividend, Divisor, SuccLbl, FailLbl) ->
- Log2 = hipe_rtl_binary:floorlog2(Divisor),
- case Divisor =:= 1 bsl Log2 of
- true -> %% Divisor is a power of 2
- %% Test that the Log2-1 lowest bits are clear
- Mask = hipe_rtl:mk_imm(Divisor - 1),
- [hipe_rtl:mk_branch(Dividend, 'and', Mask, eq, SuccLbl, FailLbl, 0.99)];
- false ->
- %% We need division, fall back to a primop
- [Tmp] = create_regs(1),
- RetLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([Tmp], is_divisible,
- [Dividend, hipe_rtl:mk_imm(Divisor)],
- hipe_rtl:label_name(RetLbl), [], not_remote),
- RetLbl,
- hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
- SuccLbl, FailLbl, 0.99)]
- end.
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
deleted file mode 100644
index 4575213838..0000000000
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ /dev/null
@@ -1,1115 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_rtl_binary_match.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Description :
-%%%
-%%% Created : 5 Mar 2007 by Per Gustafsson <pergu@it.uu.se>
-%%%-------------------------------------------------------------------
--module(hipe_rtl_binary_match).
-
--export([gen_rtl/5]).
-
--import(hipe_tagscheme, [set_field_from_term/3, get_field_from_term/3]).
-
--import(hipe_rtl_binary, [make_size/3]).
-
--include("hipe_literals.hrl").
-
-%%--------------------------------------------------------------------
-
--define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa
--define(LOW_BITS, 7). %% Three lowest bits set
--define(BYTE_SIZE, 8).
--define(MAX_SMALL_BITS, (hipe_rtl_arch:word_size() * ?BYTE_SIZE - 5)).
-
-%%--------------------------------------------------------------------
-
-%% ----- bs_start_match -----
-gen_rtl({bs_start_match, 0}, [Ms], [Binary], TrueLblName, FalseLblName) ->
- ReInitLbl = hipe_rtl:mk_new_label(),
- BinaryLbl = hipe_rtl:mk_new_label(),
- TestCode =
- [hipe_rtl:mk_move(Ms,Binary),
- hipe_tagscheme:test_matchstate(Binary,
- hipe_rtl:label_name(ReInitLbl),
- hipe_rtl:label_name(BinaryLbl),
- 0.99)],
- ReInitCode = reinit_matchstate(Ms, TrueLblName),
- OrdinaryCode = make_matchstate(Binary, 0, Ms, TrueLblName, FalseLblName),
- [TestCode,[ReInitLbl|ReInitCode],[BinaryLbl|OrdinaryCode]];
-gen_rtl({bs_start_match, Max}, [Ms], [Binary], TrueLblName, FalseLblName) ->
- MatchStateLbl = hipe_rtl:mk_new_label(),
- BinaryLbl = hipe_rtl:mk_new_label(),
- ReSizeLbl = hipe_rtl:mk_new_label(),
- ReInitLbl = hipe_rtl:mk_new_label(),
- TestCode =
- [hipe_rtl:mk_move(Ms,Binary),
- hipe_tagscheme:test_matchstate(Binary,
- hipe_rtl:label_name(MatchStateLbl),
- hipe_rtl:label_name(BinaryLbl),
- 0.99)],
- MatchStateTestCode =
- [hipe_tagscheme:compare_matchstate(Max, Ms,
- hipe_rtl:label_name(ReInitLbl),
- hipe_rtl:label_name(ReSizeLbl))],
- ReSizeCode = resize_matchstate(Ms, Max, TrueLblName),
- ReInitCode = reinit_matchstate(Ms, TrueLblName),
- OrdinaryCode = make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName),
- [TestCode, [MatchStateLbl|MatchStateTestCode], [ReSizeLbl|ReSizeCode],
- [ReInitLbl|ReInitCode], [BinaryLbl|OrdinaryCode]];
-gen_rtl({bs_start_match, _Max}, [], [Binary], TrueLblName, FalseLblName) ->
- MatchStateLbl = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_bitstr(Binary, TrueLblName,
- hipe_rtl:label_name(MatchStateLbl), 0.99),
- MatchStateLbl,
- hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)];
-gen_rtl({{bs_start_match, bitstr}, Max}, [Ms], [Binary],
- TrueLblName, FalseLblName) ->
- make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName);
-gen_rtl({{bs_start_match, bitstr}, _Max}, [], [_Binary],
- TrueLblName, _FalseLblName) ->
- [hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({{bs_start_match, ok_matchstate}, Max}, [Ms], [Binary],
- TrueLblName, FalseLblName) ->
- MatchStateLbl = hipe_rtl:mk_new_label(),
- BinaryLbl = hipe_rtl:mk_new_label(),
- TestCode =
- [hipe_rtl:mk_move(Ms,Binary),
- hipe_tagscheme:test_matchstate(Binary,
- hipe_rtl:label_name(MatchStateLbl),
- hipe_rtl:label_name(BinaryLbl),
- 0.99)],
- MatchStateCode = reinit_matchstate(Ms, TrueLblName),
- OrdinaryCode = make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName),
- TestCode ++ [MatchStateLbl|MatchStateCode] ++ [BinaryLbl|OrdinaryCode];
-gen_rtl({{bs_start_match, ok_matchstate}, _Max}, [], [Binary],
- TrueLblName, FalseLblName) ->
- MatchStateLbl = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_bitstr(Binary, TrueLblName,
- hipe_rtl:label_name(MatchStateLbl), 0.99),
- MatchStateLbl,
- hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)];
-%% ----- bs_get_integer -----
-gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms],
- TrueLblName, _FalseLblName) ->
- update_ms(NewMs, Ms) ++
- [hipe_rtl:mk_move(Dst, hipe_rtl:mk_imm(15)),
- hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({bs_get_integer, Size, Flags}, [Dst, NewMs], Args,
- TrueLblName, FalseLblName) ->
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- Signed = signed(Flags),
- LittleEndian = littleendian(Flags),
- Aligned = aligned(Flags),
- UnSafe = unsafe(Flags),
- case Args of
- [Ms] ->
- CCode = int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size),
- Flags, TrueLblName, FalseLblName),
- update_ms(NewMs, Ms) ++
- get_static_int(Dst, Ms, Size, CCode,
- Signed, LittleEndian, Aligned, UnSafe,
- TrueLblName, FalseLblName);
- [Ms, Arg] ->
- {SizeCode1, SizeReg1} = make_size(Size, Arg, FalseLblName),
- CCode = int_get_c_code(Dst, Ms, SizeReg1, Flags,
- TrueLblName, FalseLblName),
- InCode = get_dynamic_int(Dst, Ms, SizeReg1, CCode,
- Signed, LittleEndian, Aligned,
- TrueLblName, FalseLblName),
- update_ms(NewMs, Ms) ++ SizeCode1 ++ InCode
- end
- end;
-%% ----- bs_get_float -----
-gen_rtl({bs_get_float,Size,Flags}, [Dst1, NewMs], Args,
- TrueLblName, FalseLblName) ->
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- [hipe_rtl:mk_gctest(3)] ++
- case Args of
- [Ms] ->
- CCode = float_get_c_code(Dst1, Ms, hipe_rtl:mk_imm(Size), Flags,
- TrueLblName, FalseLblName),
- update_ms(NewMs, Ms) ++ CCode;
- [Ms, Arg] ->
- {SizeCode, SizeReg} = make_size(Size, Arg, FalseLblName),
- CCode = float_get_c_code(Dst1, Ms, SizeReg, Flags,
- TrueLblName, FalseLblName),
- update_ms(NewMs, Ms) ++ SizeCode ++ CCode
- end
- end;
-%% ----- bs_get_binary_all -----
-gen_rtl({bs_get_binary_all, Unit, _Flags}, [Dst], [Ms],
- TrueLblName, FalseLblName) ->
- [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
- get_binary_all(Dst, Unit, Ms, TrueLblName,FalseLblName);
-%% ----- bs_get_binary_all_2 -----
-gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst, NewMs], [Ms],
- TrueLblName, FalseLblName) ->
- [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
- update_ms(NewMs, Ms) ++
- get_binary_all(Dst, Unit, Ms, TrueLblName, FalseLblName);
-%% ----- bs_get_binary -----
-gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args,
- TrueLblName, FalseLblName) ->
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- Unsafe = unsafe(Flags),
- {OldMs, SizeReg, SizeCode} =
- case Args of
- [Ms] ->
- SzReg = hipe_rtl:mk_new_reg(),
- SzCode = [hipe_rtl:mk_move(SzReg, hipe_rtl:mk_imm(Size))],
- {Ms, SzReg, SzCode};
- [Ms, BitsVar] ->
- {SzCode, SzReg} = make_size(Size, BitsVar, FalseLblName),
- {Ms, SzReg, SzCode}
- end,
- InCode = get_binary(Dst, OldMs, SizeReg, Unsafe,
- TrueLblName, FalseLblName),
- [hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
- update_ms(NewMs, OldMs) ++ SizeCode ++ InCode
- end;
-%% ----- bs_get_utf8 -----
-gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++ utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName);
-%% ----- bs_get_utf16 -----
-gen_rtl({bs_get_utf16, Flags}, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++
- utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName);
-%% ----- bs_validate_unicode_retract -----
-gen_rtl(bs_validate_unicode_retract, [NewMs], [Src, Ms],
- TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++
- validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName);
-%% ----- bs_test_tail -----
-gen_rtl({bs_test_tail, NumBits}, [NewMs], [Ms], TrueLblName, FalseLblName) ->
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
- update_ms(NewMs, Ms) ++ ExCode ++
- [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
- hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
-%% ----- bs_test_unit -----
-gen_rtl({bs_test_unit, Unit}, [], [Ms], TrueLblName, FalseLblName) ->
- {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
- SizeReg = hipe_rtl:mk_new_reg(),
- ExCode ++
- [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
- test_alignment_code(SizeReg, Unit, TrueLblName, FalseLblName)];
-gen_rtl({bs_test_tail, NumBits}, [], [Ms], TrueLblName, FalseLblName) ->
- {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
- ExCode ++
- [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
- hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
-%% ----- bs_skip_bits_all -----
-gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
- TrueLblName, FalseLblName) ->
- opt_update_ms(Dst, Ms) ++
- skip_bits_all(Unit, Ms, TrueLblName, FalseLblName);
-%% ----- bs_skip_bits -----
-gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) ->
- MaxValue = (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)),
- opt_update_ms(Dst, Ms) ++
- case Bits < MaxValue of
- true ->
- case Args of
- [] ->
- skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
- [Arg] ->
- {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
- InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
- SizeCode ++ InCode
- end;
- false -> % handle overflow case
- case Args of
- [] ->
- [hipe_rtl:mk_goto(FalseLblName)];
- [Arg] ->
- [hipe_rtl:mk_branch(Arg, 'eq', hipe_tagscheme:mk_fixnum(0),
- TrueLblName, FalseLblName, 0.5)]
- end
- end;
-%% ----- bs_restore -----
-gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- update_ms(NewMs, Ms) ++
- [get_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Tmp1),
- set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp1),
- hipe_rtl:mk_goto(TrueLblName)];
-%% ----- bs_save -----
-gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
- {Offset, Instr} = extract_matchstate_var(offset, Ms),
- update_ms(NewMs, Ms) ++
- [Instr,
- set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset),
- hipe_rtl:mk_goto(TrueLblName)];
-%% ----- bs_match_string -----
-gen_rtl({bs_match_string, String, BitSize}, Dst, [Ms],
- TrueLblName, FalseLblName) ->
- {[Offset, BinSize, Base], Instrs} =
- extract_matchstate_vars([offset, binsize, base], Ms),
- [SuccessLbl, ALbl, ULbl] = create_lbls(3),
- [NewOffset, BitOffset] = create_gcsafe_regs(2),
- Unit = (hipe_rtl_arch:word_size() - 1) * ?BYTE_SIZE,
- Init =
- [Instrs,
- opt_update_ms(Dst, Ms),
- check_size(Offset, hipe_rtl:mk_imm(BitSize), BinSize,
- NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl],
- SplitCode =
- [hipe_rtl:mk_alub(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq,
- hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))],
- Loops = BitSize div Unit,
- SkipSize = Loops * Unit,
- {ACode1, UCode1} =
- case Loops of
- 0 ->
- {[], []};
- _ ->
- create_loops(Loops, Unit, String, Base,
- Offset, BitOffset, FalseLblName)
- end,
- <<_:SkipSize/bits, RestString/bits>> = String,
- {ACode2, UCode2} =
- case BitSize rem Unit of
- 0 ->
- {[], []};
- Rem ->
- create_rests(Rem, RestString, Base, Offset, BitOffset, FalseLblName)
- end,
- GoTo = hipe_rtl:mk_goto(TrueLblName),
- End = case Dst of
- [] -> [GoTo];
- [NewMs] -> [update_offset(NewOffset, NewMs), GoTo]
- end,
- [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2, End];
-%% ----- bs_context_to_binary -----
-gen_rtl(bs_context_to_binary, [Bin], [Var], TrueLblName, _FalseLblName) ->
- MSLabel = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_move(Bin, Var),
- hipe_tagscheme:test_matchstate(Var, hipe_rtl:label_name(MSLabel),
- TrueLblName, 0.5),
- MSLabel,
- hipe_tagscheme:convert_matchstate(Bin),
- hipe_rtl:mk_goto(TrueLblName)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Calls to C %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-int_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
- make_int_gc_code(Size) ++
- get_c_code(bs_get_integer_2, Dst1, Ms, Size, Flags,
- TrueLblName, FalseLblName).
-
-float_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
- get_c_code(bs_get_float_2, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName).
-
-get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
- SizeReg = hipe_rtl:mk_new_reg_gcsafe(),
- FlagsReg = hipe_rtl:mk_new_reg_gcsafe(),
- RetReg = hipe_rtl:mk_new_reg_gcsafe(),
- MatchBuf = hipe_rtl:mk_new_reg(),
- RetLabel = hipe_rtl:mk_new_label(),
- OkLabel = hipe_rtl:mk_new_label(),
- NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
- [hipe_rtl:mk_move(SizeReg, Size),
- hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
- hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
- hipe_rtl_arch:call_bif([RetReg], Func, [SizeReg, FlagsReg, MatchBuf],
- hipe_rtl:label_name(RetLabel), FalseLblName),
- RetLabel,
- hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
- hipe_rtl:label_name(OkLabel), 0.01),
- OkLabel,
- hipe_rtl:mk_move(Dst1, RetReg),
- hipe_rtl:mk_goto(TrueLblName)].
-
-utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) ->
- RetReg = hipe_rtl:mk_new_reg_gcsafe(),
- OkLabel = hipe_rtl:mk_new_label(),
- MatchBuf = hipe_rtl:mk_new_reg(),
- NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
- [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
- hipe_rtl_arch:call_bif([RetReg], bs_get_utf8, [MatchBuf], [], []),
- hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
- hipe_rtl:label_name(OkLabel), 0.01),
- OkLabel,
- hipe_rtl:mk_move(Dst, RetReg),
- hipe_rtl:mk_goto(TrueLblName)].
-
-utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName) ->
- RetReg = hipe_rtl:mk_new_reg_gcsafe(),
- OkLabel = hipe_rtl:mk_new_label(),
- MatchBuf = hipe_rtl:mk_new_reg(),
- NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
- FlagsReg = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
- hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
- hipe_rtl_arch:call_bif([RetReg], bs_get_utf16, [MatchBuf, FlagsReg], [], []),
- hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
- hipe_rtl:label_name(OkLabel), 0.01),
- OkLabel,
- hipe_rtl:mk_move(Dst, RetReg),
- hipe_rtl:mk_goto(TrueLblName)].
-
-validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
- MatchBuf = hipe_rtl:mk_new_reg(),
- Zero = hipe_rtl:mk_imm(0),
- Tmp = hipe_rtl:mk_new_reg(),
- [hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
- hipe_rtl_arch:call_bif([Tmp], bs_validate_unicode_retract,
- [MatchBuf, Src], [], []),
- hipe_rtl:mk_branch(Tmp, eq, Zero, FalseLblName, TrueLblName, 0.01)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Int Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) ->
- [Reg] = create_gcsafe_regs(1),
- AlignedFun = fun(Value) ->
- [get_int_to_reg(Reg, Unit, Base, Offset, 'srl',
- {unsigned, big}),
- update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
- end,
- UnAlignedFun = fun(Value) ->
- [get_unaligned_int_to_reg(Reg, Unit,
- Base, Offset, BitOffset,
- 'srl', {unsigned, big})|
- update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
- end,
- {create_loops(Loops, Unit, String, AlignedFun),
- create_loops(Loops, Unit, String, UnAlignedFun)}.
-
-create_rests(RemBits, String, Base, Offset, BitOffset, FalseLblName) ->
- [Reg] = create_gcsafe_regs(1),
- AlignedFun = fun(Value) ->
- [get_int_to_reg(Reg, RemBits, Base, Offset, 'srl',
- {unsigned, big})|
- just_test(Reg, Value, FalseLblName)]
- end,
- UnAlignedFun = fun(Value) ->
- [get_unaligned_int_to_reg(Reg, RemBits,
- Base, Offset, BitOffset,
- 'srl', {unsigned, big})|
- just_test(Reg, Value, FalseLblName)]
- end,
- {create_loops(1, RemBits, String, AlignedFun),
- create_loops(1, RemBits, String, UnAlignedFun)}.
-
-create_loops(0, _Unit, _String, _IntFun) ->
- [];
-create_loops(N, Unit, String, IntFun) ->
- {Value, RestString} = get_value(Unit, String),
- [IntFun(Value),
- create_loops(N-1, Unit, RestString, IntFun)].
-
-update_and_test(Reg, Unit, Offset, Value, FalseLblName) ->
- [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit), FalseLblName),
- just_test(Reg, Value, FalseLblName)].
-
-just_test(Reg, Value, FalseLblName) ->
- [ContLbl] = create_lbls(1),
- [hipe_rtl:mk_branch(Reg, eq, hipe_rtl:mk_imm(Value),
- hipe_rtl:label_name(ContLbl), FalseLblName),
- ContLbl].
-
-get_value(N, String) ->
- <<I:N, Rest/bits>> = String,
- {I, Rest}.
-
-make_int_gc_code(I) when is_integer(I) ->
- case hipe_tagscheme:bignum_sizeneed(I) of
- 0 -> [];
- X when is_integer(X) -> [hipe_rtl:mk_gctest(X)]
- end;
-make_int_gc_code(SReg) ->
- FixNumLbl = hipe_rtl:mk_new_label(),
- FixNumLblName = hipe_rtl:label_name(FixNumLbl),
- {ResReg,Code} = hipe_tagscheme:bignum_sizeneed_code(SReg, FixNumLblName),
- Code ++
- [hipe_rtl:mk_gctest(ResReg),
- hipe_rtl:mk_goto(FixNumLblName),
- FixNumLbl].
-
-get_static_int(Dst1, Ms, Size, CCode, Signed, LittleEndian, Aligned,
- Unsafe, TrueLblName, FalseLblName) ->
- WordSize = hipe_rtl_arch:word_size(),
- case Size =< WordSize*?BYTE_SIZE of
- true ->
- case {Aligned, LittleEndian} of
- {true, false} ->
- get_int_from_bin(Ms, Size, Dst1,Signed, LittleEndian,
- Unsafe, FalseLblName, TrueLblName);
- {true, true} ->
- case Size rem ?BYTE_SIZE of
- 0 ->
- get_int_from_bin(Ms, Size, Dst1, Signed, LittleEndian,
- Unsafe, FalseLblName, TrueLblName);
- _ ->
- CCode
- end;
- {false, false} ->
- get_int_from_unaligned_bin(Ms, Size, Dst1, Signed,
- Unsafe, FalseLblName, TrueLblName);
- {false, true} ->
- CCode
- end;
- false ->
- CCode
- end.
-
-get_dynamic_int(Dst1, Ms, SizeReg, CCode, Signed, LittleEndian, true,
- TrueLblName, FalseLblName) ->
- {Init, End} = make_dyn_prep(SizeReg, CCode),
- Init ++
- get_unknown_size_int(SizeReg, Ms, Dst1, Signed, LittleEndian,
- FalseLblName, TrueLblName) ++
- End;
-get_dynamic_int(_Dst1, _Ms, _SizeReg, CCode, _Signed, _LittleEndian, false,
- _TrueLblName, _FalseLblName) ->
- CCode.
-
-get_int_from_bin(Ms, Size, Dst1, Signed, LittleEndian,
- Unsafe, FalseLblName, TrueLblName) ->
- Shiftr = shift_type(Signed),
- Type = get_type(Signed, LittleEndian),
- NewOffset = hipe_rtl:mk_new_reg_gcsafe(),
- [SuccessLbl] = create_lbls(1),
- {[Base,Offset,BinSize], ExCode} =
- extract_matchstate_vars([base,offset,binsize], Ms),
- ExCode ++
- [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
- Unsafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl] ++
- [update_offset(NewOffset, Ms)] ++
- get_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName).
-
-get_int_from_unaligned_bin(Ms, Size, Dst1, Signed,
- UnSafe, FalseLblName, TrueLblName) ->
- Shiftr = shift_type(Signed),
- Type = get_type(Signed, false),
- NewOffset = hipe_rtl:mk_new_reg_gcsafe(),
- [SuccessLbl] = create_lbls(1),
- {[Base,Offset,BinSize], ExCode} =
- extract_matchstate_vars([base,offset,binsize], Ms),
- ExCode ++
- [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
- UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl] ++
- [update_offset(NewOffset, Ms)] ++
- get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName).
-
-get_unknown_size_int(SizeReg, Ms, Dst1, Signed, Little,
- FalseLblName, TrueLblName) ->
- Shiftr = shift_type(Signed),
- Type = get_type(Signed, false),
- [NewOffset] = create_gcsafe_regs(1),
- [SuccessLbl] = create_lbls(1),
- {[Base,Offset,BinSize], ExCode} =
- extract_matchstate_vars([base,offset,binsize], Ms),
- ExCode ++
- [check_size(Offset, SizeReg, BinSize, NewOffset,
- hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl,
- update_offset(NewOffset, Ms)] ++
- case Little of
- true ->
- get_little_unknown_int(Dst1, Base, Offset, NewOffset,
- Shiftr, Type, TrueLblName);
- false ->
- get_big_unknown_int(Dst1, Base, Offset, NewOffset,
- Shiftr, Type, TrueLblName)
- end.
-
-make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName) ->
- Base = hipe_rtl:mk_new_reg(),
- Orig = hipe_rtl:mk_new_var(),
- BinSize = hipe_rtl:mk_new_reg_gcsafe(),
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
- Lbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max),
- get_binary_bytes(Binary, BinSize, Base, Offset,
- Orig, hipe_rtl:label_name(Lbl), FalseLblName),
- Lbl,
- hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms),
- hipe_rtl:mk_goto(TrueLblName)].
-
-resize_matchstate(Ms, Max, TrueLblName) ->
- Base = hipe_rtl:mk_new_reg(),
- Orig = hipe_rtl:mk_new_var(),
- BinSize = hipe_rtl:mk_new_reg_gcsafe(),
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max),
- get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize),
- get_field_from_term({matchstate, {matchbuffer, base}}, Ms, Base),
- get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig),
- get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Offset),
- hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms),
- hipe_rtl:mk_goto(TrueLblName)].
-
-reinit_matchstate(Ms, TrueLblName) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp),
- set_field_from_term({matchstate, {saveoffset, 0}}, Ms, Tmp),
- hipe_rtl:mk_goto(TrueLblName)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%% Binary Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-get_binary_all(Dst1, 1, Ms, TrueLblName, _FalseLblName) ->
- [SizeReg] = create_gcsafe_regs(1),
- {[Offset,BinSize,Orig], ExCode} =
- extract_matchstate_vars([offset,binsize,orig], Ms),
- MakeCode =
- [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
- construct_subbin(Dst1,SizeReg,Offset,Orig)] ++
- [update_offset(BinSize, Ms),
- hipe_rtl:mk_goto(TrueLblName)],
- ExCode ++ MakeCode;
-get_binary_all(Dst1, Unit, Ms, TrueLblName, FalseLblName) ->
- [SizeReg] = create_gcsafe_regs(1),
- [SuccessLbl] = create_lbls(1),
- SLblName = hipe_rtl:label_name(SuccessLbl),
- {[Offset,BinSize,Orig], ExCode} =
- extract_matchstate_vars([offset,binsize,orig], Ms),
- MakeCode =
- [hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
- test_alignment_code(SizeReg,Unit,SLblName,FalseLblName)] ++
- [SuccessLbl|
- construct_subbin(Dst1,SizeReg,Offset,Orig)] ++
- [update_offset(BinSize, Ms),
- hipe_rtl:mk_goto(TrueLblName)],
- ExCode ++ MakeCode.
-
-get_binary(Dst1, Ms, SizeReg, UnSafe, TrueLblName, FalseLblName) ->
- [SuccessLbl] = create_lbls(1),
- [EndOffset] = create_gcsafe_regs(1),
- {[Offset,BinSize,Orig], ExCode} =
- extract_matchstate_vars([offset,binsize,orig], Ms),
- CheckCode =
- [check_size(Offset, SizeReg, BinSize, EndOffset, UnSafe,
- hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl],
- MakeCode =
- construct_subbin(Dst1, SizeReg, Offset, Orig)
- ++ [update_offset(EndOffset, Ms),
- hipe_rtl:mk_goto(TrueLblName)],
- ExCode ++ CheckCode ++ MakeCode.
-
-construct_subbin(Dst, Size, Offset, Orig) ->
- [BitOffset, ByteOffset, BitSize, ByteSize] = create_gcsafe_regs(4),
- [hipe_rtl:mk_alu(ByteSize, Size, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- hipe_rtl:mk_alu(BitSize, Size, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
- hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- hipe_rtl:mk_alu(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
- hipe_tagscheme:mk_sub_binary(Dst, ByteSize, ByteOffset,
- BitSize, BitOffset, Orig)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%% Skip Bits %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-skip_bits_all(1, Ms, TrueLblName, _FalseLblName) ->
- {[BinSize], ExCode} = extract_matchstate_vars([binsize], Ms),
- ExCode ++ [update_offset(BinSize,Ms), hipe_rtl:mk_goto(TrueLblName)];
-skip_bits_all(Unit,Ms, TrueLblName, FalseLblName) ->
- [Size] = create_gcsafe_regs(1),
- [SuccessLbl] = create_lbls(1),
- SLblName = hipe_rtl:label_name(SuccessLbl),
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
- ExCode ++
- [hipe_rtl:mk_alu(Size,BinSize,sub,Offset)]
- ++
- test_alignment_code(Size,Unit,SLblName,FalseLblName) ++
- [SuccessLbl,
- update_offset(BinSize,Ms),
- hipe_rtl:mk_goto(TrueLblName)].
-
-test_alignment_code(Size, Unit, SLblName, FalseLblName) ->
- case Unit of
- 1 -> [hipe_rtl:mk_goto(SLblName)];
- 2 -> get_fast_test_code(Size,1,SLblName,FalseLblName);
- 4 -> get_fast_test_code(Size,3,SLblName,FalseLblName);
- 8 -> get_fast_test_code(Size,7,SLblName,FalseLblName);
- 16 -> get_fast_test_code(Size,15,SLblName,FalseLblName);
- 32 -> get_fast_test_code(Size,31,SLblName,FalseLblName);
- _ -> get_slow_test_code(Size,Unit,SLblName,FalseLblName)
- end.
-
-get_fast_test_code(Size, AndTest, SLblName, FalseLblName) ->
- [hipe_rtl:mk_branch(Size, 'and', hipe_rtl:mk_imm(AndTest), 'eq',
- SLblName, FalseLblName, 0.5)].
-
-%% This is really slow
-get_slow_test_code(Size, Unit, SLblName, FalseLblName) ->
- [Tmp] = create_gcsafe_regs(1),
- [LoopLbl,Lbl1,Lbl2] = create_lbls(3),
- LoopLblName = hipe_rtl:label_name(LoopLbl),
- Lbl1Name = hipe_rtl:label_name(Lbl1),
- Lbl2Name = hipe_rtl:label_name(Lbl2),
- [hipe_rtl:mk_move(Tmp,Size),
- LoopLbl,
- hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0), SLblName, Lbl1Name),
- Lbl1,
- hipe_rtl:mk_branch(Tmp, lt, hipe_rtl:mk_imm(0), FalseLblName, Lbl2Name),
- Lbl2,
- hipe_rtl:mk_alu(Tmp,Tmp,sub,hipe_rtl:mk_imm(Unit)),
- hipe_rtl:mk_goto(LoopLblName)].
-
-skip_bits2(Ms, NoOfBits, TrueLblName, FalseLblName) ->
- [NewOffset] = create_gcsafe_regs(1),
- [TempLbl] = create_lbls(1),
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
- ExCode ++
- add_to_offset(NewOffset, NoOfBits, Offset, FalseLblName) ++
- [hipe_rtl:mk_branch(BinSize, 'ltu', NewOffset, FalseLblName,
- hipe_rtl:label_name(TempLbl), 0.01),
- TempLbl,
- update_offset(NewOffset, Ms),
- hipe_rtl:mk_goto(TrueLblName)].
-
-add_to_offset(Result, Extra, Original, FalseLblName) ->
- TrueLbl = hipe_rtl:mk_new_label(),
- %% Note: 'ltu' means 'unsigned overflow'.
- [hipe_rtl:mk_alub(Result, Extra, 'add', Original, 'ltu',
- FalseLblName, hipe_rtl:label_name(TrueLbl)),
- TrueLbl].
-
-%%%%%%%%%%%%%%%%%%%%%%% Code for start match %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-get_binary_bytes(Binary, BinSize, Base, Offset, Orig,
- TrueLblName, FalseLblName) ->
- [OrigOffset,BitSize,BitOffset] = create_gcsafe_regs(3),
- [SuccessLbl,SubLbl,OtherLbl,JoinLbl] = create_lbls(4),
- [hipe_tagscheme:test_bitstr(Binary, hipe_rtl:label_name(SuccessLbl),
- FalseLblName, 0.99),
- SuccessLbl,
- get_field_from_term({sub_binary, binsize}, Binary, BinSize),
- hipe_rtl:mk_alu(BinSize, BinSize, sll, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- hipe_tagscheme:test_subbinary(Binary, hipe_rtl:label_name(SubLbl),
- hipe_rtl:label_name(OtherLbl)),
- SubLbl,
- get_field_from_term({sub_binary, offset}, Binary, OrigOffset),
- hipe_rtl:mk_alu(Offset, OrigOffset, sll, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- get_field_from_term({sub_binary, bitoffset}, Binary, BitOffset),
- hipe_rtl:mk_alu(Offset, Offset, add, BitOffset),
- get_field_from_term({sub_binary, bitsize}, Binary, BitSize),
- hipe_rtl:mk_alu(BinSize, BinSize, add, Offset),
- hipe_rtl:mk_alu(BinSize, BinSize, add, BitSize),
- get_field_from_term({sub_binary, orig}, Binary, Orig),
- hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
- OtherLbl,
- hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_move(Orig, Binary),
- JoinLbl] ++
- get_base(Orig,Base) ++
- [hipe_rtl:mk_goto(TrueLblName)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%% UTILS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-get_base(Orig,Base) ->
- [HeapLbl,REFCLbl,WritableLbl,NotWritableLbl,EndLbl] = create_lbls(5),
- Flags = hipe_rtl:mk_new_reg_gcsafe(),
-
- [hipe_tagscheme:test_heap_binary(Orig, hipe_rtl:label_name(HeapLbl),
- hipe_rtl:label_name(REFCLbl)),
- HeapLbl,
- hipe_tagscheme:get_field_addr_from_term({heap_bin, {data, 0}}, Orig, Base),
- hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
- REFCLbl,
- get_field_from_term({proc_bin, flags}, Orig, Flags),
- hipe_rtl:mk_branch(Flags, 'ne', hipe_rtl:mk_imm(0),
- hipe_rtl:label_name(WritableLbl),
- hipe_rtl:label_name(NotWritableLbl)),
- WritableLbl,
- hipe_rtl:mk_call([], emasculate_binary, [Orig], [], [], 'not_remote'),
- NotWritableLbl,
- get_field_from_term({proc_bin, bytes}, Orig, Base),
- EndLbl].
-
-extract_matchstate_var(binsize, Ms) ->
- BinSize = hipe_rtl:mk_new_reg_gcsafe(),
- {BinSize,
- get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize)};
-extract_matchstate_var(offset, Ms) ->
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
- {Offset,
- get_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Offset)};
-extract_matchstate_var(base, Ms) ->
- Base = hipe_rtl:mk_new_reg(),
- {Base,
- get_field_from_term({matchstate, {matchbuffer, base}}, Ms, Base)};
-extract_matchstate_var(orig, Ms) ->
- Orig = hipe_rtl:mk_new_var(),
- {Orig,
- get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig)}.
-
-extract_matchstate_vars(List, Ms) ->
- lists:unzip([extract_matchstate_var(Name, Ms) || Name <- List]).
-
-check_size(Offset, Size, BinSize, Tmp1, ContLblName, FalseLblName) ->
- [add_to_offset(Tmp1, Offset, Size, FalseLblName),
- hipe_rtl:mk_branch(Tmp1, leu, BinSize, ContLblName, FalseLblName, 0.99)].
-
-check_size(Offset, Size, _BinSize, Tmp1, true, ContLblName, _FalseLblName) ->
- [hipe_rtl:mk_alu(Tmp1, Offset, add, Size),
- hipe_rtl:mk_goto(ContLblName)];
-check_size(Offset, Size, BinSize, Tmp1, false, ContLblName, FalseLblName) ->
- check_size(Offset, Size, BinSize, Tmp1, ContLblName, FalseLblName).
-
-shift_type(true) ->
- sra;
-shift_type(false) ->
- srl.
-
-get_type(true, LittleEndian) ->
- {signed, endianess(LittleEndian)};
-get_type(false, LittleEndian) ->
- {unsigned, endianess(LittleEndian)}.
-
-endianess(true) ->
- little;
-endianess(false) ->
- big.
-
-aligned(Flags) ->
- case Flags band ?BSF_ALIGNED of
- 1 -> true;
- 0 -> false
- end.
-
-littleendian(Flags) ->
- case Flags band 2 of
- 2 -> true;
- 0 -> false
- end.
-
-signed(Flags) ->
- case Flags band 4 of
- 4 -> true;
- 0 -> false
- end.
-
-unsafe(Flags) ->
- case Flags band 16 of
- 16 -> true;
- 0 -> false
- end.
-
-update_offset(NewOffset, Ms) ->
- set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, NewOffset).
-
-opt_update_ms([NewMs], OldMs) ->
- [hipe_rtl:mk_move(NewMs, OldMs)];
-opt_update_ms([], _OldMs) ->
- [].
-
-update_ms(NewMs, OldMs) ->
- [hipe_rtl:mk_move(NewMs, OldMs)].
-
-create_lbls(0) ->
- [];
-create_lbls(X) when X > 0 ->
- [hipe_rtl:mk_new_label()|create_lbls(X-1)].
-
-make_dyn_prep(SizeReg, CCode) ->
- [CLbl, SuccessLbl] = create_lbls(2),
- Init = [hipe_rtl:mk_branch(SizeReg, leu, hipe_rtl:mk_imm(?MAX_SMALL_BITS),
- hipe_rtl:label_name(SuccessLbl),
- hipe_rtl:label_name(CLbl)),
- SuccessLbl],
- End = [CLbl|CCode],
- {Init, End}.
-
-%%------------------------------------------------------------------------
-%% From hipe_rtl_binutil.erl
-%%------------------------------------------------------------------------
-
-get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) ->
- [Reg] = create_gcsafe_regs(1),
- [get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
- do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)].
-
-get_maybe_unaligned_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) ->
- [LowBits] = create_gcsafe_regs(1),
- [AlignedLbl, UnAlignedLbl, EndLbl] = create_lbls(3),
- [hipe_rtl:mk_alub(LowBits, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS),
- eq, hipe_rtl:label_name(AlignedLbl),
- hipe_rtl:label_name(UnAlignedLbl)),
- AlignedLbl,
- get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
- hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
- UnAlignedLbl,
- get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type),
- EndLbl].
-
-get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type) ->
- [ByteOffset, ShiftBits, LoadDst, Tmp, TotBits] = create_gcsafe_regs(5),
- [MoreLbl, LessLbl, JoinLbl] = create_lbls(3),
- WordSize = hipe_rtl_arch:word_size(),
- MinLoad = (Size-1) div ?BYTE_SIZE +1,
- MaxLoad = MinLoad + 1,
- Code1 =
- [hipe_rtl:mk_alu(TotBits, LowBits, 'add', hipe_rtl:mk_imm(Size)),
- hipe_rtl:mk_alu(ByteOffset, Offset, 'srl', hipe_rtl:mk_imm(?BYTE_SHIFT))],
- Code2 =
- case {Size rem ?BYTE_SIZE, MinLoad} of
- {1, _} ->
- [load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad),
- hipe_rtl:mk_alu(ShiftBits, LowBits, 'add',
- hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE))];
- {_, WordSize} ->
- UnsignedBig = {unsigned, big},
- [hipe_rtl:mk_branch(TotBits, leu, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE),
- hipe_rtl:label_name(LessLbl),
- hipe_rtl:label_name(MoreLbl)),
- LessLbl,
- load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad),
- hipe_rtl:mk_alu(ShiftBits, LowBits, 'add',
- hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLbl)),
- MoreLbl,
- load_bytes(LoadDst, Base, ByteOffset, UnsignedBig, MinLoad),
- hipe_rtl:mk_alu(LoadDst, LoadDst, 'sll', LowBits),
- load_bytes(Tmp, Base, ByteOffset, UnsignedBig, 1),
- hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', LowBits),
- hipe_rtl:mk_alu(Tmp, Tmp, 'srl', LowBits),
- hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
- hipe_rtl:mk_move(ShiftBits, hipe_rtl:mk_imm(0)),
- JoinLbl];
- {_, _} ->
- [load_bytes(LoadDst, Base, ByteOffset, Type, MaxLoad),
- hipe_rtl:mk_alu(ShiftBits, LowBits, 'add',
- hipe_rtl:mk_imm((WordSize-MaxLoad)*?BYTE_SIZE))]
- end,
- Code3 =
- [hipe_rtl:mk_alu(Tmp, LoadDst, sll, ShiftBits),
- hipe_rtl:mk_alu(Reg, Tmp, Shiftr,
- hipe_rtl:mk_imm(WordSize*?BYTE_SIZE-Size))],
- Code1 ++ Code2 ++ Code3.
-
-get_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName) ->
- [Reg] = create_gcsafe_regs(1),
- [get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type),
- do_bignum_code(Size, Type, Reg, Dst1, TrueLblName)].
-
-get_int_to_reg(Reg, Size, Base, Offset, Shiftr, Type) ->
- [ByteOffset] = create_gcsafe_regs(1),
- Code1 =
- [hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- load_bytes(Reg, Base, ByteOffset, Type, ((Size-1) div ?BYTE_SIZE +1))],
- Code2 =
- case Size rem ?BYTE_SIZE of
- 0 ->
- [];
- _ ->
- [hipe_rtl:mk_alu(Reg, Reg, Shiftr,
- hipe_rtl:mk_imm(?BYTE_SIZE -Size rem ?BYTE_SIZE))]
- end,
- Code1 ++ Code2.
-
-get_big_unknown_int(Dst1, Base, Offset, NewOffset,
- Shiftr, Type, TrueLblName) ->
- [LoadDst, ByteOffset, Limit, Tmp, LowBits] = create_gcsafe_regs(5),
- [ContLbl, BackLbl, LoopLbl, TagLbl, LastLbl, EndLbl] = create_lbls(6),
- [hipe_rtl:mk_move(LoadDst, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_branch(NewOffset, ne, Offset, hipe_rtl:label_name(ContLbl),
- hipe_rtl:label_name(TagLbl), 0.99),
- ContLbl,
- hipe_rtl:mk_alu(Limit, NewOffset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Limit, Limit, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- load_bytes(LoadDst, Base, ByteOffset, Type, 1),
- BackLbl,
- hipe_rtl:mk_branch(ByteOffset, leu, Limit, hipe_rtl:label_name(LoopLbl),
- hipe_rtl:label_name(EndLbl)),
- LoopLbl,
- load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1),
- hipe_rtl:mk_alu(LoadDst, LoadDst, sll, hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
- hipe_rtl:mk_goto(hipe_rtl:label_name(BackLbl)),
- EndLbl,
- hipe_rtl:mk_alub(LowBits, NewOffset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq,
- hipe_rtl:label_name(TagLbl), hipe_rtl:label_name(LastLbl)),
- LastLbl,
- hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), 'sub', LowBits),
- hipe_rtl:mk_alu(LoadDst, LoadDst, Shiftr, LowBits),
- TagLbl] ++
- do_bignum_code(64, Type, LoadDst, Dst1, TrueLblName).
-
-get_little_unknown_int(Dst1, Base, Offset, NewOffset,
- Shiftr, Type, TrueLblName) ->
- [LoadDst, ByteOffset, Limit, ShiftReg, LowBits, Tmp] = create_gcsafe_regs(6),
- [ContLbl, BackLbl, LoopLbl, DoneLbl, TagLbl] = create_lbls(5),
- [hipe_rtl:mk_move(LoadDst, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_branch(NewOffset, ne, Offset, hipe_rtl:label_name(ContLbl),
- hipe_rtl:label_name(TagLbl), 0.99),
- ContLbl,
- hipe_rtl:mk_alu(Tmp, NewOffset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- hipe_rtl:mk_alu(Limit, Tmp, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
- hipe_rtl:mk_move(ShiftReg, hipe_rtl:mk_imm(0)),
- BackLbl,
- hipe_rtl:mk_branch(ByteOffset, ltu, Limit,
- hipe_rtl:label_name(LoopLbl),
- hipe_rtl:label_name(DoneLbl)),
- LoopLbl,
- load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1),
- hipe_rtl:mk_alu(Tmp, Tmp, sll, ShiftReg),
- hipe_rtl:mk_alu(ShiftReg, ShiftReg, add, hipe_rtl:mk_imm(?BYTE_SIZE)),
- hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
- hipe_rtl:mk_goto(hipe_rtl:label_name(BackLbl)),
- DoneLbl,
- hipe_rtl:mk_alu(LowBits, NewOffset, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
- hipe_rtl:mk_alu(LowBits, hipe_rtl:mk_imm(?BYTE_SIZE), sub, LowBits),
- hipe_rtl:mk_alu(LowBits, LowBits, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
- load_bytes(Tmp, Base, ByteOffset, Type, 1),
- hipe_rtl:mk_alu(Tmp, Tmp, Shiftr, LowBits),
- hipe_rtl:mk_alu(Tmp, Tmp, sll, ShiftReg),
- hipe_rtl:mk_alu(LoadDst, LoadDst, 'or', Tmp),
- TagLbl] ++
- do_bignum_code(64, Type, LoadDst, Dst1, TrueLblName).
-
-do_bignum_code(Size, {Signedness,_}, Src, Dst1, TrueLblName)
- when is_integer(Size) ->
- case {Size > ?MAX_SMALL_BITS, Signedness} of
- {false, _} ->
- [hipe_tagscheme:tag_fixnum(Dst1, Src),
- hipe_rtl:mk_goto(TrueLblName)];
- {true, signed} ->
- make_int_gc_code(Size) ++
- signed_bignum(Dst1, Src, TrueLblName);
- {true, unsigned} ->
- make_int_gc_code(Size) ++
- unsigned_bignum(Dst1, Src, TrueLblName)
- end.
-
-signed_bignum(Dst1, Src, TrueLblName) ->
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- BignumLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:realtag_fixnum(Dst1, Src),
- hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1),
- hipe_rtl:mk_branch(Tmp1, eq, Src, TrueLblName,
- hipe_rtl:label_name(BignumLabel)),
- BignumLabel,
- hipe_tagscheme:unsafe_mk_big(Dst1, Src, signed),
- hipe_rtl:mk_goto(TrueLblName)].
-
-unsigned_bignum(Dst1, Src, TrueLblName) ->
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- BignumLbl = hipe_rtl:mk_new_label(),
- BignumLblName = hipe_rtl:label_name(BignumLbl),
- NxtLbl = hipe_rtl:mk_new_label(),
- NxtLblName = hipe_rtl:label_name(NxtLbl),
- [hipe_rtl:mk_branch(Src, lt, hipe_rtl:mk_imm(0), BignumLblName, NxtLblName),
- NxtLbl,
- hipe_tagscheme:realtag_fixnum(Dst1, Src),
- hipe_tagscheme:realuntag_fixnum(Tmp1, Dst1),
- hipe_rtl:mk_branch(Tmp1, eq, Src, TrueLblName, BignumLblName),
- BignumLbl,
- hipe_tagscheme:unsafe_mk_big(Dst1, Src, unsigned),
- hipe_rtl:mk_goto(TrueLblName)].
-
-load_bytes(Dst, Base, Offset, {Signedness, _Endianness},1) ->
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))];
-load_bytes(Dst, Base, Offset, {Signedness, Endianness},2) ->
- case Endianness of
- big ->
- hipe_rtl_arch:load_big_2(Dst, Base, Offset, Signedness);
- little ->
- hipe_rtl_arch:load_little_2(Dst, Base, Offset, Signedness)
- end;
-load_bytes(Dst, Base, Offset, {Signedness, Endianness},3) ->
- Tmp1 = hipe_rtl:mk_new_reg(),
- case Endianness of
- big ->
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))];
- little ->
- [hipe_rtl:mk_load(Dst, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte,unsigned),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte,Signedness),
- hipe_rtl:mk_alu(Tmp1, Tmp1, sll, hipe_rtl:mk_imm(16)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1))]
- end;
-load_bytes(Dst, Base, Offset, {Signedness, Endianness}, 4) ->
- case Endianness of
- big ->
- hipe_rtl_arch:load_big_4(Dst, Base, Offset, Signedness);
- little ->
- hipe_rtl_arch:load_little_4(Dst, Base, Offset, Signedness)
- end;
-
-load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 ->
- [LoopLbl, EndLbl] = create_lbls(2),
- [Tmp1, Limit, TmpOffset] = create_regs(3),
- case Endianness of
- big ->
- [hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)),
- hipe_rtl:mk_load(Dst, Base, Offset, byte, Signedness),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- LoopLbl,
- hipe_rtl:mk_load(Tmp1, Base, Offset, byte, unsigned),
- hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_branch(Offset, ltu, Limit, hipe_rtl:label_name(LoopLbl),
- hipe_rtl:label_name(EndLbl)),
- EndLbl];
- little ->
- [hipe_rtl:mk_alu(Limit, Offset, add, hipe_rtl:mk_imm(X)),
- hipe_rtl:mk_alu(TmpOffset, Limit, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Dst, Base, TmpOffset, byte, Signedness),
- LoopLbl,
- hipe_rtl:mk_alu(TmpOffset, TmpOffset, sub, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_load(Tmp1, Base, TmpOffset, byte, Signedness),
- hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
- hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_branch(Offset, ltu, TmpOffset, hipe_rtl:label_name(LoopLbl),
- hipe_rtl:label_name(EndLbl)),
- EndLbl,
- hipe_rtl:mk_move(Offset, Limit)]
- end.
-
-create_regs(X) when X > 0 ->
- [hipe_rtl:mk_new_reg()|create_regs(X-1)];
-create_regs(0) ->
- [].
-
-create_gcsafe_regs(X) when X > 0 ->
- [hipe_rtl:mk_new_reg_gcsafe()|create_gcsafe_regs(X-1)];
-create_gcsafe_regs(0) ->
- [].
-
-is_illegal_const(Const) ->
- Const >= 1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0.
diff --git a/lib/hipe/rtl/hipe_rtl_cfg.erl b/lib/hipe/rtl/hipe_rtl_cfg.erl
deleted file mode 100644
index ce399498d6..0000000000
--- a/lib/hipe/rtl/hipe_rtl_cfg.erl
+++ /dev/null
@@ -1,192 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_rtl_cfg).
-
--export([init/1,
- labels/1,
- params/1, params_update/2,
- start_label/1,
- succ/2,
- pred/2,
- bb/2, bb_add/3, bb_insert_between/5,
- redirect/4,
- remove_trivial_bbs/1, remove_unreachable_code/1,
- linearize/1,
- pp/1, pp/2]).
--export([preorder/1, postorder/1, reverse_postorder/1]).
-
--define(RTL_CFG, true). % needed for cfg.inc below
-
--include("../main/hipe.hrl").
--include("hipe_rtl.hrl").
--include("../flow/cfg.hrl").
--include("../flow/cfg.inc").
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% CFG interface to RTL.
-%%
-
-init(Rtl) ->
- %% hipe_rtl:pp(Rtl),
- Code = hipe_rtl:rtl_code(Rtl),
- StartLabel = hipe_rtl:label_name(hd(Code)),
- CFG0 = mk_empty_cfg(hipe_rtl:rtl_fun(Rtl),
- StartLabel,
- hipe_rtl:rtl_data(Rtl),
- hipe_rtl:rtl_is_closure(Rtl),
- hipe_rtl:rtl_is_leaf(Rtl),
- hipe_rtl:rtl_params(Rtl)),
- CFG = info_update(CFG0, hipe_rtl:rtl_info(Rtl)),
- take_bbs(Code, CFG).
-
-%% @spec is_comment(hipe_rtl:rtl_instruction()) -> boolean()
-%% @doc Succeeds if Instr has no effect.
-is_comment(Instr) ->
- hipe_rtl:is_comment(Instr).
-
-%% @spec is_goto(hipe_rtl:rtl_instruction()) -> boolean()
-%% @doc Succeeds if Instr is just a jump (no side-effects).
-is_goto(Instr) ->
- hipe_rtl:is_goto(Instr).
-
-is_label(Instr) ->
- hipe_rtl:is_label(Instr).
-
-label_name(Instr) ->
- hipe_rtl:label_name(Instr).
-
-mk_label(Name) ->
- hipe_rtl:mk_label(Name).
-
-mk_goto(Name) ->
- hipe_rtl:mk_goto(Name).
-
-branch_successors(Instr) ->
- case Instr of
- #alub{} -> [hipe_rtl:alub_true_label(Instr),
- hipe_rtl:alub_false_label(Instr)];
- #switch{} -> hipe_rtl:switch_labels(Instr);
- #call{} ->
- case hipe_rtl:call_fail(Instr) of
- [] -> [hipe_rtl:call_continuation(Instr)];
- Fail -> [hipe_rtl:call_continuation(Instr),Fail]
- end;
- #goto{} -> [hipe_rtl:goto_label(Instr)];
- #goto_index{} -> hipe_rtl:goto_index_labels(Instr);
- _ -> []
- end.
-
-fails_to(Instr) ->
- case Instr of
- #call{} -> [hipe_rtl:call_fail(Instr)];
- _ -> []
- end.
-
-is_branch(Instr) ->
- case Instr of
- #alub{} -> true;
- #switch{} -> true;
- #goto{} -> true;
- #goto_index{} -> true;
- #enter{} -> true;
- #return{} -> true;
- #call{} ->
- case hipe_rtl:call_fail(Instr) of
- [] ->
- case hipe_rtl:call_continuation(Instr) of
- [] -> false;
- _ -> true
- end;
- _ -> true
- end;
- _ -> false
- end.
-
-is_pure_branch(Instr) ->
- case Instr of
- #alub{} -> not hipe_rtl:alub_has_dst(Instr);
- #switch{} -> true;
- #goto{} -> true;
- _ -> false
- end.
-
-redirect_jmp(Jmp, ToOld, ToNew) ->
- hipe_rtl:redirect_jmp(Jmp, ToOld, ToNew).
-
-redirect_ops([Label|Labels], CFG, Map) ->
- BB = bb(CFG, Label),
- Code = hipe_bb:code(BB),
- NewCode = [rewrite(I,Map) || I <- Code],
- NewCFG = bb_add(CFG, Label, hipe_bb:code_update(BB, NewCode)),
- redirect_ops(Labels, NewCFG, Map);
-redirect_ops([],CFG,_) -> CFG.
-
-rewrite(I, Map) ->
- case I of
- #load_address{} ->
- case hipe_rtl:load_address_type(I) of
- constant -> I;
- _ ->
- NewL =
- find_new_label(hipe_rtl:load_address_addr(I), Map),
- hipe_rtl:load_address_addr_update(I, NewL)
- end;
- _ -> I
- end.
-
-
-pp(CFG) ->
- hipe_rtl:pp(linearize(CFG)).
-
-pp(Dev, CFG) ->
- hipe_rtl:pp(Dev, linearize(CFG)).
-
-linearize(CFG) ->
- Code = linearize_cfg(CFG),
- Rtl = hipe_rtl:mk_rtl(function(CFG),
- params(CFG),
- is_closure(CFG),
- is_leaf(CFG),
- Code,
- data(CFG),
- hipe_gensym:var_range(rtl),
- hipe_gensym:label_range(rtl)),
- hipe_rtl:rtl_info_update(Rtl, info(CFG)).
-
-%% %% Warning: this arity might not be the true arity.
-%% %% The true arity of a closure usually differs.
-%% arity(CFG) ->
-%% {_M,_F,A} = function(CFG),
-%% A.
-
-%% init_gensym(CFG)->
-%% HighestVar = find_highest_var(CFG),
-%% HighestLabel = find_highest_label(CFG),
-%% hipe_gensym:init(),
-%% hipe_gensym:set_var(rtl, HighestVar),
-%% hipe_gensym:set_label(rtl, HighestLabel).
-%%
-%% highest_var(Code)->
-%% hipe_rtl:highest_var(Code).
-
-is_phi(I) ->
- hipe_rtl:is_phi(I).
-
-phi_remove_pred(I, Pred) ->
- hipe_rtl:phi_remove_pred(I, Pred).
-
-phi_redirect_pred(I, OldPred, NewPred) ->
- hipe_rtl:phi_redirect_pred(I, OldPred, NewPred).
diff --git a/lib/hipe/rtl/hipe_rtl_cleanup_const.erl b/lib/hipe/rtl/hipe_rtl_cleanup_const.erl
deleted file mode 100644
index 00cc2bcb37..0000000000
--- a/lib/hipe/rtl/hipe_rtl_cleanup_const.erl
+++ /dev/null
@@ -1,80 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_rtl_cleanup_const.erl
-%%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%%% Description :
-%%%
-%%% Created : 5 Mar 2004 by Tobias Lindahl <tobiasl@it.uu.se>
-%%%-------------------------------------------------------------------
-
-%% Big constants (floats, bignums) can be used as arguments to
-%% arbitrary instructions in RTL. Since these are located in the
-%% constants area and the only instruction that currently can access
-%% them is load_address, the constants have to be moved out of the
-%% instruction and loaded into temporary variables before the
-%% instruction.
-%%
-%% Some backends can make use of the information that the arguments
-%% are really constants. Here is the place to add new backend-specific
-%% behaviour depending on this.
-
-%%--------------------------------------------------------------------
-
--module(hipe_rtl_cleanup_const).
-
--export([cleanup/1]).
-
--include("hipe_rtl.hrl").
-
-%%--------------------------------------------------------------------
-
-%%-spec cleanup(#rtl{}) -> #rtl{}.
-
-cleanup(Rtl) ->
- Code = cleanup(hipe_rtl:rtl_code(Rtl), []),
- hipe_rtl:rtl_code_update(Rtl, Code).
-
-cleanup([I|Left], Acc) ->
- Args = hipe_rtl:args(I),
- case [X || X <- Args, hipe_rtl:is_const_label(X)] of
- [] ->
- cleanup(Left, [I|Acc]);
- ConstArgs ->
- NewIns = cleanup_instr(ConstArgs, I),
- cleanup(Left, NewIns ++ Acc)
- end;
-cleanup([], Acc) ->
- lists:reverse(Acc).
-
-cleanup_instr(Consts, I) ->
- cleanup_instr(ordsets:from_list(Consts), I, []).
-
-cleanup_instr([Const|Left], I, Acc) ->
- Dst = hipe_rtl:mk_new_var(),
- ConstLabel = hipe_rtl:const_label_label(Const),
- Load = hipe_rtl:mk_load_address(Dst, ConstLabel, constant),
- case I of
- X when is_record(X, fp_unop) orelse is_record(X, fp) ->
- Fdst = hipe_rtl:mk_new_fpreg(),
- Fconv = lists:flatten(hipe_tagscheme:unsafe_untag_float(Fdst, Dst)),
- NewI = hipe_rtl:subst_uses([{Const, Fdst}], I),
- cleanup_instr(Left, NewI, lists:reverse(Fconv, [Load|Acc]));
- _ ->
- NewI = hipe_rtl:subst_uses([{Const, Dst}], I),
- cleanup_instr(Left, NewI, [Load|Acc])
- end;
-cleanup_instr([], I, Acc) ->
- [I|Acc].
diff --git a/lib/hipe/rtl/hipe_rtl_exceptions.erl b/lib/hipe/rtl/hipe_rtl_exceptions.erl
deleted file mode 100644
index 03dc959bcf..0000000000
--- a/lib/hipe/rtl/hipe_rtl_exceptions.erl
+++ /dev/null
@@ -1,113 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Filename : hipe_rtl_exceptions.erl
-%% Module : hipe_rtl_exceptions
-%% Purpose :
-%% Notes :
-%% History : * 2001-04-10 Erik Johansson (happi@it.uu.se):
-%% Created.
-%% ====================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_exceptions).
-
--export([gen_fail/3, gen_begin_handler/3]).
-
--include("../main/hipe.hrl").
--include("hipe_literals.hrl").
-
-%% --------------------------------------------------------------------
-%% Handle the Icode instruction
-%% FAIL
-%%
-gen_fail(Class, Args, L) ->
- case Args of
- [Reason] ->
- case Class of
- exit ->
- gen_exit(Reason, L);
- throw ->
- gen_throw(Reason, L);
- error ->
- gen_error(Reason, L)
- end;
- [Arg1,Arg2] ->
- case Class of
- error ->
- Reason = Arg1, ArgList = Arg2,
- gen_error(Reason, ArgList, L);
- rethrow ->
- Exception = Arg1, Reason = Arg2,
- gen_rethrow(Exception, Reason, L)
- end
- end.
-
-%% --------------------------------------------------------------------
-%% Exception handler glue; interfaces between the runtime system's
-%% exception state and the Icode view of exception handling.
-
-gen_begin_handler(I, VarMap, ConstTab) ->
- Ds = hipe_icode:begin_handler_dstlist(I),
- {Vars, VarMap1} = hipe_rtl_varmap:ivs2rvs(Ds, VarMap),
- [FTagVar,FValueVar,FTraceVar] = Vars,
- {[hipe_rtl:mk_comment('begin_handler'),
- hipe_rtl_arch:pcb_load(FValueVar, ?P_FVALUE),
- hipe_rtl_arch:pcb_load(FTraceVar, ?P_FTRACE),
- %% synthesized from P->freason by hipe_handle_exception()
- hipe_rtl_arch:pcb_load(FTagVar, ?P_ARG0)
- ],
- VarMap1, ConstTab}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Exceptions
-
-gen_exit(Reason, L) ->
- gen_fail_call({erlang,exit,1}, [Reason], L).
-
-gen_throw(Reason, L) ->
- gen_fail_call({erlang,throw,1}, [Reason], L).
-
-gen_error(Reason, L) ->
- gen_fail_call({erlang,error,1}, [Reason], L).
-
-gen_error(Reason, ArgList, L) ->
- gen_fail_call({erlang,error,2}, [Reason,ArgList], L).
-
-gen_rethrow(Exception, Reason, L) ->
- gen_fail_call(rethrow, [Exception,Reason], L).
-
-%% Generic fail. We can't use 'enter' with a fail label (there can be no
-%% stack descriptor info for an enter), so for a non-nil fail label we
-%% generate a call followed by a dummy return.
-%%
-%% Update: The runtime system now interprets the return address of
-%% the BIF call in order to list the invoking MFA in the stack trace.
-%% Generating tailcalls here defeats that purpose, so we no longer do that.
-
-%%gen_fail_call(Fun, Args, []) ->
-%% [hipe_rtl:mk_enter(Fun, Args, remote)];
-gen_fail_call(Fun, Args, L) ->
- ContLbl = hipe_rtl:mk_new_label(),
- Cont = hipe_rtl:label_name(ContLbl),
- Zero = hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
- [hipe_rtl:mk_call([], Fun, Args, Cont, L, remote),
- ContLbl,
- hipe_rtl:mk_return([Zero])].
diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl
deleted file mode 100644
index 2c8cc80e56..0000000000
--- a/lib/hipe/rtl/hipe_rtl_lcm.erl
+++ /dev/null
@@ -1,1700 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% File : hipe_rtl_lcm.erl
-%% Author : Henrik Nyman and Erik Cedheim
-%% Description : Performs Lazy Code Motion on RTL
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% @doc
-%%
-%% This module implements Lazy Code Motion on RTL.
-%%
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_lcm).
-
--export([rtl_lcm/2]).
-
--define(SETS, ordsets). %% Which set implementation module to use
- %% We have tried gb_sets, sets and ordsets and
- %% ordsets seems to be a lot faster according to
- %% our test runs.
-
--include("../main/hipe.hrl").
--include("hipe_rtl.hrl").
--include("../flow/cfg.hrl").
-
-%%-define(LCM_DEBUG, true). %% When defined and true, produces debug printouts
-
-%%=============================================================================
-
-%%
-%% @doc Performs Lazy Code Motion on RTL.
-%%
-
--spec rtl_lcm(cfg(), comp_options()) -> cfg().
-
-rtl_lcm(CFG, Options) ->
- %% Perform pre-calculation of the data sets.
- ?opt_start_timer("RTL LCM precalc"),
- {NodeInfo, EdgeInfo, AllExpr, ExprMap, IdMap, Labels} = lcm_precalc(CFG, Options),
- ?opt_stop_timer("RTL LCM precalc"),
- %% {NodeInfo, EdgeInfo, AllExpr, ExprMap, Labels} =
- %% ?option_time(lcm_precalc(CFG, Options), "RTL LCM precalc", Options),
-
- pp_debug("-------------------------------------------------~n",[]),
- %% pp_debug( "~w~n", [MFA]),
-
- %% A check if we should pretty print the result.
- case proplists:get_bool(pp_rtl_lcm, Options) of
- true ->
- pp_debug("-------------------------------------------------~n",[]),
- %% pp_debug("AllExpr: ~w~n", [AllExpr]),
- pp_debug("AllExpr:~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(AllExpr)),
- %% pp_sets(ExprMap, NodeInfo, EdgeInfo, AllExpr, CFG2<-ERROR!, Labels);
- pp_sets(ExprMap, IdMap, NodeInfo, EdgeInfo, AllExpr, CFG, Labels);
- _ ->
- ok
- end,
-
- pp_debug("-------------------------------------------------~n",[]),
- {CFG1, MoveSet} = ?option_time(perform_lcm(CFG, NodeInfo, EdgeInfo, ExprMap,
- IdMap, AllExpr, mk_edge_bb_map(),
- ?SETS:new(), Labels),
- "RTL LCM perform_lcm", Options),
-
- %% Scan through list of moved expressions and replace their
- %% assignments with the new temporary created for that expression
- MoveList = ?SETS:to_list(MoveSet),
- CFG2 = ?option_time(moved_expr_replace_assignments(CFG1, ExprMap, IdMap,
- MoveList),
- "RTL LCM moved_expr_replace_assignments", Options),
- pp_debug("-------------------------------------------------~n~n",[]),
-
- CFG2.
-
-%%=============================================================================
-%% Performs lazy code motion given the pre-calculated data sets.
-perform_lcm(CFG, _, _, _, _, _, _, MoveSet, []) ->
- {CFG, MoveSet};
-perform_lcm(CFG0, NodeInfo, EdgeInfo, ExprMap, IdMap, AllExp, BetweenMap,
- MoveSet0, [Label|Labels]) ->
- Code0 = hipe_bb:code(hipe_rtl_cfg:bb(CFG0, Label)),
- DeleteSet = delete(NodeInfo, Label),
-
- %% Check if something should be deleted from this block.
- {CFG1, MoveSet1} =
- case ?SETS:size(DeleteSet) > 0 of
- true ->
- pp_debug("Label ~w: Expressions Deleted: ~n", [Label]),
- Code1 = delete_exprs(Code0, ExprMap, IdMap, ?SETS:to_list(DeleteSet)),
- BB = hipe_bb:mk_bb(Code1),
- {hipe_rtl_cfg:bb_add(CFG0, Label, BB),
- ?SETS:union(MoveSet0, DeleteSet)};
- false ->
- {CFG0, MoveSet0}
- end,
-
- Succs = hipe_rtl_cfg:succ(CFG1, Label),
-
- %% Go through the list of successors and insert expression where needed.
- %% Also collect a list of expressions that are inserted somewhere
- {CFG2, NewBetweenMap, MoveSet2} =
- lists:foldl(fun(Succ, {CFG, BtwMap, MoveSet}) ->
- InsertSet = calc_insert_edge(NodeInfo, EdgeInfo,
- Label, Succ),
- %% Check if something should be inserted on this edge.
- case ?SETS:size(InsertSet) > 0 of
- true ->
- pp_debug("Label ~w: Expressions Inserted for Successor: ~w~n", [Label, Succ]),
- InsertList = ?SETS:to_list(InsertSet),
- {NewCFG, NewBtwMap} =
- insert_exprs(CFG, Label, Succ, ExprMap, IdMap,
- BtwMap, InsertList),
- {NewCFG, NewBtwMap, ?SETS:union(MoveSet, InsertSet)};
- false ->
- {CFG, BtwMap, MoveSet}
- end
- end,
- {CFG1, BetweenMap, MoveSet1}, Succs),
-
- perform_lcm(CFG2, NodeInfo, EdgeInfo, ExprMap, IdMap, AllExp, NewBetweenMap,
- MoveSet2, Labels).
-
-%%=============================================================================
-%% Scan through list of moved expressions and replace their
-%% assignments with the new temporary created for that expression.
-moved_expr_replace_assignments(CFG, _, _, []) ->
- CFG;
-moved_expr_replace_assignments(CFG0, ExprMap, IdMap, [ExprId|Exprs]) ->
- Expr = expr_id_map_get_expr(IdMap, ExprId),
- case expr_map_lookup(ExprMap, Expr) of
- {value, {_, ReplaceList, NewReg}} ->
- CFG1 = lists:foldl(fun({Label, Reg}, CFG) ->
- %% Find and replace expression in block
- pp_debug("Label ~w: Expressions Replaced:~n", [Label]),
- Code0 = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)),
- Code1 =
- moved_expr_do_replacement(expr_set_dst(Expr, Reg),
- Reg, NewReg, Code0),
- hipe_rtl_cfg:bb_add(CFG, Label, hipe_bb:mk_bb(Code1))
- end, CFG0, ReplaceList),
- moved_expr_replace_assignments(CFG1, ExprMap, IdMap, Exprs);
- none ->
- moved_expr_replace_assignments(CFG0, ExprMap, IdMap, Exprs)
- end.
-
-moved_expr_do_replacement(_, _, _, []) ->
- [];
-moved_expr_do_replacement(Expr, Reg, NewReg, [Expr|Instrs]) ->
- NewExpr = expr_set_dst(Expr, NewReg),
- Move = mk_expr_move_instr(Reg, NewReg),
- pp_debug(" Replacing:~n", []),
- pp_debug_instr(Expr),
- pp_debug(" With:~n", []),
- pp_debug_instr(NewExpr),
- pp_debug_instr(Move),
- [NewExpr, Move | moved_expr_do_replacement(Expr, Reg, NewReg, Instrs)];
-moved_expr_do_replacement(Expr, Reg, NewReg, [Instr|Instrs]) ->
- [Instr | moved_expr_do_replacement(Expr, Reg, NewReg, Instrs)].
-
-%%=============================================================================
-%% Goes through the given list of expressions and deletes them from the code.
-%% NOTE We do not actually delete an expression, but instead we replace it
-%% with an assignment from the new temporary containing the result of the
-%% expressions which is guaranteed to have been calculated earlier in
-%% the code.
-delete_exprs(Code, _, _, []) ->
- Code;
-delete_exprs(Code, ExprMap, IdMap, [ExprId|Exprs]) ->
- Expr = expr_id_map_get_expr(IdMap, ExprId),
- %% Lookup expression entry.
- {value, {_, _, Defines}} = expr_map_lookup(ExprMap, Expr),
- %% Go through the code and deletes all occurences of the expression.
- NewCode = delete_expr(Code, Expr, Defines, []),
- delete_exprs(NewCode, ExprMap, IdMap, Exprs).
-
-delete_expr([], _Expr, _Defines, Acc) -> lists:reverse(Acc);
-delete_expr([CodeExpr|Code], Expr, Defines, Acc) ->
- case exp_kill_expr(CodeExpr, [Expr]) of
- [] -> % Expr was killed; deleting stops here
- pp_debug(" Stopping before: ", []),
- pp_debug_instr(CodeExpr),
- lists:reverse(Acc, [CodeExpr|Code]);
- [Expr] ->
- NewCodeExpr =
- case is_expr(CodeExpr) of
- true ->
- case expr_clear_dst(CodeExpr) =:= Expr of
- true ->
- pp_debug(" Deleting: ", []),
- pp_debug_instr(CodeExpr),
- MoveCode = mk_expr_move_instr(hipe_rtl:defines(CodeExpr),
- Defines),
- pp_debug(" Replacing with: ", []),
- pp_debug_instr(MoveCode),
- MoveCode;
- false ->
- CodeExpr
- end;
- false ->
- CodeExpr
- end,
- delete_expr(Code, Expr, Defines, [NewCodeExpr|Acc])
- end.
-
-%%=============================================================================
-%% Goes through the given list of expressions and inserts them at
-%% appropriate places in the code.
-insert_exprs(CFG, _, _, _, _, BetweenMap, []) ->
- {CFG, BetweenMap};
-insert_exprs(CFG, Pred, Succ, ExprMap, IdMap, BetweenMap, [ExprId|Exprs]) ->
- Expr = expr_id_map_get_expr(IdMap, ExprId),
- Instr = expr_map_get_instr(ExprMap, Expr),
- case try_insert_expr_last(CFG, Pred, Instr) of
- {ok, NewCFG} ->
- pp_debug(" Inserted last: ", []),
- pp_debug_instr(Instr),
- insert_exprs(NewCFG, Pred, Succ, ExprMap, IdMap, BetweenMap, Exprs);
- not_safe ->
- case hipe_rtl_cfg:pred(CFG, Succ) of
- [_] ->
- pp_debug(" Inserted first: ", []),
- pp_debug_instr(Instr),
- NewCFG = insert_expr_first(CFG, Succ, Instr),
- insert_exprs(NewCFG, Pred, Succ, ExprMap, IdMap, BetweenMap, Exprs);
- _ ->
- pp_debug(" Inserted between: ", []),
- pp_debug_instr(Instr),
- {NewCFG, NewBetweenMap} =
- insert_expr_between(CFG, BetweenMap, Pred, Succ, Instr),
- insert_exprs(NewCFG, Pred, Succ, ExprMap, IdMap, NewBetweenMap, Exprs)
- end
- end.
-
-%%=============================================================================
-%% Recursively goes through the code in a block and returns a new block
-%% with the new code inserted second to last (assuming the last expression
-%% is a branch operation).
-try_insert_expr_last(CFG0, Label, Instr) ->
- case hipe_rtl_cfg:succ(CFG0, Label) of
- [_] ->
- Code0 = hipe_bb:code(hipe_rtl_cfg:bb(CFG0, Label)),
- case insert_expr_last_work(Instr, Code0) of
- not_safe -> not_safe;
- Code1 ->
- {ok, hipe_rtl_cfg:bb_add(CFG0, Label, hipe_bb:mk_bb(Code1))}
- end;
- _ -> not_safe
- end.
-
-%%=============================================================================
-%% Recursively goes through the code in a block and returns a new block
-%% with the new code inserted second to last (assuming the last expression
-%% is a branch operation).
-insert_expr_last_work(_Instr, [#call{}]) ->
- %% Call instructions clobber all expressions; we must not insert the
- %% expression before it
- not_safe;
-insert_expr_last_work(Instr, [Code1]) ->
- %% We insert the code next to last.
- [Instr, Code1];
-insert_expr_last_work(Instr, [Code|Codes]) ->
- case insert_expr_last_work(Instr, Codes) of
- not_safe -> not_safe;
- NewCodes -> [Code|NewCodes]
- end.
-
-%%=============================================================================
-%% Inserts expression first in the block for the given label.
-insert_expr_first(CFG0, Label, Instr) ->
- %% The first instruction is always a label
- [Lbl|Code0] = hipe_bb:code(hipe_rtl_cfg:bb(CFG0, Label)),
- Code1 = [Lbl, Instr | Code0],
- hipe_rtl_cfg:bb_add(CFG0, Label, hipe_bb:mk_bb(Code1)).
-
-%%=============================================================================
-%% Inserts an expression on and edge between two existing blocks.
-%% It creates a new basic block to hold the expression.
-%% Created bbs are inserted into BetweenMap to be able to reuse them for
-%% multiple inserts on the same edge.
-%% NOTE Currently creates multiple blocks for identical expression with the
-%% same successor. Since the new bb usually contains very few instructions
-%% this should not be a problem.
-insert_expr_between(CFG0, BetweenMap, Pred, Succ, Instr) ->
- PredSucc = {Pred, Succ},
- case edge_bb_map_lookup(BetweenMap, PredSucc) of
- none ->
- NewLabel = hipe_rtl:mk_new_label(),
- NewLabelName = hipe_rtl:label_name(NewLabel),
- pp_debug(" Creating new bb ~w~n", [NewLabel]),
- Code = [Instr, hipe_rtl:mk_goto(Succ)],
- CFG1 = hipe_rtl_cfg:bb_add(CFG0, NewLabelName, hipe_bb:mk_bb(Code)),
- CFG2 = hipe_rtl_cfg:redirect(CFG1, Pred, Succ, NewLabelName),
- NewBetweenMap = edge_bb_map_insert(BetweenMap, PredSucc, NewLabelName),
- pp_debug(" Mapping edge (~w,~w) to label ~w~n",
- [Pred, Succ, NewLabelName]),
- {CFG2, NewBetweenMap};
- {value, Label} ->
- pp_debug(" Using existing new bb for edge (~w,~w) with label ~w~n",
- [Pred, Succ, Label]),
- {ok, NewCfg} = try_insert_expr_last(CFG0, Label, Instr),
- {NewCfg, BetweenMap}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%% GENERAL UTILITY FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Returns true if the list of registers only contains virtual registers and
-%% no machine registers.
-no_machine_regs([]) ->
- true;
-no_machine_regs([Reg|Regs]) ->
- case hipe_rtl:is_reg(Reg) of
- true ->
- N = hipe_rtl:reg_index(Reg),
- (N >= hipe_rtl_arch:first_virtual_reg()) andalso no_machine_regs(Regs);
- _ ->
- case hipe_rtl:is_fpreg(Reg) of
- true ->
- N = hipe_rtl:fpreg_index(Reg),
- (N >= hipe_rtl_arch:first_virtual_reg()) andalso no_machine_regs(Regs);
- _ ->
- no_machine_regs(Regs)
- end
- end.
-
-%%=============================================================================
-%% Returns true if an RTL instruction is an expression.
-%%
-is_expr(I) ->
- Defines = hipe_rtl:defines(I),
- Uses = hipe_rtl:uses(I),
-
- %% We don't cosider something that doesn't define anything as an expression.
- %% Also we don't consider machine registers to be expressions.
- case length(Defines) > 0 andalso no_machine_regs(Defines)
- andalso no_machine_regs(Uses) of
- true ->
- case I of
- #alu{} -> true;
-%% #alu{} ->
-%% Dst = hipe_rtl:alu_dst(I),
-%% Src1 = hipe_rtl:alu_src1(I),
-%% Src2 = hipe_rtl:alu_src2(I),
-
- %% Check if dst updates src
-%% case Dst =:= Src1 orelse Dst =:= Src2 of
-%% true ->
-%% false;
-%% false ->
-%% true
-%% end;
-
- %% Check if alu expression is untagging of boxed (rX <- vX sub 2)
-%% case hipe_rtl:is_reg(Dst) andalso hipe_rtl:is_var(Src1) andalso
-%% (hipe_rtl:alu_op(I) =:= sub) andalso hipe_rtl:is_imm(Src2) of
-%% true ->
-%% case hipe_rtl:imm_value(Src2) of
-%% 2 -> false; %% Tag for boxed. TODO: Should not be hardcoded...
-%% _ -> true
-%% end;
-%% false ->
-%% true
-%% end;
-
- #alub{} -> false; %% TODO: Split instruction to consider alu expression?
- #call{} -> false; %% We cannot prove that a call has no side-effects
- #comment{} -> false;
- #enter{} -> false;
- %% #fail_to{} -> false; %% Deprecated?
- #fconv{} -> true;
- #fixnumop{} -> true;
- #fload{} -> true;
- #fmove{} -> false;
- #fp{} -> true;
- #fp_unop{} -> true;
- #fstore{} -> false;
- #goto{} -> false;
- #goto_index{} -> false;
- #gctest{} -> false;
- #label{} -> false;
- #load{} -> true;
- #load_address{} ->
- case hipe_rtl:load_address_type(I) of
- c_const -> false;
- closure -> false; %% not sure whether safe to move;
- %% also probably not worth it
- constant -> true
- end;
- #load_atom{} -> true;
- #load_word_index{} -> true;
- #move{} -> false;
- #multimove{} -> false;
- #phi{} -> false;
- #return{} -> false;
- #store{} -> false;
- #switch{} -> false
- end;
- false ->
- false
- end.
-
-%%=============================================================================
-%% Replaces destination of RTL expression with empty list.
-%%
-expr_set_dst(I, [Dst|_Dsts] = DstList) ->
- case I of
- #alu{} -> hipe_rtl:alu_dst_update(I, Dst);
- #call{} -> hipe_rtl:call_dstlist_update(I, DstList);
- #fconv{} -> hipe_rtl:fconv_dst_update(I, Dst);
- #fixnumop{} -> hipe_rtl:fixnumop_dst_update(I, Dst);
- #fload{} -> hipe_rtl:fload_dst_update(I, Dst);
- %% #fmove{} -> hipe_rtl:fmove_dst_update(I, Dst);
- #fp{} -> hipe_rtl:fp_dst_update(I, Dst);
- #fp_unop{} -> hipe_rtl:fp_unop_dst_update(I, Dst);
- #load{} -> hipe_rtl:load_dst_update(I, Dst);
- #load_address{} -> hipe_rtl:load_address_dst_update(I, Dst);
- #load_atom{} -> hipe_rtl:load_atom_dst_update(I, Dst);
- #load_word_index{} -> hipe_rtl:load_word_index_dst_update(I, Dst);
- %% #move{} -> hipe_rtl:move_dst_update(I, Dst);
- _ -> exit({?MODULE, expr_set_dst, "bad expression"})
- end.
-
-%%=============================================================================
-%% Replaces destination of RTL expression with empty list.
-%%
-expr_clear_dst(I) ->
- case I of
- #alu{} -> hipe_rtl:alu_dst_update(I, nil);
- #call{} -> hipe_rtl:call_dstlist_update(I, nil);
- #fconv{} -> hipe_rtl:fconv_dst_update(I, nil);
- #fixnumop{} -> hipe_rtl:fixnumop_dst_update(I, nil);
- #fload{} -> hipe_rtl:fload_dst_update(I, nil);
- %% #fmove{} -> hipe_rtl:fmove_dst_update(I, nil);
- #fp{} -> hipe_rtl:fp_dst_update(I, nil);
- #fp_unop{} -> hipe_rtl:fp_unop_dst_update(I, nil);
- #load{} -> hipe_rtl:load_dst_update(I, nil);
- #load_address{} -> hipe_rtl:load_address_dst_update(I, nil);
- #load_atom{} -> hipe_rtl:load_atom_dst_update(I, nil);
- #load_word_index{} -> hipe_rtl:load_word_index_dst_update(I, nil);
- %% #move{} -> hipe_rtl:move_dst_update(I, nil);
- _ -> exit({?MODULE, expr_clear_dst, "bad expression"})
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%% PRECALC FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Pre-calculates the flow analysis and puts the calculated sets in maps for
-%% easy access later.
-lcm_precalc(CFG, Options) ->
- %% Calculate use map and expression map.
- {ExprMap, IdMap} = ?option_time(mk_expr_map(CFG),
- "RTL LCM mk_expr_map", Options),
- UseMap = ?option_time(mk_use_map(CFG, ExprMap),
- "RTL LCM mk_use_map", Options),
- %% Labels = hipe_rtl_cfg:reverse_postorder(CFG),
- Labels = hipe_rtl_cfg:labels(CFG),
- %% StartLabel = hipe_rtl_cfg:start_label(CFG),
- %% AllExpr = all_exprs(CFG, Labels),
- AllExpr = ?SETS:from_list(gb_trees:keys(IdMap)),
-
- %% Calculate the data sets.
- NodeInfo0 = ?option_time(mk_node_info(Labels),
- "RTL LCM mk_node_info", Options),
- %% ?option_time(EdgeInfo0 = mk_edge_info(), "RTL LCM mk_edge_info",
- %% Options),
- EdgeInfo0 = mk_edge_info(),
- NodeInfo1 = ?option_time(calc_up_exp(CFG, ExprMap, NodeInfo0, Labels),
- "RTL LCM calc_up_exp", Options),
- NodeInfo2 = ?option_time(calc_down_exp(CFG, ExprMap, NodeInfo1, Labels),
- "RTL LCM calc_down_exp", Options),
- NodeInfo3 = ?option_time(calc_killed_expr(CFG, NodeInfo2, UseMap, AllExpr,
- IdMap, Labels),
- "RTL LCM calc_killed_exp", Options),
- NodeInfo4 = ?option_time(calc_avail(CFG, NodeInfo3),
- "RTL LCM calc_avail", Options),
- NodeInfo5 = ?option_time(calc_antic(CFG, NodeInfo4, AllExpr),
- "RTL LCM calc_antic", Options),
- EdgeInfo1 = ?option_time(calc_earliest(CFG, NodeInfo5, EdgeInfo0, Labels),
- "RTL LCM calc_earliest", Options),
- {NodeInfo6, EdgeInfo2} = ?option_time(calc_later(CFG, NodeInfo5, EdgeInfo1),
- "RTL LCM calc_later", Options),
- NodeInfo7 = ?option_time(calc_delete(CFG, NodeInfo6, Labels),
- "RTL LCM calc_delete", Options),
- {NodeInfo7, EdgeInfo2, AllExpr, ExprMap, IdMap, Labels}.
-
-%%%%%%%%%%%%%%%%%%% AVAILABLE IN/OUT FLOW ANALYSIS %%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fixpoint calculation of anticipated in/out sets.
-%% Uses a worklist algorithm.
-%% Performs the avail in/out flow analysis.
-
-%%=============================================================================
-%% Calculates the available in/out sets, and returns an updated NodeInfo.
-
-calc_avail(CFG, NodeInfo) ->
- StartLabel = hipe_rtl_cfg:start_label(CFG),
- Work = init_work([StartLabel]),
- %% Initialize start node
- NewNodeInfo = set_avail_in(NodeInfo, StartLabel, ?SETS:new()),
- calc_avail_fixpoint(Work, CFG, NewNodeInfo).
-
-calc_avail_fixpoint(Work, CFG, NodeInfo) ->
- case get_work(Work) of
- fixpoint ->
- NodeInfo;
- {Label, NewWork} ->
- {NewNodeInfo, NewLabels} = calc_avail_node(Label, CFG, NodeInfo),
- NewWork2 = add_work(NewWork, NewLabels),
- calc_avail_fixpoint(NewWork2, CFG, NewNodeInfo)
- end.
-
-calc_avail_node(Label, CFG, NodeInfo) ->
- %% Get avail in
- AvailIn = avail_in(NodeInfo, Label),
-
- %% Calculate avail out
- AvailOut = ?SETS:union(down_exp(NodeInfo, Label),
- ?SETS:subtract(AvailIn,
- killed_expr(NodeInfo, Label))),
-
- {Changed, NodeInfo2} =
- case avail_out(NodeInfo, Label) of
- none ->
- %% If there weren't any old avail out we use this one.
- {true, set_avail_out(NodeInfo, Label, AvailOut)};
- OldAvailOut ->
- %% Check if the avail outs are equal.
- case AvailOut =:= OldAvailOut of
- true ->
- {false, NodeInfo};
- false ->
- {true, set_avail_out(NodeInfo, Label, AvailOut)}
- end
- end,
-
- case Changed of
- true ->
- %% Update AvailIn-sets of successors and add them to worklist
- Succs = hipe_rtl_cfg:succ(CFG, Label),
- NodeInfo3 =
- lists:foldl
- (fun(Succ, NewNodeInfo) ->
- case avail_in(NewNodeInfo, Succ) of
- none ->
- %% Initialize avail in to all expressions
- set_avail_in(NewNodeInfo, Succ, AvailOut);
- OldAvailIn ->
- set_avail_in(NewNodeInfo, Succ,
- ?SETS:intersection(OldAvailIn, AvailOut))
- end
- end,
- NodeInfo2, Succs),
- {NodeInfo3, Succs};
- false ->
- {NodeInfo2, []}
- end.
-
-%%%%%%%%%%%%%%%%%% ANTICIPATED IN/OUT FLOW ANALYSIS %%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fixpoint calculation of anticipated in/out sets.
-%% Uses a worklist algorithm.
-
-%%=============================================================================
-%% Calculates the anicipated in/out sets, and returns an updated NodeInfo.
-calc_antic(CFG, NodeInfo, AllExpr) ->
- %% Initialize worklist with all nodes in postorder
- Labels = hipe_rtl_cfg:postorder(CFG),
- Work = init_work(Labels),
- calc_antic_fixpoint(Work, CFG, NodeInfo, AllExpr).
-
-calc_antic_fixpoint(Work, CFG, NodeInfo, AllExpr) ->
- case get_work(Work) of
- fixpoint ->
- NodeInfo;
- {Label, NewWork} ->
- {NewNodeInfo, NewLabels} = calc_antic_node(Label, CFG, NodeInfo, AllExpr),
- NewWork2 = add_work(NewWork, NewLabels),
- calc_antic_fixpoint(NewWork2, CFG, NewNodeInfo, AllExpr)
- end.
-
-calc_antic_node(Label, CFG, NodeInfo, AllExpr) ->
- %% Get antic out
- AnticOut =
- case antic_out(NodeInfo, Label) of
- none ->
- case is_exit_label(CFG, Label) of
- true ->
- ?SETS:new();
- false ->
- AllExpr
- end;
-
- AnticOutTemp -> AnticOutTemp
- end,
-
- %% Calculate antic in
- AnticIn = ?SETS:union(up_exp(NodeInfo, Label),
- ?SETS:subtract(AnticOut,
- killed_expr(NodeInfo, Label))),
- {Changed, NodeInfo2} =
- case antic_in(NodeInfo, Label) of
- %% If there weren't any old antic in we use this one.
- none ->
- {true, set_antic_in(NodeInfo, Label, AnticIn)};
-
- OldAnticIn ->
- %% Check if the antic in:s are equal.
- case AnticIn =:= OldAnticIn of
- true ->
- {false, NodeInfo};
- false ->
- {true,
- set_antic_in(NodeInfo, Label, AnticIn)}
- end
- end,
-
- case Changed of
- true ->
- %% Update AnticOut-sets of predecessors and add them to worklist
- Preds = hipe_rtl_cfg:pred(CFG, Label),
- NodeInfo3 =
- lists:foldl
- (fun(Pred, NewNodeInfo) ->
- case antic_out(NewNodeInfo, Pred) of
- none ->
- %% Initialize antic out to all expressions
- set_antic_out(NewNodeInfo, Pred, AnticIn);
- OldAnticOut ->
- set_antic_out(NewNodeInfo, Pred,
- ?SETS:intersection(OldAnticOut, AnticIn))
- end
- end,
- NodeInfo2, Preds),
- {NodeInfo3, Preds};
- false ->
- {NodeInfo2, []}
- end.
-
-%%%%%%%%%%%%%%%%%%%%% LATER / LATER IN FLOW ANALYSIS %%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Fixpoint calculations of Later and LaterIn sets.
-%% Uses a worklist algorithm.
-%% Note that the Later set is calculated on edges.
-
-%%=============================================================================
-%% Calculates the Later and LaterIn sets, and returns updates of both
-%% NodeInfo (with LaterIn sets) and EdgeInfo (with Later sets).
-
-calc_later(CFG, NodeInfo, EdgeInfo) ->
- StartLabel = hipe_rtl_cfg:start_label(CFG),
- Work = init_work([{node, StartLabel}]),
- %% Initialize start node
- NewNodeInfo = set_later_in(NodeInfo, StartLabel, ?SETS:new()),
- calc_later_fixpoint(Work, CFG, NewNodeInfo, EdgeInfo).
-
-calc_later_fixpoint(Work, CFG, NodeInfo, EdgeInfo) ->
- case get_work(Work) of
- {{edge, From, To}, Work2} ->
- {NewNodeInfo, NewEdgeInfo, AddWork} =
- calc_later_edge(From, To, CFG, NodeInfo, EdgeInfo),
- Work3 = add_work(Work2, AddWork),
- calc_later_fixpoint(Work3, CFG, NewNodeInfo, NewEdgeInfo);
- {{node, Label}, Work2} ->
- AddWork = calc_later_node(Label, CFG),
- Work3 = add_work(Work2, AddWork),
- calc_later_fixpoint(Work3, CFG, NodeInfo, EdgeInfo);
- fixpoint ->
- {NodeInfo, EdgeInfo}
- end.
-
-calc_later_node(Label, CFG) ->
- Succs = hipe_rtl_cfg:succ(CFG, Label),
- [{edge, Label, Succ} || Succ <- Succs].
-
-calc_later_edge(From, To, _CFG, NodeInfo, EdgeInfo) ->
- FromTo = {From, To},
- Earliest = earliest(EdgeInfo, FromTo),
- LaterIn = later_in(NodeInfo, From),
- UpExp = up_exp(NodeInfo, From),
- Later = ?SETS:union(Earliest, ?SETS:subtract(LaterIn, UpExp)),
- {Changed, EdgeInfo2} =
- case lookup_later(EdgeInfo, FromTo) of
- none -> {true, set_later(EdgeInfo, FromTo, Later)};
- Later -> {false, EdgeInfo};
- _Old -> {true, set_later(EdgeInfo, FromTo, Later)}
- end,
- case Changed of
- true ->
- %% Update later in set of To-node
- case lookup_later_in(NodeInfo, To) of
- %% If the data isn't set initialize to all expressions
- none ->
- {set_later_in(NodeInfo, To, Later), EdgeInfo2, [{node, To}]};
- OldLaterIn ->
- NewLaterIn = ?SETS:intersection(OldLaterIn, Later),
- %% Check if something changed
- %% FIXME: Implement faster equality test?
- case NewLaterIn =:= OldLaterIn of
- true ->
- {NodeInfo, EdgeInfo2, []};
- false ->
- {set_later_in(NodeInfo, To, NewLaterIn),
- EdgeInfo2, [{node, To}]}
- end
- end;
- false ->
- {NodeInfo, EdgeInfo2, []}
- end.
-
-%%%%%%%%%%%%%%%%%% UPWARDS/DOWNWARDS EXPOSED EXPRESSIONS %%%%%%%%%%%%%%%%%%%%%%
-%% Calculates upwards and downwards exposed expressions.
-
-%%=============================================================================
-%% Calculates the downwards exposed expression sets for the given labels in
-%% the CFG.
-calc_down_exp(_, _, NodeInfo, []) ->
- NodeInfo;
-calc_down_exp(CFG, ExprMap, NodeInfo, [Label|Labels]) ->
- Code = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)),
- %% Data = ?SETS:from_list(lists:map(fun expr_clear_dst/1, exp_work(Code))),
- Data = ?SETS:from_list(get_expr_ids(ExprMap, exp_work(Code))),
- NewNodeInfo = set_down_exp(NodeInfo, Label, Data),
- calc_down_exp(CFG, ExprMap, NewNodeInfo, Labels).
-
-%%=============================================================================
-%% Calculates the upwards exposed expressions sets for the given labels in
-%% the CFG.
-calc_up_exp(_, _, NodeInfo, []) ->
- NodeInfo;
-calc_up_exp(CFG, ExprMap, NodeInfo, [Label|Labels]) ->
- BB = hipe_rtl_cfg:bb(CFG, Label),
- RevCode = lists:reverse(hipe_bb:code(BB)),
- Data = ?SETS:from_list(get_expr_ids(ExprMap, exp_work(RevCode))),
- NewNodeInfo = set_up_exp(NodeInfo, Label, Data),
- calc_up_exp(CFG, ExprMap, NewNodeInfo, Labels).
-
-%%=============================================================================
-%% Given a list of expression instructions, gets a list of expression ids
-%% from an expression map.
-get_expr_ids(ExprMap, Instrs) ->
- [expr_map_get_id(ExprMap, expr_clear_dst(I)) || I <- Instrs].
-
-%%=============================================================================
-%% Does the work of the calc_*_exp functions.
-exp_work(Code) ->
- exp_work([], Code).
-
-exp_work([], [Instr|Instrs]) ->
- case is_expr(Instr) of
- true ->
- exp_work([Instr], Instrs);
- false ->
- exp_work([], Instrs)
- end;
-exp_work(Exprs, []) ->
- Exprs;
-exp_work(Exprs, [Instr|Instrs]) ->
- NewExprs = case is_expr(Instr) of
- true ->
- exp_kill_expr(Instr, [Instr|Exprs]);
- false ->
- exp_kill_expr(Instr, Exprs)
- end,
- exp_work(NewExprs, Instrs).
-
-%%=============================================================================
-%% Checks if the given instruction redefines any operands of
-%% instructions in the instruction list.
-%% It returns the list of expressions with those instructions that has
-%% operands redefined removed.
-exp_kill_expr(_Instr, []) ->
- [];
-exp_kill_expr(Instr, [CheckedExpr|Exprs]) ->
- %% Calls, gctests and stores potentially clobber everything
- case Instr of
- #call{} -> [];
- #gctest{} -> [];
- #store{} -> []; %% FIXME: Only regs and vars clobbered, not fregs...
- #fstore{} ->
- %% fstore potentially clobber float expressions
- [ExprDefine|_] = hipe_rtl:defines(CheckedExpr),
- case hipe_rtl:is_fpreg(ExprDefine) of
- true ->
- exp_kill_expr(Instr, Exprs);
- false ->
- [CheckedExpr | exp_kill_expr(Instr, Exprs)]
- end;
- _ ->
- InstrDefines = hipe_rtl:defines(Instr),
- ExprUses = hipe_rtl:uses(CheckedExpr),
- Diff = ExprUses -- InstrDefines,
- case length(Diff) < length(ExprUses) of
- true ->
- exp_kill_expr(Instr, Exprs);
- false ->
- [CheckedExpr | exp_kill_expr(Instr, Exprs)]
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%% KILLED EXPRESSIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Calculates the killed expression sets for all given labels.
-calc_killed_expr(_, NodeInfo, _, _, _, []) ->
- NodeInfo;
-calc_killed_expr(CFG, NodeInfo, UseMap, AllExpr, IdMap, [Label|Labels]) ->
- Code = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)),
- KilledExprs = calc_killed_expr_bb(Code, UseMap, AllExpr, IdMap, ?SETS:new()),
- NewNodeInfo = set_killed_expr(NodeInfo, Label, KilledExprs),
- calc_killed_expr(CFG, NewNodeInfo, UseMap, AllExpr, IdMap, Labels).
-
-%%=============================================================================
-%% Calculates the killed expressions set for one basic block.
-calc_killed_expr_bb([], _UseMap, _AllExpr, _IdMap, KilledExprs) ->
- KilledExprs;
-calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, IdMap, KilledExprs) ->
- %% Calls, gctests and stores potentially clobber everything
- case Instr of
- #call{} -> AllExpr;
- #gctest{} -> AllExpr;
- #store{} -> AllExpr; %% FIXME: Only regs and vars clobbered, not fregs...
- #fstore{} ->
- %% Kill all float expressions
- %% FIXME: Make separate function is_fp_expr
- ?SETS:from_list
- (lists:foldl(fun(ExprId, Fexprs) ->
- Expr = expr_id_map_get_expr(IdMap, ExprId),
- [Define|_] = hipe_rtl:defines(Expr),
- case hipe_rtl:is_fpreg(Define) of
- true ->
- [Expr|Fexprs];
- false ->
- Fexprs
- end
- end, [], ?SETS:to_list(AllExpr)));
- _ ->
- case hipe_rtl:defines(Instr) of
- [] ->
- calc_killed_expr_bb(Instrs, UseMap, AllExpr, IdMap, KilledExprs);
- [Define|_] ->
- NewKilledExprs = use_map_get_expr_uses(UseMap, Define),
- calc_killed_expr_bb(Instrs, UseMap, AllExpr, IdMap,
- ?SETS:union(NewKilledExprs, KilledExprs))
- end
- end.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%% EARLIEST %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Calculates the earliest set for all edges in the CFG.
-
-calc_earliest(_, _, EdgeInfo, []) ->
- EdgeInfo;
-calc_earliest(CFG, NodeInfo, EdgeInfo, [To|Labels]) ->
- EmptySet = ?SETS:new(),
- Preds = hipe_rtl_cfg:pred(CFG, To),
- NewEdgeInfo =
- case EmptySet =:= antic_in(NodeInfo, To) of
- true ->
- %% Earliest is empty for all edges into this block.
- lists:foldl(fun(From, EdgeInfoAcc) ->
- set_earliest(EdgeInfoAcc, {From, To}, EmptySet)
- end, EdgeInfo, Preds);
- false ->
- lists:foldl(fun(From, EdgeInfoAcc) ->
- IsStartLabel = (From =:= hipe_rtl_cfg:start_label(CFG)),
- Earliest =
- calc_earliest_edge(NodeInfo, IsStartLabel, From, To),
- set_earliest(EdgeInfoAcc, {From, To}, Earliest)
- end, EdgeInfo, Preds)
- end,
- calc_earliest(CFG, NodeInfo, NewEdgeInfo, Labels).
-
-%%=============================================================================
-%% Calculates the earliest set for one edge.
-
-calc_earliest_edge(NodeInfo, IsStartLabel, From, To) ->
- AnticIn = antic_in(NodeInfo, To),
- AvailOut = avail_out(NodeInfo, From),
-
- case IsStartLabel of
- true ->
- ?SETS:subtract(AnticIn, AvailOut);
- false ->
- AnticOut = antic_out(NodeInfo, From),
- ExprKill = killed_expr(NodeInfo, From),
- ?SETS:subtract(?SETS:subtract(AnticIn, AvailOut),
- ?SETS:subtract(AnticOut, ExprKill))
- end.
-%% The above used to be:
-%%
-%% ?SETS:intersection(?SETS:subtract(AnticIn, AvailOut),
-%% ?SETS:union(ExprKill, ?SETS:subtract(AllExpr, AnticOut)))
-%%
-%% But it is costly to use the AllExpr, so let's do some tricky set algebra.
-%%
-%% Let A = AnticIn, B = AvailOut, C = ExprKill, D = AnticOut, U = AllExpr
-%% Let n = intersection, u = union, ' = inverse
-%%
-%% Then
-%% (A - B) n (C u (U - D)) = <Remove D unless it is in C>
-%% = (A - B) n ((C u U) - (D - C)) = <But U is the whole universe>
-%% = (A - B) n (U - (D - C)) = <We are really meaning the complement>
-%% = (A - B) n (D - C)' = <Intersection w complement is subtraction>
-%% = (A - B) - (D - C) <Simple enough, let's stop>
-%%
-%% or in other words
-%% ?SETS:subtract(?SETS:subtract(AnticIn, AvailOut),
-%% ?SETS:subtract(AnticOut, ExprKill))
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%% INSERT / DELETE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Calculates the insert set for one edge and returns the resulting set.
-%% NOTE This does not modify the EdgeInfo set, since the resulting set is
-%% returned and used immediately, instead of being pre-calculated as are
-%% the other sets.
-calc_insert_edge(NodeInfo, EdgeInfo, From, To) ->
- Later = later(EdgeInfo, {From, To}),
- LaterIn = later_in(NodeInfo, To),
- ?SETS:subtract(Later, LaterIn).
-
-%%=============================================================================
-%% Calculates the delete set for all given labels in a CFG.
-calc_delete(_, NodeInfo, []) ->
- NodeInfo;
-calc_delete(CFG, NodeInfo, [Label|Labels]) ->
- NewNodeInfo =
- case Label =:= hipe_rtl_cfg:start_label(CFG) of
- true ->
- set_delete(NodeInfo, Label, ?SETS:new());
- false ->
- UpExp = up_exp(NodeInfo, Label),
- LaterIn = later_in(NodeInfo, Label),
- Delete = ?SETS:subtract(UpExp, LaterIn),
- set_delete(NodeInfo, Label, Delete)
- end,
- calc_delete(CFG, NewNodeInfo, Labels).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%% FIXPOINT FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Worklist used by the fixpoint calculations.
-%%
-%% We use gb_sets here, which is optimized for continuous inserts and
-%% membership tests.
-
-init_work(Labels) ->
- {Labels, [], gb_sets:from_list(Labels)}.
-
-get_work({[Label|Left], List, Set}) ->
- NewWork = {Left, List, gb_sets:delete(Label, Set)},
- {Label, NewWork};
-get_work({[], [], _Set}) ->
- fixpoint;
-get_work({[], List, Set}) ->
- get_work({lists:reverse(List), [], Set}).
-
-add_work(Work = {List1, List2, Set}, [Label|Labels]) ->
- case gb_sets:is_member(Label, Set) of
- true ->
- add_work(Work, Labels);
- false ->
- %%io:format("Adding work: ~w\n", [Label]),
- add_work({List1, [Label|List2], gb_sets:insert(Label, Set)}, Labels)
- end;
-add_work(Work, []) ->
- Work.
-
-%%=============================================================================
-%% Calculates the labels that are the exit labels.
-%% FIXME We do not detect dead-end loops spanning more than one block.
-%% This could potentially cause a bug in the future...
-%% exit_labels(CFG) ->
-%% Labels = hipe_rtl_cfg:labels(CFG),
-%% lists:foldl(fun(Label, ExitLabels) ->
-%% Succs = hipe_rtl_cfg:succ(CFG, Label),
-%% case Succs of
-%% [] ->
-%% [Label|ExitLabels];
-%% [Label] -> %% Count single bb dead-end loops as exit labels
-%% [Label|ExitLabels];
-%% _ ->
-%% ExitLabels
-%% end
-%% end, [], Labels ).
-
-%%=============================================================================
-%% Return true if label is an exit label,
-%% i.e. its bb has no successors or itself as only successor.
-is_exit_label(CFG, Label) ->
- case hipe_rtl_cfg:succ(CFG, Label) of
- [] -> true;
- [Label] -> true;
- _ -> false
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%% DATASET FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The dataset is a collection of data about the CFG.
-%% It is divided into two parts, NodeInfo and EdgeInfo.
-%% The pre-calculation step stores the calculated sets here.
-
--record(node_data, {up_exp = none,
- down_exp = none,
- killed_expr = none,
- avail_in = none,
- avail_out = none,
- antic_in = none,
- antic_out = none,
- later_in = none,
- delete = none}).
-
--record(edge_data, {earliest = none,
- later = none,
- insert = none}).
-
-%%=============================================================================
-%% Creates a node info from a CFG (one entry for each Label).
-mk_node_info(Labels) ->
- lists:foldl(fun(Label, DataTree) ->
- gb_trees:insert(Label, #node_data{}, DataTree)
- %%gb_trees:enter(Label, #node_data{}, DataTree)
- end,
- gb_trees:empty(), Labels).
-
-%%mk_edge_info(Labels) ->
-%% FIXME Should we traverse cfg and initialize edges?
-mk_edge_info() ->
- gb_trees:empty().
-
-%%=============================================================================
-%% Get methods
-up_exp(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.up_exp.
-
-down_exp(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.down_exp.
-
-killed_expr(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.killed_expr.
-
-avail_in(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.avail_in.
-
-avail_out(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.avail_out.
-
-antic_in(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.antic_in.
-
-antic_out(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.antic_out.
-
-later_in(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.later_in.
-
-lookup_later_in(NodeInfo, Label) ->
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- none;
- {value, #node_data{later_in = Data}} ->
- Data
- end.
-
-delete(NodeInfo, Label) ->
- Data = gb_trees:get(Label, NodeInfo),
- Data#node_data.delete.
-
-earliest(EdgeInfo, Edge) ->
- Data = gb_trees:get(Edge, EdgeInfo),
- Data#edge_data.earliest.
-
--ifdef(LOOKUP_EARLIEST_NEEDED).
-lookup_earliest(EdgeInfo, Edge) ->
- case gb_trees:lookup(Edge, EdgeInfo) of
- none ->
- none;
- {value, #edge_data{earliest = Data}} ->
- Data
- end.
--endif.
-
-later(EdgeInfo, Edge) ->
- Data = gb_trees:get(Edge, EdgeInfo),
- Data#edge_data.later.
-
-lookup_later(EdgeInfo, Edge) ->
- case gb_trees:lookup(Edge, EdgeInfo) of
- none ->
- none;
- {value, #edge_data{later = Data}} ->
- Data
- end.
-
-%% insert(EdgeInfo, Edge) ->
-%% case gb_trees:lookup(Edge, EdgeInfo) of
-%% none ->
-%% exit({?MODULE, insert, "edge info not found"}),
-%% none;
-%% {value, #edge_data{insert = Data}} ->
-%% Data
-%% end.
-
-%%=============================================================================
-%% Set methods
-set_up_exp(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{up_exp = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{up_exp = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_down_exp(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{down_exp = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{down_exp = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_killed_expr(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{killed_expr = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{killed_expr = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_avail_in(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{avail_in = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{avail_in = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_avail_out(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{avail_out = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{avail_out = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_antic_in(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{antic_in = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{antic_in = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_antic_out(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{antic_out = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{antic_out = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_later_in(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{later_in = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{later_in = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_delete(NodeInfo, Label, Data) ->
- NodeData =
- case gb_trees:lookup(Label, NodeInfo) of
- none ->
- #node_data{delete = Data};
- {value, OldNodeData} ->
- OldNodeData#node_data{delete = Data}
- end,
- gb_trees:enter(Label, NodeData, NodeInfo).
-
-set_earliest(EdgeInfo, Edge, Data) ->
- EdgeData =
- case gb_trees:lookup(Edge, EdgeInfo) of
- none ->
- #edge_data{earliest = Data};
- {value, OldEdgeData} ->
- OldEdgeData#edge_data{earliest = Data}
- end,
- gb_trees:enter(Edge, EdgeData, EdgeInfo).
-
-set_later(EdgeInfo, Edge, Data) ->
- EdgeData =
- case gb_trees:lookup(Edge, EdgeInfo) of
- none ->
- #edge_data{later = Data};
- {value, OldEdgeData} ->
- OldEdgeData#edge_data{later = Data}
- end,
- gb_trees:enter(Edge, EdgeData, EdgeInfo).
-
-%% set_insert(EdgeInfo, Edge, Data) ->
-%% EdgeData =
-%% case gb_trees:lookup(Edge, EdgeInfo) of
-%% none ->
-%% #edge_data{insert = Data};
-%% {value, OldEdgeData} ->
-%% OldEdgeData#edge_data{insert = Data}
-%% end,
-%% gb_trees:enter(Edge, EdgeData, EdgeInfo).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%% USE MAP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The use map is a mapping from "use" (which is an rtl register/variable)
-%% to a set of expressions (IDs) where that register/variable is used.
-%% It is used by calc_killed_expr to know what expressions are affected by
-%% a definition.
-
-%%=============================================================================
-%% Creates and calculates the use map for a CFG.
-%% It uses ExprMap to lookup the expression IDs.
-mk_use_map(CFG, ExprMap) ->
- Labels = hipe_rtl_cfg:reverse_postorder(CFG),
- NewMap = mk_use_map(gb_trees:empty(), CFG, ExprMap, Labels),
- gb_trees:balance(NewMap).
-
-mk_use_map(Map, _, _, []) ->
- Map;
-mk_use_map(Map, CFG, ExprMap, [Label|Labels]) ->
- Code = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)),
- NewMap = mk_use_map_bb(Map, ExprMap, Code),
- mk_use_map(NewMap, CFG, ExprMap, Labels).
-
-mk_use_map_bb(UseMap, _, []) ->
- UseMap;
-mk_use_map_bb(UseMap, ExprMap, [Instr|Instrs]) ->
- case is_expr(Instr) of
- true ->
- Uses = hipe_rtl:uses(Instr),
- ExprId = expr_map_get_id(ExprMap, expr_clear_dst(Instr)),
- NewUseMap = mk_use_map_insert_uses(UseMap, ExprId, Uses),
- mk_use_map_bb(NewUseMap, ExprMap, Instrs);
- false ->
- mk_use_map_bb(UseMap, ExprMap, Instrs)
- end.
-
-%%=============================================================================
-%% Worker function for mk_use_map that inserts the expression id for every
-%% rtl register the expression uses in a use map.
-mk_use_map_insert_uses(Map, _, []) ->
- Map;
-mk_use_map_insert_uses(Map, Expr, [Use|Uses]) ->
- case gb_trees:lookup(Use, Map) of
- {value, UseSet} ->
- NewUseSet = ?SETS:add_element(Expr, UseSet),
- mk_use_map_insert_uses(gb_trees:update(Use, NewUseSet, Map), Expr, Uses);
- none ->
- UseSet = ?SETS:new(),
- NewUseSet = ?SETS:add_element(Expr, UseSet),
- mk_use_map_insert_uses(gb_trees:insert(Use, NewUseSet, Map), Expr, Uses)
- end.
-
-%%=============================================================================
-%% Gets a set of expressions where the given rtl register is used.
-use_map_get_expr_uses(Map, Reg) ->
- case gb_trees:lookup(Reg, Map) of
- {value, UseSet} ->
- UseSet;
- none ->
- ?SETS:new()
- end.
-
-%%%%%%%%%%%%%%%%%%%%%% EXPRESSION MAP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% The expression map is a mapping from expression to
-%% (1) Expression Id (Integer used to speed up set operations)
-%% (2) List of definitions (labels where the expression is defined and the
-%% list of registers or variables defined by an instruction in that label,
-%% represented as a tuple {Label, Defines})
-%% (3) The list of replacement registers created for the expression
-
-%%=============================================================================
-%% Creates and calculates the expression map for a CFG.
-mk_expr_map(CFG) ->
- init_expr_id(),
- Labels = hipe_rtl_cfg:reverse_postorder(CFG),
- {ExprMap, IdMap} = mk_expr_map(gb_trees:empty(), gb_trees:empty(),
- CFG, Labels),
- {gb_trees:balance(ExprMap), gb_trees:balance(IdMap)}.
-
-mk_expr_map(ExprMap, IdMap, _, []) ->
- {ExprMap, IdMap};
-mk_expr_map(ExprMap, IdMap, CFG, [Label|Labels]) ->
- Code = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)),
- {NewExprMap, NewIdMap} = mk_expr_map_bb(ExprMap, IdMap, Label, Code),
- mk_expr_map(NewExprMap, NewIdMap, CFG, Labels).
-
-mk_expr_map_bb(ExprMap, IdMap, _, []) ->
- {ExprMap, IdMap};
-mk_expr_map_bb(ExprMap, IdMap, Label, [Instr|Instrs]) ->
- case is_expr(Instr) of
- true ->
- Expr = expr_clear_dst(Instr),
- Defines = hipe_rtl:defines(Instr),
- case gb_trees:lookup(Expr, ExprMap) of
- {value, {ExprId, DefinesList, ReplRegs}} ->
- NewExprMap = gb_trees:update(Expr, {ExprId,
- [{Label, Defines}|DefinesList],
- ReplRegs}, ExprMap),
- mk_expr_map_bb(NewExprMap, IdMap, Label, Instrs);
- none ->
- NewExprId = new_expr_id(),
- NewReplRegs = mk_replacement_regs(Defines),
- NewExprMap = gb_trees:insert(Expr, {NewExprId,
- [{Label, Defines}],
- NewReplRegs}, ExprMap),
- NewIdMap = gb_trees:insert(NewExprId, Expr, IdMap),
- mk_expr_map_bb(NewExprMap, NewIdMap, Label, Instrs)
- end;
- false ->
- mk_expr_map_bb(ExprMap, IdMap, Label, Instrs)
- end.
-
-%%=============================================================================
-%% Creates new temporaries to replace defines in moved expressions.
-mk_replacement_regs([]) ->
- [];
-mk_replacement_regs(Defines) ->
- mk_replacement_regs(Defines, []).
-
-mk_replacement_regs([], NewRegs) ->
- lists:reverse(NewRegs);
-mk_replacement_regs([Define|Defines], NewRegs) ->
- case hipe_rtl:is_reg(Define) of
- true ->
- NewReg =
- case hipe_rtl:reg_is_gcsafe(Define) of
- true -> hipe_rtl:mk_new_reg_gcsafe();
- false -> hipe_rtl:mk_new_reg()
- end,
- mk_replacement_regs(Defines, [NewReg|NewRegs]);
- false ->
- case hipe_rtl:is_var(Define) of
- true ->
- mk_replacement_regs(Defines, [hipe_rtl:mk_new_var()|NewRegs]);
- false ->
- true = hipe_rtl:is_fpreg(Define),
- mk_replacement_regs(Defines, [hipe_rtl:mk_new_fpreg()|NewRegs])
- end
- end.
-
-%%=============================================================================
-%% Performs a lookup, which returns a tuple
-%% {expression ID, list of definitions, list of replacement registers}
-expr_map_lookup(Map, Expr) ->
- gb_trees:lookup(Expr, Map).
-
-%%=============================================================================
-%% Gets the actual RTL instruction to be generated for insertions of an
-%% expression.
-expr_map_get_instr(Map, Expr) ->
- case gb_trees:lookup(Expr, Map) of
- {value, {_, _, Regs}} ->
- expr_set_dst(Expr, Regs);
- none ->
- exit({?MODULE, expr_map_get_instr, "expression missing"})
- end.
-
-%%=============================================================================
-%% Gets expression id.
-expr_map_get_id(Map, Expr) ->
- case gb_trees:lookup(Expr, Map) of
- {value, {ExprId, _, _}} ->
- ExprId;
- none ->
- exit({?MODULE, expr_map_get_instr, "expression missing"})
- end.
-
-%%=============================================================================
-%% Creates an rtl instruction that moves a value
-mk_expr_move_instr([Reg], [Define]) ->
- case hipe_rtl:is_fpreg(Reg) of
- true ->
- hipe_rtl:mk_fmove(Reg, Define);
- false ->
- %% FIXME Check is_var() orelse is_reg() ?
- hipe_rtl:mk_move(Reg, Define)
- end;
-mk_expr_move_instr([_Reg|_Regs] = RegList, Defines) ->
- %% FIXME Does this really work? What about floats...
- %% (Multiple defines does not seem to be used by any of the
- %% instructions considered by rtl_lcm at the moment so this is pretty much
- %% untested/unused.)
- hipe_rtl:mk_multimove(RegList, Defines);
-mk_expr_move_instr(_, []) ->
- exit({?MODULE, mk_expr_move_instr, "bad match"}).
-
-%%=============================================================================
-%% Returns a set of all expressions in the code.
-%% all_exprs(_CFG, []) ->
-%% ?SETS:new();
-%% all_exprs(CFG, [Label|Labels]) ->
-%% BB = hipe_rtl_cfg:bb(CFG, Label),
-%% Code = hipe_bb:code(BB),
-%% ?SETS:union(all_exprs_bb(Code),
-%% all_exprs(CFG, Labels)).
-
-%%=============================================================================
-%% Returns a set of expressions in a basic block.
-%% all_exprs_bb([]) ->
-%% ?SETS:new();
-%% all_exprs_bb([Instr|Instrs]) ->
-%% case is_expr(Instr) of
-%% true ->
-%% Expr = expr_clear_dst(Instr),
-%% ExprSet = all_exprs_bb(Instrs),
-%% ?SETS:add_element(Expr, ExprSet);
-%% false ->
-%% all_exprs_bb(Instrs)
-%% end.
-
-%%%%%%%%%%%%%%%%%% EXPRESSION ID -> EXPRESSION MAP %%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Map from expression IDs to expressions.
-%%=============================================================================
-%% mk_expr_id_map() ->
-%% gb_trees:empty().
-
-%% expr_id_map_insert(Map, ExprId, Expr) ->
-%% gb_trees:insert(ExprId, Expr, Map).
-
-%% expr_id_map_lookup(Map, ExprId) ->
-%% gb_trees:lookup(ExprId, Map).
-
-%%=============================================================================
-%% Given expression id, gets expression.
-expr_id_map_get_expr(Map, ExprId) ->
- case gb_trees:lookup(ExprId, Map) of
- {value, Expr} ->
- Expr;
- none ->
- exit({?MODULE, expr_id_map_get_expr, "expression id missing"})
- end.
-
-%%=============================================================================
-%% Expression ID counter
-init_expr_id() ->
- put({rtl_lcm,expr_id_count}, 0),
- ok.
-
--spec new_expr_id() -> non_neg_integer().
-new_expr_id() ->
- Obj = {rtl_lcm, expr_id_count},
- V = get(Obj),
- put(Obj, V+1),
- V.
-
-%%%%%%%%%%%%%%%%%% EDGE BB (INSERT BETWEEN) MAP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Map from edges to labels.
-%% This is used by insert_expr_between to remember what new bbs it has created
-%% for insertions on edges, and thus for multiple insertions on the same edge
-%% to end up in the same bb.
-%%=============================================================================
-mk_edge_bb_map() ->
- gb_trees:empty().
-
-edge_bb_map_insert(Map, Edge, Label) ->
- gb_trees:enter(Edge, Label, Map).
-
-edge_bb_map_lookup(Map, Edge) ->
- gb_trees:lookup(Edge, Map).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PRETTY-PRINTING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%=============================================================================
-%% Prints debug messages.
--ifdef(LCM_DEBUG).
-
-pp_debug(Str, Args) ->
- case ?LCM_DEBUG of
- true ->
- io:format(standard_io, Str, Args);
- false ->
- ok
- end.
-
-pp_debug_instr(Instr) ->
- case ?LCM_DEBUG of
- true ->
- hipe_rtl:pp_instr(standard_io, Instr);
- false ->
- ok
- end.
-
--else.
-
-pp_debug(_, _) ->
- ok.
-
-pp_debug_instr(_) ->
- ok.
-
--endif. %% DEBUG
-
-%%=============================================================================
-%% Pretty-prints the calculated sets for the lazy code motion.
-pp_sets(_, _, _, _, _, _, []) ->
- ok;
-pp_sets(ExprMap, IdMap, NodeInfo, EdgeInfo, AllExpr, CFG, [Label|Labels]) ->
- Preds = hipe_rtl_cfg:pred(CFG, Label),
- Succs = hipe_rtl_cfg:succ(CFG, Label),
-
- io:format(standard_io, "Label ~w~n", [Label]),
- io:format(standard_io, " Preds: ~w~n", [Preds]),
- io:format(standard_io, " Succs: ~w~n", [Succs]),
-
- case up_exp(NodeInfo, Label) of
- none -> ok;
- UpExp ->
- case ?SETS:size(UpExp) =:= 0 of
- false ->
- io:format(standard_io, " UEExpr: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(UpExp));
- true -> ok
- end
- end,
- case down_exp(NodeInfo, Label) of
- none -> ok;
- DownExp ->
- case ?SETS:size(DownExp) =:= 0 of
- false ->
- io:format(standard_io, " DEExpr: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(DownExp));
- true -> ok
- end
- end,
- case killed_expr(NodeInfo, Label) of
- none -> ok;
- KilledExpr ->
- case ?SETS:size(KilledExpr) =:= 0 of
- false ->
- io:format(standard_io, " ExprKill: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(KilledExpr));
- true -> ok
- end
- end,
- case avail_in(NodeInfo, Label) of
- none -> ok;
- AvailIn ->
- case ?SETS:size(AvailIn) =:= 0 of
- false ->
- io:format(standard_io, " AvailIn: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(AvailIn));
- true -> ok
- end
- end,
- case avail_out(NodeInfo, Label) of
- none -> ok;
- AvailOut ->
- case ?SETS:size(AvailOut) =:= 0 of
- false ->
- io:format(standard_io, " AvailOut: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(AvailOut));
- true -> ok
- end
- end,
- case antic_in(NodeInfo, Label) of
- none -> ok;
- AnticIn ->
- case ?SETS:size(AnticIn) =:= 0 of
- false ->
- io:format(standard_io, " AnticIn: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(AnticIn));
- true -> ok
- end
- end,
- case antic_out(NodeInfo, Label) of
- none -> ok;
- AnticOut ->
- case ?SETS:size(AnticOut) =:= 0 of
- false ->
- io:format(standard_io, " AnticOut: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(AnticOut));
- true -> ok
- end
- end,
- case later_in(NodeInfo, Label) of
- none -> ok;
- LaterIn ->
- case ?SETS:size(LaterIn) =:= 0 of
- false ->
- io:format(standard_io, " LaterIn: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(LaterIn));
- true -> ok
- end
- end,
-
- pp_earliest(ExprMap, IdMap, EdgeInfo, Label, Succs),
- pp_later(ExprMap, IdMap, EdgeInfo, Label, Succs),
-
- case delete(NodeInfo, Label) of
- none -> ok;
- Delete ->
- case ?SETS:size(Delete) =:= 0 of
- false ->
- io:format(standard_io, " Delete: ~n", []),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(Delete));
- true -> ok
- end
- end,
- pp_sets(ExprMap, IdMap, NodeInfo, EdgeInfo, AllExpr, CFG, Labels).
-
-%%=============================================================================
-%% Pretty-prints the later set.
-pp_later(_, _, _, _, []) ->
- ok;
-pp_later(ExprMap, IdMap, EdgeInfo, Pred, [Succ|Succs]) ->
- case later(EdgeInfo, {Pred, Succ}) of
- none -> ok;
- Later ->
- case ?SETS:size(Later) =:= 0 of
- false ->
- io:format(standard_io, " Later(~w->~w): ~n", [Pred,Succ]),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(Later));
- true -> ok
- end
- end,
- pp_later(ExprMap, IdMap, EdgeInfo, Pred, Succs).
-
-%%=============================================================================
-%% Pretty-prints the earliest set.
-pp_earliest(_, _, _, _, []) ->
- ok;
-pp_earliest(ExprMap, IdMap, EdgeInfo, Pred, [Succ|Succs]) ->
- case earliest(EdgeInfo, {Pred, Succ}) of
- none -> ok;
- Earliest ->
- case ?SETS:size(Earliest) =:= 0 of
- false ->
- io:format(standard_io, " Earliest(~w->~w): ~n", [Pred,Succ]),
- pp_exprs(ExprMap, IdMap, ?SETS:to_list(Earliest));
- true -> ok
- end
- end,
- pp_earliest(ExprMap, IdMap, EdgeInfo, Pred, Succs).
-
-%%=============================================================================
-%% Pretty-prints an expression
-pp_expr(ExprMap, IdMap, ExprId) ->
- Expr = expr_id_map_get_expr(IdMap, ExprId),
- hipe_rtl:pp_instr(standard_io, expr_map_get_instr(ExprMap, Expr)).
-
-pp_exprs(_, _, []) ->
- ok;
-pp_exprs(ExprMap, IdMap, [E|Es]) ->
- pp_expr(ExprMap, IdMap, E),
- pp_exprs(ExprMap, IdMap, Es).
diff --git a/lib/hipe/rtl/hipe_rtl_liveness.erl b/lib/hipe/rtl/hipe_rtl_liveness.erl
deleted file mode 100644
index 98376439f3..0000000000
--- a/lib/hipe/rtl/hipe_rtl_liveness.erl
+++ /dev/null
@@ -1,139 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% LIVENESS ANALYSIS
-%%
-%% Exports:
-%% ~~~~~~~
-%% analyze(CFG) - returns a liveness analysis of CFG.
-%% liveout(Liveness, Label) - returns a set of variables that are live on
-%% exit from basic block named Label.
-%% livein(Liveness, Label) - returns a set of variables that are live on
-%% entry to the basic block named Label.
-%% list(Instructions, LiveOut) - Given a list of instructions and a liveout
-%% set, returns a set of variables live at the first instruction.
-%%
-
--module(hipe_rtl_liveness).
-
-%% -define(DEBUG_LIVENESS,true).
--define(LIVEOUT_NEEDED,true). % needed for liveness.inc below.
--define(PRETTY_PRINT,false).
-
--include("hipe_rtl.hrl").
--include("../flow/liveness.inc").
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface to CFG and RTL.
-%%
-
-cfg_bb(CFG, L) ->
- hipe_rtl_cfg:bb(CFG, L).
-
-cfg_postorder(CFG) ->
- hipe_rtl_cfg:postorder(CFG).
-
-cfg_succ(CFG, L) ->
- hipe_rtl_cfg:succ(CFG, L).
-
-uses(Instr) ->
- hipe_rtl:uses(Instr).
-
-defines(Instr) ->
- hipe_rtl:defines(Instr).
-
-%%
-%% This is the list of registers that are live at exit from a function
-%%
-
-liveout_no_succ() ->
- hipe_rtl_arch:live_at_return().
-
-%%
-%% The following are used only if annotation of the code is requested.
-%%
-
-cfg_labels(CFG) ->
- hipe_rtl_cfg:reverse_postorder(CFG).
-
-pp_block(Label, CFG) ->
- BB=hipe_rtl_cfg:bb(CFG, Label),
- Code=hipe_bb:code(BB),
- hipe_rtl:pp_block(Code).
-
-pp_liveness_info(LiveList) ->
- NewList=remove_precoloured(LiveList),
- print_live_list(NewList).
-
-print_live_list([]) ->
- io:format(" none~n", []);
-print_live_list([Last]) ->
- io:format(" ", []),
- print_var(Last),
- io:format("~n", []);
-print_live_list([Var|Rest]) ->
- io:format(" ", []),
- print_var(Var),
- io:format(",", []),
- print_live_list(Rest).
-
-print_var(A) ->
- case hipe_rtl:is_var(A) of
- true ->
- pp_var(A);
- false ->
- case hipe_rtl:is_reg(A) of
- true ->
- pp_reg(A);
- false ->
- case hipe_rtl:is_fpreg(A) of
- true ->
- io:format("f~w", [hipe_rtl:fpreg_index(A)]);
- false ->
- io:format("unknown:~w", [A])
- end
- end
- end.
-
-pp_hard_reg(N) ->
- io:format("~s", [hipe_rtl_arch:reg_name(N)]).
-
-pp_reg(Arg) ->
- case hipe_rtl_arch:is_precoloured(Arg) of
- true ->
- pp_hard_reg(hipe_rtl:reg_index(Arg));
- false ->
- io:format("r~w", [hipe_rtl:reg_index(Arg)])
- end.
-
-pp_var(Arg) ->
- case hipe_rtl_arch:is_precoloured(Arg) of
- true ->
- pp_hard_reg(hipe_rtl:var_index(Arg));
- false ->
- io:format("v~w", [hipe_rtl:var_index(Arg)])
- end.
-
-remove_precoloured(List) ->
- List.
- %% [X || X <- List, not hipe_rtl_arch:is_precoloured(X)].
-
--ifdef(DEBUG_LIVENESS).
-cfg_bb_add(CFG, L, NewBB) ->
- hipe_rtl_cfg:bb_add(CFG, L, NewBB).
-
-mk_comment(Text) ->
- hipe_rtl:mk_comment(Text).
--endif.
diff --git a/lib/hipe/rtl/hipe_rtl_mk_switch.erl b/lib/hipe/rtl/hipe_rtl_mk_switch.erl
deleted file mode 100644
index d5cc6bd5df..0000000000
--- a/lib/hipe/rtl/hipe_rtl_mk_switch.erl
+++ /dev/null
@@ -1,980 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Filename : hipe_rtl_mk_switch.erl
-%% Module : hipe_rtl_mk_switch
-%% Purpose : Implements switching on Erlang values.
-%% Notes : Only fixnums are supported well,
-%% atoms work with table search,
-%% the inline search of atoms might have some bugs.
-%% Should be extended to handle bignums and floats.
-%%
-%% History : * 2001-02-28 Erik Johansson (happi@it.uu.se):
-%% Created.
-%% * 2001-04-01 Erik Trulsson (ertr1013@csd.uu.se):
-%% Stefan Lindström (stli3993@csd.uu.se):
-%% Added clustering and inlined binary search trees.
-%% * 2001-07-30 EJ (happi@it.uu.se):
-%% Fixed some bugs and started cleanup.
-%% ====================================================================
-%% Exports :
-%% gen_switch_val(I, VarMap, ConstTab, Options)
-%% gen_switch_tuple(I, Map, ConstTab, Options)
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_mk_switch).
-
--export([gen_switch_val/4, gen_switch_tuple/4]).
-
-%%-------------------------------------------------------------------------
-
--include("../main/hipe.hrl").
-
-%%-------------------------------------------------------------------------
-
--define(MINFORJUMPTABLE,9).
- % Minimum number of integers needed to use something else than an inline search.
--define(MINFORINTSEARCHTREE,65). % Must be at least 3
- % Minimum number of integer elements needed to use a non-inline binary search.
-
--define(MININLINEATOMSEARCH,8).
- % Minimum number of atoms needed to use an inline binary search instead
- % of a fast linear search.
-
--define(MINFORATOMSEARCHTREE,20). % Must be at least 3
- % Minimum number of atoms needed to use a non-inline binary search instead
- % of a linear search.
-
--define(MAXINLINEATOMSEARCH,64). % Must be at least 3
- % The cutoff point between inlined and non-inlined binary search for atoms
-
--define(WORDSIZE, hipe_rtl_arch:word_size()).
--define(MINDENSITY, 0.5).
- % Minimum density required to use a jumptable instead of a binary search.
-
-%% The reason why MINFORINTSEARCHTREE and MINFORATOMSEARCHTREE must be
-%% at least 3 is that the function tab/5 will enter an infinite loop
-%% and hang when faced with a switch of size 1 or 2.
-
-
-%% Options used by this module:
-%%
-%% [no_]use_indexing
-%% Determines if any indexing be should be done at all. Turned on
-%% by default at optimization level o2 and higher.
-%%
-%% [no_]use_clusters
-%% Controls whether we attempt to divide sparse integer switches
-%% into smaller dense clusters for which jumptables are practical.
-%% Turned off by default since it can increase compilation time
-%% considerably and most programs will gain little benefit from it.
-%%
-%% [no_]use_inline_atom_search
-%% Controls whether we use an inline binary search for small number
-%% of atoms. Turned off by default since this is currently only
-%% supported on SPARC (and not on x86) and probably needs a bit
-%% more testing before it can be turned on by default.
-
-gen_switch_val(I, VarMap, ConstTab, Options) ->
- case proplists:get_bool(use_indexing, Options) of
- false -> gen_slow_switch_val(I, VarMap, ConstTab, Options);
- true -> gen_fast_switch_val(I, VarMap, ConstTab, Options)
- end.
-
-gen_fast_switch_val(I, VarMap, ConstTab, Options) ->
- {Arg, VarMap0} =
- hipe_rtl_varmap:icode_var2rtl_var(hipe_icode:switch_val_term(I), VarMap),
- IcodeFail = hipe_icode:switch_val_fail_label(I),
- {Fail, VarMap1} = hipe_rtl_varmap:icode_label2rtl_label(IcodeFail, VarMap0),
- %% Important that the list of cases is sorted when handling integers.
- UnsortedCases = hipe_icode:switch_val_cases(I),
- Cases = lists:sort(UnsortedCases),
-
- check_duplicates(Cases),
- %% This check is currently not really necessary. The checking
- %% happens at an earlier phase of the compilation.
- {Types, InitCode} = split_types(Cases, Arg),
- handle_types(Types, InitCode, VarMap1, ConstTab, Arg, {I, Fail, Options}).
-
-handle_types([{Type,Lbl,Cases}|Types], Code, VarMap, ConstTab, Arg, Info) ->
- {Code1,VarMap1,ConstTab1} = gen_fast_switch_on(Type, Cases,
- VarMap,
- ConstTab, Arg, Info),
- handle_types(Types, [Code,Lbl,Code1], VarMap1, ConstTab1, Arg, Info);
-handle_types([], Code, VarMap, ConstTab, _, _) ->
- {Code, VarMap, ConstTab}.
-
-
-gen_fast_switch_on(integer, Cases, VarMap, ConstTab, Arg, {I, Fail, Options}) ->
- {First,_} = hd(Cases),
- Min = hipe_icode:const_value(First),
- if length(Cases) < ?MINFORJUMPTABLE ->
- gen_small_switch_val(Arg,Cases,Fail,VarMap,ConstTab,Options);
- true ->
- case proplists:get_bool(use_clusters, Options) of
- false ->
- M = list_to_tuple(Cases),
- D = density(M, 1, tuple_size(M)),
- if
- D >= ?MINDENSITY ->
- gen_jump_table(Arg,Fail,hipe_icode:switch_val_fail_label(I),VarMap,ConstTab,Cases,Min);
- true ->
- gen_search_switch_val(Arg, Cases, Fail, VarMap, ConstTab, Options)
- end;
- true ->
- MC = minclusters(Cases),
- Cl = cluster_split(Cases,MC),
- CM = cluster_merge(Cl),
- find_cluster(CM,VarMap,ConstTab,Options,Arg,Fail,hipe_icode:switch_val_fail_label(I))
- end
- end;
-gen_fast_switch_on(atom, Cases, VarMap, ConstTab, Arg, {_I, Fail, Options}) ->
- case proplists:get_bool(use_inline_atom_search, Options) of
- true ->
- if
- length(Cases) < ?MININLINEATOMSEARCH ->
- gen_linear_switch_val(Arg, Cases, Fail, VarMap, ConstTab, Options);
- length(Cases) > ?MAXINLINEATOMSEARCH ->
- gen_search_switch_val(Arg, Cases, Fail, VarMap, ConstTab, Options);
- true ->
- gen_atom_switch_val(Arg,Cases,Fail,VarMap,ConstTab,Options)
- end;
- false ->
- if length(Cases) < ?MINFORATOMSEARCHTREE ->
- gen_linear_switch_val(Arg, Cases, Fail, VarMap, ConstTab, Options);
- true ->
- gen_search_switch_val(Arg, Cases, Fail, VarMap, ConstTab, Options)
- end
- end;
-gen_fast_switch_on(_, _, VarMap, ConstTab, _, {I,_Fail,Options}) ->
- %% We can only handle smart indexing of integers and atoms
- %% TODO: Consider bignum
- gen_slow_switch_val(I, VarMap, ConstTab, Options).
-
-
-%% Split different types into separate switches.
-split_types([Case|Cases], Arg) ->
- Type1 = casetype(Case),
- Types = split(Cases,Type1,[Case],[]),
- switch_on_types(Types,[], [], Arg);
-split_types([],_) ->
- %% Cant happen.
- ?EXIT({empty_caselist}).
-
-switch_on_types([{Type,Cases}], AccCode, AccCases, _Arg) ->
- Lbl = hipe_rtl:mk_new_label(),
- I = hipe_rtl:mk_goto(hipe_rtl:label_name(Lbl)),
- {[{Type,Lbl,lists:reverse(Cases)} | AccCases], lists:reverse([I|AccCode])};
-switch_on_types([{other,Cases} | Rest], AccCode, AccCases, Arg) ->
- %% Make sure the general case is handled last.
- switch_on_types(Rest ++ [{other,Cases}], AccCode, AccCases, Arg);
-switch_on_types([{Type,Cases} | Rest], AccCode, AccCases, Arg) ->
- TLab = hipe_rtl:mk_new_label(),
- FLab = hipe_rtl:mk_new_label(),
- TestCode =
- case Type of
- integer ->
- hipe_tagscheme:test_fixnum(Arg, hipe_rtl:label_name(TLab),
- hipe_rtl:label_name(FLab), 0.5);
- atom ->
- hipe_tagscheme:test_atom(Arg, hipe_rtl:label_name(TLab),
- hipe_rtl:label_name(FLab), 0.5);
- bignum ->
- hipe_tagscheme:test_bignum(Arg, hipe_rtl:label_name(TLab),
- hipe_rtl:label_name(FLab), 0.5);
- _ -> ?EXIT({ooops, type_not_handled, Type})
- end,
- switch_on_types(Rest, [[TestCode,FLab] | AccCode],
- [{Type,TLab,lists:reverse(Cases)} | AccCases], Arg).
-
-split([Case|Cases], Type, Current, Rest) ->
- case casetype(Case) of
- Type ->
- split(Cases, Type, [Case|Current],Rest);
- Other ->
- split(Cases, Other, [Case], [{Type,Current}|Rest])
- end;
-split([], Type, Current, Rest) ->
- [{Type, Current} | Rest].
-
-%% Determine what type an entry in the caselist has
-
-casetype({Const,_}) ->
- casetype(hipe_icode:const_value(Const));
-casetype(A) ->
- if
- is_integer(A) ->
- case hipe_tagscheme:is_fixnum(A) of
- true -> integer;
- false -> bignum
- end;
- is_float(A) -> float;
- is_atom(A) -> atom;
- true -> other
- end.
-
-%% check that no duplicate values occur in the case list and also
-%% check that all case values have the same type.
-check_duplicates([]) -> true;
-check_duplicates([_]) -> true;
-check_duplicates([{Const1,_},{Const2,L2}|T]) ->
- C1 = hipe_icode:const_value(Const1),
- C2 = hipe_icode:const_value(Const2),
- %% T1 = casetype(C1),
- %% T2 = casetype(C2),
- if C1 =/= C2 -> %% , T1 =:= T2 ->
- check_duplicates([{Const2,L2}|T]);
- true ->
- ?EXIT({bad_values_in_switchval,C1})
- end.
-
-%%
-%% Determine the optimal way to divide Cases into clusters such that each
-%% cluster is dense.
-%%
-%% See:
-%% Producing Good Code for the Case Statement, Robert L. Bernstein
-%% Software - Practice and Experience vol 15, 1985, no 10, pp 1021--1024
-%% And
-%% Correction to "Producing Good Code for the Case Statement"
-%% Sampath Kannan and Todd A. Proebsting,
-%% Software - Practice and Experience vol 24, 1994, no 2, p 233
-%%
-%% (The latter is where the algorithm comes from.)
-
-%% This function will return a tuple with the first element being 0
-%% The rest of the elements being integers. A value of M at index N
-%% (where the first element is considered to have index 0) means that
-%% the first N cases can be divided into M (but no fewer) clusters where
-%% each cluster is dense.
-
-minclusters(Cases) when is_list(Cases) ->
- minclusters(list_to_tuple(Cases));
-minclusters(Cases) when is_tuple(Cases) ->
- N = tuple_size(Cases),
- MinClusters = list_to_tuple([0|n_list(N,inf)]),
- i_loop(1,N,MinClusters,Cases).
-
-%% Create a list with N elements initialized to Init
-n_list(0,_) -> [];
-n_list(N,Init) -> [Init | n_list(N-1,Init)].
-
-%% Do the dirty work of minclusters
-i_loop(I,N,MinClusters,_Cases) when I > N ->
- MinClusters;
-i_loop(I,N,MinClusters,Cases) when I =< N ->
- M = j_loop(0, I-1, MinClusters, Cases),
- i_loop(I+1, N, M, Cases).
-
-%% More dirty work
-j_loop(J,I1,MinClusters,_Cases) when J > I1 ->
- MinClusters;
-j_loop(J,I1,MinClusters,Cases) when J =< I1 ->
- D = density(Cases,J+1,I1+1),
- A0 = element(J+1,MinClusters),
- A = if
- is_number(A0) ->
- A0+1;
- true ->
- A0
- end,
- B = element(I1+2,MinClusters),
- M = if
- D >= ?MINDENSITY, A<B ->
- setelement(I1+2,MinClusters,A);
- true ->
- MinClusters
- end,
- j_loop(J+1,I1,M,Cases).
-
-
-%% Determine the density of a (subset of a) case list
-%% A is a tuple with the cases in order from smallest to largest
-%% I is the index of the first element and J of the last
-
-density(A,I,J) ->
- {AI,_} = element(I,A),
- {AJ,_} = element(J,A),
- (J-I+1)/(hipe_icode:const_value(AJ)-hipe_icode:const_value(AI)+1).
-
-
-%% Split a case list into dense clusters
-%% Returns a list of lists of cases.
-%%
-%% Cases is the case list and Clust is a list describing the optimal
-%% clustering as returned by minclusters
-%%
-%% If the value in the last place in minclusters is M then we can
-%% split the case list into M clusters. We then search for the last
-%% (== right-most) occurance of the value M-1 in minclusters. That
-%% indicates the largest number of cases that can be split into M-1
-%% clusters. This means that the cases in between constitute one
-%% cluster. Then we recurse on the remainder of the cases.
-%%
-%% The various calls to lists:reverse are just to ensure that the
-%% cases remain in the correct, sorted order.
-
-cluster_split(Cases, Clust) ->
- A = tl(tuple_to_list(Clust)),
- Max = element(tuple_size(Clust), Clust),
- L1 = lists:reverse(Cases),
- L2 = lists:reverse(A),
- cluster_split(Max, [], [], L1, L2).
-
-cluster_split(0, [], Res, Cases, _Clust) ->
- L = lists:reverse(Cases),
- {H,_} = hd(L),
- {T,_} = hd(Cases),
- [{dense,hipe_icode:const_value(H),hipe_icode:const_value(T),L}|Res];
-cluster_split(N, [], Res, Cases, [N|_] = Clust) ->
- cluster_split(N-1, [], Res, Cases, Clust);
-cluster_split(N,Sofar,Res,Cases,[N|Clust]) ->
- {H,_} = hd(Sofar),
- {T,_} = lists:last(Sofar),
- cluster_split(N-1,[],[{dense,hipe_icode:const_value(H),hipe_icode:const_value(T),Sofar}|Res],Cases,[N|Clust]);
-cluster_split(N,Sofar,Res,[C|Cases],[_|Clust]) ->
- cluster_split(N,[C|Sofar],Res,Cases,Clust).
-
-%%
-%% Merge adjacent small clusters into larger sparse clusters
-%%
-cluster_merge([C]) -> [C];
-cluster_merge([{dense,Min,Max,C}|T]) when length(C) >= ?MINFORJUMPTABLE ->
- C2 = cluster_merge(T),
- [{dense,Min,Max,C}|C2];
-cluster_merge([{sparse,Min,_,C},{sparse,_,Max,D}|T]) ->
- R = {sparse,Min,Max,C ++ D},
- cluster_merge([R|T]);
-cluster_merge([{sparse,Min,_,C},{dense,_,Max,D}|T]) when length(D) < ?MINFORJUMPTABLE ->
- R = {sparse,Min,Max,C ++ D},
- cluster_merge([R|T]);
-cluster_merge([{dense,Min,_,C},{dense,_,Max,D}|T]) when length(C) < ?MINFORJUMPTABLE, length(D) < ?MINFORJUMPTABLE ->
- R = {sparse,Min,Max,C ++ D},
- cluster_merge([R|T]);
-cluster_merge([{dense,Min,_,D},{sparse,_,Max,C}|T]) when length(D) < ?MINFORJUMPTABLE ->
- R = {sparse,Min,Max,C ++ D},
- cluster_merge([R|T]);
-cluster_merge([A,{dense,Min,Max,C}|T]) when length(C) >= ?MINFORJUMPTABLE ->
- R = cluster_merge([{dense,Min,Max,C}|T]),
- [A|R].
-
-
-%% Generate code to search for the correct cluster
-
-find_cluster([{sparse,_Min,_Max,C}],VarMap,ConstTab,Options,Arg,Fail,_IcodeFail) ->
- case length(C) < ?MINFORINTSEARCHTREE of
- true ->
- gen_small_switch_val(Arg,C,Fail,VarMap,ConstTab,Options);
- _ ->
- gen_search_switch_val(Arg,C,Fail,VarMap,ConstTab,Options)
- end;
-find_cluster([{dense,Min,_Max,C}],VarMap,ConstTab,Options,Arg,Fail,IcodeFail) ->
- case length(C) < ?MINFORJUMPTABLE of
- true ->
- gen_small_switch_val(Arg,C,Fail,VarMap,ConstTab,Options);
- _ ->
- gen_jump_table(Arg,Fail,IcodeFail,VarMap,ConstTab,C,Min)
- end;
-find_cluster([{Density,Min,Max,C}|T],VarMap,ConstTab,Options,Arg,Fail,IcodeFail) ->
- ClustLab = hipe_rtl:mk_new_label(),
- NextLab = hipe_rtl:mk_new_label(),
- {ClustCode,V1,C1} = find_cluster([{Density,Min,Max,C}],VarMap,ConstTab,Options,Arg,Fail,IcodeFail),
-
- {Rest,V2,C2} = find_cluster(T,V1,C1,Options,Arg,Fail,IcodeFail),
-
- {[
- hipe_rtl:mk_branch(Arg, gt, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(Max)),
- hipe_rtl:label_name(NextLab),
- hipe_rtl:label_name(ClustLab), 0.50),
- ClustLab
- ] ++
- ClustCode ++
- [NextLab] ++
- Rest,
- V2,C2}.
-
-%% Generate efficient code for a linear search through the case list.
-%% Only works for atoms and integer.
-gen_linear_switch_val(Arg,Cases,Fail,VarMap,ConstTab,_Options) ->
- {Values,_Labels} = split_cases(Cases),
- {LabMap,VarMap1} = lbls_from_cases(Cases,VarMap),
- Code = fast_linear_search(Arg,Values,LabMap,Fail),
- {Code,VarMap1,ConstTab}.
-
-fast_linear_search(_Arg,[],[],Fail) ->
- [hipe_rtl:mk_goto(hipe_rtl:label_name(Fail))];
-fast_linear_search(Arg,[Case|Cases],[Label|Labels],Fail) ->
- Reg = hipe_rtl:mk_new_reg_gcsafe(),
- NextLab = hipe_rtl:mk_new_label(),
- C2 = fast_linear_search(Arg,Cases,Labels,Fail),
- C1 =
- if
- is_integer(Case) ->
- TVal = hipe_tagscheme:mk_fixnum(Case),
- [
- hipe_rtl:mk_move(Reg,hipe_rtl:mk_imm(TVal)),
- hipe_rtl:mk_branch(Arg,eq,Reg,
- Label,
- hipe_rtl:label_name(NextLab), 0.5),
- NextLab
- ];
- is_atom(Case) ->
- [
- hipe_rtl:mk_load_atom(Reg,Case),
- hipe_rtl:mk_branch(Arg,eq,Reg,
- Label,
- hipe_rtl:label_name(NextLab), 0.5),
- NextLab
- ];
- true -> % This should never happen !
- ?EXIT({internal_error_in_switch_val,Case})
- end,
- [C1,C2].
-
-
-%% Generate code to search through a small cluster of integers using
-%% binary search
-gen_small_switch_val(Arg,Cases,Fail,VarMap,ConstTab,_Options) ->
- {Values,_Labels} = split_cases(Cases),
- {LabMap,VarMap1} = lbls_from_cases(Cases,VarMap),
- Keys = [hipe_tagscheme:mk_fixnum(X) % Add tags to the values
- || X <- Values],
- Code = inline_search(Keys, LabMap, Arg, Fail),
- {Code, VarMap1, ConstTab}.
-
-
-%% Generate code to search through a small cluster of atoms
-gen_atom_switch_val(Arg,Cases,Fail,VarMap,ConstTab,_Options) ->
- {Values, _Labels} = split_cases(Cases),
- {LabMap,VarMap1} = lbls_from_cases(Cases,VarMap),
- LMap = [{label,L} || L <- LabMap],
- {NewConstTab,Id} = hipe_consttab:insert_sorted_block(ConstTab, Values),
- {NewConstTab2,LabId} =
- hipe_consttab:insert_sorted_block(NewConstTab, word, LMap, Values),
- Code = inline_atom_search(0, length(Cases)-1, Id, LabId, Arg, Fail, LabMap),
- {Code, VarMap1, NewConstTab2}.
-
-
-%% calculate the middle position of a list (+ 1 because of 1-indexing of lists)
-get_middle(List) ->
- N = length(List),
- N div 2 + 1.
-
-%% get element [N1, N2] from a list
-get_cases(_, 0, 0) ->
- [];
-get_cases([H|T], 0, N) ->
- [H | get_cases(T, 0, N - 1)];
-get_cases([_|T], N1, N2) ->
- get_cases(T, N1 - 1, N2 - 1).
-
-
-%% inline_search/4 creates RTL code for a inlined binary search.
-%% It requires two sorted tables - one with the keys to search
-%% through and one with the corresponding labels to jump to.
-%%
-%% Input:
-%% KeyList - A list of keys to search through.
-%% LableList - A list of labels to jump to.
-%% KeyReg - A register containing the key to search for.
-%% Default - A label to jump to if the key is not found.
-%%
-
-inline_search([], _LabelList, _KeyReg, _Default) -> [];
-inline_search(KeyList, LabelList, KeyReg, Default) ->
- %% Create some registers and labels that we need.
- Reg = hipe_rtl:mk_new_reg_gcsafe(),
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- Lab3 = hipe_rtl:mk_new_label(),
-
- Length = length(KeyList),
-
- if
- Length >= 3 ->
- %% Get middle element and keys/labels before that and after
- Middle_pos = get_middle(KeyList),
- Middle_key = lists:nth(Middle_pos, KeyList),
- Keys_beginning = get_cases(KeyList, 0, Middle_pos - 1),
- Labels_beginning = get_cases(LabelList, 0, Middle_pos - 1),
- Keys_ending = get_cases(KeyList, Middle_pos, Length),
- Labels_ending = get_cases(LabelList, Middle_pos, Length),
-
- %% Create the code.
-
- %% Get the label and build it up properly
- Middle_label = lists:nth(Middle_pos, LabelList),
-
- A = [hipe_rtl:mk_move(Reg, hipe_rtl:mk_imm(Middle_key)),
- hipe_rtl:mk_branch(KeyReg, lt, Reg,
- hipe_rtl:label_name(Lab2),
- hipe_rtl:label_name(Lab1), 0.5),
- Lab1,
- hipe_rtl:mk_branch(KeyReg, gt, Reg,
- hipe_rtl:label_name(Lab3),
- Middle_label , 0.5),
- Lab2],
- %% build search tree for keys less than the middle element
- B = inline_search(Keys_beginning, Labels_beginning, KeyReg, Default),
- %% ...and for keys bigger than the middle element
- D = inline_search(Keys_ending, Labels_ending, KeyReg, Default),
-
- %% append the code and return it
- A ++ B ++ [Lab3] ++ D;
-
- Length =:= 2 ->
- %% get the first and second elements and theirs labels
- Key_first = hd(KeyList),
- First_label = hd(LabelList),
-
- %% Key_second = hipe_tagscheme:mk_fixnum(lists:nth(2, KeyList)),
- Key_second = lists:nth(2, KeyList),
- Second_label = lists:nth(2, LabelList),
-
- NewLab = hipe_rtl:mk_new_label(),
-
- %% compare them
- A = [hipe_rtl:mk_move(Reg,hipe_rtl:mk_imm(Key_first)),
- hipe_rtl:mk_branch(KeyReg, eq, Reg,
- First_label,
- hipe_rtl:label_name(NewLab) , 0.5),
- NewLab],
-
- B = [hipe_rtl:mk_move(Reg,hipe_rtl:mk_imm(Key_second)),
- hipe_rtl:mk_branch(KeyReg, eq, Reg,
- Second_label,
- hipe_rtl:label_name(Default) , 0.5)],
- A ++ B;
-
- Length =:= 1 ->
- Key = hd(KeyList),
- Label = hd(LabelList),
-
- [hipe_rtl:mk_move(Reg,hipe_rtl:mk_imm(Key)),
- hipe_rtl:mk_branch(KeyReg, eq, Reg,
- Label,
- hipe_rtl:label_name(Default) , 0.5)]
- end.
-
-
-inline_atom_search(Start, End, Block, LBlock, KeyReg, Default, Labels) ->
- Reg = hipe_rtl:mk_new_reg_gcsafe(),
-
- Length = (End - Start) + 1,
-
- if
- Length >= 3 ->
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- Lab3 = hipe_rtl:mk_new_label(),
- Lab4 = hipe_rtl:mk_new_label(),
-
- Mid = ((End-Start) div 2)+Start,
- End1 = Mid-1,
- Start1 = Mid+1,
- A = [
- hipe_rtl:mk_load_word_index(Reg,Block,Mid),
- hipe_rtl:mk_branch(KeyReg, lt, Reg,
- hipe_rtl:label_name(Lab2),
- hipe_rtl:label_name(Lab1), 0.5),
- Lab1,
- hipe_rtl:mk_branch(KeyReg, gt, Reg,
- hipe_rtl:label_name(Lab3),
- hipe_rtl:label_name(Lab4), 0.5),
- Lab4,
- hipe_rtl:mk_goto_index(LBlock, Mid, Labels),
- Lab2
- ],
- B = [inline_atom_search(Start,End1,Block,LBlock,KeyReg,Default,Labels)],
- C = [inline_atom_search(Start1,End,Block,LBlock,KeyReg,Default,Labels)],
- A ++ B ++ [Lab3] ++ C;
-
- Length =:= 2 ->
- L1 = hipe_rtl:mk_new_label(),
- L2 = hipe_rtl:mk_new_label(),
- L3 = hipe_rtl:mk_new_label(),
- [
- hipe_rtl:mk_load_word_index(Reg,Block,Start),
- hipe_rtl:mk_branch(KeyReg,eq,Reg,
- hipe_rtl:label_name(L1),
- hipe_rtl:label_name(L2), 0.5),
- L1,
- hipe_rtl:mk_goto_index(LBlock,Start,Labels),
-
- L2,
- hipe_rtl:mk_load_word_index(Reg,Block,End),
- hipe_rtl:mk_branch(KeyReg,eq,Reg,
- hipe_rtl:label_name(L3),
- hipe_rtl:label_name(Default), 0.5),
- L3,
- hipe_rtl:mk_goto_index(LBlock, End, Labels)
- ];
-
- Length =:= 1 ->
- NewLab = hipe_rtl:mk_new_label(),
- [
- hipe_rtl:mk_load_word_index(Reg,Block,Start),
- hipe_rtl:mk_branch(KeyReg, eq, Reg,
- hipe_rtl:label_name(NewLab),
- hipe_rtl:label_name(Default), 0.9),
- NewLab,
- hipe_rtl:mk_goto_index(LBlock, Start, Labels)
- ]
- end.
-
-
-%% Create a jumptable
-gen_jump_table(Arg,Fail,IcodeFail,VarMap,ConstTab,Cases,Min) ->
- %% Map is a rtl mapping of Dense
- {Max,DenseTbl} = dense_interval(Cases,Min,IcodeFail),
- {Map,VarMap2} = lbls_from_cases(DenseTbl,VarMap),
-
- %% Make some labels and registers that we need.
- BelowLab = hipe_rtl:mk_new_label(),
- UntaggedR = hipe_rtl:mk_new_reg_gcsafe(),
- StartR = hipe_rtl:mk_new_reg_gcsafe(),
-
- %% Generate the code to do the switch...
- {[
- %% Untag the index.
- hipe_tagscheme:untag_fixnum(UntaggedR, Arg)|
- %% Check that the index is within Min and Max.
- case Min of
- 0 -> %% First element is 0 this is simple.
- [hipe_rtl:mk_branch(UntaggedR, gtu, hipe_rtl:mk_imm(Max),
- hipe_rtl:label_name(Fail),
- hipe_rtl:label_name(BelowLab), 0.01),
- BelowLab,
- %% StartR contains the index into the jumptable
- hipe_rtl:mk_switch(UntaggedR, Map)];
- _ -> %% First element is not 0
- [hipe_rtl:mk_alu(StartR, UntaggedR, sub,
- hipe_rtl:mk_imm(Min)),
- hipe_rtl:mk_branch(StartR, gtu, hipe_rtl:mk_imm(Max-Min),
- hipe_rtl:label_name(Fail),
- hipe_rtl:label_name(BelowLab), 0.01),
- BelowLab,
- %% StartR contains the index into the jumptable
- hipe_rtl:mk_switch(StartR, Map)]
- end],
- VarMap2,
- ConstTab}.
-
-
-%% Generate the jumptable for Cases while filling in unused positions
-%% with the fail label
-
-dense_interval(Cases, Min, IcodeFail) ->
- dense_interval(Cases, Min, IcodeFail, 0, 0).
-dense_interval([Pair = {Const,_}|Rest], Pos, Fail, Range, NoEntries) ->
- Val = hipe_icode:const_value(Const),
- if
- Pos < Val ->
- {Max, Res} =
- dense_interval([Pair|Rest], Pos+1, Fail, Range+1, NoEntries),
- {Max,[{hipe_icode:mk_const(Pos), Fail}|Res]};
- true ->
- {Max, Res} = dense_interval(Rest, Pos+1, Fail, Range+1, NoEntries+1),
- {Max, [Pair | Res]}
- end;
-dense_interval([], Max, _, _, _) ->
- {Max-1, []}.
-
-
-%%-------------------------------------------------------------------------
-%% switch_val without jumptable
-%%
-
-gen_slow_switch_val(I, VarMap, ConstTab, Options) ->
- Is = rewrite_switch_val(I),
- ?IF_DEBUG_LEVEL(3,?msg("Switch: ~w\n", [Is]), no_debug),
- hipe_icode2rtl:translate_instrs(Is, VarMap, ConstTab, Options).
-
-rewrite_switch_val(I) ->
- Var = hipe_icode:switch_val_term(I),
- Fail = hipe_icode:switch_val_fail_label(I),
- Cases = hipe_icode:switch_val_cases(I),
- rewrite_switch_val_cases(Cases, Fail, Var).
-
-rewrite_switch_val_cases([{C,L}|Cases], Fail, Arg) ->
- Tmp = hipe_icode:mk_new_var(),
- NextLab = hipe_icode:mk_new_label(),
- [hipe_icode:mk_move(Tmp, C),
- hipe_icode:mk_if(op_exact_eqeq_2, [Arg, Tmp], L,
- hipe_icode:label_name(NextLab)),
- NextLab |
- rewrite_switch_val_cases(Cases, Fail, Arg)];
-rewrite_switch_val_cases([], Fail, _Arg) ->
- [hipe_icode:mk_goto(Fail)].
-
-
-%%-------------------------------------------------------------------------
-%% switch_val with binary search jumptable
-%%
-
-gen_search_switch_val(Arg, Cases, Default, VarMap, ConstTab, _Options) ->
- ValTableR = hipe_rtl:mk_new_reg_gcsafe(),
-
- {Values,_Labels} = split_cases(Cases),
- {NewConstTab,Id} = hipe_consttab:insert_sorted_block(ConstTab, Values),
- {LabMap,VarMap1} = lbls_from_cases(Cases,VarMap),
-
- Code =
- [hipe_rtl:mk_load_address(ValTableR, Id, constant)|
- tab(Values,LabMap,Arg,ValTableR,Default)],
- {Code, VarMap1, NewConstTab}.
-
-
-%%-------------------------------------------------------------------------
-%%
-%% tab/5 creates RTL code for a binary search.
-%% It requires two sorted tables one with the keys to search
-%% through and one with the corresponding labels to jump to.
-%%
-%% The implementation is derived from John Bentlys
-%% Programming Pearls.
-%%
-%% Input:
-%% KeyList - A list of keys to search through.
-%% (Just used to calculate the number of elements.)
-%% LableList - A list of labels to jump to.
-%% KeyReg - A register containing the key to search for.
-%% TablePntrReg - A register containing a pointer to the
-%% tables with keys
-%% Default - A lable to jump to if the key is not found.
-%%
-%% Example:
-%% KeyTbl: < a, b, d, f, h, i, z >
-%% Lbls: < 5, 3, 2, 4, 1, 7, 6 >
-%% Default: 8
-%% KeyReg: v37
-%% TablePntrReg: r41
-%%
-%% should give code like:
-%% r41 <- KeyTbl
-%% r42 <- 0
-%% r43 <- [r41+16]
-%% if (r43 gt v37) then L17 (0.50) else L16
-%% L16:
-%% r42 <- 16
-%% goto L17
-%% L17:
-%% r46 <- r42 add 16
-%% r45 <- [r41+r46]
-%% if (r45 gt v37) then L21 (0.50) else L20
-%% L20:
-%% r42 <- r46
-%% goto L21
-%% L21:
-%% r48 <- r42 add 8
-%% r47 <- [r41+r48]
-%% if (r47 gt v37) then L23 (0.50) else L22
-%% L22:
-%% r42 <- r48
-%% goto L23
-%% L23:
-%% r50 <- r42 add 4
-%% r49 <- [r41+r50]
-%% if (r49 gt v37) then L25 (0.50) else L24
-%% L24:
-%% r42 <- r42 add 4
-%% goto L25
-%% L25:
-%% if (r42 gt 28) then L6 (0.50) else L18
-%% L18:
-%% r44 <- [r41+r42]
-%% if (r44 eq v37) then L19 (0.90) else L8
-%% L19:
-%% r42 <- r42 sra 2
-%% switch (r42) <L5, L3, L2, L4, L1,
-%% L7, L6>
-
-%%
-%% The search is done like a rolled out binary search,
-%% but instead of starting in the middle we start at
-%% the power of two closest above the middle.
-%%
-%% We let IndexReg point to the lower bound of our
-%% search, and then we speculatively look at a
-%% position at IndexReg + I where I is a power of 2.
-%%
-%% Example: Looking for 'h' in
-%% KeyTbl: < a, b, d, f, h, i, z >
-%%
-%% We start with IndexReg=0 and I=4
-%% < a, b, d, f, h, i, z >
-%% ^ ^
-%% IndexReg + I
-%%
-%% 'f' < 'h' so we add I to IndexReg and divide I with 2
-%% IndexReg=4 and I=2
-%% < a, b, d, f, h, i, z >
-%% ^ ^
-%% IndexReg + I
-%%
-%% 'i' > 'h' so we keep IndexReg and divide I with 2
-%% IndexReg=4 and I=1
-%% < a, b, d, f, h, i, z >
-%% ^ ^
-%% IndexReg+ I
-%% Now we have found 'h' so we add I to IndexReg -> 5
-%% And we can load switch to the label at position 5 in
-%% the label table.
-%%
-%% Now since the wordsize is 4 all numbers above are
-%% Multiples of 4.
-
-tab(KeyList, LabelList, KeyReg, TablePntrReg, Default) ->
- %% Calculate the size of the table:
- %% the number of keys * wordsize
- LastOffset = (length(KeyList)-1)*?WORDSIZE,
-
- %% Calculate the power of two closest to the size of the table.
- Pow2 = 1 bsl trunc(math:log(LastOffset) / math:log(2)),
-
- %% Create some registers and lables that we need
- IndexReg = hipe_rtl:mk_new_reg_gcsafe(),
- Temp = hipe_rtl:mk_new_reg_gcsafe(),
- Temp2 = hipe_rtl:mk_new_reg_gcsafe(),
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- Lab3 = hipe_rtl:mk_new_label(),
- Lab4 = hipe_rtl:mk_new_label(),
-
- %% Calculate the position to start looking at
- Init = (LastOffset)-Pow2,
-
- %% Create the code
- [
- hipe_rtl:mk_move(IndexReg,hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_load(Temp,TablePntrReg,hipe_rtl:mk_imm(Init)),
- hipe_rtl:mk_branch(Temp, geu, KeyReg,
- hipe_rtl:label_name(Lab2),
- hipe_rtl:label_name(Lab1), 0.5),
- Lab1,
- hipe_rtl:mk_alu(IndexReg, IndexReg, add, hipe_rtl:mk_imm(Init+?WORDSIZE)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(Lab2)),
- Lab2] ++
-
- step(Pow2 div 2, TablePntrReg, IndexReg, KeyReg) ++
-
- [hipe_rtl:mk_branch(IndexReg, gt, hipe_rtl:mk_imm(LastOffset),
- hipe_rtl:label_name(Default),
- hipe_rtl:label_name(Lab3), 0.5),
- Lab3,
- hipe_rtl:mk_load(Temp2,TablePntrReg,IndexReg),
- hipe_rtl:mk_branch(Temp2, eq, KeyReg,
- hipe_rtl:label_name(Lab4),
- hipe_rtl:label_name(Default), 0.9),
- Lab4,
- hipe_rtl:mk_alu(IndexReg, IndexReg, sra,
- hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size())),
- hipe_rtl:mk_sorted_switch(IndexReg, LabelList, KeyList)
- ].
-
-step(I,TablePntrReg,IndexReg,KeyReg) ->
- Temp = hipe_rtl:mk_new_reg_gcsafe(),
- TempIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_alu(TempIndex, IndexReg, add, hipe_rtl:mk_imm(I)),
- hipe_rtl:mk_load(Temp,TablePntrReg,TempIndex),
- hipe_rtl:mk_branch(Temp, gtu, KeyReg,
- hipe_rtl:label_name(Lab2),
- hipe_rtl:label_name(Lab1) , 0.5),
- Lab1] ++
- case ?WORDSIZE of
- I -> %% Recursive base case
- [hipe_rtl:mk_alu(IndexReg, IndexReg, add, hipe_rtl:mk_imm(I)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(Lab2)),
- Lab2
- ];
- _ -> %% Recursion case
- [hipe_rtl:mk_move(IndexReg, TempIndex),
- hipe_rtl:mk_goto(hipe_rtl:label_name(Lab2)),
- Lab2
- | step(I div 2, TablePntrReg, IndexReg, KeyReg)
- ]
- end.
-
-%%-------------------------------------------------------------------------
-
-lbls_from_cases([{_,L}|Rest], VarMap) ->
- {Map,VarMap1} = lbls_from_cases(Rest, VarMap),
- {RtlL, VarMap2} = hipe_rtl_varmap:icode_label2rtl_label(L,VarMap1),
- %% {[{label,hipe_rtl:label_name(RtlL)}|Map],VarMap2};
- {[hipe_rtl:label_name(RtlL)|Map],VarMap2};
-lbls_from_cases([], VarMap) ->
- {[], VarMap}.
-
-%%-------------------------------------------------------------------------
-
-split_cases(L) ->
- split_cases(L, [], []).
-
-split_cases([], Vs, Ls) -> {lists:reverse(Vs),lists:reverse(Ls)};
-split_cases([{V,L}|Rest], Vs, Ls) ->
- split_cases(Rest, [hipe_icode:const_value(V)|Vs], [L|Ls]).
-
-%%-------------------------------------------------------------------------
-%%
-%% {switch_tuple_arity,X,Fail,N,[{A1,L1},...,{AN,LN}]}
-%%
-%% if not boxed(X) goto Fail
-%% Hdr := *boxed_val(X)
-%% switch_int(Hdr,Fail,[{H(A1),L1},...,{H(AN),LN}])
-%% where H(Ai) = make_arityval(Ai)
-%%
-%%-------------------------------------------------------------------------
-
-gen_switch_tuple(I, Map, ConstTab, _Options) ->
- Var = hipe_icode:switch_tuple_arity_term(I),
- {X, Map1} = hipe_rtl_varmap:icode_var2rtl_var(Var, Map),
- Fail0 = hipe_icode:switch_tuple_arity_fail_label(I),
- {Fail1, Map2} = hipe_rtl_varmap:icode_label2rtl_label(Fail0, Map1),
- FailLab = hipe_rtl:label_name(Fail1),
- {Cases, Map3} =
- lists:foldr(fun({A,L}, {Rest,M}) ->
- {L1,M1} = hipe_rtl_varmap:icode_label2rtl_label(L, M),
- L2 = hipe_rtl:label_name(L1),
- A1 = hipe_icode:const_value(A),
- H1 = hipe_tagscheme:mk_arityval(A1),
- {[{H1,L2}|Rest], M1} end,
- {[], Map2},
- hipe_icode:switch_tuple_arity_cases(I)),
- Hdr = hipe_rtl:mk_new_reg_gcsafe(),
- IsBoxedLab = hipe_rtl:mk_new_label(),
- {[hipe_tagscheme:test_is_boxed(X, hipe_rtl:label_name(IsBoxedLab),
- FailLab, 0.9),
- IsBoxedLab,
- hipe_tagscheme:get_header(Hdr, X) |
- gen_switch_int(Hdr, FailLab, Cases)],
- Map3, ConstTab}.
-
-%%
-%% RTL-level switch-on-int
-%%
-
-gen_switch_int(X, FailLab, [{C,L}|Rest]) ->
- NextLab = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_branch(X, eq, hipe_rtl:mk_imm(C), L,
- hipe_rtl:label_name(NextLab), 0.5),
- NextLab |
- gen_switch_int(X, FailLab, Rest)];
-gen_switch_int(_, FailLab, []) ->
- [hipe_rtl:mk_goto(FailLab)].
-
diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl
deleted file mode 100644
index ce5433379e..0000000000
--- a/lib/hipe/rtl/hipe_rtl_primops.erl
+++ /dev/null
@@ -1,1280 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Filename : hipe_rtl_primops.erl
-%% Purpose :
-%% Notes :
-%% History : * 2001-03-15 Erik Johansson (happi@it.uu.se):
-%% Created.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_primops).
-
--export([gen_primop/3, gen_enter_primop/3, gen_call_builtin/6,
- gen_enter_builtin/2]).
-
-%% --------------------------------------------------------------------
-
--include("../main/hipe.hrl").
--include("../icode/hipe_icode_primops.hrl").
--include("hipe_rtl.hrl").
--include("hipe_literals.hrl").
-
-%% --------------------------------------------------------------------
-%% Handling of known MFA builtins that are inline expanded
-
-gen_call_builtin(Fun, Dst, Args, IsGuard, Cont, Fail) ->
- case Fun of
- {erlang, apply, 3} ->
- gen_apply(Dst, Args, Cont, Fail);
-
- {erlang, element, 2} ->
- gen_element(Dst, Args, IsGuard, Cont, Fail);
-
- {erlang, self, 0} ->
- gen_self(Dst, Cont);
-
- {erlang, is_tuple, 1} ->
- gen_is_tuple(Dst, Args, Cont);
-
- {hipe_bifs, in_native, 0} ->
- Dst1 =
- case Dst of
- [] -> %% The result is not used.
- hipe_rtl:mk_new_var();
- [Dst0] -> Dst0
- end,
- [hipe_rtl:mk_load_atom(Dst1, true), hipe_rtl:mk_goto(Cont)];
-
- _ -> [] % not a builtin
- end.
-
-%% (Recall that enters cannot occur within a catch-region in the same
-%% function, so we do not need to consider fail-continuations here.)
-%% TODO: should we inline expand more functions here? Cf. above.
-gen_enter_builtin(Fun, Args) ->
- case Fun of
- {erlang, apply, 3} ->
- gen_enter_apply(Args);
-
-%% TODO
-%% {erlang, element, 2} ->
-%% gen_enter_element(Args, IsGuard);
-
-%% TODO
-%% {erlang, self, 0} ->
-%% gen_enter_self();
-
- {hipe_bifs, in_native, 0} ->
- Dst = hipe_rtl:mk_new_var(),
- [hipe_rtl:mk_load_atom(Dst, true), hipe_rtl:mk_return([Dst])];
-
- _ -> [] % not a builtin
- end.
-
-%% --------------------------------------------------------------------
-%% Generate code to jump to in case the inlined function fails.
-
-gen_fail_code(Fail, Type) ->
- gen_fail_code(Fail, Type, false).
-
-gen_fail_code(Fail, Type, IsGuard) ->
- case IsGuard of
- true when Fail =/= [] ->
- {Fail, []}; % go directly to target
- false ->
- NewLabel = hipe_rtl:mk_new_label(),
- NewLabelName = hipe_rtl:label_name(NewLabel),
- {NewLabelName, [NewLabel | fail_code(Fail, Type)]}
- end.
-
-fail_code(Fail, Type) when is_atom(Type) ->
- Var = hipe_rtl:mk_new_var(),
- [hipe_rtl:mk_load_atom(Var, Type),
- hipe_rtl_exceptions:gen_fail(error, [Var], Fail)];
-fail_code(Fail, {Type, Value}) when is_atom(Type) ->
- Var = hipe_rtl:mk_new_var(),
- [hipe_rtl:mk_load_atom(Var, Type),
- hipe_rtl:mk_gctest(3), % room for a 2-tuple
- gen_mk_tuple(Var,[Var,Value]),
- hipe_rtl_exceptions:gen_fail(error, [Var], Fail)].
-
-fp_fail_code(TmpFailLbl, FailLbl) ->
- [TmpFailLbl |
- hipe_rtl_arch:handle_fp_exception() ++
- [fail_code(FailLbl, badarith)]].
-
-%% --------------------------------------------------------------------
-%% CALL PRIMOP
-%%
-%% @doc
-%% Generates RTL code for primops. This is mostly a dispatch function.
-%% Tail calls to primops (enter_fun, apply, etc.) are not handled here!
-%% @end
-
-gen_primop({Op,Dst,Args,Cont,Fail}, IsGuard, ConstTab) ->
- GotoCont = hipe_rtl:mk_goto(Cont),
- case Op of
- %%
- %% Binary Syntax
- %%
- {hipe_bs_primop, BsOP} ->
- {FailLabelName, FailCode1} = gen_fail_code(Fail, badarg, IsGuard),
- {SysLimLblName, FailCode2} = gen_fail_code(Fail, system_limit, IsGuard),
- {Code1,NewConstTab} =
- hipe_rtl_binary:gen_rtl(BsOP, Dst, Args, Cont, FailLabelName,
- SysLimLblName, ConstTab),
- {[Code1,FailCode1,FailCode2], NewConstTab};
- %%
- %% Other primops
- %%
- _ ->
- Code =
- case Op of
- %% Arithmetic
- '+' ->
- %gen_extra_unsafe_add_2(Dst, Args, Cont);
- gen_add_sub_2(Dst, Args, Cont, Fail, Op, add);
- '-' ->
- gen_add_sub_2(Dst, Args, Cont, Fail, Op, sub);
- '*' ->
- gen_mul_2(Dst, Args, Cont, Fail);
- '/' ->
- %% BIF call: am_Div -> nbif_div_2 -> erts_mixed_div
- [hipe_rtl:mk_call(Dst, '/', Args, Cont, Fail, not_remote)];
- 'gen_add' ->
- gen_general_add_sub(Dst, Args, Cont, Fail, '+');
- 'gen_sub' ->
- gen_general_add_sub(Dst, Args, Cont, Fail, '-');
- 'unsafe_add' ->
- %gen_extra_unsafe_add_2(Dst, Args, Cont);
- gen_unsafe_add_sub_2(Dst, Args, Cont, Fail, '+', add);
- 'extra_unsafe_add' ->
- gen_extra_unsafe_add_2(Dst, Args, Cont);
- 'unsafe_sub' ->
- gen_unsafe_add_sub_2(Dst, Args, Cont, Fail, '-', sub);
- 'extra_unsafe_sub' ->
- gen_extra_unsafe_sub_2(Dst, Args, Cont);
- %'unsafe_mul' ->
- % gen_unsafe_mul_2(Dst, Args, Cont, Fail, '*');
- 'div' ->
- %% BIF call: am_div -> nbif_intdiv_2 -> intdiv_2
- [hipe_rtl:mk_call(Dst, 'div', Args, Cont, Fail, not_remote)];
- 'rem' ->
- %% BIF call: am_rem -> nbif_rem_2 -> rem_2
- [hipe_rtl:mk_call(Dst, 'rem', Args, Cont, Fail, not_remote)];
- 'band' ->
- gen_bitop_2(Dst, Args, Cont, Fail, Op, 'and');
- 'bor' ->
- gen_bitop_2(Dst, Args, Cont, Fail, Op, 'or');
- 'bxor' ->
- gen_bitop_2(Dst, Args, Cont, Fail, Op, 'xor');
- 'bnot' ->
- gen_bnot_2(Dst, Args, Cont, Fail, Op);
- 'bsr'->
- %% BIF call: am_bsr -> nbif_bsr_2 -> bsr_2
- gen_bsr_2(Dst, Args, Cont, Fail, Op);
- %[hipe_rtl:mk_call(Dst, 'bsr', Args, Cont, Fail, not_remote)];
- 'bsl' ->
- %% BIF call: am_bsl -> nbif_bsl_2 -> bsl_2
- [hipe_rtl:mk_call(Dst, 'bsl', Args, Cont, Fail, not_remote)];
- unsafe_band ->
- gen_unsafe_bitop_2(Dst, Args, Cont, 'and');
- unsafe_bor ->
- gen_unsafe_bitop_2(Dst, Args, Cont, 'or');
- unsafe_bxor ->
- gen_unsafe_bitop_2(Dst, Args, Cont, 'xor');
- unsafe_bnot ->
- gen_unsafe_bnot_2(Dst, Args, Cont);
- unsafe_bsr ->
- gen_unsafe_bsr_2(Dst, Args, Cont);
- unsafe_bsl ->
- gen_unsafe_bsl_2(Dst, Args, Cont);
- %%---------------------------------------------
- %% List handling
- %%---------------------------------------------
- cons ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- [gen_cons(Dst1, Args), GotoCont]
- end;
- unsafe_hd ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- [gen_unsafe_hd(Dst1, Args), GotoCont]
- end;
- unsafe_tl ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- [gen_unsafe_tl(Dst1, Args),GotoCont]
- end;
- %%---------------------------------------------
- %% Tuple handling
- %%---------------------------------------------
- mktuple ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- [gen_mk_tuple(Dst1, Args),GotoCont]
- end;
- #unsafe_element{index=N} ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- [Tuple] = Args,
- [gen_unsafe_element(Dst1, hipe_rtl:mk_imm(N), Tuple),GotoCont]
- end;
- #unsafe_update_element{index=N} ->
- [Dst1] = Dst,
- [Tuple, Value] = Args,
- [gen_unsafe_update_element(Tuple, hipe_rtl:mk_imm(N), Value),
- hipe_rtl:mk_move(Dst1, Tuple),
- GotoCont];
- {element, [TupleInfo, IndexInfo]} ->
- Dst1 =
- case Dst of
- [] -> %% The result is not used.
- hipe_rtl:mk_new_var();
- [Dst0] -> Dst0
- end,
- [Index, Tuple] = Args,
- [gen_element_1(Dst1, Index, Tuple, IsGuard, Cont, Fail,
- TupleInfo, IndexInfo)];
-
- %%---------------------------------------------
- %% Apply-fixarity
- %%---------------------------------------------
- #apply_N{arity = Arity} ->
- gen_apply_N(Dst, Arity, Args, Cont, Fail);
-
- %%---------------------------------------------
- %% GC test
- %%---------------------------------------------
- #gc_test{need = Need} ->
- [hipe_rtl:mk_gctest(Need), GotoCont];
-
- %%---------------------------------------------
- %% Process handling
- %%---------------------------------------------
- redtest ->
- [gen_redtest(1), GotoCont];
- %%---------------------------------------------
- %% Receives
- %%---------------------------------------------
- check_get_msg ->
- gen_check_get_msg(Dst, GotoCont, Fail);
- next_msg ->
- gen_next_msg(Dst, GotoCont);
- select_msg ->
- gen_select_msg(Dst, Cont);
- clear_timeout ->
- gen_clear_timeout(Dst, GotoCont);
- recv_mark ->
- gen_recv_mark(Dst, GotoCont);
- recv_set ->
- gen_recv_set(Dst, Cont);
- set_timeout ->
- %% BIF call: am_set_timeout -> nbif_set_timeout -> hipe_set_timeout
- [hipe_rtl:mk_call(Dst, set_timeout, Args, Cont, Fail, not_remote)];
- suspend_msg ->
- gen_suspend_msg(Dst, Cont);
- %%---------------------------------------------
- %% Closures
- %%---------------------------------------------
- call_fun ->
- gen_call_fun(Dst, Args, Cont, Fail);
- #mkfun{mfa=MFA, magic_num=MagicNum, index=Index} ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- _ ->
- [gen_mkfun(Dst, MFA, MagicNum, Index, Args), GotoCont]
- end;
- #closure_element{n=N} ->
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- [Closure] = Args,
- [gen_closure_element(Dst1, hipe_rtl:mk_imm(N), Closure),
- GotoCont]
- end;
- %%---------------------------------------------
- %% Floating point instructions.
- %%---------------------------------------------
- fp_add ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- hipe_rtl:mk_fp(hipe_rtl:mk_new_fpreg(), Arg1, 'fadd', Arg2);
- [Dst1] ->
- hipe_rtl:mk_fp(Dst1, Arg1, 'fadd', Arg2)
- end;
- fp_sub ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- hipe_rtl:mk_fp(hipe_rtl:mk_new_fpreg(), Arg1, 'fsub', Arg2);
- [Dst1] ->
- hipe_rtl:mk_fp(Dst1, Arg1, 'fsub', Arg2)
- end;
- fp_mul ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- hipe_rtl:mk_fp(hipe_rtl:mk_new_fpreg(), Arg1, 'fmul', Arg2);
- [Dst1] ->
- hipe_rtl:mk_fp(Dst1, Arg1, 'fmul', Arg2)
- end;
- fp_div ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- hipe_rtl:mk_fp(hipe_rtl:mk_new_fpreg(), Arg1, 'fdiv', Arg2);
- [Dst1] ->
- hipe_rtl:mk_fp(Dst1, Arg1, 'fdiv', Arg2)
- end;
- fnegate ->
- [Arg] = Args,
- case Dst of
- [] ->
- hipe_rtl:mk_fp_unop(hipe_rtl:mk_new_fpreg(), Arg, 'fchs');
- [Dst1] ->
- hipe_rtl:mk_fp_unop(Dst1, Arg, 'fchs')
- end;
- fclearerror ->
- gen_fclearerror();
- fcheckerror ->
- gen_fcheckerror(Cont, Fail);
- conv_to_float ->
- case Dst of
- [] ->
- gen_conv_to_float(hipe_rtl:mk_new_fpreg(), Args, Cont, Fail);
- [Dst1] ->
- gen_conv_to_float(Dst1, Args, Cont, Fail)
- end;
- unsafe_untag_float ->
- [Arg] = Args,
- case Dst of
- [] ->
- hipe_tagscheme:unsafe_untag_float(hipe_rtl:mk_new_fpreg(),
- Arg);
- [Dst1]->
- hipe_tagscheme:unsafe_untag_float(Dst1, Arg)
- end;
- unsafe_tag_float ->
- [Arg] = Args,
- case Dst of
- [] ->
- hipe_tagscheme:unsafe_tag_float(hipe_rtl:mk_new_var(), Arg);
- [Dst1]->
- hipe_tagscheme:unsafe_tag_float(Dst1, Arg)
- end;
- debug_native_called ->
- [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
- build_stacktrace ->
- [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
- raw_raise ->
- [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)];
-
- %% Only names listed above are accepted! MFA:s are not primops!
- _ ->
- erlang:error({bad_primop, Op})
- end,
- {Code, ConstTab}
- end.
-
-gen_enter_primop({Op, Args}, IsGuard, ConstTab) ->
- case Op of
- enter_fun ->
- %% Tail-call to a closure must preserve tail-callness!
- %% (Passing Continuation = [] to gen_call_fun/5 does this.)
- Code = gen_call_fun([], Args, [], []),
- {Code, ConstTab};
-
- #apply_N{arity=Arity} ->
- %% Tail-call to a closure must preserve tail-callness!
- %% (Passing Continuation = [] to gen_apply_N/5 does this.)
- Code = gen_apply_N([], Arity, Args, [], []),
- {Code, ConstTab};
-
- _ ->
- %% All other primop tail calls are converted to call + return.
- Dst = [hipe_rtl:mk_new_var()],
- OkLab = hipe_rtl:mk_new_label(),
- {Code,ConstTab1} =
- gen_primop({Op,Dst,Args,hipe_rtl:label_name(OkLab),[]},
- IsGuard, ConstTab),
- {Code ++ [OkLab, hipe_rtl:mk_return(Dst)], ConstTab1}
- end.
-
-
-%% --------------------------------------------------------------------
-%% ARITHMETIC
-%% --------------------------------------------------------------------
-
-%%
-%% Inline addition & subtraction
-%%
-
-gen_general_add_sub(Dst, Args, Cont, Fail, Op) ->
- case Dst of
- [] ->
- [hipe_rtl:mk_call([hipe_rtl:mk_new_var()],
- Op, Args, Cont, Fail, not_remote)];
- [Res] ->
- [hipe_rtl:mk_call([Res], Op, Args, Cont, Fail, not_remote)]
- end.
-
-gen_add_sub_2(Dst, Args, Cont, Fail, Op, AluOp) ->
- [Arg1, Arg2] = Args,
- GenCaseLabel = hipe_rtl:mk_new_label(),
- case Dst of
- [] ->
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenCaseLabel))|
- gen_op_general_case(hipe_rtl:mk_new_var(),
- Op, Args, Cont, Fail, GenCaseLabel)];
- [Res] ->
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenCaseLabel)),
- hipe_tagscheme:fixnum_addsub(AluOp, Arg1, Arg2, Res, GenCaseLabel)|
- gen_op_general_case(Res,Op, Args, Cont, Fail, GenCaseLabel)]
- end.
-
-gen_unsafe_add_sub_2(Dst, Args, Cont, Fail, Op, AluOp) ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- [hipe_rtl:mk_goto(Cont)];
- [Res] ->
- case Fail of
- []->
- GenCaseLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:fixnum_addsub(AluOp, Arg1, Arg2, Res, GenCaseLabel)|
- gen_op_general_case(Res,Op, Args, Cont, Fail, GenCaseLabel)];
- _ ->
- [hipe_tagscheme:fixnum_addsub(AluOp, Arg1, Arg2, Res,
- hipe_rtl:mk_label(Fail))]
- end
- end.
-
-gen_extra_unsafe_add_2(Dst, Args, Cont) ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- [hipe_rtl:mk_goto(Cont)];
- [Res] ->
- hipe_tagscheme:unsafe_fixnum_add(Arg1, Arg2, Res)
- end.
-
-gen_extra_unsafe_sub_2(Dst, Args, Cont) ->
- [Arg1, Arg2] = Args,
- case Dst of
- [] ->
- [hipe_rtl:mk_goto(Cont)];
- [Res] ->
- hipe_tagscheme:unsafe_fixnum_sub(Arg1, Arg2, Res)
- end.
-
-gen_op_general_case(Res, Op, Args, Cont, Fail, GenCaseLabel) ->
- [hipe_rtl:mk_goto(Cont),
- GenCaseLabel,
- hipe_rtl:mk_call([Res], Op, Args, Cont, Fail, not_remote)].
-
-%%
-%% Inline multiplication
-%%
-
-gen_mul_2(Dst, Args, Cont, Fail) ->
- [Arg1,Arg2] = Args,
- GenCaseLabel = hipe_rtl:mk_new_label(),
- {Res1,I2} =
- case Dst of
- [] ->
- {hipe_rtl:mk_new_var(), []};
- [Res0] ->
- {Res0, hipe_tagscheme:fixnum_mul(Arg1, Arg2, Res0, GenCaseLabel)}
- end,
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2, hipe_rtl:label_name(GenCaseLabel)),
- I2,
- %% BIF call: am_Times -> nbif_mul_2 -> erts_mixed_times
- gen_op_general_case(Res1, '*', Args, Cont, Fail, GenCaseLabel)].
-
-%% gen_unsafe_mul_2([Res], Args, Cont, Fail, Op) ->
-%% [Arg1, Arg2] = Args,
-%% GenCaseLabel = hipe_rtl:mk_new_label(),
-%% [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
-%% hipe_rtl:label_name(GenCaseLabel)),
-%% hipe_tagscheme:fixnum_mul(Arg1, Arg2, Res, GenCaseLabel)|
-%% gen_op_general_case(Res, Op, Args, Cont, Fail, GenCaseLabel)].
-
-%%
-%% Inline bitoperations.
-%% Only works for band, bor and bxor.
-%% The shift operations are too expensive to inline.
-%%
-
-gen_bitop_2(Res, Args, Cont, Fail, Op, BitOp) ->
- [Arg1, Arg2] = Args,
- GenCaseLabel = hipe_rtl:mk_new_label(),
- case Res of
- [] -> %% The result is not used.
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenCaseLabel))|
- gen_op_general_case(hipe_rtl:mk_new_var(),
- Op, Args, Cont, Fail, GenCaseLabel)];
- [Res0] ->
- [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
- hipe_rtl:label_name(GenCaseLabel)),
- hipe_tagscheme:fixnum_andorxor(BitOp, Arg1, Arg2, Res0)|
- gen_op_general_case(Res0, Op, Args, Cont, Fail, GenCaseLabel)]
- end.
-
-gen_unsafe_bitop_2(Res, Args, Cont, BitOp) ->
- case Res of
- [] -> %% The result is not used.
- [hipe_rtl:mk_goto(Cont)];
- [Res0] ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_andorxor(BitOp, Arg1, Arg2, Res0),
- hipe_rtl:mk_goto(Cont)]
- end.
-
-gen_bsr_2(Res, Args, Cont, Fail, Op) ->
- [Arg1, Arg2] = Args,
- GenCaseLabel = hipe_rtl:mk_new_label(),
- case hipe_rtl:is_imm(Arg2) of
- true ->
- Val = hipe_tagscheme:fixnum_val(hipe_rtl:imm_value(Arg2)),
- Limit = ?bytes_to_bits(hipe_rtl_arch:word_size()),
- if
- Val < Limit, Val >= 0 ->
- case Res of
- [] ->
- FixLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_fixnum(Arg1,
- hipe_rtl:label_name(FixLabel),
- hipe_rtl:label_name(GenCaseLabel),
- 0.99),
- FixLabel,
- gen_op_general_case(hipe_rtl:mk_new_var(), Op, Args, Cont, Fail,
- GenCaseLabel)];
- [Res0] ->
- FixLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_fixnum(Arg1,
- hipe_rtl:label_name(FixLabel),
- hipe_rtl:label_name(GenCaseLabel),
- 0.99),
- FixLabel,
- hipe_tagscheme:fixnum_bsr(Arg1, Arg2, Res0),
- gen_op_general_case(Res0, Op, Args, Cont, Fail, GenCaseLabel)]
- end;
- true ->
- [hipe_rtl:mk_call(Res, 'bsr', Args, Cont, Fail, not_remote)]
- end;
- false ->
- [hipe_rtl:mk_call(Res, 'bsr', Args, Cont, Fail, not_remote)]
- end.
-
-gen_unsafe_bsr_2(Res, Args, Cont) ->
- case Res of
- [] -> %% The result is not used.
- [hipe_rtl:mk_goto(Cont)];
- [Res0] ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_bsr(Arg1, Arg2, Res0),
- hipe_rtl:mk_goto(Cont)]
- end.
-
-gen_unsafe_bsl_2(Res, Args, Cont) ->
- case Res of
- [] -> %% The result is not used.
- [hipe_rtl:mk_goto(Cont)];
- [Res0] ->
- [Arg1, Arg2] = Args,
- [hipe_tagscheme:fixnum_bsl(Arg1, Arg2, Res0),
- hipe_rtl:mk_goto(Cont)]
- end.
-
-%%
-%% Inline not.
-%%
-
-gen_bnot_2(Res, Args, Cont, Fail, Op) ->
- [Arg] = Args,
- GenCaseLabel = hipe_rtl:mk_new_label(),
- case Res of
- [] -> %% The result is not used.
- FixLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_fixnum(Arg, hipe_rtl:label_name(FixLabel),
- hipe_rtl:label_name(GenCaseLabel), 0.99),
- FixLabel,
- gen_op_general_case(hipe_rtl:mk_new_var(), Op, Args, Cont, Fail,
- GenCaseLabel)];
-
- [Res0] ->
- FixLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_fixnum(Arg, hipe_rtl:label_name(FixLabel),
- hipe_rtl:label_name(GenCaseLabel), 0.99),
- FixLabel,
- hipe_tagscheme:fixnum_not(Arg, Res0),
- gen_op_general_case(Res0, Op, Args, Cont, Fail, GenCaseLabel)]
- end.
-
-gen_unsafe_bnot_2(Res, Args, Cont) ->
- case Res of
- [] -> %% The result is not used.
- [hipe_rtl:mk_goto(Cont)];
- [Res0] ->
- [Arg1] = Args,
- [hipe_tagscheme:fixnum_not(Arg1, Res0),
- hipe_rtl:mk_goto(Cont)]
- end.
-
-
-%% --------------------------------------------------------------------
-%%
-
-%%
-%% Inline cons
-%%
-
-gen_cons(Dst, [Arg1, Arg2]) ->
- Tmp = hipe_rtl:mk_new_reg(),
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- WordSize = hipe_rtl_arch:word_size(),
- HeapNeed = 2*WordSize,
- [GetHPInsn,
- hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), Arg1),
- hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(WordSize), Arg2),
- hipe_rtl:mk_move(Tmp, HP),
- hipe_tagscheme:tag_cons(Dst, Tmp),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(HeapNeed)),
- PutHPInsn].
-
-%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% --------------------------------------------------------------------
-%% Handling of closures...
-%% --------------------------------------------------------------------
-
-%% --------------------------------------------------------------------
-%% gen_mkfun
-%%
-%% The gc_test should have expanded to
-%% unsigned needed = ERL_FUN_SIZE + num_free;
-%% ErlFunThing* funp = (ErlFunThing *) HAlloc(p, needed);
-%%
-%% The code generated should do the equivalent of:
-%% Copy arguments to the fun thing
-%% Eterm* hp = funp->env;
-%% for (i = 0; i < num_free; i++) {
-%% *hp++ = reg[i];
-%% }
-%%
-%% Fill in fileds
-%% funp->thing_word = HEADER_FUN;
-%% funp->fe = fe;
-%% funp->num_free = num_free;
-%% funp->creator = p->id;
-%% funp->native_code = fe->native_code;
-%% Increase refcount
-%% fe->refc++;
-%%
-%% Link to the process off_heap list
-%% funp->next = p->off_heap.first;
-%% p->off_heap.first = funp;
-%%
-%% Tag the thing
-%% return make_fun(funp);
-%%
-gen_mkfun([Dst], {_Mod, _FunId, _Arity} = MFidA, MagicNr, Index, FreeVars) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- NumFree = length(FreeVars),
-
- %% Copy arguments to the fun thing
- %% Eterm* hp = funp->env;
- %% for (i = 0; i < num_free; i++) {
- %% *hp++ = reg[i];
- %% }
- CopyFreeVarsCode = gen_free_vars(FreeVars, HP),
-
- %% Fill in fields
- %% funp->thing_word = HEADER_FUN;
- %% funp->fe = fe;
- %% funp->num_free = num_free;
- %% funp->creator = p->id;
- %% funp->native_code = fe->native_code;
- %% Increase refcount
- %% fe->refc++;
- SkeletonCode = gen_fun_thing_skeleton(HP, MFidA, NumFree, MagicNr, Index),
-
- %% Link to the process off_heap list
- %% funp->next = p->off_heap.first;
- %% p->off_heap.first = funp;
- LinkCode = gen_link_closure(HP),
-
- %% Tag the thing and increase the heap_pointer.
- %% make_fun(funp);
- WordSize = hipe_rtl_arch:word_size(),
- HeapNeed = (?ERL_FUN_SIZE + NumFree) * WordSize,
- TagCode = [hipe_tagscheme:tag_fun(Dst, HP),
- %% AdjustHPCode
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(HeapNeed)),
- PutHPInsn],
- [[GetHPInsn | CopyFreeVarsCode], SkeletonCode, LinkCode, TagCode].
-
-
-gen_fun_thing_skeleton(FunP, FunName={_Mod,_FunId,Arity}, NumFree,
- MagicNr, Index) ->
- %% Assumes that funp == heap_pointer
- %% Fill in fields
- %% funp->thing_word = HEADER_FUN;
- %% funp->fe = fe;
- %% funp->num_free = num_free;
- %% funp->creator = p->id;
- %% funp->native_code = fe->native_code;
- %% And creates a fe (at load time).
- FeVar = hipe_rtl:mk_new_reg(),
- PidVar = hipe_rtl:mk_new_reg_gcsafe(),
-
- [hipe_rtl:mk_load_address(FeVar, {FunName, MagicNr, Index}, closure),
- store_struct_field(FunP, ?EFT_FE, FeVar),
-
- store_struct_field(FunP, ?EFT_ARITY, hipe_rtl:mk_imm(Arity-NumFree)),
-
- gen_inc_refc(FeVar, ?EFE_REFC),
-
- store_struct_field(FunP, ?EFT_NUM_FREE, hipe_rtl:mk_imm(NumFree)),
- load_p_field(PidVar, ?P_ID),
- store_struct_field(FunP, ?EFT_CREATOR, PidVar),
- store_struct_field(FunP, ?EFT_THING, hipe_tagscheme:mk_fun_header())].
-
-gen_inc_refc(Ptr, Offset) ->
- case ?ERTS_IS_SMP of
- 0 -> gen_inc_refc_notsmp(Ptr, Offset);
- 1 -> gen_inc_refc_smp(Ptr, Offset)
- end.
-
-gen_inc_refc_notsmp(Ptr, Offset) ->
- Refc = hipe_rtl:mk_new_reg(),
- [load_struct_field(Refc, Ptr, Offset, int32),
- hipe_rtl:mk_alu(Refc, Refc, add, hipe_rtl:mk_imm(1)),
- store_struct_field(Ptr, Offset, Refc, int32)].
-
-gen_inc_refc_smp(Ptr, Offset) ->
- Refc = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_alu(Refc, Ptr, 'add', hipe_rtl:mk_imm(Offset)),
- hipe_rtl:mk_call([], 'atomic_inc', [Refc], [], [], not_remote)].
-
-gen_link_closure(FUNP) ->
- case ?P_OFF_HEAP_FUNS of
- [] -> gen_link_closure_non_private(FUNP);
- _ -> gen_link_closure_private(FUNP)
- end.
-
-gen_link_closure_private(FUNP) ->
- %% Link fun to the process off_heap list
- %% funp->next = p->off_heap.first;
- %% p->off_heap.first = funp;
- FunsVar = hipe_rtl:mk_new_reg(),
-
- [load_p_field(FunsVar,?P_OFF_HEAP_FIRST),
- hipe_rtl:mk_store(FUNP, hipe_rtl:mk_imm(?EFT_NEXT), FunsVar),
- store_p_field(FUNP,?P_OFF_HEAP_FIRST)].
-
-gen_link_closure_non_private(_FUNP) -> [].
-
-load_p_field(Dst,Offset) ->
- hipe_rtl_arch:pcb_load(Dst, Offset).
-store_p_field(Src, Offset) ->
- hipe_rtl_arch:pcb_store(Offset, Src).
-
-store_struct_field(StructP, Offset, Src) ->
- hipe_rtl:mk_store(StructP, hipe_rtl:mk_imm(Offset), Src).
-
-load_struct_field(Dest, StructP, Offset) ->
- hipe_rtl:mk_load(Dest, StructP, hipe_rtl:mk_imm(Offset)).
-
-store_struct_field(StructP, Offset, Src, int32) ->
- hipe_rtl:mk_store(StructP, hipe_rtl:mk_imm(Offset), Src, int32).
-
-load_struct_field(Dest, StructP, Offset, int32) ->
- hipe_rtl:mk_load(Dest, StructP, hipe_rtl:mk_imm(Offset), int32, signed).
-
-gen_free_vars(Vars, HPReg) ->
- HPVar = hipe_rtl:mk_new_var(),
- WordSize = hipe_rtl_arch:word_size(),
- [hipe_rtl:mk_alu(HPVar, HPReg, add, hipe_rtl:mk_imm(?EFT_ENV)) |
- gen_free_vars(Vars, HPVar, 0, WordSize, [])].
-
-gen_free_vars([Var|Vars], EnvPVar, Offset, WordSize, AccCode) ->
- Code = hipe_rtl:mk_store(EnvPVar, hipe_rtl:mk_imm(Offset), Var),
- gen_free_vars(Vars, EnvPVar, Offset + WordSize, WordSize,
- [Code|AccCode]);
-gen_free_vars([], _, _, _, AccCode) -> AccCode.
-
-%% ------------------------------------------------------------------
-%%
-%% call_fun (also handles enter_fun when Continuation = [])
-
-gen_call_fun(Dst, ArgsAndFun, Continuation, Fail) ->
- NCNAddressReg = hipe_rtl:mk_new_reg(),
- ArityReg = hipe_rtl:mk_new_reg_gcsafe(),
- [Fun|RevArgs] = lists:reverse(ArgsAndFun),
-
- %% {BadFunLabName, BadFunCode} = gen_fail_code(Fail, {badfun, Fun}),
- Args = lists:reverse(RevArgs),
- NonClosureLabel = hipe_rtl:mk_new_label(),
- CallNonClosureLabel = hipe_rtl:mk_new_label(),
- BadFunLabName = hipe_rtl:label_name(NonClosureLabel),
- BadFunCode =
- [NonClosureLabel,
- hipe_rtl:mk_call([NCNAddressReg],
- 'nonclosure_address',
- [Fun, hipe_rtl:mk_imm(length(Args))],
- hipe_rtl:label_name(CallNonClosureLabel),
- Fail,
- not_remote),
- CallNonClosureLabel,
- case Continuation of
- [] ->
- hipe_rtl:mk_enter(NCNAddressReg, Args, not_remote);
- _ ->
- hipe_rtl:mk_call(Dst, NCNAddressReg, Args,
- Continuation, Fail, not_remote)
- end],
-
- {BadArityLabName, BadArityCode} = gen_fail_code(Fail, {badarity, Fun}),
-
- CNAddressReg = hipe_rtl:mk_new_reg(),
- CheckGetCode =
- hipe_tagscheme:if_fun_get_arity_and_address(ArityReg, CNAddressReg,
- Fun, BadFunLabName,
- 0.9),
- CheckArityCode = check_arity(ArityReg, length(RevArgs), BadArityLabName),
- CallCode =
- case Continuation of
- [] -> %% This is a tailcall
- [hipe_rtl:mk_enter(CNAddressReg, ArgsAndFun, not_remote)];
- _ -> %% Ordinary call
- [hipe_rtl:mk_call(Dst, CNAddressReg, ArgsAndFun,
- Continuation, Fail, not_remote)]
- end,
- [CheckGetCode, CheckArityCode, CallCode, BadFunCode, BadArityCode].
-
-check_arity(ArityReg, Arity, BadArityLab) ->
- TrueLab1 = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_branch(ArityReg, eq, hipe_rtl:mk_imm(Arity),
- hipe_rtl:label_name(TrueLab1), BadArityLab, 0.9),
- TrueLab1].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% apply
-%%
-%% The tail call case is not handled here.
-
-gen_apply(Dst, Args = [_M,_F,_AppArgs], Cont, Fail) ->
- %% Dst can be [Res] or [].
- [hipe_rtl:mk_call(Dst, hipe_apply, Args, Cont, Fail, not_remote)].
-
-gen_enter_apply(Args=[_M,_F,_AppArgs]) ->
- %% 'apply' in tail-call context
- [hipe_rtl:mk_enter(hipe_apply, Args, not_remote)].
-
-%%
-%% apply_N
-%% also handles tailcall case (Cont=[])
-%%
-
-gen_apply_N(Dst, Arity, [M,F|CallArgs], Cont, Fail) ->
- MM = hipe_rtl:mk_new_var(),
- NotModuleLbl = hipe_rtl:mk_new_label(),
- NotModuleLblName = hipe_rtl:label_name(NotModuleLbl),
- Tuple = M,
- Index = hipe_rtl:mk_imm(1),
- IndexInfo = 1,
- [hipe_tagscheme:element(MM, Index, Tuple, NotModuleLblName, unknown, IndexInfo),
- gen_apply_N_common(Dst, Arity+1, MM, F, CallArgs ++ [M], Cont, Fail),
- NotModuleLbl,
- gen_apply_N_common(Dst, Arity, M, F, CallArgs, Cont, Fail)].
-
-gen_apply_N_common(Dst, Arity, M, F, CallArgs, Cont, Fail) ->
- CallLabel = hipe_rtl:mk_new_label(),
- CodeAddress = hipe_rtl:mk_new_reg(),
- [hipe_rtl:mk_call([CodeAddress], find_na_or_make_stub,
- [M,F,hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(Arity))],
- hipe_rtl:label_name(CallLabel),
- Fail, not_remote),
- CallLabel,
- case Cont of
- [] -> % tailcall
- hipe_rtl:mk_enter(CodeAddress, CallArgs, not_remote);
- _ -> % recursive call
- hipe_rtl:mk_call(Dst, CodeAddress, CallArgs, Cont, Fail, not_remote)
- end].
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% mkTuple
-%%
-
-gen_mk_tuple(Dst, Elements) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- Arity = length(Elements),
- WordSize = hipe_rtl_arch:word_size(),
- HeapNeed = (Arity+1)*WordSize,
- [GetHPInsn,
- gen_tuple_header(HP, Arity),
- set_tuple_elements(HP, WordSize, WordSize, Elements, []),
- hipe_tagscheme:tag_tuple(Dst, HP),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(HeapNeed)),
- PutHPInsn].
-
-set_tuple_elements(HP, Offset, WordSize, [Element|Elements], Stores) ->
- Store = hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(Offset), Element),
- set_tuple_elements(HP, Offset+WordSize, WordSize, Elements, [Store|Stores]);
-set_tuple_elements(_, _, _, [], Stores) ->
- lists:reverse(Stores).
-
-%%
-%% @doc Generate RTL code for the reduction test.
-%%
-gen_redtest(Amount) ->
- {GetFCallsInsn, FCalls, PutFCallsInsn} = hipe_rtl_arch:fcalls(),
- SuspendLabel = hipe_rtl:mk_new_label(),
- StayLabel = hipe_rtl:mk_new_label(),
- ContinueLabel = hipe_rtl:mk_new_label(),
- [GetFCallsInsn,
- hipe_rtl:mk_alub(FCalls, FCalls, 'sub', hipe_rtl:mk_imm(Amount), 'lt',
- hipe_rtl:label_name(SuspendLabel),
- hipe_rtl:label_name(StayLabel), 0.01),
- SuspendLabel,
- %% The suspend path should not execute PutFCallsInsn.
- hipe_rtl:mk_call([], suspend_0, [],
- hipe_rtl:label_name(ContinueLabel), [], not_remote),
- StayLabel,
- PutFCallsInsn,
- ContinueLabel].
-
-gen_self(Dst, Cont) ->
- case Dst of
- [] -> %% The result is not used.
- [hipe_rtl:mk_goto(Cont)];
- [Dst1] ->
- [load_p_field(Dst1, ?P_ID),
- hipe_rtl:mk_goto(Cont)]
- end.
-
-%%
-%% @doc Generate is_tuple/1 test
-%%
-gen_is_tuple(Dst, [Arg], Cont) ->
- GotoCont = hipe_rtl:mk_goto(Cont),
- case Dst of
- [] -> %% The result is not used.
- [GotoCont];
- [Dst1] ->
- TrueLabel = hipe_rtl:mk_new_label(),
- FalseLabel = hipe_rtl:mk_new_label(),
- [hipe_tagscheme:test_tuple(Arg, hipe_rtl:label_name(TrueLabel),
- hipe_rtl:label_name(FalseLabel), 0.5),
- TrueLabel,
- hipe_rtl:mk_load_atom(Dst1, true),
- GotoCont,
- FalseLabel,
- hipe_rtl:mk_load_atom(Dst1, false),
- GotoCont]
- end.
-
-%%
-%% @doc Generate unsafe head
-%%
-gen_unsafe_hd(Dst, [Arg]) -> hipe_tagscheme:unsafe_car(Dst, Arg).
-
-%%
-%% @doc Generate unsafe tail
-%%
-gen_unsafe_tl(Dst, [Arg]) -> hipe_tagscheme:unsafe_cdr(Dst, Arg).
-
-%%
-%% element
-%%
-gen_element(Dst, Args, IsGuard, Cont, Fail) ->
- Dst1 =
- case Dst of
- [] -> %% The result is not used.
- hipe_rtl:mk_new_var();
- [Dst0] -> Dst0
- end,
- [Index, Tuple] = Args,
- gen_element_1(Dst1, Index, Tuple, IsGuard, Cont, Fail, unknown, unknown).
-
-gen_element_1(Dst, Index, Tuple, IsGuard, Cont, Fail, TupleInfo, IndexInfo) ->
- {FailLblName, FailCode} = gen_fail_code(Fail, badarg, IsGuard),
- [hipe_tagscheme:element(Dst, Index, Tuple, FailLblName, TupleInfo, IndexInfo),
- hipe_rtl:mk_goto(Cont),
- FailCode].
-
-%%
-%% unsafe element
-%%
-gen_unsafe_element(Dst, Index, Tuple) ->
- case hipe_rtl:is_imm(Index) of
- true -> hipe_tagscheme:unsafe_constant_element(Dst, Index, Tuple);
- false -> ?EXIT({illegal_index_to_unsafe_element,Index})
- end.
-
-gen_unsafe_update_element(Tuple, Index, Value) ->
- case hipe_rtl:is_imm(Index) of
- true ->
- hipe_tagscheme:unsafe_update_element(Tuple, Index, Value);
- false ->
- ?EXIT({illegal_index_to_unsafe_update_element,Index})
- end.
-
-
-gen_closure_element(Dst, Index, Closure) ->
- hipe_tagscheme:unsafe_closure_element(Dst, Index, Closure).
-
-%%
-%% @doc Generate RTL code that writes a tuple header.
-%%
-gen_tuple_header(Ptr, Arity) ->
- Header = hipe_tagscheme:mk_arityval(Arity),
- hipe_rtl:mk_store(Ptr, hipe_rtl:mk_imm(0), hipe_rtl:mk_imm(Header)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%
-%%% Receives
-
-%%% recv_mark is:
-%%% p->msg.saved_last = p->msg.last;
-gen_recv_mark([], GotoCont) ->
- TmpLast = hipe_rtl:mk_new_reg(),
- [load_p_field(TmpLast, ?P_MSG_LAST),
- store_p_field(TmpLast, ?P_MSG_SAVED_LAST),
- GotoCont].
-
-%%% recv_set is:
-%%% if (p->msg.saved_last)
-%%% p->msg.save = p->msg.saved_last;
-gen_recv_set([], Cont) ->
- TmpSave = hipe_rtl:mk_new_reg(),
- TrueLbl = hipe_rtl:mk_new_label(),
- [load_p_field(TmpSave, ?P_MSG_SAVED_LAST),
- hipe_rtl:mk_branch(TmpSave, ne, hipe_rtl:mk_imm(0),
- hipe_rtl:label_name(TrueLbl), Cont),
- TrueLbl,
- store_p_field(TmpSave, ?P_MSG_SAVE),
- hipe_rtl:mk_goto(Cont)].
-
-gen_check_get_msg(Dsts, GotoCont, Fail) ->
- gen_check_get_msg_outofline(Dsts, GotoCont, Fail).
-
-gen_clear_timeout([], GotoCont) ->
- case ?ERTS_IS_SMP of
- 0 -> gen_clear_timeout_notsmp(GotoCont);
- 1 -> gen_clear_timeout_smp(GotoCont)
- end.
-
--ifdef(notdef). % for reference, currently unused
-%%% check_get_msg is:
-%%% if (!PEEK_MESSAGE(p)) goto Fail;
-%%% Dst = ERL_MESSAGE_TERM(PEEK_MESSAGE(p));
-%%% i.e.,
-%%% ErlMessage **save = p->msg.save;
-%%% ErlMessage *msg = *save;
-%%% if (!msg) goto Fail;
-%%% Dst = msg->m[0];
-gen_check_get_msg_inline(Dsts, GotoCont, Fail) ->
- Save = hipe_rtl:mk_new_reg(),
- Msg = hipe_rtl:mk_new_reg(),
- TrueLbl = hipe_rtl:mk_new_label(),
- [load_p_field(Save, ?P_MSG_SAVE),
- load_struct_field(Msg, Save, 0),
- hipe_rtl:mk_branch(Msg, eq, hipe_rtl:mk_imm(0), Fail,
- hipe_rtl:label_name(TrueLbl), 0.1),
- TrueLbl |
- case Dsts of
- [Dst] ->
- [load_struct_field(Dst, Msg, ?MSG_MESSAGE),
- GotoCont];
- [] -> % receive which throws away the message
- [GotoCont]
- end].
--endif.
-
-%%% next_msg is:
-%%% SAVE_MESSAGE(p);
-%%% i.e.,
-%%% ErlMessage **save = p->msg.save;
-%%% ErlMessage *msg = *save;
-%%% ErlMessage **next = &msg->next;
-%%% p->msg.save = next;
-gen_next_msg([], GotoCont) ->
- Save = hipe_rtl:mk_new_reg(),
- Msg = hipe_rtl:mk_new_reg(),
- Next = hipe_rtl:mk_new_reg(),
- [load_p_field(Save, ?P_MSG_SAVE),
- load_struct_field(Msg, Save, 0),
- hipe_rtl:mk_alu(Next, Msg, 'add', hipe_rtl:mk_imm(?MSG_NEXT)),
- store_p_field(Next, ?P_MSG_SAVE),
- GotoCont].
-
-%%% clear_timeout is:
-%%% p->flags &= ~F_TIMO; JOIN_MESSAGE(p);
-%%% i.e.,
-%%% p->flags &= ~F_TIMO;
-%%% p->msg.save = &p->msg.first;
-gen_clear_timeout_notsmp(GotoCont) ->
- Flags1 = hipe_rtl:mk_new_reg(),
- Flags2 = hipe_rtl:mk_new_reg_gcsafe(),
- First = hipe_rtl:mk_new_reg_gcsafe(),
- [load_p_field(Flags1, ?P_FLAGS),
- hipe_rtl:mk_alu(Flags2, Flags1, 'and', hipe_rtl:mk_imm(bnot(?F_TIMO))),
- store_p_field(Flags2, ?P_FLAGS),
- hipe_rtl_arch:pcb_address(First, ?P_MSG_FIRST),
- store_p_field(First, ?P_MSG_SAVE),
- GotoCont].
-
-gen_check_get_msg_outofline(Dsts, GotoCont, Fail) ->
- RetLbl = hipe_rtl:mk_new_label(),
- TrueLbl = hipe_rtl:mk_new_label(),
- Tmp = hipe_rtl:mk_new_reg(),
- TheNonValue = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
- [hipe_rtl_arch:call_bif([Tmp], check_get_msg, [],
- hipe_rtl:label_name(RetLbl), []),
- RetLbl,
- hipe_rtl:mk_branch(Tmp, eq, TheNonValue, Fail,
- hipe_rtl:label_name(TrueLbl), 0.1),
- TrueLbl |
- case Dsts of
- [Dst] ->
- [hipe_rtl:mk_move(Dst, Tmp),
- GotoCont];
- [] -> % receive which throws away the message
- [GotoCont]
- end].
-
-gen_clear_timeout_smp(GotoCont) ->
- RetLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl_arch:call_bif([], clear_timeout, [],
- hipe_rtl:label_name(RetLbl), []),
- RetLbl,
- GotoCont].
-
-gen_select_msg([], Cont) ->
- [hipe_rtl_arch:call_bif([], select_msg, [], Cont, [])].
-
-gen_suspend_msg([], Cont) ->
- [hipe_rtl:mk_call([], suspend_msg, [], Cont, [], not_remote)].
-
-%% --------------------------------------------------------------------
-%%
-%% Floating point handling
-%%
-
-gen_fclearerror() ->
- case ?P_FP_EXCEPTION of
- [] ->
- [];
- Offset ->
- Tmp = hipe_rtl:mk_new_reg(),
- FailLbl = hipe_rtl:mk_new_label(),
- ContLbl = hipe_rtl:mk_new_label(),
- ContLblName = hipe_rtl:label_name(ContLbl),
- [hipe_rtl_arch:pcb_load(Tmp, Offset),
- hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0), ContLblName,
- hipe_rtl:label_name(FailLbl), 0.9),
- FailLbl,
- hipe_rtl:mk_call([], 'fclearerror_error', [], [], [], not_remote),
- hipe_rtl:mk_goto(ContLblName),
- ContLbl]
- end.
-
-gen_fcheckerror(ContLbl, FailLbl) ->
- case ?P_FP_EXCEPTION of
- [] ->
- [];
- Offset ->
- Tmp = hipe_rtl:mk_new_reg(),
- TmpFailLbl0 = hipe_rtl:mk_new_label(),
- FailCode = fp_fail_code(TmpFailLbl0, FailLbl),
- PreFailLbl = hipe_rtl:mk_new_label(),
- hipe_rtl_arch:fwait() ++
- [hipe_rtl_arch:pcb_load(Tmp, Offset),
- hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0), ContLbl,
- hipe_rtl:label_name(PreFailLbl), 0.9),
- PreFailLbl,
- hipe_rtl_arch:pcb_store(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_goto(hipe_rtl:label_name(TmpFailLbl0)) |
- FailCode]
- end.
-
-gen_conv_to_float(Dst, [Src], ContLbl, FailLbl) ->
- case hipe_rtl:is_var(Src) of
- true ->
- Tmp = hipe_rtl:mk_new_var(),
- TmpReg = hipe_rtl:mk_new_reg_gcsafe(),
- TrueFixNum = hipe_rtl:mk_new_label(),
- ContFixNum = hipe_rtl:mk_new_label(),
- TrueFp = hipe_rtl:mk_new_label(),
- ContFp = hipe_rtl:mk_new_label(),
- ContBigNum = hipe_rtl:mk_new_label(),
- TestFixNum = hipe_tagscheme:test_fixnum(Src,
- hipe_rtl:label_name(TrueFixNum),
- hipe_rtl:label_name(ContFixNum),
- 0.5),
- TestFp = hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(TrueFp),
- hipe_rtl:label_name(ContFp), 0.5),
- GotoCont = hipe_rtl:mk_goto(ContLbl),
- TmpFailLbl0 = hipe_rtl:mk_new_label(),
- FailCode = fp_fail_code(TmpFailLbl0, FailLbl),
-
- TestFixNum ++
- [TrueFixNum,
- hipe_tagscheme:untag_fixnum(TmpReg, Src),
- hipe_rtl:mk_fconv(Dst, TmpReg),
- GotoCont,
- ContFixNum] ++
- TestFp ++
- [TrueFp,
- hipe_tagscheme:unsafe_untag_float(Dst, Src),
- GotoCont,
- ContFp] ++
- [hipe_rtl:mk_call([Tmp], conv_big_to_float, [Src],
- hipe_rtl:label_name(ContBigNum),
- hipe_rtl:label_name(TmpFailLbl0), not_remote)]++
- FailCode ++
- [ContBigNum,
- hipe_tagscheme:unsafe_untag_float(Dst, Tmp)];
- _ ->
- %% This must be an attempt to convert an illegal term.
- [gen_fail_code(FailLbl, badarith)]
- end.
-
diff --git a/lib/hipe/rtl/hipe_rtl_ssa.erl b/lib/hipe/rtl/hipe_rtl_ssa.erl
deleted file mode 100644
index 70f9eeedc9..0000000000
--- a/lib/hipe/rtl/hipe_rtl_ssa.erl
+++ /dev/null
@@ -1,88 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_rtl_ssa.erl
-%% Author : Kostis Sagonas <kostis@it.uu.se>
-%% Created : 30 Jan 2004
-%% Purpose : Provides interface functions for converting RTL code into
-%% SSA form and back using the generic SSA converter.
-%%----------------------------------------------------------------------
-
--module(hipe_rtl_ssa).
-
--export([uses_to_rename/1]). %% needed by hipe_rtl_ssa_const_prop
-
-%% The following defines are needed by the included file below
--define(CODE, hipe_rtl).
--define(CFG, hipe_rtl_cfg).
--define(LIVENESS, hipe_rtl_liveness).
-
--include("hipe_rtl.hrl").
--include("../ssa/hipe_ssa.inc").
-
-%%----------------------------------------------------------------------
-%% Auxiliary operations which seriously differ between Icode and RTL.
-%%----------------------------------------------------------------------
-
-defs_to_rename(Statement) ->
- Defs = hipe_rtl:defines(Statement),
- [D || D <- Defs, not hipe_rtl_arch:is_precoloured(D)].
-
-uses_to_rename(Statement) ->
- Uses = hipe_rtl:uses(Statement),
- [U || U <- Uses, not hipe_rtl_arch:is_precoloured(U)].
-
-liveout_no_succ() ->
- hipe_rtl_arch:live_at_return().
-
-%-----------------------------------------------------------------------
-
-reset_var_indx() ->
- hipe_gensym:set_var(rtl, hipe_rtl_arch:first_virtual_reg()).
-
-%%----------------------------------------------------------------------
-
-is_fp_temp(Temp) ->
- hipe_rtl:is_fpreg(Temp).
-
-mk_new_fp_temp() ->
- hipe_rtl:mk_new_fpreg().
-
-%-----------------------------------------------------------------------
-%% Procedure : makePhiMove
-%% Purpose : Create an RTL-specific version of a move instruction
-%% depending on the type of the arguments.
-%% Arguments : Dst, Src - the arguments of a Phi instruction that is
-%% to be moved up the predecessor block as part
-%% of the SSA un-convert phase.
-%% Returns : Code
-%% Note : ?CODE here is hipe_rtl
-%%----------------------------------------------------------------------
-
-makePhiMove(Dst, Src) ->
- case hipe_rtl:is_fpreg(Dst) of
- false ->
- case hipe_rtl:is_fpreg(Src) of %% this test is just a sanity check
- false ->
- hipe_rtl:mk_move(Dst, Src)
- end;
- true ->
- case hipe_rtl:is_fpreg(Src) of %% this test is just a sanity check
- true ->
- hipe_rtl:mk_fmove(Dst, Src)
- end
- end.
-
-%-----------------------------------------------------------------------
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_avail_expr.erl b/lib/hipe/rtl/hipe_rtl_ssa_avail_expr.erl
deleted file mode 100644
index 3fbbf6287f..0000000000
--- a/lib/hipe/rtl/hipe_rtl_ssa_avail_expr.erl
+++ /dev/null
@@ -1,351 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_rtl_ssa_avail_expr.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Description : A couple of optimizations on rtl_ssa
-%%% 1. Remove unnecessary loads (Global)
-%%% 2. Remove unnecessary stores (Local)
-%%% 3. Remove unnecessary tag/untag operations
-%%%
-%%% Changed : 7 Feb 2007 by Per Gustafsson <pergu@it.uu.se>
-%%%-------------------------------------------------------------------
--module(hipe_rtl_ssa_avail_expr).
-
--export([cfg/1]).
-
--include("../main/hipe.hrl").
--include("hipe_rtl.hrl").
-
-cfg(CFG) ->
- CFG1 = remove_loads(CFG),
- CFG2 = remove_stores(CFG1),
- CFG3 = optimize_fixnums(CFG2),
- hipe_rtl_ssa:remove_dead_code(CFG3).
-
-%%%=============================================================================
-%%%
-%%% Remove unnecessary loads
-%%%
-%%%=============================================================================
-
-remove_loads(CFG) ->
- LoadsFun = fun spread_info/2,
- Info=fix_point(CFG, LoadsFun),
- pass_through(CFG, LoadsFun, Info).
-
-spread_info(Code, Info) ->
- lists:foldl(fun do_instr/2, {[],Info}, Code).
-
-do_instr(Instr, {Acc,Info}) ->
- case Instr of
- #call{} ->
- {Acc++[Instr], new_env()};
- #store{} ->
- {Acc++[Instr], new_env()};
- #gctest{} ->
- {Acc++[Instr], new_env()};
- #load{} ->
- Dst = hipe_rtl:load_dst(Instr),
- LoadType = {hipe_rtl:load_src(Instr), hipe_rtl:load_offset(Instr),
- hipe_rtl:load_size(Instr), hipe_rtl:load_sign(Instr)},
- NewInstr =
- case lookup_y(LoadType, Info) of
- none ->
- Instr;
- Var ->
- hipe_rtl:mk_move(Dst, Var)
- end,
- Fun = fun load_filter_fun/2,
- {Acc++[NewInstr], insert(Dst,LoadType,remove_defines(Instr,Info,Fun))};
- _ ->
- {Acc++[Instr],remove_defines(Instr,Info,fun load_filter_fun/2)}
- end.
-
-load_filter_fun({X1,{X2,X3,_,_}},PreColDefs) ->
- not (lists:member(X1,PreColDefs) or
- lists:member(X2,PreColDefs) or
- lists:member(X3,PreColDefs)).
-
-%%%=============================================================================
-%%%
-%%% Remove unnecessary stores (local optimization)
-%%%
-%%%=============================================================================
-
-remove_stores(CFG) ->
- pass_through(CFG, fun remove_store/2, new_info()).
-
-remove_store(Code,_) ->
- remove_store_from_bb(Code).
-
-remove_store_from_bb(Code) ->
- remove_store_from_bb(lists:reverse(Code), new_env(), []).
-
-remove_store_from_bb([Instr|Instrs], Env, Acc) ->
- {NewAcc, NewEnv} =
- case Instr of
- #call{} ->
- {[Instr|Acc],new_env()};
- #gctest{} ->
- {[Instr|Acc], new_env()};
- #store{} ->
- Base = hipe_rtl:store_base(Instr),
- Offset = hipe_rtl:store_offset(Instr),
- Size = hipe_rtl:store_size(Instr),
- StoreType = {Base, Offset, Size},
- case lookup_y(StoreType, Env) of
- none ->
- {[Instr|Acc], insert(StoreType, true, Env)};
- true ->
- {Acc, Env}
- end;
- #load{} ->
- {[Instr|Acc],new_env()};
- _ ->
- {[Instr|Acc],remove_defines(Instr,Env,fun store_filter_fun/2)}
- end,
- remove_store_from_bb(Instrs, NewEnv, NewAcc);
-remove_store_from_bb([], Env, Acc) ->
- {Acc,Env}.
-
-store_filter_fun({{X1,X2,_},_},PreColDefs) ->
- not (lists:member(X1,PreColDefs) or
- lists:member(X2,PreColDefs)).
-
-%%%=============================================================================
-%%%
-%%% Optimize Fixnum Operations
-%%%
-%%%=============================================================================
-
-optimize_fixnums(CFG) ->
- FixFun = fun fixnum_opt/2,
- Info=fix_point(CFG, FixFun),
- pass_through(CFG, FixFun, Info).
-
-fixnum_opt(Code,Info) ->
- lists:foldl(fun do_fixnums/2, {[],Info}, Code).
-
-do_fixnums(Instr, {Acc,Env}) ->
- case Instr of
- #call{} ->
- {Acc++[Instr],Env};
- #gctest{} ->
- {Acc++[Instr],Env};
- #fixnumop{dst=Dst,src=Src} ->
- case lookup_y(Src,Env) of
- none ->
- case lookup_x(Src,Env) of
- none ->
- case hipe_rtl_arch:is_precoloured(Src) or
- hipe_rtl_arch:is_precoloured(Dst) of
- true ->
- {Acc++[Instr],Env}; %% To Avoid non ssa problems
- false ->
- {Acc++[Instr],insert(Dst,Src,Env)}
- end;
- OtherSrc ->
- {Acc++[hipe_rtl:mk_move(Dst,OtherSrc)],Env}
- end;
- OtherDst ->
- {Acc++[hipe_rtl:mk_move(Dst,OtherDst)],Env}
- end;
- _ ->
- {Acc++[Instr],Env}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Code handling functions
-%%
-
-get_code_from_label(Label,CFG) ->
- CurrentBB = hipe_rtl_cfg:bb(CFG, Label),
- hipe_bb:code(CurrentBB).
-
-put_code_at_label(Label,Code,CFG) ->
- NewBB = hipe_bb:mk_bb(Code),
- hipe_rtl_cfg:bb_add(CFG, Label, NewBB).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The info environment.
-%% An info environment is a mapping from labels to info_out
-%%
-
-new_info() ->
- gb_trees:empty().
-
-get_info(Label,Info) ->
- case gb_trees:lookup(Label, Info) of
- {value, V} -> V;
- none -> none
- end.
-
-add_info(Label, NewInfo, OldInfo) ->
- gb_trees:enter(Label, NewInfo, OldInfo).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Simple worklist utility
-%%
-
-add_succ_to_list(NewList, OldList) ->
- RealNew = [New || New <- NewList, lists:member(New,OldList)],
- OldList ++ RealNew.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Generic Fixpoint Code
-%%
-
-fix_point(CFG, Fun) ->
- Start = hipe_rtl_cfg:start_label(CFG),
- Info = new_info(),
- fix_point([Start], CFG, Fun, Info).
-
-fix_point([Label|Labels], CFG, Fun, Info) ->
- case initial_stage(Label,CFG,Fun,Info) of
- {true, _, _} ->
- fix_point(Labels, CFG, Fun, Info);
- {false, _, NewInfoOut} ->
- Succ = hipe_rtl_cfg:succ(CFG, Label),
- NewList = add_succ_to_list(Succ, Labels),
- NewInfo = add_info(Label, NewInfoOut, Info),
- fix_point(NewList, CFG, Fun, NewInfo)
- end;
-fix_point([], _CFG, _Fun, Info) ->
- Info.
-
-pass_through(CFG, Fun, Info) ->
- pass_through(hipe_rtl_cfg:reverse_postorder(CFG),
- CFG, Fun, Info).
-
-pass_through([Label|Labels], CFG, Fun, Info) ->
- {_, NewCode, _} = initial_stage(Label,CFG,Fun,Info),
- NewCFG = put_code_at_label(Label,NewCode,CFG),
- pass_through(Labels, NewCFG, Fun, Info);
-pass_through([], CFG, _Fun, _Info) ->
- CFG.
-
-initial_stage(Label,CFG,Fun,Info) ->
- OldInfoOut = get_info(Label,Info),
- Pred = hipe_rtl_cfg:pred(CFG,Label),
- InfoEnv = join([get_info(L,Info) || L <- Pred]),
- OldCode = get_code_from_label(Label,CFG),
- {PhiCode,Code} = split_code(OldCode),
- InfoIn = join_phi(PhiCode,Info,InfoEnv),
- {NewCode, NewInfoOut} = Fun(Code, InfoIn),
- {OldInfoOut=:=NewInfoOut,PhiCode++NewCode, NewInfoOut}.
-
-join_phi([#phi{dst=Dst,arglist=AList}|Rest], Info, Env) ->
- case lists:foldl(fun(Val,Acc) ->
- check_label(Val,Info,Acc)
- end, none, AList) of
- no_val ->
- join_phi(Rest,Info,Env);
- none ->
- join_phi(Rest,Info,Env);
- Expr ->
- join_phi(Rest,Info,insert(Dst,Expr,Env))
- end;
-join_phi([], _Info, Env) ->
- Env.
-
-check_label({Lbl,Var}, Info, Acc) ->
- case gb_trees:lookup(Lbl,Info) of
- none -> Acc;
- {value,Env} ->
- case lookup_x(Var,Env) of
- none -> no_val;
- Acc -> Acc;
- V ->
- if Acc =:= none -> V;
- true -> no_val
- end
- end
- end.
-
-split_code(Code) ->
- Phis = extract_phis(Code),
- {Phis,Code--Phis}.
-
-extract_phis(Code) ->
- [I || #phi{}=I <- Code].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% One2One Environment
-%%
-
-new_env() ->
- {gb_trees:empty(),gb_trees:empty()}.
-
-insert(X,Y,{XtoY,YtoX}) ->
- NewYtoX = remove_old_binding(X,XtoY,YtoX),
- NewXtoY = remove_old_binding(Y,YtoX,XtoY),
- {gb_trees:enter(X,Y,NewXtoY),
- gb_trees:enter(Y,X,NewYtoX)}.
-
-remove_old_binding(Key,LookupTree,ChangeTree) ->
- case gb_trees:lookup(Key,LookupTree) of
- none ->
- ChangeTree;
- {value,V} ->
- gb_trees:balance(gb_trees:delete(V,ChangeTree))
- end.
-
-lookup_x(X,{XtoY,_YtoX}) ->
- case gb_trees:lookup(X,XtoY) of
- none -> none;
- {value,Val} -> Val
- end.
-
-lookup_y(Y,{_XtoY,YtoX}) ->
- case gb_trees:lookup(Y,YtoX) of
- none -> none;
- {value,Val} -> Val
- end.
-
-join([]) -> new_env();
-join([none]) -> new_env();
-join([E]) -> E;
-join([E1,E2|Rest]) -> join([join(E1,E2)|Rest]).
-
-join({MapXY1,MapYX1},{MapXY2,MapYX2}) ->
- {join_maps(MapXY1,MapXY2),
- join_maps(MapYX1,MapYX2)};
-join(none,E) -> E;
-join(E,none) -> E.
-
-join_maps(Map1,Map2) ->
- OrdDict = ordsets:intersection(gb_trees:to_list(Map1),
- gb_trees:to_list(Map2)),
- gb_trees:from_orddict(OrdDict).
-
-remove_defines(Instr,Info,Fun) ->
- Defs = hipe_rtl:defines(Instr),
- case [Def || Def <- Defs, hipe_rtl_arch:is_precoloured(Def)] of
- [] ->
- Info;
- PreColDefs ->
- filter_environments(PreColDefs,Info,Fun)
- end.
-
-filter_environments(PreColDefs,{M1,_M2},Fun) ->
- L1 = gb_trees:to_list(M1),
- F1 = [Tup || Tup <- L1, Fun(Tup,PreColDefs)],
- F2 = [{Y,X} || {X,Y} <- F1],
- {gb_trees:from_orddict(F1),gb_trees:from_orddict(orddict:from_list(F2))}.
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
deleted file mode 100644
index 72373e536d..0000000000
--- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
+++ /dev/null
@@ -1,1018 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% ============================================================================
-%% Filename : hipe_rtl_ssa_const_prop.erl
-%% Authors : Bjorn Bergman, Bjarni Juliusson
-%% Purpose : Perform sparse conditional constant propagation on RTL.
-%% Notes : Works on an SSA-converted control-flow graph.
-%%
-%% History : * 2004-03-14: Blatantly stolen from Icode (code by
-%% Daniel Luna and Erik Andersson) and query-replaced for RTL.
-%% * 2004-04-30: Added in the repository.
-%% ============================================================================
-%%
-%% Exports: propagate/1.
-%%
-%% ============================================================================
-%%
-%% Some things to note:
-%%
-%% 1. All precoloured registers are assumed to contain bottom. We cannot
-%% do anything with them since they are not in SSA-form. This might be
-%% possible to resolve in some way, but we decided to not go there.
-%%
-%% 2. const_labels are assumed to be bottom, we cannot find the address
-%% in any nice way (that I know of, maybe someone can help ?). I
-%% suppose they don't get a value until linking (or some step that
-%% resembles it). They are only affecting bignums and floats (at least
-%% as far as I can tell), which are both stored in memory and hence
-%% not handled very well by us anyway.
-%%
-%% 3. can v <- Constant be removed ? I think so. all uses of v will be
-%% replaced with an immediate. So why not ?
-%%
-%% ============================================================================
-%%
-%% TODO:
-%%
-%% Take care of failures in call and replace operation with apropriate
-%% failure.
-%%
-%% Handle ifs with non-binary operators
-%%
-%% We want multisets for easier (and faster) creation of env->ssa_edges
-%%
-%% Propagation of constant arguments when some of the arguments are bottom
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
--module(hipe_rtl_ssa_const_prop).
--export([propagate/1]).
-
--include("../main/hipe.hrl").
--include("hipe_rtl.hrl").
--include("../flow/cfg.hrl").
-
-%-define(DEBUG, true).
-
--ifdef(DEBUG).
--define(SCCPDBG(W), W).
--define(DEBUG_TST, true). % make sure that we can use ?DEBUG in if-cases...
--else.
--define(DEBUG_TST, false). % make sure that we can use ?DEBUG in if-cases...
--define(SCCPDBG(W), ok).
--endif.
-
-%%-----------------------------------------------------------------------------
-%% Include stuff shared between SCCP on Icode and RTL.
-%% NOTE: Needs to appear after DEBUG is possibly defined.
-%%-----------------------------------------------------------------------------
-
--define(CODE, hipe_rtl).
--define(CFG, hipe_rtl_cfg).
--include("../ssa/hipe_ssa_const_prop.inc").
-
--type bool_lattice() :: 'true' | 'false' | 'top' | 'bottom'.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_expression/2
-%% Purpose : do a symbolic execution of the given instruction. This is just
-%% a wrapper that chooses the right function to handle a particular
-%% instruction.
-%% Arguments : Instructions - the instruction
-%% Environment - have a guess.
-%% Returns : {FlowWorkList, SSAWorkList, Environment}
-%%-----------------------------------------------------------------------------
-visit_expression(Instruction, Environment) ->
- case Instruction of
- #alu{} ->
- visit_alu(Instruction, Environment);
- #alub{} ->
- visit_alub(Instruction, Environment);
- #call{} ->
- visit_call(Instruction, Environment);
-%% #comment{} ->
-%% visit_comment(Instruction, Environment);
-%% #enter{} ->
-%% visit_enter(Instruction, Environment);
- #fconv{} ->
- visit_fconv(Instruction, Environment);
- #fixnumop{} ->
- visit_fixnumop(Instruction, Environment);
- #fload{} ->
- visit_fload(Instruction, Environment);
- #fmove{} ->
- visit_fmove(Instruction, Environment);
- #fp{} ->
- visit_fp(Instruction, Environment);
- #fp_unop{} ->
- visit_fp_unop(Instruction, Environment);
-%% #fstore{} ->
-%% visit_fstore(Instruction, Environment);
-%% #gctest{} ->
-%% visit_gctest(Instruction, Environment);
- #goto{} ->
- visit_goto(Instruction, Environment);
- #goto_index{} ->
- visit_goto_index(Instruction, Environment);
-%% #label{} ->
-%% visit_label(Instruction, Environment);
- #load{} ->
- visit_load(Instruction, Environment);
- #load_address{} ->
- visit_load_address(Instruction, Environment);
- #load_atom{} ->
- visit_load_atom(Instruction, Environment);
- #load_word_index{} ->
- visit_load_word_index(Instruction, Environment);
- #move{} ->
- visit_move(Instruction, Environment);
- #multimove{} ->
- visit_multimove(Instruction, Environment);
-%% phi-nodes are handled in scc
-%% #phi{} ->
-%% visit_phi(Instruction, Environment);
-%% #return{} ->
-%% visit_return(Instruction, Environment);
-%% #store{} ->
-%% visit_store(Instruction, Environment);
- #switch{} ->
- visit_switch(Instruction, Environment);
- _ ->
- %% label, end_try, comment, return, fail, et al
- {[], [], Environment}
- end.
-
-
-%%-----------------------------------------------------------------------------
-%% Procedure : set_to/3
-%% Purpose : many of the visit_<inst> functions ends in a update of the
-%% environment (and resulting SSA-edges) this function does the
-%% update in a nice way and formats the result so that it can be
-%% imediatly returned to visit_expression
-%% Arguments : Dst - the destination may be a list of destinations.
-%% Val - the new value (bottom, or some constant).
-%% Env - the environment in which the update should be done.
-%% Returns : { FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-set_to(Dst, Val, Env) ->
- {Env1, SSAWork} = update_lattice_value({Dst, Val}, Env),
- {[], SSAWork, Env1}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : evaluate_fixnumop/2
-%% Purpose : try to evaluate a fixnumop.
-%% Arguments : Val1 - operand (an integer, 'top' or 'bottom')
-%% Op - the operation.
-%% Returns : Result
-%% where result is an integer, 'top' or 'bottom'
-%%-----------------------------------------------------------------------------
-
-evaluate_fixnumop(Val1, Op) ->
- if Val1 =:= top ->
- top;
- Val1 =:= bottom ->
- bottom;
- is_integer(Val1) ->
- case Op of
- tag ->
- hipe_tagscheme:mk_fixnum(Val1);
- untag ->
- hipe_tagscheme:fixnum_val(Val1)
- end
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_alu/2
-%% Purpose : do symbolic exection of a alu
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : { FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_alu(Inst, Env) ->
- Val1 = lookup_lattice_value(hipe_rtl:alu_src1(Inst), Env),
- Val2 = lookup_lattice_value(hipe_rtl:alu_src2(Inst), Env),
- {NewVal, _, _, _, _} = evaluate_alu(Val1, hipe_rtl:alu_op(Inst), Val2),
- set_to(hipe_rtl:alu_dst(Inst), NewVal, Env).
-
-%% Here follows the alu-evaluation stuff. This is the most involved part I
-%% guess. The function that you may want to use is evaluate_alu/3. The
-%% evaluation functions returns
-%% { Result, SignFlag, ZeroFlag, Overflow flag, CarryBit}
-%% it uses some helpers which are explained breifly:
-%% lattice_meet/2 - handles the general case of most alu-operations, called
-%% when at least one of the operands is nonconstant, and the
-%% operation-specifics have been taken care of.
-%% all_ones/0 - returns the value of a rtl-word set to all 1 bits.
-%% partial_eval_alu - tries to catch some operation specific special cases
-%% when one (or both) of the operands is nonconstant.
-
-lattice_meet(Val1, Val2) ->
- M = if (Val1 =:= top) or (Val2 =:= top) -> top;
- (Val1 =:= bottom) or (Val2 =:= bottom) -> bottom
- % the check is realy just sanity
- end,
- {M, M, M, M, M}.
-
-all_ones() ->
- (1 bsl ?bytes_to_bits(hipe_rtl_arch:word_size())) - 1.
-
-%% when calling partial_eval*() we know that at least one of the Values
-%% are bottom or top. They return { Value, Sign, Zero, Overflow, Carry }.
-%% (just like hipe_rtl_arch:eval_alu)
-
-%% logic shifts are very similar each other. Limit is the number of
-%% bits in the words.
-partial_eval_shift(Limit, Val1, Val2) ->
- if
- Val2 =:= 0 -> {Val1, Val1, Val1, Val1, Val1};
- Val1 =:= 0 -> {0, false, true, false, false};
- is_integer(Val2), Val2 >= Limit -> % (Val2 =/= top) and (Val2 =/= bottom)
- {0, false, true, Val1, Val1}; % OVerflow & carry we dont know about.
- true -> lattice_meet(Val1, Val2)
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : partial_eval_alu/3
-%% Purpose : try to evaluate as much as possible an alu operation where at
-%% least one of the operands is not constant.
-%% Arguments : Val1, Val2 - operands (integer, top or bottom)
-%% Op - the operation.
-%% Returns : {Result, Sign, Zero, Overflow, Carry}
-%% where Result is an integer, 'top' or 'bottom'
-%% and the others are bool, 'top' or 'bottom'.
-%%-----------------------------------------------------------------------------
-
-partial_eval_alu(Val1, add, Val2) ->
- if
- (Val1 == 0) -> {Val2, Val2, Val2, false, false};
- (Val2 == 0) -> {Val1, Val1, Val1, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, sub, Val2) ->
- if
- (Val2 == 0) -> {Val1, Val1, Val1, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, 'or', Val2) ->
- All_ones = all_ones(),
- if
- (Val1 == 0) -> {Val2, Val2, Val2, false, false};
- (Val2 == 0) -> {Val1, Val1, Val1, false, false};
- (Val1 == All_ones) or (Val2 == All_ones) ->
- {All_ones, true, false, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, 'and', Val2) ->
- All_ones = all_ones(),
- if
- Val1 == All_ones -> {Val2, Val2, Val2, false, false};
- Val2 == All_ones -> {Val1, Val1, Val1, false, false};
- (Val1 == 0) or (Val2 == 0) -> {0, false, true, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, 'xor', Val2) ->
- if
- (Val1 == 0) -> {Val2, Val2, Val2, false, false};
- (Val2 == 0) -> {Val1, Val1, Val1, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, 'xornot', Val2) ->
- All_ones = all_ones(),
- if
- Val1 == All_ones -> {Val2, Val2, Val2, false, false};
- Val2 == All_ones -> {Val1, Val1, Val1, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, andnot, Val2) ->
- All_ones = all_ones(),
- if
- (Val2 == 0) -> {Val1, Val1, Val1, false, false};
- (Val1 == 0) or (Val2 == All_ones) -> {0, false, true, false, false};
- true -> lattice_meet(Val1, Val2)
- end;
-partial_eval_alu(Val1, Op, Val2) when (Op =:= 'sll') or (Op =:= 'srl') ->
- BitSize = ?bytes_to_bits(hipe_rtl_arch:word_size()),
- partial_eval_shift(BitSize, Val1, Val2);
-partial_eval_alu(Val1, Op, Val2) when (Op =:= 'sllx') or (Op =:= 'srlx') ->
- partial_eval_shift(64, Val1, Val2);
-partial_eval_alu(Val1, mul, Val2) -> lattice_meet(Val1, Val2); % XXX: suboptimal
-
-% arithmetic shifts are more tricky, shifting something unknown can
-% generate all_ones() and 0 depenging on the sign of Val1.
-partial_eval_alu(Val1, Op, Val2) when (Op =:= 'sra') or (Op =:= 'srax') ->
- if
- (Val2 == 0) -> {Val1, Val1, Val1, false, false};
- (Val1 == 0) -> {0, false, true, false, false};
- true -> lattice_meet(Val1, Val2)
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : evaluate_alu/3
-%% Purpose : try to evaluate as much as possible of a alu operation.
-%% Arguments : Val1, Val2 - operands (an integer, 'top' or 'bottom')
-%% Op - the operation.
-%% Returns : {Result, Sign, Zero, Overflow, Carry}
-%% where result is an integer, 'top' or 'bottom'
-%% and the others are Bool, 'top' or 'bottom'.
-%%-----------------------------------------------------------------------------
-
-evaluate_alu(Val1, Op, Val2) ->
- if
- (Val1 =:= top) or (Val2 =:= top) or
- (Val1 =:= bottom) or (Val2 =:= bottom) -> partial_eval_alu(Val1, Op, Val2);
- true ->
- case Op of
- sllx -> hipe_rtl_arith_64:eval_alu('sll', Val1, Val2);
- srlx -> hipe_rtl_arith_64:eval_alu('srl', Val1, Val2);
- srax -> hipe_rtl_arith_64:eval_alu('sra', Val1, Val2);
- _ -> hipe_rtl_arch:eval_alu(Op, Val1, Val2)
- end
- end.
-
-maybe_top_or_bottom(List) ->
- maybe_top_or_bottom(List, false).
-
-maybe_top_or_bottom([], TB) -> TB;
-maybe_top_or_bottom([top | Rest], _) -> maybe_top_or_bottom(Rest, top);
-maybe_top_or_bottom([bottom | _], _) -> bottom;
-maybe_top_or_bottom([_ | Rest], TB) -> maybe_top_or_bottom(Rest, TB).
-
--spec partial_eval_branch(hipe_rtl:alub_cond(), bool_lattice(), bool_lattice(),
- bool_lattice() | 0, bool_lattice() | 0) ->
- bool_lattice().
-partial_eval_branch(Cond, N0, Z0, V0, C0) ->
- {N, Z, V, C} =
- if Cond =:= 'eq';
- Cond =:= 'ne' -> {true, Z0, true, true};
- Cond =:= 'gt';
- Cond =:= 'le' -> {N0, Z0, V0, true};
- Cond =:= 'leu';
- Cond =:= 'gtu' -> {true, Z0, true, C0 };
- Cond =:= 'lt';
- Cond =:= 'ge' -> {N0, true, V0, true};
- Cond =:= 'geu';
- Cond =:= 'ltu' -> {true, true, true, C0 };
- Cond =:= 'overflow';
- Cond =:= 'not_overflow' -> {true, true, V0, true}
- end,
- case maybe_top_or_bottom([N, Z, V, C]) of
- false -> hipe_rtl_arch:eval_cond_bits(Cond, N, Z, V, C);
- top -> top;
- bottom -> bottom
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_alub/2
-%% Purpose : do symbolic exection of a alub instruction
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : { FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_alub(Inst, Env) ->
- Val1 = lookup_lattice_value(hipe_rtl:alub_src1(Inst), Env),
- Val2 = lookup_lattice_value(hipe_rtl:alub_src2(Inst), Env),
- {NewVal, N, Z, C, V} = evaluate_alu(Val1, hipe_rtl:alub_op(Inst), Val2),
- Labels =
- case NewVal of
- bottom -> [hipe_rtl:alub_true_label(Inst),
- hipe_rtl:alub_false_label(Inst)];
- top -> [];
- _ ->
- %% if the partial branch cannot be evaluated we must execute the
- %% instruction at runtime.
- case partial_eval_branch(hipe_rtl:alub_cond(Inst), N, Z, C, V) of
- bottom -> [hipe_rtl:alub_true_label(Inst),
- hipe_rtl:alub_false_label(Inst)];
- top -> [];
- true -> [hipe_rtl:alub_true_label(Inst)];
- false -> [hipe_rtl:alub_false_label(Inst)]
- end
- end,
- {[], NewSSA, NewEnv} =
- case hipe_rtl:alub_has_dst(Inst) of
- false -> {[], [], Env};
- true -> set_to(hipe_rtl:alub_dst(Inst), NewVal, Env)
- end,
- {Labels, NewSSA, NewEnv}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_fixnumop/2
-%% Purpose : do symbolic exection of a fixnumop instruction.
-%% fixnumop is like a specialized alu.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : { FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_fixnumop(Inst, Env) ->
- Val = lookup_lattice_value(hipe_rtl:fixnumop_src(Inst), Env),
- Res = evaluate_fixnumop(Val, hipe_rtl:fixnumop_type(Inst)),
- set_to(hipe_rtl:fixnumop_dst(Inst), Res, Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_f*
-%% Purpose : Do symbolic execution of floating point instructions.
-%% All floating-point hitngs are mapped to bottom. In order to
-%% implement them we would have to add hipe_rtl_arch:eval_f*
-%% instructions since floating point is no exact science.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_fconv(Inst, Env) ->
- set_to(hipe_rtl:fconv_dst(Inst), bottom, Env).
-
-visit_fp(Inst, Env) ->
- set_to(hipe_rtl:fp_dst(Inst), bottom, Env).
-
-visit_fp_unop(Inst, Env) ->
- set_to(hipe_rtl:fp_unop_dst(Inst), bottom, Env).
-
-visit_fload(Inst, Env) ->
- set_to(hipe_rtl:fload_dst(Inst), bottom, Env).
-
-visit_fmove(Inst, Env) ->
- set_to(hipe_rtl:fmove_dst(Inst), bottom, Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_move/2
-%% Purpose : execute a register-copy
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_move(Inst, Env) ->
- Src = hipe_rtl:move_src(Inst),
- Dst = hipe_rtl:move_dst(Inst),
- set_to(Dst, lookup_lattice_value(Src, Env), Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_goto/2
-%% Purpose : execute a goto
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_goto(Instruction, Environment) ->
- GotoLabel = hipe_rtl:goto_label(Instruction),
- {[GotoLabel], [], Environment}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_goto_index/2
-%% Purpose : execute a goto_index
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_goto_index(Inst, Env) ->
- Index = hipe_rtl:goto_index_index(Inst),
- case lookup_lattice_value(Index, Env) of
- top -> { [], [], Env };
- bottom -> %% everything is reachable
- { hipe_rtl:goto_index_labels(Inst), [], Env };
- I -> %% only the ith label will be taken.
- io:format("hipe_rtl_ssa_const_prop foud goto-index with constant index ~w in ~w\n",
- [I, Inst]),
- { [ lists:nth(hipe_rtl:goto_index_labels(Inst), I) ], [], Env }
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_load/2
-%% Purpose : do a visit_load. Its hard to track whats in memory, and it's
-%% not in ssa form, so let's assume bottom-values !
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_load(Inst, Env) ->
- set_to(hipe_rtl:load_dst(Inst), bottom, Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_load_address/2
-%% Purpose : execute a load_address instruction, while there might be things
-%% here that are runtime-constant they are not compile-time
-%% constant since code loading interferes with addresses.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_load_address(Inst, Env) ->
- Dst = hipe_rtl:load_address_dst(Inst),
- Val = bottom, %% all these are probably run-time, but not
- %% compile-time constants
- set_to(Dst, Val, Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_load_atom/2
-%% Purpose : Like loadadress this one gets something that is not
-%% compiletime-constant
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_load_atom(Inst, Env) ->
- set_to(hipe_rtl:load_atom_dst(Inst), bottom, Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_load_word_index/2
-%% Purpose : execute a load_word_index. Here is probably room for
-%% improvement, we should be able to find some constants here,
-%% since we can get the labeled values from the environment, and
-%% then find the value with the given index.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_load_word_index(Inst, Env) ->
- io:format(" this is load word index: ~w\n", [Inst]),
- set_to(hipe_rtl:load_word_index_dst(Inst), bottom, Env).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_multimove/2 & visit_multimove/4
-%% Purpose : execute a multimove instruction.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_multimove([Dst | Dsts], [Val | Vals], MyEnv, MySSA) ->
- {NewEnv, NewSSA} = update_lattice_value({Dst, Val}, MyEnv),
- visit_multimove(Dsts, Vals, NewEnv, MySSA ++ NewSSA);
-visit_multimove([], [], MyEnv, MySSA) ->
- {MyEnv, MySSA}.
-
-visit_multimove(Inst, Env) ->
- Srcs = [lookup_lattice_value(S, Env) ||
- S <- hipe_rtl:multimove_srclist(Inst)],
- {NewEnv, NewSSA} = visit_multimove(hipe_rtl:multimove_dstlist(Inst),
- Srcs, Env, []),
- {[], NewSSA, NewEnv}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_call/2
-%% Purpose : execute a call-instruction. All calls return bottom. We make
-%% this assumption since the icode-leel have taken care of BIF's
-%% and we belive that we are left with the things that cannot be
-%% done att compile time.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-visit_call(Inst, Env) ->
- {Env1, SSAWork} =
- update_lattice_value({hipe_rtl:call_dstlist(Inst), bottom}, Env),
- % remeber to add both continuation & failto things to the cfgwl
- Cont = case hipe_rtl:call_continuation(Inst) of
- [] -> [];
- C -> [C]
- end,
- Succ = case hipe_rtl:call_fail(Inst) of
- [] -> Cont;
- Fail -> [Fail | Cont]
- end,
- {Succ, SSAWork, Env1}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_switch/2
-%% Purpose : execute a switch-statement.
-%% Arguments : Inst - The instruction
-%% Env - The environment
-%% Returns : {FlowWorkList, SSAWorkList, NewEnvironment}
-%%-----------------------------------------------------------------------------
-
-%% first two helpers that are used to handle the mapping from value to label.
-%% why isn't there a function that does this ?
-
-find_switch_label(Inst, Val) ->
- Labels = hipe_rtl:switch_labels(Inst),
- ?SCCPDBG(io:format("finding switch_label, ~w in ~w\n", [Val,Inst])),
- %% it seems like the index is zero based. nth uses 1-based indexing.
- lists:nth(Val + 1, Labels).
-
-%% Switches seem tricky. the sort-order is a list of key-values to be
-%% tested in order. (if elem i matches then we should jump to elem i of
-%% the labels-list)
-visit_switch(Inst, Env) ->
- case lookup_lattice_value(hipe_rtl:switch_src(Inst), Env) of
- top ->
- {[], [], Env};
- bottom ->
- {hipe_rtl:switch_labels(Inst), [], Env};
- Val ->
- {[find_switch_label(Inst, Val) ], [], Env}
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_instruction/2
-%% Purpose : update the given instruction using any information found in
-%% the environment.
-%% Arguments : Inst - the instruction
-%% Environment - in which everything happens.
-%% Returns : list of new instructions.
-%%-----------------------------------------------------------------------------
-
-%% idea: what to do with vi <- Constant. wouldn't it be possible to
-%% remove those ? (and similarily for alu-instructions. and alub
-%% instructions also ! (of course this will be done in some later step dead
-%% code elimination ? but it's a simple check.)
-update_instruction(Inst, Env) ->
- case Inst of
- #alu{} ->
- update_alu(Inst, Env);
- #alub{} ->
- update_alub(Inst, Env);
- #call{} ->
- subst_all_uses(Inst, Env);
-%% #comment{} ->
-%% [Inst];
- #enter{} ->
- subst_all_uses(Inst, Env);
- #fconv{} ->
- subst_all_uses(Inst, Env);
- #fload{} ->
- subst_all_uses(Inst, Env);
- #fmove{} ->
- subst_all_uses(Inst, Env);
- #fp{} ->
- subst_all_uses(Inst, Env);
- #fp_unop{} ->
- subst_all_uses(Inst, Env);
- #fstore{} ->
- subst_all_uses(Inst, Env);
- #gctest{} ->
- subst_all_uses(Inst, Env);
-%% #goto{} ->
-%% [ Inst ];
- #goto_index{} ->
- update_goto_index(Inst, Env);
-%% #label{} ->
-%% [ Inst ];
- #load{} ->
- subst_all_uses(Inst, Env);
- #load_address{} ->
- subst_all_uses(Inst, Env);
- #load_atom{} ->
- subst_all_uses(Inst, Env);
- #load_word_index{} ->
- subst_all_uses(Inst, Env);
- #move{} ->
- subst_all_uses(Inst, Env);
- #multimove{} ->
- subst_all_uses(Inst, Env);
- #return{} ->
- subst_all_uses(Inst, Env);
- #store{} ->
- subst_all_uses(Inst, Env);
- #switch{} ->
- update_switch(Inst, Env);
- #phi{} ->
- update_phi(Inst, Env);
- _ -> % for the others it's sufficient to just update any thing they use.
- [ Inst ]
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : subst_uses/2
-%% Purpose : looks up all things that an instruction uses and replaces
-%% anything that is determined to be constant.
-%% Arguments : Inst - the instruction
-%% Env - in which everything happen.
-%% Returns : list of instructions to replace Inst with.
-%%-----------------------------------------------------------------------------
-
-subst_all_uses(Inst, Env) ->
- Uses = hipe_rtl_ssa:uses_to_rename(Inst),
- [ hipe_rtl:subst_uses(update_srcs(Uses, Env), Inst) ].
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_srcs/2
-%% Purpose : given the things that a instruction use return a list
-%% {Src, NewValue} pairs that can be sent to subs_uses.
-%% Arguments : Srcs - list of uses
-%% Env - in which everything happens.
-%% Returns : list of {Src, NewValue} pairs.
-%%-----------------------------------------------------------------------------
-
-update_srcs(Srcs, Env) ->
- Update =
- fun(Src, Os) ->
- case lookup_lattice_value(Src, Env) of
- bottom -> Os;
- top -> % this would be realy strange.
- ?EXIT({"update_src, top", Src });
- Constant ->
- [ {Src, hipe_rtl:mk_imm(Constant)} | Os]
- end
- end,
- lists:foldl(Update, [], Srcs ).
-
-%%-----------------------------------------------------------------------------
-%% functions for performing partial evaluation of alu-operations. They can
-%% return either an integer (the actual result), move_src1 or move_src2 in
-%% which case the alu-operation can be replace with a move, or keep_it in
-%% which case the instruction must be kept.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : partial_update_shift/3
-%% Purpose : perform a shift
-%% Arguments : Limit - the number of bits in the word to shift.
-%% Val1 - the shiftee
-%% Val2 - number of bits to shift
-%% Returns : Integer, move_src1, keep_it
-%%-----------------------------------------------------------------------------
-
-partial_update_shift(Limit, Val1, Val2) ->
- if
- (Val1 =:= bottom) and (Val2 =:= 0) -> move_src1;
- (Val1 =:= 0) or ((Val2 =/= bottom) and (Val2 >= Limit)) -> 0;
- true -> keep_it
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : partial_update_alu/3
-%% Purpose : perform as much of alu-operations where exatcly one of the
-%% operands is bottom.
-%% Arguments : Val1, Val2 - operands
-%% Op - the operation.
-%% Returns : Integer, move_src1, move_src2, keep_it
-%%-----------------------------------------------------------------------------
-
-%% we know that exactly one of the operands are bottom this one
-%% returns what to do with the instruction (it's either replace with
-%% src1, replace src2 replace with constant or keep it.
-
-partial_update_alu(Val1, 'add', Val2) ->
- if
- (Val1 == 0) -> move_src2;
- (Val2 == 0) -> move_src1;
- true -> keep_it
- end;
-partial_update_alu(_Val1, 'sub', Val2) ->
- if
- (Val2 == 0) -> move_src1;
- true -> keep_it
- end;
-partial_update_alu(Val1, 'or', Val2) ->
- All_ones = all_ones(),
- if
- (Val1 == 0) -> move_src2;
- (Val2 == 0) -> move_src1;
- (Val1 == All_ones) or (Val2 == All_ones) -> All_ones;
- true -> keep_it
- end;
-partial_update_alu(Val1, 'and', Val2) ->
- All_ones = all_ones(),
- if
- Val1 == All_ones -> move_src2;
- Val2 == All_ones -> move_src1;
- (Val1 == 0) or (Val2 == 0) -> 0;
- true -> keep_it
- end;
-partial_update_alu(Val1, 'xor', Val2) ->
- if
- (Val1 == 0) -> move_src2;
- (Val2 == 0) -> move_src1;
- true -> keep_it
- end;
-partial_update_alu(Val1, 'xornot', Val2) ->
- All_ones = all_ones(),
- if
- (Val1 == All_ones) -> move_src2;
- (Val2 == All_ones) -> move_src1;
- true -> keep_it
- end;
-partial_update_alu(Val1, andnot, Val2) ->
- All_ones = all_ones(),
- if
- Val2 == 0 -> move_src1;
- (Val1 == 0) or (Val2 == All_ones) -> 0;
- true -> keep_it
- end;
-partial_update_alu(Val1, Op, Val2) when (Op =:= 'sll') or (Op =:= 'srl') ->
- BitSize = ?bytes_to_bits(hipe_rtl_arch:word_size()),
- partial_update_shift(BitSize, Val1, Val2);
-partial_update_alu(Val1, Op, Val2) when (Op =:= 'sllx') or (Op =:= 'srlx') ->
- partial_update_shift(64, Val1, Val2);
-partial_update_alu(Val1, Op, Val2) when (Op =:= 'sra') or (Op =:= 'srax') ->
- if
- Val2 == 0 -> move_src1;
- Val1 == 0 -> 0;
- true -> keep_it
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_alu/2
-%% Purpose : update an alu-instruction.
-%% Arguments : Inst - the instruction.
-%% Env - in which everything happens.
-%% Returns : list of new instruction
-%%-----------------------------------------------------------------------------
-
-update_alu(Inst, Env) ->
- Val1 = lookup_lattice_value(hipe_rtl:alu_src1(Inst), Env),
- Val2 = lookup_lattice_value(hipe_rtl:alu_src2(Inst), Env),
- if
- (Val1 =:= bottom) and (Val2 =:= bottom) ->
- [Inst];
- (Val1 =:= bottom) or (Val2 =:= bottom) ->
- NewInst =
- case partial_update_alu(Val1, hipe_rtl:alu_op(Inst), Val2) of
- move_src1 ->
- hipe_rtl:mk_move(hipe_rtl:alu_dst(Inst), hipe_rtl:alu_src1(Inst));
- move_src2 ->
- hipe_rtl:mk_move(hipe_rtl:alu_dst(Inst), hipe_rtl:alu_src2(Inst));
- keep_it ->
- S1 = make_alub_subst_list(Val1, hipe_rtl:alu_src1(Inst), []),
- S2 = make_alub_subst_list(Val2, hipe_rtl:alu_src2(Inst), S1),
- hipe_rtl:subst_uses(S2, Inst);
- Constant ->
- hipe_rtl:mk_move(hipe_rtl:alu_dst(Inst), hipe_rtl:mk_imm(Constant))
- end,
- [NewInst];
- true ->
- {Val,_,_,_,_} = evaluate_alu(Val1, hipe_rtl:alu_op(Inst), Val2),
- [hipe_rtl:mk_move(hipe_rtl:alu_dst(Inst), hipe_rtl:mk_imm(Val))]
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_alub/2
-%% Purpose : update an alub-instruction. Here are some finer points, we might
-%% be able to do the math (think b = a+0), but it's hard to replace
-%% the branch, since the mapping b/w AluOp,RelOp to BranchInstr is
-%% boring to do. (lazyness is a bliss).
-%% Arguments : Inst - the instruction.
-%% Env - in which everything happens.
-%% Returns : list of new instructions
-%%-----------------------------------------------------------------------------
-
-%% some small helpers.
-alub_to_move(Inst, Res, Lab) ->
- Goto = [hipe_rtl:mk_goto(Lab)],
- case hipe_rtl:alub_has_dst(Inst) of
- false -> Goto;
- true ->
- [hipe_rtl:mk_move(hipe_rtl:alub_dst(Inst), Res) | Goto]
- end.
-
-make_alub_subst_list(bottom, _, Tail) -> Tail;
-make_alub_subst_list(top, Src, _) ->
- ?EXIT({"~w is top during update",Src });
-make_alub_subst_list(Val, Src, Tail) ->
- case hipe_rtl:is_imm(Src) of
- true -> Tail;
- false -> [{Src, hipe_rtl:mk_imm(Val)} | Tail]
- end.
-
-update_alub(Inst, Env) ->
- Src1 = hipe_rtl:alub_src1(Inst),
- Src2 = hipe_rtl:alub_src2(Inst),
- Val1 = lookup_lattice_value(Src1, Env),
- Val2 = lookup_lattice_value(Src2, Env),
- {ResVal, N, Z, C, V} = evaluate_alu(Val1, hipe_rtl:alub_op(Inst), Val2),
- CondRes = partial_eval_branch(hipe_rtl:alub_cond(Inst), N, Z, C, V),
- case CondRes of
- bottom ->
- %% if we can't evaluate the branch, we have to keep it as a alub isnt
- %% since other optimizations might insert other instructions b/w the
- %% move and the branch. We can however replace variable with constants:
- S1 = make_alub_subst_list(Val1, Src1, []),
- S2 = make_alub_subst_list(Val2, Src2, S1),
- [hipe_rtl:subst_uses(S2, Inst)];
- _ -> %% we know where we will be going, let's find out what Dst should be.
- %% knowing where we are going means that at most one of the values is
- %% bottom, hence we can replace the alu-instr with a move.
- %% remember, a = b + 0 can give us enough info to know what jump to
- %% do without knowing the value of a. (I wonder if this will ever
- %% actualy happen ;)
- Res = case ResVal of
- bottom -> % something nonconstant.
- if (Val1 =:= bottom) -> Src1;
- (Val2 =:= bottom) -> Src2
- end;
- _ -> hipe_rtl:mk_imm(ResVal)
- end,
- case CondRes of
- top ->
- io:format("oops. something VERY bad: ~w ~w V1 & 2 ~w ~w\n",
- [Inst, {ResVal, N, Z, C, V} , Val1, Val2]),
- [Inst];
- true -> alub_to_move(Inst, Res, hipe_rtl:alub_true_label(Inst));
- false -> alub_to_move(Inst, Res, hipe_rtl:alub_false_label(Inst))
- end
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_goto_index/2
-%% Purpose : update a goto_index instruction.
-%% Arguments : Inst - the instruction.
-%% Env - in which everything happens.
-%% Returns : list of new instructions.
-%%-----------------------------------------------------------------------------
-
-update_goto_index(Inst, Env) ->
- Index = hipe_rtl:goto_index_index(Inst),
- case lookup_lattice_value(Index, Env) of
- bottom -> %% everything is reachable
- [Inst];
- I -> %% only the ith label will be taken.
- [hipe_rtl:mk_goto(lists:nth(hipe_rtl:goto_index_labels(Inst), I))]
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_switch/2
-%% Purpose : update a switch instruction.
-%% Arguments : Inst - the instruction.
-%% Env - in which everything happens.
-%% Returns : list of new instructions.
-%%-----------------------------------------------------------------------------
-
-update_switch(Inst, Env) ->
- case lookup_lattice_value(hipe_rtl:switch_src(Inst), Env) of
- bottom ->
- [Inst];
- Const ->
- Lab = find_switch_label(Inst, Const),
- [hipe_rtl:mk_goto(Lab)]
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_phi/3
-%% Purpose : Update a phi-function w.r.t. constants. do nothing for now.
-%% Arguments : Instruction - The instruction
-%% Environment - The environment
-%% Returns : [NewInstruction]
-%%-----------------------------------------------------------------------------
-
-update_phi(Instruction, Environment) ->
- Destination = hipe_rtl:phi_dst(Instruction),
- case lookup_lattice_value(Destination, Environment) of
- bottom ->
- [Instruction];
- top ->
- ?WARNING_MSG("The dst of ~w is top after SCCP. Strange\n",[Instruction]),
- ?EXIT({"bang !", Instruction}),
- [Instruction];
- Value ->
- [hipe_rtl:mk_move(Destination, hipe_rtl:mk_imm(Value))]
- end.
-
-%%-----------------------------------------------------------------------------
-
-%% make sure that all precoloured registers are taken out of the equation.
-lookup_lattice_value(X, Environment) ->
- case hipe_rtl_arch:is_precoloured(X) or hipe_rtl:is_const_label(X) of
- true ->
- bottom;
- false ->
- lookup_lattice_value2(X, Environment)
- end.
-
-lookup_lattice_value2(X, Environment) ->
- LatticeValues = env__lattice_values(Environment),
- case hipe_rtl:is_imm(X) of
- true ->
- hipe_rtl:imm_value(X);
- false ->
- case gb_trees:lookup(X, LatticeValues) of
- none ->
- io:format("~w~n",[LatticeValues]),
- ?WARNING_MSG("Earlier compiler steps generated erroneous "
- "code for X = ~w. We are ignoring this.\n",[X]),
- bottom;
- {value, top} ->
- ?EXIT({"lookup_lattice_value, top", X}),
- top;
- {value, Y} ->
- Y
- end
- end.
-
-%%----------------------------- End of file -----------------------------------
diff --git a/lib/hipe/rtl/hipe_rtl_ssapre.erl b/lib/hipe/rtl/hipe_rtl_ssapre.erl
deleted file mode 100644
index eacaa28196..0000000000
--- a/lib/hipe/rtl/hipe_rtl_ssapre.erl
+++ /dev/null
@@ -1,1666 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% File : hipe_rtl_ssapre.erl
-%% Author : He Bingwen and Frédéric Haziza
-%% Description : Performs Partial Redundancy Elimination on SSA form.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% @doc
-%%
-%% This module implements the <a href="http://cs.wheaton.edu/%7Etvandrun/writings/spessapre.pdf">Anticipation-SSAPRE algorithm</a>,
-%% with several modifications for Partial Redundancy Elimination on SSA form.
-%% We actually found problems in this algorithm, so
-%% we implement another version with several advantages:
-%% - No loop for Xsi insertions
-%% - No fix point iteration for the downsafety part
-%% - Less computations for Will Be Available part
-%% - Complexity of the overall algorithm is improved
-%%
-%% We were supposed to publish these results anyway :D
-%%
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_ssapre).
-
--export([rtl_ssapre/2]).
-
--include("../main/hipe.hrl").
--include("hipe_rtl.hrl").
-
-%%-define(SSAPRE_DEBUG, true ). %% When uncommented, produces debug printouts
--define( SETS, ordsets ). %% Which set implementation module to use
--define( CFG, hipe_rtl_cfg ).
--define( RTL, hipe_rtl ).
--define( BB, hipe_bb ).
--define( ARCH, hipe_rtl_arch ).
--define( GRAPH, digraph ).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Debugging stuff
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--ifndef(SSAPRE_DEBUG).
--define(pp_debug(_Str, _Args), ok).
--else.
--define(pp_debug(Str, Args), io:format(standard_io, Str, Args)).
--endif.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Records / Structures
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--record(xsi_link, {num}). %% Number is the index of the temporary (a Key into the Xsi Tree)
--record(temp, {key, var}).
--record(bottom, {key, var}).
--record(xsi, {inst, %% Associated instruction
- def, %% Hypothetical temporary variable
- %% that stores the result of the computation
- label, %% Block Label where the xsi is inserted
- opList, %% List of operands
- cba, %%
- later, %%
- wba
- }).
-
--record(pre_candidate, {alu, def}).
--record(xsi_op, {pred, op}).
-
--record(mp, {xsis, maps, preds, defs, uses, ndsSet}).
--record(block, {type, attributes}).
-
--record(eop, {expr, var, stopped_by}).
--record(insertion, {code, from}).
-
--record(const_expr, {var, value}).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Main function
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-rtl_ssapre(RtlSSACfg, Options) ->
- %% io:format("\n################ Original CFG ################\n"),
- %% hipe_rtl_cfg:pp(RtlSSACfg),
- %% io:format("\n\n############ SSA-Form CHECK ==> ~w\n",[hipe_rtl_ssa:check(RtlSSACfg)]),
-
- {CFG2,XsiGraph,CFGGraph,MPs} = perform_Xsi_insertion(RtlSSACfg,Options),
- %%?pp_debug("~n~n################ Xsi CFG ################\n",[]),pp_cfg(CFG2,XsiGraph),
- XsiList = ?GRAPH:vertices(XsiGraph),
- case XsiList of
- [] ->
- %% No Xsi
- ?pp_debug("~n~n################ No Xsi Inserted ################~n",[]),
- ok;
- _ ->
- ?pp_debug("~n############ Downsafety ##########~n",[]),
- ?option_time(perform_downsafety(MPs,CFGGraph,XsiGraph),"RTL A-SSAPRE Downsafety",Options),
- ?pp_debug("~n~n################ CFG Graph ################~n",[]),pp_cfggraph(CFGGraph),
- ?pp_debug("~n############ Will Be Available ##########~n",[]),
- ?option_time(perform_will_be_available(XsiGraph,CFGGraph,Options),"RTL A-SSAPRE WillBeAvailable",Options)
- end,
-
- ?pp_debug("~n############ No more need for the CFG Graph....Deleting...",[]),?GRAPH:delete(CFGGraph),
- ?pp_debug("~n~n################ Xsi Graph ################~n",[]),pp_xsigraph(XsiGraph),
-
- ?pp_debug("~n############ Code Motion ##########~n",[]),
- Labels = ?CFG:preorder(CFG2),
-
- ?pp_debug("~n~n################ Xsi CFG ################~n",[]),pp_cfg(CFG2,XsiGraph),
-
- init_redundancy_count(),
- FinalCFG = ?option_time(perform_code_motion(Labels,CFG2,XsiGraph),"RTL A-SSAPRE Code Motion",Options),
-
- ?pp_debug("\n############ No more need for the Xsi Graph....Deleting...",[]),?GRAPH:delete(XsiGraph),
-
- %% io:format("\n################ Final CFG ################\n"),
- %% hipe_rtl_cfg:pp(FinalCFG),
- %% io:format("\n\n############ SSA-Form CHECK ==> ~w\n",
- %% [hipe_rtl_ssa:check(FinalCFG)]),
- ?pp_debug("\nSSAPRE : ~w redundancies were found\n",[get_redundancy_count()]),
-
- FinalCFG.
-
-%% ##########################################################################
-%% ######################## XSI INSERTION ###################################
-%% ##########################################################################
-
-perform_Xsi_insertion(Cfg, Options) ->
- init_counters(), %% Init counters for Bottoms and Temps
- DigraphOpts = [cyclic, private],
- XsiGraph = digraph:new(DigraphOpts),
- %% Be careful, the digraph component is NOT garbage collected,
- %% so don't create 20 millions of instances!
- %% finds the longest depth
- %% Depth-first, preorder traversal over Basic Blocks.
- %%Labels = ?CFG:reverse_postorder(Cfg),
- Labels = ?CFG:preorder(Cfg),
-
- ?pp_debug("~n~n############# Finding definitions for computation~n~n",[]),
- {Cfg2,XsiGraph} = ?option_time(find_definition_for_computations(Labels,Cfg,XsiGraph),"RTL A-SSAPRE Xsi Insertion, searching from instructions",Options),
-
- %% Active List creation
- GeneratorXsiList = lists:sort(?GRAPH:vertices(XsiGraph)),
- ?pp_debug("~n~n############# Inserted Xsis ~w",[GeneratorXsiList]),
- ?pp_debug("~n~n############# Finding operands~n",[]),
- {Cfg3,XsiGraph} = ?option_time(find_operands(Cfg2,XsiGraph,GeneratorXsiList,0),"RTL A-SSAPRE Xsi Insertion, finding operands",Options),
-
- %% Creating the CFGGraph
- ?pp_debug("~n~n############# Creating CFG Graph",[]),
- ?pp_debug("~n############# Labels = ~w",[Labels]),
- CFGGraph = digraph:new(DigraphOpts),
- [StartLabel|Others] = Labels, % adding the start label as a leaf
- ?pp_debug("~nAdding a vertex for the start label: ~w",[StartLabel]),
- ?GRAPH:add_vertex(CFGGraph, StartLabel, #block{type = top}),
- % Doing the others
- MPs = ?option_time(create_cfggraph(Others,Cfg3,CFGGraph,[],[],[],XsiGraph),"RTL A-SSAPRE Xsi Insertion, creating intermediate 'SSAPRE Graph'",Options),
-
- %% Return the collected information
- {Cfg3,XsiGraph,CFGGraph,MPs}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-find_definition_for_computations([], Cfg, XsiGraph) ->
- {Cfg,XsiGraph}; %% No more block to inspect in the depth-first order
-find_definition_for_computations([Label|Rest], Cfg, XsiGraph) ->
- Code = ?BB:code(?CFG:bb(Cfg,Label)),
- {NewCfg,XsiGraph} = find_definition_for_computations_in_block(Label,Code,Cfg,[],XsiGraph),
- find_definition_for_computations(Rest, NewCfg, XsiGraph).
-
-%%===========================================================================
-%% Searches from instruction for one block BlockLabel.
-%% We process forward over instructions.
-
-find_definition_for_computations_in_block(BlockLabel,[],Cfg,
- VisitedInstructions,XsiGraph)->
- Code = lists:reverse(VisitedInstructions),
- NewBB = ?BB:mk_bb(Code),
- NewCfg = ?CFG:bb_add(Cfg,BlockLabel,NewBB),
- {NewCfg,XsiGraph}; %% No more instructions to inspect in this block
-find_definition_for_computations_in_block(BlockLabel,[Inst|Rest],Cfg,
- VisitedInstructions,XsiGraph) ->
- %% ?pp_debug(" Inspecting instruction: ",[]),pp_instr(Inst,nil),
- case Inst of
- #alu{} ->
- %% Is Inst interesting for SSAPRE?
- %% i.e., is Inst an arithmetic operation which doesn't deal with precoloured?
- %% Note that since we parse forward, we have no 'pre_candidate'-type so far.
- case check_definition(Inst,VisitedInstructions,BlockLabel,Cfg,XsiGraph) of
- {def_found,Def} ->
- %% Replacing Inst in Cfg
- NewInst = #pre_candidate{alu=Inst,def=Def},
- NewVisited = [NewInst|VisitedInstructions],
- %% Recurse forward over instructions, same CFG, same XsiGraph
- find_definition_for_computations_in_block(BlockLabel,Rest,Cfg,
- NewVisited,XsiGraph);
- {merge_point,Xsi} ->
- Def = Xsi#xsi.def,
- Key = Def#temp.key,
- NewInst = #pre_candidate{alu=Inst,def=Def},
- XsiLink = #xsi_link{num=Key},
-
- %% Add a vertex to the Xsi Graph
- ?GRAPH:add_vertex(XsiGraph,Key,Xsi),
- ?pp_debug(" Inserting Xsi: ",[]),pp_xsi(Xsi),
-
- Label = Xsi#xsi.label,
- {NewCfg, NewVisited} =
- case BlockLabel =:= Label of
- false ->
- %% Insert the Xsi in the appropriate block
- Code = hipe_bb:code(?CFG:bb(Cfg,Label)),
- {BeforeCode,AfterCode} = split_for_xsi(lists:reverse(Code),[]),
- NewCode = BeforeCode++[XsiLink|AfterCode],
- NewBB = hipe_bb:mk_bb(NewCode),
- {?CFG:bb_add(Cfg,Label,NewBB), [NewInst|VisitedInstructions]};
- _->
- {BeforeCode,AfterCode} = split_for_xsi(VisitedInstructions,[]),
- TempVisited = BeforeCode++[XsiLink|AfterCode],
- TempVisited2 = lists:reverse(TempVisited),
- {Cfg, [NewInst|TempVisited2]}
- end,
- find_definition_for_computations_in_block(BlockLabel, Rest, NewCfg,
- NewVisited, XsiGraph)
- end;
- _ ->
- %%?pp_debug("~n [L~w] Not concerned with: ~w",[BlockLabel,Inst]),
- %% If the instruction is not a SSAPRE candidate, we skip it and keep on
- %% processing instructions
- %% Prepend Inst, so that we have all in reverse order.
- %% Easy to parse backwards
- find_definition_for_computations_in_block(BlockLabel, Rest, Cfg,
- [Inst|VisitedInstructions], XsiGraph)
- end.
-
-%% ############################################################################
-%% We have E as an expression, I has an alu (arithmetic operation), and
-%% we inspect backwards the previous instructions to find a definition for E.
-%% Since we parse in forward order, we know that the previous SSAPRE
-%% instruction will have a definition.
-
-check_definition(E,[],BlockLabel,Cfg,XsiGraph)->
- %% No more instructions in that block
- %% No definition found in that block
- %% Search is previous blocks
- Preds = ?CFG:pred(Cfg, BlockLabel),
- %% ?pp_debug("~n CHECKING DEFINITION ####### Is L~w a merge block? It has ~w preds. So far E=",[BlockLabel,length(Preds)]),pp_expr(E),
- case Preds of
- [] ->
- %% Entry Point
- {def_found,bottom};
- [P] ->
- %% One predecessor only, we just keep looking for a definition in that block
- VisitedInstructions = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,P))),
- check_definition(E,VisitedInstructions,P,Cfg,XsiGraph);
- _ ->
- Temp = new_temp(),
- %% It's a merge point
- OpList = [#xsi_op{pred=X} || X<-Preds],
- Xsi = #xsi{inst=E,def=Temp,label=BlockLabel,opList=OpList},
- {merge_point,Xsi}
- end;
-check_definition(E,[CC|Rest],BlockLabel,Cfg,XsiGraph) ->
- SRC1 = ?RTL:alu_src1(E),
- SRC2 = ?RTL:alu_src2(E),
- case CC of
- #alu{} ->
- exit({?MODULE,should_not_be_an_alu,
- {"Why the hell do we still have an alu???",CC}});
- #pre_candidate{} ->
- %% C is the previous instruction
- C = CC#pre_candidate.alu,
- DST = ?RTL:alu_dst(C),
- case DST =:= SRC1 orelse DST =:= SRC2 of
- false ->
- case check_match(E,C) of
- true -> %% It's a computation of E!
- %% Get the dst of the alu
- {def_found,DST};
- _->
- check_definition(E,Rest,BlockLabel,Cfg,XsiGraph)
- end;
- true ->
- %% Get the definition of C, since C is PRE-candidate AND has been processed before
- DEF = CC#pre_candidate.def,
- case DEF of
- bottom ->
- %% Def(E)=bottom, STOP
- {def_found,bottom};
- _ ->
- %% Emend E with this def(C)
- %%?pp_debug("Parameters are E=~w, DST=~w, DEF=~w",[E,DST,DEF]),
- F = emend(E,DST,DEF),
- check_definition(F,Rest,BlockLabel,Cfg,XsiGraph) %% Continue the search
- end
- end;
- #move{} ->
- %% It's a move, we emend E, and continue the definition search
- DST = ?RTL:move_dst(CC),
- F = case SRC1 =:= DST orelse SRC2 =:= DST of
- true ->
- SRC = ?RTL:move_src(CC),
- emend(E,DST,SRC);
- _ ->
- E
- end,
- check_definition(F,Rest,BlockLabel,Cfg,XsiGraph); %% Continue the search
- #xsi_link{} ->
- {_K,Xsi} = ?GRAPH:vertex(XsiGraph,CC#xsi_link.num),
- C = Xsi#xsi.inst,
- case check_match(C,E) of
- true -> %% There is a Xsi already with a computation of E!
- %% fetch definition of C, and give it to E
- {def_found,Xsi#xsi.def};
- _->
- check_definition(E,Rest,BlockLabel,Cfg,XsiGraph)
- end;
- #phi{} ->
- %% skip them. NOTE: Important to separate this case from the next one
- check_definition(E,Rest,BlockLabel,Cfg,XsiGraph);
- _ ->
- %% Note: the function calls or some other instructions can change the pre-coloured registers
- %% which are able to be redefined. This breaks of course the SSA form.
- %% If there is a redefinition we can give bottom to the computation, and no xsi will be inserted.
- %% (In some sens, the result of the computation is new at that point.)
- PreColouredTest = ?ARCH:is_precoloured(SRC1) orelse ?ARCH:is_precoloured(SRC2),
-
- %%RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)) orelse ?RTL:is_reg(SRC1) orelse ?RTL:is_reg(SRC2),
- RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)), %% That means we cannot reuse the result held in this register...
-
- case PreColouredTest orelse RegisterTest of
- true ->
- {def_found,bottom};
- false ->
- DC = ?RTL:defines(CC),
- case lists:member(SRC1,DC) orelse lists:member(SRC2,DC) of
- true ->
- {def_found,bottom};
- false ->
- %% Orthogonal to E, we continue the search
- check_definition(E,Rest,BlockLabel,Cfg,XsiGraph)
- end
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-check_match(E, C) ->
- OpE = ?RTL:alu_op(E),
- OpC = ?RTL:alu_op(C),
- case OpE =:= OpC of
- false ->
- false;
- true ->
- Src1E = ?RTL:alu_src1(E),
- Src2E = ?RTL:alu_src2(E),
- Src1C = ?RTL:alu_src1(C),
- Src2C = ?RTL:alu_src2(C),
- case Src1E =:= Src1C of
- true ->
- Src2E =:= Src2C;
- false ->
- Src1E =:= Src2C andalso Src2E =:= Src1C
- end
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-expr_is_const(E) ->
- ?RTL:is_imm(?RTL:alu_src1(E)) andalso ?RTL:is_imm(?RTL:alu_src2(E)).
-%% is_number(?RTL:alu_src1(E)) andalso is_number(?RTL:alu_src2(E)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Must be an arithmetic operation, i.e. #alu{}
-emend(Expr, S, Var) ->
- SRC1 = ?RTL:alu_src1(Expr),
- NewExpr = case SRC1 =:= S of
- true -> ?RTL:alu_src1_update(Expr,Var);
- false -> Expr
- end,
- SRC2 = ?RTL:alu_src2(NewExpr),
- case SRC2 =:= S of
- true -> ?RTL:alu_src2_update(NewExpr,Var);
- false -> NewExpr
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-split_for_xsi([], Acc) ->
- {[], Acc}; % no_xsi_no_phi_found;
-split_for_xsi([I|Is] = Code, Acc) -> %% [I|Is] in backward order, Acc in order
- case I of
- #xsi_link{} ->
- {lists:reverse(Code), Acc};
- #phi{} ->
- {lists:reverse(Code), Acc};
- _ ->
- split_for_xsi(Is, [I|Acc])
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Phase 1.B : Search for operands
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-find_operands(Cfg,XsiGraph,[],_Count) ->
- {Cfg,XsiGraph};
-find_operands(Cfg,XsiGraph,ActiveList,Count) ->
- {NewCfg,TempActiveList} = find_operands_for_active_list(Cfg,XsiGraph,ActiveList,[]),
- NewActiveList = lists:reverse(TempActiveList),
- ?pp_debug("~n################ Finding operands (iteration ~w): ~w have been introduced. Now ~w in total~n",
- [Count+1, length(NewActiveList), length(?GRAPH:vertices(XsiGraph))]),
- find_operands(NewCfg,XsiGraph,NewActiveList,Count+1).
-
-find_operands_for_active_list(Cfg,_XsiGraph,[],ActiveListAcc) ->
- {Cfg,ActiveListAcc};
-find_operands_for_active_list(Cfg,XsiGraph,[K|Ks],ActiveListAcc) ->
- {_Key,Xsi} = ?GRAPH:vertex(XsiGraph,K),
- ?pp_debug("~n Inspecting operands of : ~n",[]),pp_xsi(Xsi),
- Preds = ?CFG:pred(Cfg, Xsi#xsi.label),
- {NewCfg,NewActiveListAcc}=determine_operands(Xsi,Preds,Cfg,K,XsiGraph,ActiveListAcc),
- {_Key2,Xsi2} = ?GRAPH:vertex(XsiGraph,K),
- ?pp_debug("~n ** Final Xsi: ~n",[]),pp_xsi(Xsi2),
- ?pp_debug("~n #####################################################~n",[]),
- find_operands_for_active_list(NewCfg,XsiGraph,Ks,NewActiveListAcc).
-
-determine_operands(_Xsi,[],Cfg,_K,_XsiGraph,ActiveAcc) ->
- %% All operands have been determined.
- %% The CFG is not updated, only the XsiGraph
- {Cfg,ActiveAcc};
-determine_operands(Xsi,[P|Ps],Cfg,K,XsiGraph,ActiveAcc) ->
- Label = Xsi#xsi.label,
- ReverseCode = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,Label))),
- VisitedInstructions = get_visited_instructions(Xsi,ReverseCode),
- Res = determine_e_prime(Xsi#xsi.inst,VisitedInstructions,P,XsiGraph),
- case Res of
- operand_is_bottom ->
- NewXsi = xsi_arg_update(Xsi,P,new_bottom()),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
- determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc);
- operand_is_const_expr ->
- NewXsi = xsi_arg_update(Xsi,P,new_bottom()),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
- determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc);
- {sharing_operand,Op} ->
- NewXsi = xsi_arg_update(Xsi,P,Op),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
- determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc);
- {revised_expression,E_prime} ->
- ?pp_debug(" E' is determined : ",[]),pp_expr(E_prime),
- ?pp_debug(" and going along the edge L~w~n",[P]),
- %% Go along the edge P
- RevCode = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,P))),
- case check_one_operand(E_prime,RevCode,P,Cfg,K,XsiGraph) of
- {def_found,Def} ->
- NewXsi = xsi_arg_update(Xsi,P,Def),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
- determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc);
-
- {expr_found,ChildExpr} ->
- NewXsi = xsi_arg_update(Xsi,P,ChildExpr),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
- determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc);
-
- {expr_is_const, Op} ->
- %% We detected that the expression is of the form: 'N op M'
- %% where N and M are constant.
- NewXsi = xsi_arg_update(Xsi,P,Op),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
- determine_operands(NewXsi,Ps,Cfg,K,XsiGraph,ActiveAcc);
-
- {merge_point,XsiChild} ->
- %% Update that Xsi, give its definition as Operand for the
- %% search, and go on
- XsiChildDef = XsiChild#xsi.def,
- NewXsi = xsi_arg_update(Xsi,P,XsiChildDef),
- ?GRAPH:add_vertex(XsiGraph,K,NewXsi),
-
- KeyChild = XsiChildDef#temp.key,
- XsiChildLink = #xsi_link{num=KeyChild},
- ?GRAPH:add_vertex(XsiGraph,KeyChild,XsiChild),
-
- %% Should not be the same block !!!!!!!
- RCode = lists:reverse(hipe_bb:code(?CFG:bb(Cfg,XsiChild#xsi.label))),
- {BCode,ACode} = split_code_for_xsi(RCode,[]),
-
- NewCode = BCode++[XsiChildLink|ACode],
- NewBB = hipe_bb:mk_bb(NewCode),
- NewCfg = ?CFG:bb_add(Cfg, XsiChild#xsi.label, NewBB),
-
- ?pp_debug(" -- ",[]),pp_arg(Xsi#xsi.def),?pp_debug(" causes insertion of: ~n",[]),pp_xsi(XsiChild),
- ?pp_debug(" -- Adding an edge ",[]),pp_arg(Xsi#xsi.def),?pp_debug(" -> ",[]),pp_arg(XsiChild#xsi.def),
-
- %% Adding an edge...
- %%?GRAPH:add_edge(XsiGraph,K,KeyChild,"family"),
- ?GRAPH:add_edge(XsiGraph,K,KeyChild),
- determine_operands(NewXsi,Ps,NewCfg,K,XsiGraph,[KeyChild|ActiveAcc])
- end
- end.
-
-determine_e_prime(Expr,VisitedInstructions,Pred,XsiGraph) ->
- %% MUST FETCH FROM THE XSI TREE, since Xsis are not updated yet in the CFG
- NewExpr = emend_with_phis(Expr,VisitedInstructions,Pred),
- emend_with_processed_xsis(NewExpr,VisitedInstructions,Pred,XsiGraph).
-
-emend_with_phis(EmendedE, [], _) ->
- EmendedE;
-emend_with_phis(E, [I|Rest], Pred) ->
- case I of
- #phi{} ->
- Dst = ?RTL:phi_dst(I),
- UE = ?RTL:uses(E), %% Should we get SRC1 and SRC2 instead?
- case lists:member(Dst, UE) of
- false ->
- emend_with_phis(E, Rest, Pred);
- true ->
- NewE = emend(E, Dst, ?RTL:phi_arg(I,Pred)),
- emend_with_phis(NewE, Rest, Pred)
- end;
- _ ->
- emend_with_phis(E, Rest, Pred)
- end.
-
-emend_with_processed_xsis(EmendedE, [], _, _) ->
- {revised_expression,EmendedE};
-emend_with_processed_xsis(E, [I|Rest], Pred, XsiGraph) ->
- case I of
- #xsi_link{} ->
- Key = I#xsi_link.num,
- {_KK,Xsi} = ?GRAPH:vertex(XsiGraph,Key),
- Def = Xsi#xsi.def,
- UE = ?RTL:uses(E), %% Should we get SRC1 and SRC2 instead?
- case lists:member(Def,UE) of
- false ->
- CE = Xsi#xsi.inst,
- case check_match(E,CE) of
- true -> %% It's a computation of E!
- case xsi_arg(Xsi,Pred) of
- undetermined_operand ->
- exit({?MODULE,check_operand_sharing,"######## Ôh Dear, we trusted Kostis !!!!!!!!! #############"});
- XsiOp ->
- {sharing_operand,XsiOp} %% They share operands
- end;
- _->
- emend_with_processed_xsis(E,Rest,Pred,XsiGraph)
- end;
- true ->
- A = xsi_arg(Xsi,Pred),
- %% ?pp_debug(" ######### xsi_arg(I:~w,Pred:~w) = ~w~n",[I,Pred,A]),
- case A of
- #bottom{} ->
- operand_is_bottom;
- #const_expr{} ->
- operand_is_const_expr;
- #eop{} ->
- NewE = emend(E,Def,A#eop.var),
- emend_with_processed_xsis(NewE,Rest,Pred,XsiGraph);
- undetermined_operand ->
- exit({?MODULE,emend_with_processed_xsis,"######## Ôh Dear, we trusted Kostis, again !!!!!!!!! #############"});
- XsiOp ->
- NewE = emend(E,Def,XsiOp),
- emend_with_processed_xsis(NewE,Rest,Pred,XsiGraph)
- end
- end;
- _ ->
- emend_with_processed_xsis(E,Rest,Pred,XsiGraph)
- end.
-
-%% get_visited_instructions(Xsi,[]) ->
-%% ?pp_debug("~nWe don't find this xsi with def ",[]),pp_arg(Xsi#xsi.def),?pp_debug(" in L~w : ",[Xsi#xsi.label]),
-%% exit({?MODULE,no_such_xsi_in_block,"We didn't find that Xsi in the block"});
-get_visited_instructions(Xsi, [I|Is]) ->
- case I of
- #xsi_link{} ->
- XsiDef = Xsi#xsi.def,
- Key = XsiDef#temp.key,
- case I#xsi_link.num =:= Key of
- true ->
- Is;
- false ->
- get_visited_instructions(Xsi, Is)
- end;
- _ ->
- get_visited_instructions(Xsi, Is)
- end.
-
-split_code_for_xsi([], Acc) ->
- {[],Acc};
-split_code_for_xsi([I|Is] = Code, Acc) ->
- case I of
- #xsi_link{} ->
- {lists:reverse(Code), Acc};
- #phi{} ->
- {lists:reverse(Code), Acc};
- _ ->
- split_code_for_xsi(Is, [I|Acc])
- end.
-
-check_one_operand(E, [], BlockLabel, Cfg, XsiKey, XsiGraph) ->
- %% No more instructions in that block
- %% No definition found in that block
- %% Search is previous blocks
- Preds = ?CFG:pred(Cfg, BlockLabel),
- case Preds of
- [] ->
- %% Entry Point
- {def_found,new_bottom()};
- [P] ->
- %% One predecessor only, we just keep looking for a definition in that block
- case expr_is_const(E) of
- true ->
- ?pp_debug("\n\n############## Wow expr is constant: ~w",[E]),
- Var = ?RTL:mk_new_var(),
- Value = eval_expr(E),
- Op = #const_expr{var = Var, value = Value},
- {expr_is_const, Op};
- false ->
- VisitedInstructions = lists:reverse(?BB:code(?CFG:bb(Cfg,P))),
- check_one_operand(E, VisitedInstructions, P, Cfg, XsiKey, XsiGraph)
- end;
- _ ->
- %% It's a merge point
- case expr_is_const(E) of
- true ->
- ?pp_debug("\n\n############## Wow expr is constant at merge point: ~w",[E]),
- Var = ?RTL:mk_new_var(),
- Value = eval_expr(E),
- Op = #const_expr{var = Var, value = Value},
- {expr_is_const, Op};
- false ->
- Temp = new_temp(),
- OpList = [#xsi_op{pred = X} || X <- Preds],
- Xsi = #xsi{inst = E, def = Temp, label = BlockLabel, opList = OpList},
- {merge_point, Xsi}
- end
- end;
-check_one_operand(E, [CC|Rest], BlockLabel, Cfg, XsiKey, XsiGraph) ->
- SRC1 = ?RTL:alu_src1(E),
- SRC2 = ?RTL:alu_src2(E),
- %% C is the previous instruction
- case CC of
- #alu{} ->
- exit({?MODULE,should_not_be_an_alu,
- {"Why the hell do we still have an alu???",CC}});
- #xsi{} ->
- exit({?MODULE,should_not_be_a_xsi,
- {"Why the hell do we still have a xsi???",CC}});
- #pre_candidate{} ->
- C = CC#pre_candidate.alu,
- DST = ?RTL:alu_dst(C),
- case DST =:= SRC1 orelse DST =:= SRC2 of
- true ->
- %% Get the definition of C, since C is PRE-candidate AND has
- %% been processed before
- DEF = CC#pre_candidate.def,
- case DEF of
- bottom ->
- %% Def(E)=bottom, STOP
- %% No update of the XsiGraph
- {def_found,new_bottom()};
- _->
- %% Simply emend
- F = emend(E,DST,DEF),
- ?pp_debug("~nEmendation : E= ",[]),pp_expr(E),?pp_debug(" ==> E'= ",[]),pp_expr(F),?pp_debug("~n",[]),
- check_one_operand(F,Rest,BlockLabel,Cfg,XsiKey,XsiGraph)
- end;
- false ->
- case check_match(C,E) of
- true -> %% It's a computation of E!
- %% It should give DST and not Def
- %% No update of the XsiGraph, cuz we use DST and not Def
- %% The operand is therefore gonna be a real variable
- {def_found,DST};
- _->
- %% Nothing to do with E
- check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph)
- end
- end;
- #move{} ->
- %% It's a move, we emend E, and continue the definition search
- DST = ?RTL:move_dst(CC),
- case SRC1 =:= DST orelse SRC2 =:= DST of
- true ->
- SRC = ?RTL:move_src(CC),
- F = emend(E,DST,SRC),
- check_one_operand(F,Rest,BlockLabel,Cfg,XsiKey,XsiGraph); %% Continue the search
- _ ->
- check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph) %% Continue the search
- end;
- #xsi_link{} ->
- Key = CC#xsi_link.num,
- %% Is Key a family member of XsiDef ?
- {_KK,Xsi} = ?GRAPH:vertex(XsiGraph,Key),
- C = Xsi#xsi.inst,
- case check_match(E,C) of
- true -> %% There is a Xsi already with a computation of E!
- %% fetch definition of C, and give it to E
- %% Must update an edge in the XsiGraph, and here, we know it's a Temp
- %% Note: this can create a loop (= a cycle of length 1)
- ?pp_debug(" -- Found a cycle with match: Adding an edge t~w -> t~w",[XsiKey,Key]),
- ?GRAPH:add_edge(XsiGraph,XsiKey,Key),
- {def_found,Xsi#xsi.def};
- _ ->
- case ?GRAPH:get_path(XsiGraph,Key,XsiKey) of
- false ->
- %% Is it a loop back to itself???
- case Key =:= XsiKey of
- false ->
- check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph);
- _ ->
- {expr_found,#eop{expr=E,var=?RTL:mk_new_var(),stopped_by=Key}}
- end;
- _ ->
- %% Returning the expression instead of looping
- %% And in case of no match
- ExprOp = #eop{expr=E,var=?RTL:mk_new_var(),stopped_by=Key},
- {expr_found,ExprOp}
- end
- end;
- #phi{} -> %% skip them
- check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph);
- _ ->
- PreColouredTest = ?ARCH:is_precoloured(SRC1) orelse ?ARCH:is_precoloured(SRC2),
-
- %%RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)) orelse ?RTL:is_reg(SRC1) orelse ?RTL:is_reg(SRC2),
- RegisterTest = ?RTL:is_reg(?RTL:alu_dst(E)),
- case PreColouredTest orelse RegisterTest of
- true ->
- {def_found,new_bottom()};
- _->
- DC = ?RTL:defines(CC),
- case lists:member(SRC1,DC) orelse lists:member(SRC2,DC) of
- true ->
- {def_found,new_bottom()};
- _ ->
- %% Orthogonal to E, we continue the search
- check_one_operand(E,Rest,BlockLabel,Cfg,XsiKey,XsiGraph)
- end
- end
- end.
-
-eval_expr(E) ->
- ?pp_debug("~n Evaluating the result of ~w~n", [E]),
- Op1 = ?RTL:alu_src1(E),
- Op2 = ?RTL:alu_src2(E),
- true = ?RTL:is_imm(Op1),
- Val1 = ?RTL:imm_value(Op1),
- true = ?RTL:is_imm(Op2),
- Val2 = ?RTL:imm_value(Op2),
- {Result, _Sign, _Zero, _Overflow, _Carry} = ?ARCH:eval_alu(?RTL:alu_op(E), Val1, Val2),
- ?pp_debug("~n Result is then ~w~n", [Result]),
- ?RTL:mk_imm(Result).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%% CREATTING CFGGRAPH %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-create_cfggraph([],_Cfg,CFGGraph,ToBeFactorizedAcc,MPAcc,LateEdges,_XsiGraph) ->
- ?pp_debug("~n~n ############# PostProcessing ~n~w~n",[LateEdges]),
- post_process(LateEdges,CFGGraph),
- ?pp_debug("~n~n ############# Factorizing ~n~w~n",[ToBeFactorizedAcc]),
- factorize(ToBeFactorizedAcc,CFGGraph),
- MPAcc;
-create_cfggraph([Label|Ls],Cfg,CFGGraph,ToBeFactorizedAcc,MPAcc,LateEdges,XsiGraph) ->
- Preds = ?CFG:pred(Cfg, Label),
- case Preds of
- [] ->
- exit({?MODULE,do_not_call_on_top,{"Why the hell do we call that function on the start label???",Label}});
- [P] ->
- Code = ?BB:code(?CFG:bb(Cfg, Label)),
- Defs = get_defs_in_non_merge_block(Code, []),
- ?pp_debug("~nAdding a vertex for ~w", [Label]),
- Succs = ?CFG:succ(Cfg, Label),
- NewToBeFactorizedAcc =
- case Succs of
- [] -> %% Exit point
- ?GRAPH:add_vertex(CFGGraph, Label, #block{type = exit}),
- ToBeFactorizedAcc;
- _ -> %% Split point
- ?GRAPH:add_vertex(CFGGraph,Label,#block{type=not_mp,attributes={P,Succs}}),
- [Label|ToBeFactorizedAcc]
- end,
- ?pp_debug("~nAdding an edge ~w -> ~w (~w)",[P,Label,Defs]),
- case ?GRAPH:add_edge(CFGGraph,P,Label,Defs) of
- {error,Reason} ->
- exit({?MODULE,forget_that_for_christs_sake_bingwen_please,{"Bad edge",Reason}});
- _ ->
- ok
- end,
- create_cfggraph(Ls,Cfg,CFGGraph,NewToBeFactorizedAcc,MPAcc,LateEdges,XsiGraph);
- _ -> %% Merge point
- Code = ?BB:code(?CFG:bb(Cfg,Label)),
- {Defs,Xsis,Maps,Uses} = get_info_in_merge_block(Code,XsiGraph,[],[],gb_trees:empty(),gb_trees:empty()),
- Attributes = #mp{preds=Preds,xsis=Xsis,defs=Defs,maps=Maps,uses=Uses},
- MergeBlock = #block{type=mp,attributes=Attributes},
- ?pp_debug("~nAdding a vertex for ~w with Defs= ~w",[Label,Defs]),
- ?GRAPH:add_vertex(CFGGraph,Label,MergeBlock),
- %% Add edges
- NewLateEdges = add_edges_for_mp(Preds,Label,LateEdges),
- create_cfggraph(Ls,Cfg,CFGGraph,ToBeFactorizedAcc,[Label|MPAcc],NewLateEdges,XsiGraph)
- end.
-
-get_defs_in_non_merge_block([], Acc) ->
- ?SETS:from_list(Acc);
-get_defs_in_non_merge_block([Inst|Rest], Acc) ->
- case Inst of
- #pre_candidate{} ->
- Def = Inst#pre_candidate.def,
- case Def of
- #temp{} ->
- %% {temp,Key,_Var} ->
- %% get_defs_in_non_merge_block(Rest,[Key|Acc]);
- get_defs_in_non_merge_block(Rest, [Def#temp.key|Acc]);
- _-> %% Real variables or bottom
- get_defs_in_non_merge_block(Rest, Acc)
- end;
- _ ->
- get_defs_in_non_merge_block(Rest, Acc)
- end.
-
-get_info_in_merge_block([],_XsiGraph,Defs,Xsis,Maps,Uses) ->
- {?SETS:from_list(Defs),Xsis,Maps,Uses}; %% Xsis are in backward order
-get_info_in_merge_block([Inst|Rest],XsiGraph,Defs,Xsis,Maps,Uses) ->
- case Inst of
- #pre_candidate{} ->
- Def = Inst#pre_candidate.def,
- case Def of
- #temp{} ->
- get_info_in_merge_block(Rest,XsiGraph,[Def#temp.key|Defs],Xsis,Maps,Uses);
- _ ->
- get_info_in_merge_block(Rest,XsiGraph,Defs,Xsis,Maps,Uses)
- end;
- #xsi_link{} ->
- Key = Inst#xsi_link.num,
- {_Key,Xsi} = ?GRAPH:vertex(XsiGraph,Key),
- OpList = xsi_oplist(Xsi),
- {NewMaps,NewUses} = add_map_and_uses(OpList,Key,Maps,Uses),
- get_info_in_merge_block(Rest,XsiGraph,Defs,[Key|Xsis],NewMaps,NewUses);
- _ ->
- get_info_in_merge_block(Rest,XsiGraph,Defs,Xsis,Maps,Uses)
- end.
-
-add_edges_for_mp([], _Label, LateEdges) ->
- LateEdges;
-add_edges_for_mp([P|Ps], Label, LateEdges) ->
- add_edges_for_mp(Ps,Label,[{P,Label}|LateEdges]).
-
-%% Doesn't do anything so far
-add_map_and_uses([], _Key, Maps, Uses) ->
- {Maps, Uses};
-add_map_and_uses([XsiOp|Ops], Key, Maps, Uses) ->
- {NewMaps, NewUses} =
- case XsiOp#xsi_op.op of
- #bottom{} ->
- Set = case gb_trees:lookup(XsiOp, Maps) of
- {value, V} ->
- ?SETS:add_element(Key, V);
- none ->
- ?SETS:from_list([Key])
- end,
- {gb_trees:enter(XsiOp, Set, Maps), Uses};
- #temp{} ->
- Set = case gb_trees:lookup(XsiOp, Maps) of
- {value, V} ->
- ?SETS:add_element(Key, V);
- none ->
- ?SETS:from_list([Key])
- end,
- Pred = XsiOp#xsi_op.pred,
- OOP = XsiOp#xsi_op.op,
- SSet = case gb_trees:lookup(Pred, Uses) of
- {value, VV} ->
- ?SETS:add_element(OOP#temp.key, VV);
- none ->
- ?SETS:from_list([OOP#temp.key])
- end,
- {gb_trees:enter(XsiOp, Set, Maps), gb_trees:enter(Pred, SSet, Uses)};
- #eop{} ->
- Set = case gb_trees:lookup(XsiOp, Maps) of
- {value, V} ->
- ?SETS:add_element(Key, V);
- none ->
- ?SETS:from_list([Key])
- end,
- Pred = XsiOp#xsi_op.pred,
- Op = XsiOp#xsi_op.op,
- SSet = case gb_trees:lookup(Pred, Uses) of
- {value, VV} ->
- ?SETS:add_element(Op#eop.stopped_by, VV);
- none ->
- ?SETS:from_list([Op#eop.stopped_by])
- end,
- {gb_trees:enter(XsiOp, Set, Maps), gb_trees:enter(Pred, SSet, Uses)};
- _->
- {Maps, Uses}
- end,
- add_map_and_uses(Ops, Key, NewMaps, NewUses).
-
-post_process([], _CFGGraph) -> ok;
-post_process([E|Es], CFGGraph) ->
- {Pred,Label} = E,
- {_PP,Block} = ?GRAPH:vertex(CFGGraph,Label),
- Att = Block#block.attributes,
- Uses = Att#mp.uses,
- SetToAdd = case gb_trees:lookup(Pred,Uses) of
- {value, Set} ->
- Set;
- none ->
- ?SETS:new()
- end,
- %% ?pp_debug("~nAdding an edge ~w -> ~w (~w)",[Pred,Label,SetToAdd]),
- ?GRAPH:add_edge(CFGGraph, Pred, Label, SetToAdd),
- post_process(Es, CFGGraph).
-
-factorize([], _CFGGraph) -> ok;
-factorize([P|Ps], CFGGraph) ->
- [OE|OEs] = ?GRAPH:out_edges(CFGGraph,P),
- %% ?pp_debug("~nIn_degrees ~w : ~w",[P,?GRAPH:in_degree(CFGGraph,P)]),
- [InEdge] = ?GRAPH:in_edges(CFGGraph,P),
- {E,V1,V2,Label} = ?GRAPH:edge(CFGGraph,InEdge),
- {_OEE,_OEV1,_OEV2,LOE} = ?GRAPH:edge(CFGGraph,OE),
- List = shoot_info_upwards(OEs,LOE,CFGGraph),
- NewLabel = ?SETS:union(Label,List),
- ?GRAPH:add_edge(CFGGraph,E,V1,V2,NewLabel),
- factorize(Ps, CFGGraph).
-
-shoot_info_upwards([], Acc, _CFGGraph) -> Acc;
-shoot_info_upwards([E|Es], Acc, CFGGraph) ->
- {_E,_V1,_V2,Set} = ?GRAPH:edge(CFGGraph,E),
- NewAcc = ?SETS:intersection(Acc, Set),
- case ?SETS:size(NewAcc) of
- 0 -> NewAcc;
- _ -> shoot_info_upwards(Es,NewAcc,CFGGraph)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DOWNSAFETY %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-perform_downsafety([], _G, _XsiG) ->
- ok;
-perform_downsafety([MP|MPs], G, XG) ->
- {V,Block} = ?GRAPH:vertex(G, MP),
- NDS = ?SETS:new(),
- Att = Block#block.attributes,
- Maps = Att#mp.maps,
- Defs = Att#mp.defs,
- OutEdges = ?GRAPH:out_edges(G, MP),
- %% ?pp_debug("~n Inspection Maps : ~w",[Maps]),
- NewNDS = parse_keys(gb_trees:keys(Maps),Maps,OutEdges,G,Defs,NDS,XG),
- NewAtt = Att#mp{ndsSet = NewNDS},
- ?GRAPH:add_vertex(G, V, Block#block{attributes = NewAtt}),
- ?pp_debug("~n Not Downsafe at L~w: ~w", [V, NewNDS]),
- %%io:format(standard_io,"~n Not Downsafe at L~w: ~w",[V,NewNDS]),
- perform_downsafety(MPs, G, XG).
-
-parse_keys([], _Maps, _OutEdges, _G, _Defs, NDS, _XsiG) ->
- NDS;
-parse_keys([M|Ms], Maps, OutEdges, G, Defs, NDS, XsiG) ->
- KillerSet = gb_trees:get(M,Maps),
- %% ?pp_debug("~n Inspection ~w -> ~w",[M,KillerSet]),
- TempSet = ?SETS:intersection(KillerSet,Defs),
- NewNDS = case ?SETS:size(TempSet) of
- 0 -> getNDS(M,KillerSet,NDS,OutEdges,G,XsiG);
- _ ->
- %% One Xsi which has M as operand has killed it
- %% M is then Downsafe
- %% and is not added to the NotDownsafeSet (NDS)
- NDS
- end,
- parse_keys(Ms, Maps, OutEdges, G, Defs, NewNDS, XsiG).
-
-getNDS(_M, _KillerSet, NDS, [], _G, _XsiG) ->
- NDS;
-getNDS(M, KillerSet, NDS, [E|Es], G, XsiG) ->
- {_EE,_V1,_V2,Label} = ?GRAPH:edge(G, E),
- Set = ?SETS:intersection(KillerSet, Label),
- %% ?pp_debug("~n ######## Intersection between KillerSet: ~w and Label: ~w",[KillerSet,Label]),
- %% ?pp_debug("~n ######## ~w",[Set]),
- case ?SETS:size(Set) of
- 0 ->
- %% M is not downsafe
- ?SETS:add_element(M, NDS);
- _ ->
- %% Try the other edges
- getNDS(M, KillerSet, NDS, Es, G, XsiG)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%% WILL BE AVAILABLE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-perform_will_be_available(XsiGraph,CFGGraph,Options) ->
- Keys = ?GRAPH:vertices(XsiGraph),
- ?pp_debug("~n############ Can Be Available ##########~n",[]),
- ?option_time(perform_can_be_available(Keys,XsiGraph,CFGGraph),"RTL A-SSAPRE WillBeAvailable - Compute CanBeAvailable",Options),
- ?pp_debug("~n############ Later ##########~n",[]),
- ?option_time(perform_later(Keys,XsiGraph),"RTL A-SSAPRE WillBeAvailable - Compute Later",Options).
-
-perform_can_be_available([],_XsiGraph,_CFGGraph) -> ok;
-perform_can_be_available([Key|Keys],XsiGraph,CFGGraph) ->
- {V,Xsi} = ?GRAPH:vertex(XsiGraph,Key),
- case Xsi#xsi.cba of
- undefined ->
- {_VV,Block} = ?GRAPH:vertex(CFGGraph,Xsi#xsi.label),
- Att = Block#block.attributes,
- NDS = Att#mp.ndsSet,
- OpList = ?SETS:from_list(xsi_oplist(Xsi)),
- Set = ?SETS:intersection(NDS,OpList),
- case ?SETS:size(Set) of
- 0 ->
- ?GRAPH:add_vertex(XsiGraph, V, Xsi#xsi{cba = true}),
- perform_can_be_available(Keys, XsiGraph, CFGGraph);
- _ ->
- LIST = [X || #temp{key=X} <- ?SETS:to_list(Set)],
- case LIST of
- [] ->
- ?GRAPH:add_vertex(XsiGraph, V, Xsi#xsi{cba = false}),
- ImmediateParents = ?GRAPH:in_neighbours(XsiGraph, Key),
- propagate_cba(ImmediateParents,XsiGraph,Xsi#xsi.def,CFGGraph);
- _ ->
- ok
- end,
- perform_can_be_available(Keys, XsiGraph, CFGGraph)
- end;
- _ -> %% True or False => recurse
- perform_can_be_available(Keys, XsiGraph, CFGGraph)
- end.
-
-propagate_cba([],_XG,_Def,_CFGG) -> ok;
-propagate_cba([IPX|IPXs],XsiGraph,XsiDef,CFGGraph) ->
- {V,IPXsi} = ?GRAPH:vertex(XsiGraph,IPX),
- {_VV,Block} = ?GRAPH:vertex(CFGGraph,IPXsi#xsi.label),
- Att = Block#block.attributes,
- NDS = Att#mp.ndsSet,
- List = ?SETS:to_list(?SETS:intersection(NDS,?SETS:from_list(xsi_oplist(IPXsi)))),
- case IPXsi#xsi.cba of
- false -> ok;
- _ ->
- case lists:keymember(XsiDef, #xsi_op.op, List) of
- true ->
- ?GRAPH:add_vertex(XsiGraph, V, IPXsi#xsi{cba = false}),
- ImmediateParents = ?GRAPH:in_neighbours(XsiGraph, IPX),
- propagate_cba(ImmediateParents,XsiGraph,IPXsi#xsi.def,CFGGraph);
- _ ->
- ok
- end
- end,
- propagate_cba(IPXs,XsiGraph,XsiDef,CFGGraph).
-
-perform_later([], _XsiGraph) -> ok;
-perform_later([Key|Keys], XsiGraph) ->
- {V, Xsi} = ?GRAPH:vertex(XsiGraph, Key),
- %% ?pp_debug("~n DEBUG : inspecting later of ~w (~w)~n",[Key,Xsi#xsi.later]),
- case Xsi#xsi.later of
- undefined ->
- OpList = xsi_oplist(Xsi),
- case parse_ops(OpList,fangpi) of %% It means "fart" in chinese :D
- has_temp ->
- perform_later(Keys,XsiGraph);
- has_real ->
- case Xsi#xsi.cba of
- true ->
- ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=false,wba=true});
- undefined ->
- ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=false,wba=true});
- _ ->
- ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=false,wba=false})
- end,
- AllParents = digraph_utils:reaching([Key], XsiGraph),
- ?pp_debug("~nPropagating to all parents of t~w: ~w",[Key,AllParents]),
- propagate_later(AllParents,XsiGraph),
- perform_later(Keys,XsiGraph);
- _ -> %% Just contains bottoms and/or expressions
- ?GRAPH:add_vertex(XsiGraph,V,Xsi#xsi{later=true}),
- perform_later(Keys,XsiGraph)
- end;
- _ -> %% True or False => recurse
- perform_later(Keys,XsiGraph)
- end.
-
-propagate_later([], _XG) -> ok;
-propagate_later([IPX|IPXs], XsiGraph) ->
- {V,IPXsi} = ?GRAPH:vertex(XsiGraph,IPX),
- case IPXsi#xsi.later of
- false ->
- ?pp_debug("~nThrough propagation, later of t~w is already reset",[IPX]),
- propagate_later(IPXs,XsiGraph);
- _ ->
- ?pp_debug("~nThrough propagation, resetting later of t~w",[IPX]),
- case IPXsi#xsi.cba of
- true ->
- ?GRAPH:add_vertex(XsiGraph,V,IPXsi#xsi{later=false,wba=true});
- undefined ->
- ?GRAPH:add_vertex(XsiGraph,V,IPXsi#xsi{later=false,wba=true});
- _ ->
- ?GRAPH:add_vertex(XsiGraph,V,IPXsi#xsi{later=false,wba=false})
- end,
- propagate_later(IPXs,XsiGraph)
- end.
-
-parse_ops([], Res) ->
- Res;
-parse_ops([Op|Ops], Res) ->
- case Op#xsi_op.op of
- #temp{} ->
- NewRes = has_temp,
- parse_ops(Ops,NewRes);
- #bottom{} ->
- parse_ops(Ops,Res);
- #eop{} ->
- parse_ops(Ops,Res);
- _ ->
- has_real
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CODE MOTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-perform_code_motion([], Cfg, _XsiG) ->
- Cfg;
-perform_code_motion([L|Labels], Cfg, XsiG) ->
- Code=?BB:code(?CFG:bb(Cfg,L)),
- ?pp_debug("~n################ Code Motion in L~w~n",[L]),
- ?pp_debug("~nCode to move ~n",[]),
- pp_instrs(Code,XsiG),
- NewCfg = code_motion_in_block(L,Code,Cfg,XsiG,[],gb_trees:empty()),
- ?pp_debug("~n################ Code Motion successful in L~w~n",[L]),
- perform_code_motion(Labels,NewCfg,XsiG).
-
-code_motion_in_block(Label,[],Cfg,_XsiG,Visited,InsertionsAcc) ->
- InsertionsAlong = gb_trees:keys(InsertionsAcc),
- Code = lists:reverse(Visited),
- NewBB = ?BB:mk_bb(Code),
- Cfg2 = ?CFG:bb_add(Cfg,Label,NewBB),
- %% Must come after the bb_add, since redirect will update the Phis too...
- Cfg3 = make_insertions(Label,InsertionsAlong,InsertionsAcc,Cfg2),
- %% ?pp_debug("~nChecking the Code at L~w:~n~p",[Label,?BB:code(?CFG:bb(Cfg3,Label))]),
- Cfg3;
-code_motion_in_block(L,[Inst|Insts],Cfg,XsiG,Visited,InsertionsAcc) ->
- ?pp_debug("~nInspecting Inst : ~n",[]),pp_instr(Inst,XsiG),
- case Inst of
- #pre_candidate{} ->
- Def = Inst#pre_candidate.def,
- Alu = Inst#pre_candidate.alu,
- InstToAdd =
- case Def of
- bottom ->
- Alu;
- #temp{} ->
- Key = Def#temp.key,
- {_V,Xsi} = ?GRAPH:vertex(XsiG,Key),
- case Xsi#xsi.wba of
- true ->
- %% Turn into a move
- Dst = ?RTL:alu_dst(Alu),
- Move = ?RTL:mk_move(Dst,Def#temp.var),
- pp_instr(Inst#pre_candidate.alu,nil), ?pp_debug(" ==> ",[]), pp_instr(Move,nil),
- %% Counting redundancies
- redundancy_add(),
- Move;
- _ ->
- Alu
- end;
- _ -> %% Def is a real variable
- %% Turn into a move
- Dst = ?RTL:alu_dst(Alu),
- Move = ?RTL:mk_move(Dst,Def),
- pp_instr(Alu,nil), ?pp_debug(" ==> ",[]), pp_instr(Move,nil),
- %% Counting redundancies
- redundancy_add(),
- Move
- end,
- code_motion_in_block(L,Insts,Cfg,XsiG,[InstToAdd|Visited],InsertionsAcc);
- #xsi_link{} ->
- Key = Inst#xsi_link.num,
- {_V,Xsi} = ?GRAPH:vertex(XsiG,Key),
- case Xsi#xsi.wba of
- true ->
- %% Xsi is a WBA, it might trigger insertions
- OpList = xsi_oplist(Xsi),
- ?pp_debug(" This Xsi is a 'Will be available'",[]),
- %% Cleaning the instruction
- Expr = prepare_inst(Xsi#xsi.inst),
- {NewOpList,NewInsertionsAcc} = get_insertions(OpList,[],InsertionsAcc,Visited,Expr,XsiG),
- %% Making Xsi a Phi with Oplist
- PhiOpList = [{Pred,Var} || #xsi_op{pred=Pred,op=Var} <- NewOpList],
- Def = Xsi#xsi.def,
- Phi = ?RTL:phi_arglist_update(?RTL:mk_phi(Def#temp.var),PhiOpList),
- ?pp_debug("~n Xsi is turned into Phi : ~w",[Phi]),
- code_motion_in_block(L,Insts,Cfg,XsiG,[Phi|Visited],NewInsertionsAcc);
- _ ->
- ?pp_debug(" This Xsi is not a 'Will be available'",[]),
- code_motion_in_block(L,Insts,Cfg,XsiG,Visited,InsertionsAcc)
- end;
-%% phi ->
-%% code_motion_in_block(L,Insts,Cfg,XsiG,[Inst|Visited],InsertionsAcc);
- _ ->
- %% Other instructions.... Phis too
- code_motion_in_block(L,Insts,Cfg,XsiG,[Inst|Visited],InsertionsAcc)
- end.
-
-prepare_inst(Expr) ->
- S1 = ?RTL:alu_src1(Expr),
- S2 = ?RTL:alu_src2(Expr),
- NewInst = case S1 of
- #temp{} -> ?RTL:alu_src1_update(Expr,S1#temp.var);
- _ -> Expr
- end,
- case S2 of
- #temp{} -> ?RTL:alu_src2_update(NewInst,S2#temp.var);
- _ -> NewInst
- end.
-
-get_insertions([],OpAcc,InsertionsAcc,_Visited,_Expr,_XsiG) ->
- {OpAcc,InsertionsAcc};
-get_insertions([XsiOp|Ops],OpAcc,InsertionsAcc,Visited,Expr,XsiG) ->
- Pred = XsiOp#xsi_op.pred,
- Op = XsiOp#xsi_op.op,
- {Dst, NewInsertionsAcc} =
- case Op of
- #bottom{} ->
- case gb_trees:lookup(Pred,InsertionsAcc) of
- {value,Insertion} ->
- From = Insertion#insertion.from,
- case lists:keyfind(Op, 1, From) of
- false ->
- ?pp_debug("~nThere has been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op),
- D = Op#bottom.var,
- Expr2 = ?RTL:alu_dst_update(Expr,D),
- Inst = manufacture_computation(Pred,Expr2,Visited),
- Code = Insertion#insertion.code,
- NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]},
- {D, gb_trees:update(Pred, NewInsertion, InsertionsAcc)};
- {_, Val} ->
- ?pp_debug("~nThere has been insertions along the edge L~w already, and for that operand too | Op=",[Pred]),pp_arg(Op),
- {Val, InsertionsAcc}
- end;
- none ->
- ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course)| Op=",[Pred]),pp_arg(Op),
- D = Op#bottom.var,
- Expr2 = ?RTL:alu_dst_update(Expr, D),
- Inst = manufacture_computation(Pred,Expr2,Visited),
- NewInsertion = #insertion{from=[{Op,D}],code=[Inst]},
- {D, gb_trees:insert(Pred,NewInsertion, InsertionsAcc)}
- end;
- #const_expr{} ->
- case gb_trees:lookup(Pred,InsertionsAcc) of
- {value,Insertion} ->
- From = Insertion#insertion.from,
- case lists:keyfind(Op, 1, From) of
- false ->
- ?pp_debug("~nThere have been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op),
- D = Op#const_expr.var,
- Val = Op#const_expr.value,
- Inst = ?RTL:mk_move(D, Val),
- Code = Insertion#insertion.code,
- NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]},
- {D, gb_trees:update(Pred,NewInsertion,InsertionsAcc)};
- {_, Val} ->
- ?pp_debug("~nThere have been insertions along the edge L~w already, and for that operand too | Op=",[Pred]),pp_arg(Op),
- {Val, InsertionsAcc}
- end;
- none ->
- ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course)| Op=",[Pred]),pp_arg(Op),
- D = Op#const_expr.var,
- Val = Op#const_expr.value,
- Inst = ?RTL:mk_move(D, Val),
- NewInsertion = #insertion{from=[{Op,D}],code=[Inst]},
- {D, gb_trees:insert(Pred,NewInsertion, InsertionsAcc)}
- end;
- #eop{} ->
- %% We treat expressions like bottoms
- %% The value must be recomputed, and therefore not available...
- case gb_trees:lookup(Pred,InsertionsAcc) of
- {value,Insertion} ->
- From = Insertion#insertion.from,
- case lists:keyfind(Op, 1, From) of
- false ->
- ?pp_debug("~nThere has been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op),
- D = Op#eop.var,
- Expr2 = ?RTL:alu_dst_update(Expr, D),
- Inst = manufacture_computation(Pred,Expr2,Visited),
- Code = Insertion#insertion.code,
- NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]},
- {D, gb_trees:update(Pred,NewInsertion, InsertionsAcc)};
- {_, Val} ->
- ?pp_debug("~nThere has been insertions along the edge L~w already, and for that operand too | Op=",[Pred]),pp_arg(Op),
- {Val, InsertionsAcc}
- end;
- none ->
- ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course)| Op=",[Pred]),pp_arg(Op),
- D = Op#eop.var,
- Expr2 = ?RTL:alu_dst_update(Expr, D),
- Inst = manufacture_computation(Pred,Expr2,Visited),
- NewInsertion = #insertion{from=[{Op,D}],code=[Inst]},
- {D, gb_trees:insert(Pred, NewInsertion, InsertionsAcc)}
- end;
- #temp{} ->
- case gb_trees:lookup(Pred,InsertionsAcc) of
- {value,Insertion} ->
- From = Insertion#insertion.from,
- case lists:keyfind(Op, 1, From) of
- false ->
- ?pp_debug("~nThere has been insertions along the edge L~w already, but not for that operand | Op=",[Pred]),pp_arg(Op),
- Key = Op#temp.key,
- {_V,Xsi} = ?GRAPH:vertex(XsiG,Key),
- case Xsi#xsi.wba of
- true ->
- ?pp_debug("~nBut the operand is a WBA Xsi: no need for insertion",[]),
- {Op#temp.var, InsertionsAcc};
- _ ->
- ?pp_debug("~nBut the operand is a NOT WBA Xsi: we must make an insertion",[]),
- D = ?RTL:mk_new_var(),
- Expr2 = ?RTL:alu_dst_update(Expr, D),
- Inst = manufacture_computation(Pred,Expr2,Visited),
- Code = Insertion#insertion.code,
- NewInsertion = Insertion#insertion{from=[{Op,D}|From],code=[Inst|Code]},
- {D, gb_trees:update(Pred, NewInsertion, InsertionsAcc)}
- end;
- {_, Val} ->
- ?pp_debug("~nThere has been insertions along the edge L~w already, and for that operand too (Op=~w)",[Pred,Op]),
- ?pp_debug("~nThis means, this temp is a WBA Xsi's definition",[]),
- {Val, InsertionsAcc}
- end;
- none ->
- ?pp_debug("~nThere has been no insertion along the edge L~w, (and not for that operand, of course | Op=",[Pred]),pp_arg(Op),
- Key = Op#temp.key,
- {_V,Xsi} = ?GRAPH:vertex(XsiG,Key),
- case Xsi#xsi.wba of
- true ->
- ?pp_debug("~nBut the operand is a WBA Xsi: no need for insertion",[]),
- {Op#temp.var, InsertionsAcc};
- _ ->
- ?pp_debug("~nBut the operand is a NOT WBA Xsi: we must make an insertion",[]),
- D = ?RTL:mk_new_var(),
- Expr2 = ?RTL:alu_dst_update(Expr, D),
- Inst = manufacture_computation(Pred,Expr2,Visited),
- NewInsertion = #insertion{from=[{Op,D}],code=[Inst]},
- {D, gb_trees:insert(Pred, NewInsertion, InsertionsAcc)}
- end
- end;
- _ ->
- ?pp_debug("~nThe operand (Op=",[]),pp_arg(Op),?pp_debug(") is a real variable, no need for insertion along L~w",[Pred]),
- {Op, InsertionsAcc}
- end,
- NewXsiOp = XsiOp#xsi_op{op=Dst},
- get_insertions(Ops, [NewXsiOp|OpAcc], NewInsertionsAcc, Visited, Expr, XsiG).
-
-manufacture_computation(_Pred, Expr, []) ->
- ?pp_debug("~n Manufactured computation : ~w", [Expr]),
- Expr;
-manufacture_computation(Pred, Expr, [I|Rest]) ->
- %% ?pp_debug("~n Expr = ~w",[Expr]),
- SRC1 = ?RTL:alu_src1(Expr),
- SRC2 = ?RTL:alu_src2(Expr),
- case I of
- #xsi_link{} ->
- exit({?MODULE,should_not_be_a_xsi_link,{"Why the hell do we still have a xsi link???",I}});
- #xsi{} ->
- exit({?MODULE,should_not_be_a_xsi,{"Why the hell do we still have a xsi ???",I}});
- #phi{} ->
- DST = ?RTL:phi_dst(I),
- Arg = ?RTL:phi_arg(I,Pred),
- NewInst = case DST =:= SRC1 of
- true -> ?RTL:alu_src1_update(Expr,Arg);
- false -> Expr
- end,
- NewExpr = case DST =:= SRC2 of
- true -> ?RTL:alu_src2_update(NewInst,Arg);
- false -> NewInst
- end,
- manufacture_computation(Pred,NewExpr,Rest)
- end.
-
-make_insertions(_L, [], _ITree, Cfg) ->
- Cfg;
-make_insertions(L, [OldPred|Is], ITree, Cfg) ->
- NewPred = ?RTL:label_name(?RTL:mk_new_label()),
- I = gb_trees:get(OldPred, ITree),
- CodeToInsert = lists:reverse([?RTL:mk_goto(L)|I#insertion.code]),
- BBToInsert = ?BB:mk_bb(CodeToInsert),
- NewCfg = ?CFG:bb_insert_between(Cfg, NewPred, BBToInsert, OldPred, L),
- make_insertions(L, Is, ITree, NewCfg).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%% XSI INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-xsi_oplist(#xsi{opList=OpList}) ->
- case OpList of undefined -> [] ; _ -> OpList end.
-xsi_arg(Xsi, Pred) ->
- case lists:keyfind(Pred, #xsi_op.pred, xsi_oplist(Xsi)) of
- false ->
- undetermined_operand;
- R ->
- R#xsi_op.op
- end.
-xsi_arg_update(Xsi, Pred, Op) ->
- NewOpList = lists:keyreplace(Pred, #xsi_op.pred, xsi_oplist(Xsi),
- #xsi_op{pred=Pred,op=Op}),
- Xsi#xsi{opList=NewOpList}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PRETTY-PRINTING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--ifndef(SSAPRE_DEBUG).
-
-%%pp_cfg(Cfg,_) -> ?CFG:pp(Cfg).
-pp_cfg(_,_) -> ok.
-pp_instr(_,_) -> ok.
-pp_instrs(_,_) -> ok.
-pp_expr(_) -> ok.
-pp_xsi(_) -> ok.
-pp_arg(_) -> ok.
-pp_xsigraph(_) -> ok.
-pp_cfggraph(_) -> ok.
-%% pp_xsigraph(G) ->
-%% Vertices = lists:sort(?GRAPH:vertices(G)),
-%% io:format(standard_io, "Size of the Xsi Graph: ~w", [length(Vertices)]).
-%% pp_cfggraph(G) ->
-%% Vertices = lists:sort(?GRAPH:vertices(G)),
-%% io:format(standard_io, "Size of the CFG Graph: ~w", [length(Vertices)]).
-
--else.
-
-pp_cfg(Cfg, Graph) ->
- Labels = ?CFG:preorder(Cfg),
- pp_blocks(Labels, Cfg, Graph).
-
-pp_blocks([], _, _) ->
- ok;
-pp_blocks([L|Ls], Cfg, Graph) ->
- Code = hipe_bb:code(?CFG:bb(Cfg,L)),
- io:format(standard_io,"~n########## Label L~w~n", [L]),
- pp_instrs(Code, Graph),
- pp_blocks(Ls, Cfg, Graph).
-
-pp_instrs([], _) ->
- ok;
-pp_instrs([I|Is], Graph) ->
- pp_instr(I, Graph),
- pp_instrs(Is, Graph).
-
-pp_xsi_link(Key, Graph) ->
- {_Key,Xsi} = ?GRAPH:vertex(Graph, Key),
- pp_xsi(Xsi).
-
-pp_xsi(Xsi) ->
- io:format(standard_io, " [L~w] ", [Xsi#xsi.label]),
- io:format(standard_io, "[", []), pp_expr(Xsi#xsi.inst),
- io:format(standard_io, "] Xsi(", []), pp_xsi_args(xsi_oplist(Xsi)),
- io:format(standard_io, ") (", []), pp_xsi_def(Xsi#xsi.def),
- io:format(standard_io, ") cba=~w, later=~w | wba=~w~n", [Xsi#xsi.cba,Xsi#xsi.later,Xsi#xsi.wba]).
-
-pp_instr(I, Graph) ->
- case I of
- #alu{} ->
- io:format(standard_io, " ", []),
- pp_arg(?RTL:alu_dst(I)),
- io:format(standard_io, " <- ", []),
- pp_expr(I),
- io:format(standard_io, "~n", []);
- _ ->
- try ?RTL:pp_instr(standard_io, I)
- catch _:_ ->
- case I of
- #pre_candidate{} ->
- pp_pre(I);
- #xsi{} ->
- pp_xsi(I);
- #xsi_link{} ->
- pp_xsi_link(I#xsi_link.num, Graph);
- _->
- io:format(standard_io,"*** ~w ***~n", [I])
- end
- end
- end.
-
-pp_pre(I) ->
- A = I#pre_candidate.alu,
- io:format(standard_io, " ", []),
- pp_arg(?RTL:alu_dst(A)),
- io:format(standard_io, " <- ", []),pp_expr(A),
- io:format(standard_io, " [ ", []),pp_arg(I#pre_candidate.def),
- %%io:format(standard_io, "~w", [I#pre_candidate.def]),
- io:format(standard_io, " ]~n",[]).
-
-pp_expr(I) ->
- pp_arg(?RTL:alu_dst(I)),
- io:format(standard_io, " <- ", []),
- pp_arg(?RTL:alu_src1(I)),
- io:format(standard_io, " ~w ", [?RTL:alu_op(I)]),
- pp_arg(?RTL:alu_src2(I)).
-
-pp_arg(Arg) ->
- case Arg of
- bottom ->
- io:format(standard_io, "_|_", []);
- #bottom{} ->
- io:format(standard_io, "_|_:~w (", [Arg#bottom.key]),pp_arg(Arg#bottom.var),io:format(standard_io,")",[]);
- #temp{} ->
- pp_xsi_def(Arg);
- #eop{} ->
- io:format(standard_io,"#",[]),pp_expr(Arg#eop.expr),io:format(standard_io,"(",[]),pp_arg(Arg#eop.var),io:format(standard_io,")#",[]);
- #const_expr{} ->
- io:format(standard_io,"*",[]),pp_arg(Arg#const_expr.var),io:format(standard_io," -> ",[]),pp_arg(Arg#const_expr.value),io:format(standard_io,"*",[]);
- undefined ->
- io:format(standard_io, "...", []); %%"undefined", []);
- _->
- case Arg of
- #alu{} ->
- pp_expr(Arg);
- _->
- ?RTL:pp_arg(standard_io, Arg)
- end
- end.
-
-pp_args([]) ->
- ok;
-pp_args(undefined) ->
- io:format(standard_io, "...,...,...", []);
-pp_args([A]) ->
- pp_arg(A);
-pp_args([A|As]) ->
- pp_arg(A),
- io:format(standard_io, ", ", []),
- pp_args(As).
-
-pp_xsi_args([]) -> ok;
-pp_xsi_args([XsiOp]) ->
- io:format(standard_io, "{~w| ", [XsiOp#xsi_op.pred]),
- pp_arg(XsiOp#xsi_op.op),
- io:format(standard_io, "}", []);
-pp_xsi_args([XsiOp|Args]) ->
- io:format(standard_io, "{~w| ", [XsiOp#xsi_op.pred]),
- pp_arg(XsiOp#xsi_op.op),
- io:format(standard_io, "}, ", []),
- pp_xsi_args(Args);
-pp_xsi_args(Args) ->
- pp_args(Args).
-
-pp_xsi_def(Arg) ->
- D = Arg#temp.key,
- V = Arg#temp.var,
- io:format(standard_io, "t~w (", [D]),pp_arg(V),io:format(standard_io,")",[]).
-
-pp_cfggraph(G) ->
- Vertices = lists:sort(?GRAPH:vertices(G)),
- io:format(standard_io, "Size of the CFG Graph: ~w ~n", [length(Vertices)]),
- pp_cfgvertex(Vertices, G).
-
-pp_xsigraph(G) ->
- Vertices = lists:sort(?GRAPH:vertices(G)),
- io:format(standard_io, "Size of the Xsi Graph: ~w ~n", [length(Vertices)]),
- pp_xsivertex(Vertices,G).
-
-pp_xsivertex([], _G) ->
- ok;
-pp_xsivertex([Key|Keys], G) ->
- {V,Xsi} = ?GRAPH:vertex(G, Key),
- OutNeighbours = ?GRAPH:out_neighbours(G, V),
- ?pp_debug(" ~w -> ~w", [V,OutNeighbours]), pp_xsi(Xsi),
- pp_xsivertex(Keys, G).
-
-pp_cfgvertex([], _G) ->
- ok;
-pp_cfgvertex([Key|Keys], G) ->
- {V,Block} = ?GRAPH:vertex(G,Key),
- case Block#block.type of
- mp ->
- ?pp_debug("~n Block ~w's attributes: ~n", [V]),
- pp_attributes(Block),
- ?pp_debug("~n Block ~w's edges: ~n", [V]),
- pp_edges(G, ?GRAPH:in_edges(G,Key), ?GRAPH:out_edges(G,Key));
- _->
- ok
- end,
- pp_cfgvertex(Keys, G).
-
-pp_attributes(Block) ->
- Att = Block#block.attributes,
- case Att of
- undefined ->
- ok;
- _ ->
- ?pp_debug(" Maps: ~n",[]),pp_maps(gb_trees:keys(Att#mp.maps),Att#mp.maps),
- ?pp_debug(" Uses: ~n",[]),pp_uses(gb_trees:keys(Att#mp.uses),Att#mp.uses),
- ?pp_debug(" Defs: ~w~n",[Att#mp.defs]),
- ?pp_debug(" Xsis: ~w~n",[Att#mp.xsis]),
- ?pp_debug(" NDS : ",[]),pp_nds(?SETS:to_list(Att#mp.ndsSet))
- end.
-
-pp_maps([], _Maps) -> ok;
-pp_maps([K|Ks], Maps) ->
- ?pp_debug(" ",[]),pp_arg(K#xsi_op.op),?pp_debug("-> ~w~n",[?SETS:to_list(gb_trees:get(K,Maps))]),
- pp_maps(Ks, Maps).
-
-pp_uses([], _Maps) -> ok;
-pp_uses([K|Ks], Maps) ->
- ?pp_debug(" ~w -> ~w~n",[K,?SETS:to_list(gb_trees:get(K,Maps))]),
- pp_uses(Ks, Maps).
-
-pp_nds([]) -> ?pp_debug("~n",[]);
-pp_nds(undefined) -> ?pp_debug("None",[]);
-pp_nds([K]) ->
- pp_arg(K#xsi_op.op), ?pp_debug("~n",[]);
-pp_nds([K|Ks]) ->
- pp_arg(K#xsi_op.op), ?pp_debug(", ",[]),
- pp_nds(Ks).
-
-pp_edges(_G, [], []) -> ok;
-pp_edges(G, [], [OUT|OUTs]) ->
- {_E,V1,V2,Label} = ?GRAPH:edge(G,OUT),
- ?pp_debug(" Out edge ~w -> ~w (~w)~n", [V1,V2,?SETS:to_list(Label)]),
- pp_edges(G, [], OUTs);
-pp_edges(G, [IN|INs], Outs) ->
- {_E,V1,V2,Label} = ?GRAPH:edge(G,IN),
- ?pp_debug(" In edge ~w -> ~w (~w)~n", [V1,V2,?SETS:to_list(Label)]),
- pp_edges(G, INs, Outs).
-
--endif.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% COUNTERS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init_counters() ->
- put({ssapre_temp,temp_count}, 0),
- put({ssapre_index,index_count}, 0).
-
-new_bottom() ->
- IndxCountPair = {ssapre_index, index_count},
- V = get(IndxCountPair),
- put(IndxCountPair, V+1),
- #bottom{key = V, var = ?RTL:mk_new_var()}.
-
-new_temp() ->
- TmpCountPair = {ssapre_temp, temp_count},
- V = get(TmpCountPair),
- put(TmpCountPair, V+1),
- #temp{key = V, var = ?RTL:mk_new_var()}.
-
-init_redundancy_count() ->
- put({ssapre_redundancy,redundancy_count}, 0).
-
-redundancy_add() ->
- RedCountPair = {ssapre_redundancy, redundancy_count},
- V = get(RedCountPair),
- put(RedCountPair, V+1).
-
--ifdef(SSAPRE_DEBUG).
-get_redundancy_count() ->
- get({ssapre_redundancy,redundancy_count}).
--endif.
diff --git a/lib/hipe/rtl/hipe_rtl_symbolic.erl b/lib/hipe/rtl/hipe_rtl_symbolic.erl
deleted file mode 100644
index 8ca307952b..0000000000
--- a/lib/hipe/rtl/hipe_rtl_symbolic.erl
+++ /dev/null
@@ -1,94 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-------------------------------------------------------------------
-%% File : hipe_rtl_symbolic.erl
-%% Author : Per Gustafsson <pergu@it.uu.se>
-%% Description : Expansion of symbolic instructions.
-%%
-%% Created : 18 May 2004 by Per Gustafsson <pergu@it.uu.se>
-%%-------------------------------------------------------------------
-
--module(hipe_rtl_symbolic).
-
--export([expand/1]).
-
--include("hipe_rtl.hrl").
--include("hipe_literals.hrl").
--include("../icode/hipe_icode_primops.hrl").
-
-expand(Cfg) ->
- Linear = hipe_rtl_cfg:linearize(Cfg),
- Code = hipe_rtl:rtl_code(Linear),
- NonFlatCode = [expand_instr(Instr) || Instr <- Code],
- NewCode = lists:flatten(NonFlatCode),
- Linear1 = hipe_rtl:rtl_code_update(Linear, NewCode),
- hipe_rtl_cfg:init(Linear1).
-
-expand_instr(Instr) ->
- case Instr of
- #fixnumop{} ->
- expand_fixnumop(Instr);
- #gctest{} ->
- expand_gctest(Instr);
- _ ->
- Instr
- end.
-
-expand_fixnumop(Instr) ->
- case hipe_rtl:fixnumop_type(Instr) of
- untag ->
- Dst = hipe_rtl:fixnumop_dst(Instr),
- Src = hipe_rtl:fixnumop_src(Instr),
- hipe_tagscheme:realuntag_fixnum(Dst, Src);
- tag ->
- Dst = hipe_rtl:fixnumop_dst(Instr),
- Src = hipe_rtl:fixnumop_src(Instr),
- hipe_tagscheme:realtag_fixnum(Dst, Src)
- end.
-
-expand_gctest(Instr) ->
- HeapNeed = hipe_rtl:gctest_words(Instr),
- {GetHPInsn, HP, _PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- {GetHLIMITInsn, H_LIMIT} = hipe_rtl_arch:heap_limit(),
- ContLabel = hipe_rtl:mk_new_label(),
- GCLabel = hipe_rtl:mk_new_label(),
- ContLabelName = hipe_rtl:label_name(ContLabel),
- GCLabelName = hipe_rtl:label_name(GCLabel),
- Tmp = hipe_rtl:mk_new_reg(), % diff between two gc-unsafe pointers
- StartCode =
- [GetHPInsn,
- GetHLIMITInsn,
- hipe_rtl:mk_alu(Tmp, H_LIMIT, 'sub', HP)],
- {SeparateCode, GCAmount, HPAmount} =
- case hipe_rtl:is_reg(HeapNeed) of
- true ->
- GA = hipe_rtl:mk_new_reg_gcsafe(),
- HA = hipe_rtl:mk_new_reg_gcsafe(),
- {[hipe_rtl:mk_alu(HA, HeapNeed, sll,
- hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size()))|
- hipe_tagscheme:realtag_fixnum(GA, HeapNeed)], GA, HA};
- false ->
- WordsNeeded = hipe_rtl:imm_value(HeapNeed),
- GA = hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(WordsNeeded)),
- HA = hipe_rtl:mk_imm(WordsNeeded*hipe_rtl_arch:word_size()),
- {[], GA, HA}
- end,
- EndCode =
- [hipe_rtl:mk_branch(Tmp, 'lt', HPAmount, GCLabelName, ContLabelName, 0.01),
- GCLabel,
- hipe_rtl:mk_call([], 'gc_1', [GCAmount], ContLabelName, [], not_remote),
- ContLabel],
- StartCode ++ SeparateCode ++ EndCode.
-
diff --git a/lib/hipe/rtl/hipe_rtl_varmap.erl b/lib/hipe/rtl/hipe_rtl_varmap.erl
deleted file mode 100644
index f34c66ab85..0000000000
--- a/lib/hipe/rtl/hipe_rtl_varmap.erl
+++ /dev/null
@@ -1,155 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Module : hipe_rtl_varmap
-%% Purpose :
-%% Notes :
-%% History : * 2001-04-10 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_rtl_varmap).
-
--export([init/1,
- ivs2rvs/2,
- icode_var2rtl_var/2,
- icode_label2rtl_label/2]).
-
-%-------------------------------------------------------------------------
-
--include("../main/hipe.hrl").
--include("../icode/hipe_icode.hrl").
-
-%-------------------------------------------------------------------------
-
-%% @spec init(IcodeRecord::#icode{}) -> {Args, VarMap}
-%%
-%% @doc Initializes gensym for RTL.
-
--spec init(#icode{}) -> {[_], _}. % XXX: fix me please
-
-init(IcodeRecord) ->
- hipe_gensym:init(rtl),
- hipe_gensym:set_var(rtl, hipe_rtl_arch:first_virtual_reg()),
- hipe_gensym:set_label(rtl, 0),
- VarMap = new_var_map(),
- {_Args, _VarMap1} = ivs2rvs(hipe_icode:icode_params(IcodeRecord), VarMap).
-
-
-%%------------------------------------------------------------------------
-%%
-%% Mapping of labels and variables from Icode to RTL.
-%%
-%%------------------------------------------------------------------------
-
-
-%% @spec icode_label2rtl_label(Icode_Label::term(), LabelMap::term()) ->
-%% {RTL_Label, NewLabelMap}
-%%
-%% @doc Converts an Icode label to an RTL label.
-
-icode_label2rtl_label(LabelName, Map) ->
- case lookup(LabelName, Map) of
- {value, NewLabel} ->
- {NewLabel, Map};
- none ->
- NewLabel = hipe_rtl:mk_new_label(),
- {NewLabel, insert(LabelName, NewLabel, Map)}
- end.
-
-
-%% @spec ivs2rvs(Icode_Vars::[term()], VarMap::term()) -> {[RTL_Var],NewVarMap}
-%%
-%% @doc Converts a list of Icode variables to a list of RTL variables.
-
-ivs2rvs([], VarMap) ->
- {[], VarMap};
-ivs2rvs([V|Vs], VarMap) ->
- {NewV, VarMap0} = icode_var2rtl_var(V, VarMap),
- {NewVs, VarMap1} = ivs2rvs(Vs, VarMap0),
- {[NewV|NewVs], VarMap1}.
-
-
-%% @spec icode_var2rtl_var(Icode_Var::term(), VarMap::term()) ->
-%% {RTL_Var, NewVarMap}
-%%
-%% @doc Converts an Icode variable to an RTL variable.
-
-icode_var2rtl_var(Var, Map) ->
- Value = lookup(Var, Map),
- case Value of
- none ->
- case type_of_var(Var) of
- fvar ->
- NewVar = hipe_rtl:mk_new_fpreg(),
- {NewVar, insert(Var, NewVar, Map)};
- var ->
- NewVar = hipe_rtl:mk_new_var(),
- {NewVar, insert(Var, NewVar, Map)};
- {reg, IsGcSafe} ->
- NewVar =
- case IsGcSafe of
- true -> hipe_rtl:mk_new_reg_gcsafe();
- false -> hipe_rtl:mk_new_reg()
- end,
- {NewVar, insert(Var, NewVar, Map)}
- end;
- {value, NewVar} ->
- {NewVar, Map}
- end.
-
-%%
-%% Simple type test
-%%
-
-type_of_var(X) ->
- case hipe_icode:is_fvar(X) of
- true ->
- fvar;
- false ->
- case hipe_icode:is_var(X) of
- true ->
- var;
- false ->
- case hipe_icode:is_reg(X) of
- true ->
- {reg, hipe_icode:reg_is_gcsafe(X)};
- false ->
- %% Sanity check
- case hipe_icode:is_const(X) of
- true -> const;
- false ->
- exit({"Unknown Icode variable", X})
- end
- end
- end
- end.
-
-%%
-%% Helping utilities
-%%
-
-new_var_map() ->
- gb_trees:empty().
-
-lookup(V, Map) ->
- gb_trees:lookup(V, Map).
-
-insert(Key, Val, Map) ->
- gb_trees:insert(Key, Val, Map).
diff --git a/lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl b/lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl
deleted file mode 100644
index 01d7e89ccd..0000000000
--- a/lib/hipe/rtl/hipe_rtl_verify_gcsafe.erl
+++ /dev/null
@@ -1,89 +0,0 @@
-%% -*- mode: erlang; erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
--module(hipe_rtl_verify_gcsafe).
-
--export([check/1]).
-
--include("../flow/cfg.hrl"). %% needed for the specs
--include("hipe_rtl.hrl").
-
-check(CFG) ->
- Liveness = hipe_rtl_liveness:analyze(CFG),
- put({?MODULE, 'fun'}, CFG#cfg.info#cfg_info.'fun'),
- lists:foreach(
- fun(Lb) ->
- put({?MODULE, label}, Lb),
- Liveout = hipe_rtl_liveness:liveout(Liveness, Lb),
- BB = hipe_rtl_cfg:bb(CFG, Lb),
- check_instrs(lists:reverse(hipe_bb:code(BB)), Liveout)
- end, hipe_rtl_cfg:labels(CFG)),
- erase({?MODULE, 'fun'}),
- erase({?MODULE, label}),
- erase({?MODULE, instr}),
- ok.
-
-check_instrs([], _Livein) -> ok;
-check_instrs([I|Is], LiveOut) ->
- Def = ordsets:from_list(hipe_rtl:defines(I)),
- Use = ordsets:from_list(hipe_rtl:uses(I)),
- LiveOver = ordsets:subtract(LiveOut, Def),
- LiveIn = ordsets:union(LiveOver, Use),
- case (hipe_rtl:is_call(I)
- andalso not safe_primop(hipe_rtl:call_fun(I)))
- orelse is_record(I, gctest)
- of
- false -> ok;
- true ->
- put({?MODULE, instr}, I),
- lists:foreach(fun verify_live/1, LiveOver)
- end,
- check_instrs(Is, LiveIn).
-
-verify_live(T) ->
- case hipe_rtl:is_reg(T) of
- false -> ok;
- true ->
- case hipe_rtl:reg_is_gcsafe(T) of
- true -> ok;
- false ->
- error({gcunsafe_live_over_call,
- get({?MODULE, 'fun'}),
- {label, get({?MODULE, label})},
- get({?MODULE, instr}),
- T})
- end
- end.
-
-%% Primops that can't gc
-%% Note: This information is essentially duplicated from hipe_bif_list.m4
-safe_primop(is_divisible) -> true;
-safe_primop(is_unicode) -> true;
-safe_primop(cmp_2) -> true;
-safe_primop(eq_2) -> true;
-safe_primop(bs_allocate) -> true;
-safe_primop(bs_reallocate) -> true;
-safe_primop(bs_utf8_size) -> true;
-safe_primop(bs_get_utf8) -> true;
-safe_primop(bs_put_utf8) -> true;
-safe_primop(bs_utf16_size) -> true;
-safe_primop(bs_get_utf16) -> true;
-safe_primop(bs_validate_unicode_retract) -> true;
-safe_primop(bs_put_small_float) -> true;
-safe_primop(bs_put_bits) -> true;
-safe_primop(emasculate_binary) -> true;
-safe_primop(atomic_inc) -> true;
-%% Not noproc but manually verified
-safe_primop(bs_put_big_integer) -> true;
-safe_primop(_) -> false.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
deleted file mode 100644
index 737f0ec5e3..0000000000
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ /dev/null
@@ -1,1302 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%========================================================================
-%%
-%% Filename : hipe_tagscheme.erl
-%% Note : This is specific to Erlang >= 5.* (i.e. starting with R9).
-%%
-%% Modifications:
-%% 020904: Happi - added support for external pids and ports.
-%%========================================================================
-
--module(hipe_tagscheme).
-
--export([mk_nil/0, mk_fixnum/1, mk_arityval/1, mk_non_value/0]).
--export([is_fixnum/1]).
--export([tag_tuple/2, tag_cons/2]).
--export([test_is_boxed/4, get_header/2]).
--export([test_nil/4, test_cons/4, test_flonum/4, test_fixnum/4,
- test_tuple/4, test_atom/4, test_bignum/4, test_pos_bignum/4,
- test_any_pid/4, test_any_port/4,
- test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
- test_binary/4, test_bitstr/4, test_list/4, test_map/4,
- test_integer/4, test_number/4, test_tuple_N/5,
- test_pos_bignum_arity/6]).
--export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
--export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
- unsafe_fixnum_sub/3,
- fixnum_gt/5, fixnum_lt/5, fixnum_ge/5, fixnum_le/5, fixnum_val/1,
- fixnum_mul/4, fixnum_addsub/5, fixnum_andorxor/4, fixnum_not/2,
- fixnum_bsr/3, fixnum_bsl/3]).
--export([test_either_immed/4]).
--export([unsafe_car/2, unsafe_cdr/2,
- unsafe_constant_element/3, unsafe_update_element/3, element/6]).
--export([unsafe_closure_element/3]).
--export([mk_fun_header/0, tag_fun/2]).
--export([unsafe_untag_float/2, unsafe_tag_float/2]).
--export([mk_sub_binary/6, mk_sub_binary/7]).
--export([unsafe_mk_big/3, unsafe_load_float/3]).
--export([bignum_sizeneed/1, bignum_sizeneed_code/2, get_one_word_pos_bignum/3,
- unsafe_get_one_word_pos_bignum/2]).
--export([test_subbinary/3, test_heap_binary/3]).
--export([create_heap_binary/3, create_refc_binary/3, create_refc_binary/4]).
--export([create_matchstate/6, convert_matchstate/1, compare_matchstate/4]).
--export([get_field_addr_from_term/3,
- get_field_from_term/3, get_field_from_pointer/3,
- set_field_from_term/3, set_field_from_pointer/3,
- extract_matchbuffer/2, extract_binary_bytes/2]).
-
--include("hipe_rtl.hrl").
--include("hipe_literals.hrl").
-
--export([if_fun_get_arity_and_address/5]).
-
--undef(TAG_PRIMARY_BOXED).
--undef(TAG_IMMED2_MASK).
--undef(TAG_IMMED2_CATCH).
--undef(TAG_IMMED2_SIZE).
-
-%%------------------------------------------------------------------------
-
--define(TAG_PRIMARY_SIZE, 2).
--define(TAG_PRIMARY_MASK, 16#3).
--define(TAG_PRIMARY_HEADER, 16#0).
--define(TAG_PRIMARY_LIST, 16#1).
--define(TAG_PRIMARY_BOXED, 16#2).
--define(TAG_PRIMARY_IMMED1, 16#3).
-
-%% Only when ?ERTS_USE_LITERAL_TAG =:= 1
--define(TAG_PTR_MASK__, 16#7).
--define(TAG_LITERAL_PTR, 16#4).
-
--define(TAG_IMMED1_SIZE, 4).
--define(TAG_IMMED1_MASK, 16#F).
--define(TAG_IMMED1_PID, ((16#0 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)).
--define(TAG_IMMED1_PORT, ((16#1 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)).
--define(TAG_IMMED1_IMMED2,((16#2 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)).
--define(TAG_IMMED1_SMALL, ((16#3 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)).
-
--define(TAG_IMMED2_SIZE, 6).
--define(TAG_IMMED2_MASK, 16#3F).
--define(TAG_IMMED2_ATOM, ((16#0 bsl ?TAG_IMMED1_SIZE) bor ?TAG_IMMED1_IMMED2)).
--define(TAG_IMMED2_CATCH, ((16#1 bsl ?TAG_IMMED1_SIZE) bor ?TAG_IMMED1_IMMED2)).
--define(TAG_IMMED2_NIL, ((16#3 bsl ?TAG_IMMED1_SIZE) bor ?TAG_IMMED1_IMMED2)).
-
--define(TAG_HEADER_ARITYVAL,((16#0 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_BIN_MATCHSTATE, ((16#1 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_POS_BIG, ((16#2 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_NEG_BIG, ((16#3 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(BIG_SIGN_BIT, (16#1 bsl ?TAG_PRIMARY_SIZE)).
--define(TAG_HEADER_REF, ((16#4 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_FUN, ((16#5 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_FLOAT, ((16#6 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_EXPORT, ((16#7 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(BINARY_XXX_MASK, (16#3 bsl ?TAG_PRIMARY_SIZE)).
--define(TAG_HEADER_REFC_BIN,((16#8 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_HEAP_BIN,((16#9 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_SUB_BIN, ((16#A bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_EXTERNAL_PID, ((16#C bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_EXTERNAL_PORT,((16#D bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_EXTERNAL_REF, ((16#E bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
--define(TAG_HEADER_MAP, ((16#F bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-
--define(TAG_HEADER_MASK, 16#3F).
--define(HEADER_ARITY_OFFS, 6).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-mk_header(SZ, TAG) -> (SZ bsl ?HEADER_ARITY_OFFS) + TAG.
-
-mk_arityval(SZ) -> mk_header(SZ, ?TAG_HEADER_ARITYVAL).
-
-size_from_header(Sz, Header) ->
- [hipe_rtl:mk_alu(Sz, Header, 'srl', hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))].
-
-mk_var_header(Header, Size, Tag) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, Size, sll, hipe_rtl:mk_imm(?HEADER_ARITY_OFFS)),
- hipe_rtl:mk_alu(Header, Tmp, 'add', hipe_rtl:mk_imm(Tag))].
-
-mk_fixnum(X) -> (X bsl ?TAG_IMMED1_SIZE) + ?TAG_IMMED1_SMALL.
-
--define(NIL, ((-1 bsl ?TAG_IMMED2_SIZE) bor ?TAG_IMMED2_NIL)).
-mk_nil() -> ?NIL.
-%% mk_atom(X) -> (X bsl ?TAG_IMMED2_SIZE) + ?TAG_IMMED2_ATOM.
-mk_non_value() -> ?THE_NON_VALUE.
-
--spec is_fixnum(integer()) -> boolean().
-is_fixnum(N) when is_integer(N) ->
- Bits = ?bytes_to_bits(hipe_rtl_arch:word_size()) - ?TAG_IMMED1_SIZE,
- (N =< ((1 bsl (Bits - 1)) - 1)) andalso (N >= -(1 bsl (Bits - 1))).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--define(HEADER_EXPORT, mk_header(1, ?TAG_HEADER_EXPORT)).
--define(HEADER_FUN, mk_header(?ERL_FUN_SIZE-2, ?TAG_HEADER_FUN)).
--define(HEADER_PROC_BIN, mk_header(?PROC_BIN_WORDSIZE-1, ?TAG_HEADER_REFC_BIN)).
--define(HEADER_SUB_BIN, mk_header(?SUB_BIN_WORDSIZE-2, ?TAG_HEADER_SUB_BIN)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-tag_boxed(Res, X) ->
- hipe_rtl:mk_alu(Res, X, 'add', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)).
-
-%% tag_bignum(Res, X) -> tag_boxed(Res, X).
-tag_flonum(Res, X) -> tag_boxed(Res, X).
-tag_tuple(Res, X) -> tag_boxed(Res, X).
-
-tag_cons(Res, X) ->
- hipe_rtl:mk_alu(Res, X, 'add', hipe_rtl:mk_imm(?TAG_PRIMARY_LIST)).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-ptr_val(Res, X) ->
- hipe_rtl:mk_alu(Res, X, 'and', hipe_rtl:mk_imm(bnot ?TAG_PTR_MASK__)).
-
-%% Returns {Base, Offset, Untag}. To be used like, for example:
-%% {Base, Offset, Untag} = untag_ptr(X, ?TAG_PRIMARY_BOXED),
-%% ...
-%% [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
-%%
-%% NB: Base might either be X or a new temp. It must thus not be modified.
-untag_ptr(X, Tag) ->
- case ?ERTS_USE_LITERAL_TAG of
- 0 ->
- {X, -Tag, []};
- 1 ->
- Base = hipe_rtl:mk_new_reg(),
- Untag = ptr_val(Base, X),
- {Base, 0, Untag}
- end.
-
-untag_ptr_nooffset(Dst, X, Tag) ->
- %% We could just use ptr_val in all cases, but subtraction can use LEA on x86
- %% and can be inlined into effective address computations on several
- %% architectures.
- case ?ERTS_USE_LITERAL_TAG of
- 0 ->
- hipe_rtl:mk_alu(Dst, X, 'sub', hipe_rtl:mk_imm(Tag));
- 1 ->
- ptr_val(Dst, X)
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%% Operations to test if an object has a known type T.
-
-test_nil(X, TrueLab, FalseLab, Pred) ->
- hipe_rtl:mk_branch(X, eq, hipe_rtl:mk_imm(?NIL), TrueLab, FalseLab, Pred).
-
-test_cons(X, TrueLab, FalseLab, Pred) ->
- Mask = hipe_rtl:mk_imm(?TAG_PRIMARY_MASK - ?TAG_PRIMARY_LIST),
- hipe_rtl:mk_branch(X, 'and', Mask, 'eq', TrueLab, FalseLab, Pred).
-
-test_is_boxed(X, TrueLab, FalseLab, Pred) ->
- Mask = hipe_rtl:mk_imm(?TAG_PRIMARY_MASK - ?TAG_PRIMARY_BOXED),
- hipe_rtl:mk_branch(X, 'and', Mask, 'eq', TrueLab, FalseLab, Pred).
-
-get_header(Res, X) ->
- {Base, Offset, Untag} = untag_ptr(X, ?TAG_PRIMARY_BOXED),
- [Untag, hipe_rtl:mk_load(Res, Base, hipe_rtl:mk_imm(Offset))].
-
-mask_and_compare(X, Mask, Value, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, X, 'sub', hipe_rtl:mk_imm(Value)),
- hipe_rtl:mk_branch(Tmp, 'and', hipe_rtl:mk_imm(Mask),
- eq, TrueLab, FalseLab, Pred)].
-
-test_immed1(X, Value, TrueLab, FalseLab, Pred) ->
- mask_and_compare(X, ?TAG_IMMED1_MASK, Value, TrueLab, FalseLab, Pred).
-
-test_internal_pid(X, TrueLab, FalseLab, Pred) ->
- test_immed1(X, ?TAG_IMMED1_PID, TrueLab, FalseLab, Pred).
-
-test_any_pid(X, TrueLab, FalseLab, Pred) ->
- NotInternalPidLab = hipe_rtl:mk_new_label(),
- [test_internal_pid(X, TrueLab, hipe_rtl:label_name(NotInternalPidLab), Pred),
- NotInternalPidLab,
- test_external_pid(X, TrueLab, FalseLab, Pred)].
-
-test_external_pid(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- ExternalPidMask = ?TAG_HEADER_MASK,
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, ExternalPidMask, ?TAG_HEADER_EXTERNAL_PID,
- TrueLab, FalseLab, Pred)].
-
-test_internal_port(X, TrueLab, FalseLab, Pred) ->
- test_immed1(X, ?TAG_IMMED1_PORT, TrueLab, FalseLab, Pred).
-
-test_any_port(X, TrueLab, FalseLab, Pred) ->
- NotInternalPortLab = hipe_rtl:mk_new_label(),
- [test_internal_port(X, TrueLab, hipe_rtl:label_name(NotInternalPortLab), Pred),
- NotInternalPortLab,
- test_external_port(X, TrueLab, FalseLab, Pred)].
-
-test_external_port(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- ExternalPortMask = ?TAG_HEADER_MASK,
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, ExternalPortMask, ?TAG_HEADER_EXTERNAL_PORT,
- TrueLab, FalseLab, Pred)].
-
-test_fixnum(X, TrueLab, FalseLab, Pred) ->
- test_immed1(X, ?TAG_IMMED1_SMALL, TrueLab, FalseLab, Pred).
-
-test_atom(X, TrueLab, FalseLab, Pred) ->
- mask_and_compare(X, ?TAG_IMMED2_MASK, ?TAG_IMMED2_ATOM,
- TrueLab, FalseLab, Pred).
-
-test_tuple(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- hipe_rtl:mk_branch(Tmp, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
- TrueLab, FalseLab, Pred)].
-
-test_tuple_N(X, N, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(mk_arityval(N)),
- TrueLab, FalseLab, Pred)].
-
-test_map(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- MapMask = ?TAG_HEADER_MASK,
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, MapMask, ?TAG_HEADER_MAP, TrueLab, FalseLab, Pred)].
-
-test_ref(X, TrueLab, FalseLab, Pred) ->
- Hdr = hipe_rtl:mk_new_reg_gcsafe(),
- Tag = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- TwoThirdsTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Hdr, X),
- hipe_rtl:mk_alu(Tag, Hdr, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK)),
- hipe_rtl:mk_branch(Tag, 'eq', hipe_rtl:mk_imm(?TAG_HEADER_REF),
- TrueLab, hipe_rtl:label_name(TwoThirdsTrueLab), Pred),
- TwoThirdsTrueLab,
- hipe_rtl:mk_branch(Tag, 'eq', hipe_rtl:mk_imm(?TAG_HEADER_EXTERNAL_REF),
- TrueLab, FalseLab, Pred)
- ].
-
-test_closure(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_FUN,
- TrueLab, FalseLab, Pred)].
-
-test_fun(X, TrueLab, FalseLab, Pred) ->
- Hdr = hipe_rtl:mk_new_reg_gcsafe(),
- Tag = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- TwoThirdsTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Hdr, X),
- hipe_rtl:mk_alu(Tag, Hdr, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK)),
- hipe_rtl:mk_branch(Tag, 'eq', hipe_rtl:mk_imm(?TAG_HEADER_FUN),
- TrueLab, hipe_rtl:label_name(TwoThirdsTrueLab), Pred),
- TwoThirdsTrueLab,
- hipe_rtl:mk_branch(Tag, 'eq', hipe_rtl:mk_imm(?TAG_HEADER_EXPORT),
- TrueLab, FalseLab, Pred)].
-
-test_fun2(X, Arity, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- TFalse = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_call([Tmp], {erlang,is_function,2}, [X,Arity],
- hipe_rtl:label_name(HalfTrueLab), FalseLab, 'not_remote'),
- HalfTrueLab,
- hipe_rtl:mk_load_atom(TFalse, 'false'),
- hipe_rtl:mk_branch(Tmp, 'ne', TFalse, TrueLab, FalseLab, Pred)].
-
-flonum_header() ->
- mk_header(8 div hipe_rtl_arch:word_size(), ?TAG_HEADER_FLOAT).
-
-test_flonum(X, TrueLab, FalseLab, Pred) ->
- HeaderFlonum = flonum_header(),
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(HeaderFlonum),
- TrueLab, FalseLab, Pred)].
-
-test_bignum(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- BigMask = ?TAG_HEADER_MASK - ?BIG_SIGN_BIT,
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
- TrueLab, FalseLab, Pred)].
-
-test_pos_bignum(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- BigMask = ?TAG_HEADER_MASK,
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
- TrueLab, FalseLab, Pred)].
-
-test_pos_bignum_arity(X, Arity, TrueLab, NotPosBignumLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- BoxedLab = hipe_rtl:mk_new_label(),
- HeaderImm = hipe_rtl:mk_imm(mk_header(Arity, ?TAG_HEADER_POS_BIG)),
- [test_is_boxed(X, hipe_rtl:label_name(BoxedLab), NotPosBignumLab, Pred),
- BoxedLab,
- get_header(Tmp, X)] ++
- case NotPosBignumLab =:= FalseLab of
- true -> [];
- false ->
- BignumLab = hipe_rtl:mk_new_label(),
- BigMask = ?TAG_HEADER_MASK,
- [mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
- hipe_rtl:label_name(BignumLab), NotPosBignumLab, Pred),
- BignumLab]
- end ++
- [hipe_rtl:mk_branch(Tmp, 'eq', HeaderImm, TrueLab, FalseLab, Pred)].
-
-test_matchstate(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_BIN_MATCHSTATE,
- TrueLab, FalseLab, Pred)].
-
-test_bitstr_header(HdrTmp, TrueLab, FalseLab, Pred) ->
- Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK,
- mask_and_compare(HdrTmp, Mask, ?TAG_HEADER_REFC_BIN, TrueLab, FalseLab, Pred).
-
-test_bitstr(X, TrueLab, FalseLab, Pred) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- HalfTrueLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
- HalfTrueLab,
- get_header(Tmp, X),
- test_bitstr_header(Tmp, TrueLab, FalseLab, Pred)].
-
-test_binary(X, TrueLab, FalseLab, Pred) ->
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
- IsBoxedLab = hipe_rtl:mk_new_label(),
- IsBitStrLab = hipe_rtl:mk_new_label(),
- IsSubBinLab = hipe_rtl:mk_new_label(),
- [test_is_boxed(X, hipe_rtl:label_name(IsBoxedLab), FalseLab, Pred),
- IsBoxedLab,
- get_header(Tmp1, X),
- test_bitstr_header(Tmp1, hipe_rtl:label_name(IsBitStrLab), FalseLab, Pred),
- IsBitStrLab,
- mask_and_compare(Tmp1, ?TAG_HEADER_MASK, ?TAG_HEADER_SUB_BIN,
- hipe_rtl:label_name(IsSubBinLab), TrueLab, 0.5),
- IsSubBinLab,
- get_field_from_term({sub_binary, bitsize}, X, Tmp2),
- hipe_rtl:mk_branch(Tmp2, eq, hipe_rtl:mk_imm(0), TrueLab, FalseLab, Pred)].
-
-test_list(X, TrueLab, FalseLab, Pred) ->
- Lab = hipe_rtl:mk_new_label(),
- [test_cons(X, TrueLab, hipe_rtl:label_name(Lab), 0.5),
- Lab,
- test_nil(X, TrueLab, FalseLab, Pred)].
-
-test_integer(X, TrueLab, FalseLab, Pred) ->
- Lab = hipe_rtl:mk_new_label(),
- [test_fixnum(X, TrueLab, hipe_rtl:label_name(Lab), 0.5),
- Lab,
- test_bignum(X, TrueLab, FalseLab, Pred)].
-
-test_number(X, TrueLab, FalseLab, Pred) ->
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- Lab3 = hipe_rtl:mk_new_label(),
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- BigMask = ?TAG_HEADER_MASK - ?BIG_SIGN_BIT,
- HeaderFlonum = flonum_header(),
- [test_fixnum(X, TrueLab, hipe_rtl:label_name(Lab1), 0.5),
- Lab1,
- test_is_boxed(X, hipe_rtl:label_name(Lab2), FalseLab, 0.5),
- Lab2,
- get_header(Tmp, X),
- mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
- TrueLab, hipe_rtl:label_name(Lab3), 0.5),
- Lab3,
- hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(HeaderFlonum),
- TrueLab, FalseLab, Pred)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-tag_fixnum(DestVar, SrcReg) ->
- [hipe_rtl:mk_fixnumop(DestVar, SrcReg, tag)].
-%% [hipe_rtl:mk_alu(DestVar, SrcReg, sll, hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)),
-%% hipe_rtl:mk_alu(DestVar, DestVar, add, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))].
-
-realtag_fixnum(DestVar, SrcReg) ->
- [hipe_rtl:mk_alu(DestVar, SrcReg, sll, hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)),
- hipe_rtl:mk_alu(DestVar, DestVar, add, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))].
-
-untag_fixnum(DestReg, SrcVar) ->
- hipe_rtl:mk_fixnumop(DestReg, SrcVar, untag).
-%% hipe_rtl:mk_alu(DestReg, SrcVar, 'sra', hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)).
-
-realuntag_fixnum(DestReg, SrcVar) ->
- hipe_rtl:mk_alu(DestReg, SrcVar, 'sra', hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)).
-
-fixnum_val(Fixnum) ->
- Fixnum bsr ?TAG_IMMED1_SIZE.
-
-test_fixnums(Args, TrueLab, FalseLab, Pred) ->
- {Reg, Ands} = test_fixnums_1(Args, []),
- Ands ++ [test_fixnum(Reg, TrueLab, FalseLab, Pred)].
-
-test_fixnums_1([Arg1, Arg2], Acc) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- {Tmp, lists:reverse([hipe_rtl:mk_alu(Tmp, Arg1, 'and', Arg2)|Acc])};
-test_fixnums_1([Arg1, Arg2|Args], Acc) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- test_fixnums_1([Tmp|Args], [hipe_rtl:mk_alu(Tmp, Arg1, 'and', Arg2)|Acc]).
-
-test_two_fixnums(Arg, Arg, FalseLab) ->
- TrueLab = hipe_rtl:mk_new_label(),
- [test_fixnum(Arg, hipe_rtl:label_name(TrueLab), FalseLab, 0.99),
- TrueLab];
-test_two_fixnums(Arg1, Arg2, FalseLab) ->
- TrueLab = hipe_rtl:mk_new_label(),
- case hipe_rtl:is_imm(Arg1) orelse hipe_rtl:is_imm(Arg2) of
- true ->
- {Imm, Var} =
- case hipe_rtl:is_imm(Arg1) of
- true -> {Arg1, Arg2};
- false -> {Arg2, Arg1}
- end,
- Value = hipe_rtl:imm_value(Imm),
- case Value band ?TAG_IMMED1_MASK of
- ?TAG_IMMED1_SMALL ->
- [test_fixnum(Var, hipe_rtl:label_name(TrueLab), FalseLab, 0.99),
- TrueLab];
- _ ->
- [hipe_rtl:mk_goto(FalseLab)]
- end;
- false ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, Arg1, 'and', Arg2),
- test_fixnum(Tmp, hipe_rtl:label_name(TrueLab), FalseLab, 0.99),
- TrueLab]
- end.
-
-fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, CmpOp) ->
- hipe_rtl:mk_branch(Arg1, CmpOp, Arg2, TrueLab, FalseLab, Pred).
-
-fixnum_gt(Arg1, Arg2, TrueLab, FalseLab, Pred) ->
- fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, gt).
-
-fixnum_lt(Arg1, Arg2, TrueLab, FalseLab, Pred) ->
- fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, lt).
-
-fixnum_ge(Arg1, Arg2, TrueLab, FalseLab, Pred) ->
- fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, ge).
-
-fixnum_le(Arg1, Arg2, TrueLab, FalseLab, Pred) ->
- fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, le).
-
-%% We know the answer will be a fixnum
-unsafe_fixnum_add(Arg1, Arg2, Res) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, Arg2, sub, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
- hipe_rtl:mk_alu(Res, Arg1, add, Tmp)].
-
-%% We know the answer will be a fixnum
-unsafe_fixnum_sub(Arg1, Arg2, Res) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, Arg2, sub, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
- hipe_rtl:mk_alu(Res, Arg1, sub, Tmp)].
-
-%%% (16X+tag)+((16Y+tag)-tag) = 16X+tag+16Y = 16(X+Y)+tag
-%%% (16X+tag)-((16Y+tag)-tag) = 16X+tag-16Y = 16(X-Y)+tag
-fixnum_addsub(AluOp, Arg1, Arg2, FinalRes, OtherLab) ->
- NoOverflowLab = hipe_rtl:mk_new_label(),
- %% XXX: Consider moving this test to the users of fixnum_addsub.
- {Res, Tail} =
- case Arg1 =/= FinalRes andalso Arg2 =/= FinalRes of
- true ->
- %% Args differ from res.
- {FinalRes, [NoOverflowLab]};
- false ->
- %% At least one of the arguments is the same as Res.
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- {Tmp, [NoOverflowLab, hipe_rtl:mk_move(FinalRes, Tmp)]}
- end,
- case (hipe_rtl:is_imm(Arg1) andalso AluOp =:= 'add')
- orelse hipe_rtl:is_imm(Arg2)
- of
- true ->
- %% Pre-compute the untagged immediate. The optimisers won't do this for us
- %% since they don't know that the untag never underflows.
- {Var, Imm0} =
- case hipe_rtl:is_imm(Arg2) of
- true -> {Arg1, Arg2};
- false -> {Arg2, Arg1}
- end,
- Imm = hipe_rtl:mk_imm(hipe_rtl:imm_value(Imm0) - ?TAG_IMMED1_SMALL),
- [hipe_rtl:mk_alub(Res, Var, AluOp, Imm, not_overflow,
- hipe_rtl:label_name(NoOverflowLab),
- hipe_rtl:label_name(OtherLab), 0.99)
- |Tail];
- false ->
- %% Commute add to save a move on x86
- {UntagFirst, Lhs, Rhs} =
- case AluOp of
- 'add' -> {Arg1, Res, Arg2};
- 'sub' -> {Arg2, Arg1, Res}
- end,
- [hipe_rtl:mk_alu(Res, UntagFirst, sub,
- hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
- hipe_rtl:mk_alub(Res, Lhs, AluOp, Rhs, not_overflow,
- hipe_rtl:label_name(NoOverflowLab),
- hipe_rtl:label_name(OtherLab), 0.99)
- |Tail]
- end.
-
-%%% ((16X+tag) div 16) * ((16Y+tag)-tag) + tag = X*16Y+tag = 16(XY)+tag
-fixnum_mul(Arg1, Arg2, Res, OtherLab) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- U1 = hipe_rtl:mk_new_reg_gcsafe(),
- U2 = hipe_rtl:mk_new_reg_gcsafe(),
- NoOverflowLab = hipe_rtl:mk_new_label(),
- [untag_fixnum(U1, Arg1),
- hipe_rtl:mk_alu(U2, Arg2, 'sub', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
- hipe_rtl:mk_alub(Tmp, U1, 'mul', U2, overflow, hipe_rtl:label_name(OtherLab),
- hipe_rtl:label_name(NoOverflowLab), 0.01),
- NoOverflowLab,
- hipe_rtl:mk_alu(Res, Tmp, 'add', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))].
-
-fixnum_andorxor(AluOp, Arg1, Arg2, Res) ->
- case AluOp of
- 'xor' ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, Arg1, 'sub', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
- hipe_rtl:mk_alu(Res, Tmp, 'xor', Arg2)];
- _ -> hipe_rtl:mk_alu(Res, Arg1, AluOp, Arg2)
- end.
-
-fixnum_not(Arg, Res) ->
- Mask = (-1 bsl ?TAG_IMMED1_SIZE),
- hipe_rtl:mk_alu(Res, Arg, 'xor', hipe_rtl:mk_imm(Mask)).
-
-fixnum_bsr(Arg1, Arg2, Res) ->
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
- [untag_fixnum(Tmp1, Arg2),
- hipe_rtl:mk_alu(Tmp2, Arg1, 'sra', Tmp1),
- hipe_rtl:mk_alu(Res, Tmp2, 'or', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))].
-
-%% If someone knows how to make this better, please do.
-fixnum_bsl(Arg1, Arg2, Res) ->
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp3 = hipe_rtl:mk_new_reg_gcsafe(),
- [untag_fixnum(Tmp2, Arg2),
- hipe_rtl:mk_alu(Tmp1, Arg1, 'sub', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
- hipe_rtl:mk_alu(Tmp3, Tmp1, 'sll', Tmp2),
- hipe_rtl:mk_alu(Res, Tmp3, 'or', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% Test if either of two values are immediate (primary tag IMMED1, 0x3)
-test_either_immed(Arg1, Arg2, TrueLab, FalseLab) ->
- %% This test assumes primary tag 0x0 is reserved and immed has tag 0x3
- 16#0 = ?TAG_PRIMARY_HEADER,
- 16#3 = ?TAG_PRIMARY_IMMED1,
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp1, Arg1, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Tmp2, Arg2, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Tmp2, Tmp2, 'or', Tmp1),
- hipe_rtl:mk_branch(Tmp2, 'and', hipe_rtl:mk_imm(2), eq,
- FalseLab, TrueLab, 0.01)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-unsafe_car(Dst, Arg) ->
- {Base, Offset, Untag} = untag_ptr(Arg, ?TAG_PRIMARY_LIST),
- [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
-
-unsafe_cdr(Dst, Arg) ->
- {Base, Offset, Untag} = untag_ptr(Arg, ?TAG_PRIMARY_LIST),
- WordSize = hipe_rtl_arch:word_size(),
- [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset+WordSize))].
-
-unsafe_constant_element(Dst, Index, Tuple) -> % Index is an immediate
- WordSize = hipe_rtl_arch:word_size(),
- {Base, Offset0, Untag} = untag_ptr(Tuple, ?TAG_PRIMARY_BOXED),
- Offset = Offset0 + WordSize * hipe_rtl:imm_value(Index),
- [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
-
-unsafe_update_element(Tuple, Index, Value) -> % Index is an immediate
- WordSize = hipe_rtl_arch:word_size(),
- {Base, Offset0, Untag} = untag_ptr(Tuple, ?TAG_PRIMARY_BOXED),
- Offset = Offset0 + WordSize * hipe_rtl:imm_value(Index),
- [Untag, hipe_rtl:mk_store(Base, hipe_rtl:mk_imm(Offset), Value)].
-
-%%% wrong semantics
-%% unsafe_variable_element(Dst, Index, Tuple) -> % Index is an unknown fixnum
-%% %% Load word at (Tuple - 2) + ((Index >> 4) << 2).
-%% %% Offset = ((Index >> 4) << 2) - 2.
-%% %% Index = x..x1111 (fixnum tag is 2#1111).
-%% %% (Index >> 2) = 00x..x11 and ((Index >> 4) << 2) = 00x..x00.
-%% %% Therefore, ((Index >> 4) << 2) = (Index >> 2) - 3.
-%% %% So Offset = ((Index >> 4) << 2) - 2 = (Index >> 2) - (3 + 2).
-%% Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
-%% Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
-%% Shift = ?TAG_IMMED1_SIZE - 2,
-%% {Base, Off0, Untag} = untag_ptr(Tuple, ?TAG_PRIMARY_BOXED),
-%% OffAdj = (?TAG_IMMED1_SMALL bsr Shift) - Off0,
-%% [hipe_rtl:mk_alu(Tmp1, Index, 'srl', hipe_rtl:mk_imm(Shift)),
-%% hipe_rtl:mk_alu(Tmp2, Tmp1, 'sub', hipe_rtl:mk_imm(OffAdj)),
-%% Untag,
-%% hipe_rtl:mk_load(Base, Tuple, Tmp2)].
-
-element(Dst, Index, Tuple, FailLabName, {tuple, A}, IndexInfo) ->
- FixnumOkLab = hipe_rtl:mk_new_label(),
- IndexOkLab = hipe_rtl:mk_new_label(),
- UIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Arity = hipe_rtl:mk_imm(A),
- case IndexInfo of
- valid ->
- %% This is no branch, 1 load and 3 alus = 4 instr
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
- Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
- [untag_fixnum(UIndex, Index),
- untag_ptr_nooffset(Ptr, Tuple, ?TAG_PRIMARY_BOXED),
- hipe_rtl:mk_alu(Offset, UIndex, 'sll',
- hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size())),
- hipe_rtl:mk_load(Dst, Ptr, Offset)];
- fixnums ->
- %% This is 1 branch, 1 load and 4 alus = 6 instr
- [untag_fixnum(UIndex, Index),
- gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)];
- _ ->
- %% This is 3 branches, 1 load and 5 alus = 9 instr
- [test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab),
- FailLabName, 0.99),
- FixnumOkLab,
- untag_fixnum(UIndex, Index),
- gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)]
- end;
-element(Dst, Index, Tuple, FailLabName, tuple, IndexInfo) ->
- FixnumOkLab = hipe_rtl:mk_new_label(),
- IndexOkLab = hipe_rtl:mk_new_label(),
- Header = hipe_rtl:mk_new_reg_gcsafe(),
- UIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Arity = hipe_rtl:mk_new_reg_gcsafe(),
- case IndexInfo of
- fixnums ->
- %% This is 1 branch, 2 loads and 5 alus = 8 instr
- [get_header(Header, Tuple),
- untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Arity,Header,'srl',hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)];
- Num when is_integer(Num) ->
- %% This is 1 branch, 1 load and 3 alus = 5 instr
- gen_element_tail(Dst, Tuple, hipe_rtl:mk_imm(Num), UIndex, FailLabName,
- IndexOkLab);
- _ ->
- %% This is 2 branches, 2 loads and 6 alus = 10 instr
- [test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab), FailLabName, 0.99),
- FixnumOkLab,
- get_header(Header, Tuple),
- untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Arity,Header,'srl',hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)]
- end;
-element(Dst, Index, Tuple, FailLabName, unknown, IndexInfo) ->
- FixnumOkLab = hipe_rtl:mk_new_label(),
- BoxedOkLab = hipe_rtl:mk_new_label(),
- TupleOkLab = hipe_rtl:mk_new_label(),
- IndexOkLab = hipe_rtl:mk_new_label(),
- Header = hipe_rtl:mk_new_reg_gcsafe(),
- UIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Arity = hipe_rtl:mk_new_reg_gcsafe(),
- case IndexInfo of
- fixnums ->
- %% This is 3 branches, 2 loads and 5 alus = 10 instr
- [test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab),
- FailLabName, 0.99),
- BoxedOkLab,
- get_header(Header, Tuple),
- hipe_rtl:mk_branch(Header, 'and',
- hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
- hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99),
- TupleOkLab,
- untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Arity, Header, 'srl',
- hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)];
- Num when is_integer(Num) ->
- %% This is 3 branches, 2 loads and 4 alus = 9 instr
- [test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab),
- FailLabName, 0.99),
- BoxedOkLab,
- get_header(Header, Tuple),
- hipe_rtl:mk_branch(Header, 'and',
- hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
- hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99),
- TupleOkLab,
- hipe_rtl:mk_alu(Arity, Header, 'srl',
- hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Tuple, Arity, hipe_rtl:mk_imm(Num), FailLabName,
- IndexOkLab)];
- _ ->
- %% This is 4 branches, 2 loads, and 6 alus = 12 instr :(
- [test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab),
- FailLabName, 0.99),
- FixnumOkLab,
- test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab),
- FailLabName, 0.99),
- BoxedOkLab,
- get_header(Header, Tuple),
- hipe_rtl:mk_branch(Header, 'and',
- hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
- hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99),
- TupleOkLab,
- untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Arity, Header, 'srl',
- hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)]
- end.
-
-gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab) ->
- ZeroIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
- Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
- %% now check that 1 <= UIndex <= Arity
- %% by checking the equivalent (except for when Arity>=2^(WordSize-1))
- %% (UIndex - 1) <u Arity
- [hipe_rtl:mk_alu(ZeroIndex, UIndex, 'sub', hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_branch(ZeroIndex, 'geu', Arity, FailLabName,
- hipe_rtl:label_name(IndexOkLab), 0.01),
- IndexOkLab,
- untag_ptr_nooffset(Ptr, Tuple, ?TAG_PRIMARY_BOXED),
- hipe_rtl:mk_alu(Offset, UIndex, 'sll',
- hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size())),
- hipe_rtl:mk_load(Dst, Ptr, Offset)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-unsafe_closure_element(Dst, Index, Closure) -> % Index is an immediate
- %% XXX: Can there even be closure literals?
- {Base, Offset0, Untag} = untag_ptr(Closure, ?TAG_PRIMARY_BOXED),
- Offset = Offset0 %% Untag
- + ?EFT_ENV %% Field offset
- %% Index from 1 to N hence -1)
- + (hipe_rtl_arch:word_size() * (hipe_rtl:imm_value(Index)-1)),
- [Untag, hipe_rtl:mk_load(Dst, Base, hipe_rtl:mk_imm(Offset))].
-
-mk_fun_header() ->
- hipe_rtl:mk_imm(?HEADER_FUN).
-
-tag_fun(Res, X) ->
- tag_boxed(Res, X).
-
-%% untag_fun(Res, X) ->
-%% untag_ptr_nooffset(Res, X, ?TAG_PRIMARY_BOXED).
-
-if_fun_get_arity_and_address(ArityReg, AddressReg, FunP, BadFunLab, Pred) ->
- %% EmuAddressPtrReg = hipe_rtl:mk_new_reg(),
- FEPtrReg = hipe_rtl:mk_new_reg(),
- %% ArityReg = hipe_rtl:mk_new_reg(),
- %% NumFreeReg = hipe_rtl:mk_new_reg(),
- %% RealArityReg = hipe_rtl:mk_new_reg(),
- TrueLab0 = hipe_rtl:mk_new_label(),
- %% TrueLab1 = hipe_rtl:mk_new_label(),
- IsFunCode = test_closure(FunP, hipe_rtl:label_name(TrueLab0), BadFunLab, Pred),
- {Base, Offset, Untag} = untag_ptr(FunP, ?TAG_PRIMARY_BOXED),
- GetArityCode =
- [TrueLab0,
- %% Funp->arity contains the arity
- Untag,
- hipe_rtl:mk_load(ArityReg, Base,
- hipe_rtl:mk_imm(Offset+?EFT_ARITY)),
- hipe_rtl:mk_load(FEPtrReg, Base,
- hipe_rtl:mk_imm(Offset+?EFT_FE)),
- hipe_rtl:mk_load(AddressReg, FEPtrReg,
- hipe_rtl:mk_imm(?EFE_NATIVE_ADDRESS))],
- IsFunCode ++ GetArityCode.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Binary Code
-%%
-
-create_heap_binary(Base, Size, Dst) when is_integer(Size) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- WordSize = hipe_rtl_arch:word_size(),
- NoWords=(Size + 3*WordSize-1) div WordSize,
- NoBytes = NoWords*WordSize,
- HeapBinHeader = hipe_rtl:mk_imm(mk_header(NoWords-1,
- ?TAG_HEADER_HEAP_BIN)),
- [GetHPInsn,
- tag_boxed(Dst, HP),
- set_field_from_pointer({heap_bin, thing_word}, HP, HeapBinHeader),
- set_field_from_pointer({heap_bin, binsize}, HP, hipe_rtl:mk_imm(Size)),
- hipe_rtl:mk_alu(Base, HP, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA)),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(NoBytes)),
- PutHPInsn];
-
-create_heap_binary(Base, Size, Dst) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- WordSize = hipe_rtl_arch:word_size(),
- Log2WordSize = hipe_rtl_arch:log2_word_size(),
- EvenWordSize = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
- Header = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp3 = hipe_rtl:mk_new_reg(), % offset from HP
- Tmp4 = hipe_rtl:mk_new_reg(), % offset from HP
- [GetHPInsn,
- hipe_rtl:mk_alu(Tmp1, Size, add, hipe_rtl:mk_imm(WordSize-1)),
- hipe_rtl:mk_alu(EvenWordSize, Tmp1, sra, hipe_rtl:mk_imm(Log2WordSize)),
- hipe_rtl:mk_alu(Tmp2, EvenWordSize, add, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_alu(Base, HP, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA)),
- mk_var_header(Header, Tmp2, ?TAG_HEADER_HEAP_BIN),
- set_field_from_pointer({heap_bin, thing_word}, HP, Header),
- set_field_from_pointer({heap_bin, binsize}, HP, Size),
- tag_boxed(Dst, HP),
- hipe_rtl:mk_alu(Tmp3, HP, add, Size),
- hipe_rtl:mk_alu(Tmp4, Tmp3, add, hipe_rtl:mk_imm(3*WordSize-1)),
- hipe_rtl:mk_alu(HP, Tmp4, 'and', hipe_rtl:mk_imm(-WordSize)),
- PutHPInsn].
-
-create_refc_binary(Base, Size, Dst) ->
- create_refc_binary(Base, Size, hipe_rtl:mk_imm(0), Dst).
-
-create_refc_binary(Base, Size, Flags, Dst) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- ProcBinHeader = hipe_rtl:mk_imm(?HEADER_PROC_BIN),
- WordSize = hipe_rtl_arch:word_size(),
- Val = hipe_rtl:mk_new_reg(), % offset from Base
- [GetHPInsn,
- tag_boxed(Dst, HP),
- set_field_from_pointer({proc_bin, thing_word}, HP, ProcBinHeader),
- set_field_from_pointer({proc_bin, binsize}, HP, Size),
- heap_arch_spec(HP),
- hipe_rtl:mk_alu(Val, Base, sub, hipe_rtl:mk_imm(?BINARY_ORIG_BYTES)),
- set_field_from_pointer({proc_bin, val}, HP, Val),
- set_field_from_pointer({proc_bin, bytes}, HP, Base),
- set_field_from_pointer({proc_bin, flags}, HP, Flags),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(?PROC_BIN_WORDSIZE*WordSize)),
- PutHPInsn].
-
-heap_arch_spec(HP) ->
- Tmp1 = hipe_rtl:mk_new_reg(), % MSO state
- [hipe_rtl_arch:pcb_load(Tmp1, ?P_OFF_HEAP_FIRST),
- set_field_from_pointer({proc_bin, next}, HP, Tmp1),
- hipe_rtl_arch:pcb_store(?P_OFF_HEAP_FIRST, HP)].
-
-test_heap_binary(Binary, TrueLblName, FalseLblName) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [get_header(Tmp, Binary),
- mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_HEAP_BIN,
- TrueLblName, FalseLblName, 0.5)].
-
-mk_sub_binary(Dst, ByteSize, ByteOffs, BitSize, BitOffs, Orig) ->
- mk_sub_binary(Dst, ByteSize, ByteOffs, BitSize, BitOffs,
- hipe_rtl:mk_imm(0), Orig).
-
-mk_sub_binary(Dst, ByteSize, ByteOffs, BitSize, BitOffs,
- Writable, Orig) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- WordSize = hipe_rtl_arch:word_size(),
- [GetHPInsn,
- tag_boxed(Dst, HP),
- build_sub_binary(Dst, ByteSize, ByteOffs, BitSize, BitOffs, Writable, Orig),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE*WordSize)),
- PutHPInsn].
-
-build_sub_binary(Dst, ByteSize, ByteOffs, BitSize, BitOffs,
- Writable, Orig) ->
- Head = hipe_rtl:mk_imm(?HEADER_SUB_BIN),
- [set_field_from_term({sub_binary, thing_word}, Dst, Head),
- set_field_from_term({sub_binary, binsize}, Dst, ByteSize),
- set_field_from_term({sub_binary, offset}, Dst, ByteOffs),
- set_field_from_term({sub_binary, bitsize}, Dst, BitSize),
- set_field_from_term({sub_binary, bitoffset}, Dst, BitOffs),
- set_field_from_term({sub_binary, is_writable}, Dst, Writable),
- set_field_from_term({sub_binary, orig}, Dst, Orig)].
-
-test_subbinary(Binary, TrueLblName, FalseLblName) ->
- Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [get_header(Tmp, Binary),
- mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_SUB_BIN,
- TrueLblName, FalseLblName, 0.5)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Float Code
-
-unsafe_load_float(DstLo, DstHi, Src) ->
- WordSize = hipe_rtl_arch:word_size(),
- {Base, Offset0, Untag} = untag_ptr(Src, ?TAG_PRIMARY_BOXED),
- Offset1 = Offset0 + WordSize,
- Offset2 = Offset1 + 4, %% This should really be 4 and not WordSize
- case hipe_rtl_arch:endianess() of
- little ->
- [Untag,
- hipe_rtl:mk_load(DstLo, Base, hipe_rtl:mk_imm(Offset1), int32, unsigned),
- hipe_rtl:mk_load(DstHi, Base, hipe_rtl:mk_imm(Offset2), int32, unsigned)];
- big ->
- [Untag,
- hipe_rtl:mk_load(DstHi, Base, hipe_rtl:mk_imm(Offset1), int32, unsigned),
- hipe_rtl:mk_load(DstLo, Base, hipe_rtl:mk_imm(Offset2), int32, unsigned)]
- end.
-
-unsafe_untag_float(Dst, Src) ->
- {Base, Offset0, Untag} = untag_ptr(Src, ?TAG_PRIMARY_BOXED),
- Offset = Offset0 + hipe_rtl_arch:word_size(),
- [Untag, hipe_rtl:mk_fload(Dst, Base, hipe_rtl:mk_imm(Offset))].
-
-unsafe_tag_float(Dst, Src) ->
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- Head = hipe_rtl:mk_imm(flonum_header()),
- WordSize = hipe_rtl_arch:word_size(),
- [GetHPInsn,
- hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), Head),
- hipe_rtl:mk_fstore(HP, hipe_rtl:mk_imm(WordSize), Src),
- tag_flonum(Dst, HP),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(WordSize+8)),
- PutHPInsn].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% BigNum Code
-
-unsafe_mk_big(Dst, Src, Signedness) ->
- WordSize = hipe_rtl_arch:word_size(),
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)),
- NegHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_NEG_BIG)),
- PosLabel = hipe_rtl:mk_new_label(),
- NegLabel = hipe_rtl:mk_new_label(),
- JoinLabel = hipe_rtl:mk_new_label(),
- PutHeaderCode =
- case Signedness of
- unsigned ->
- [hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0*WordSize), PosHead)];
- signed ->
- [hipe_rtl:mk_branch(Src, ge, hipe_rtl:mk_imm(0),
- hipe_rtl:label_name(PosLabel),
- hipe_rtl:label_name(NegLabel)),
- PosLabel,
- hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0*WordSize), PosHead),
- hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLabel)),
- NegLabel,
- hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0*WordSize), NegHead),
- JoinLabel]
- end,
- RestCode =
- [hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(1*WordSize), Src),
- tag_boxed(Dst, HP),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(2*WordSize)),
- PutHPInsn],
- [GetHPInsn] ++ PutHeaderCode ++ RestCode.
-
-get_one_word_pos_bignum(USize, Size, Fail) ->
- Header = hipe_rtl:mk_new_reg(),
- HalfLbl = hipe_rtl:mk_new_label(),
- HalfLblName = hipe_rtl:label_name(HalfLbl),
- PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)),
- [get_header(Header, Size),
- hipe_rtl:mk_branch(Header, eq, PosHead, HalfLblName, Fail),
- HalfLbl |
- unsafe_get_one_word_pos_bignum(USize, Size)].
-
-unsafe_get_one_word_pos_bignum(USize, Size) ->
- WordSize = hipe_rtl_arch:word_size(),
- {Base, Offset, Untag} = untag_ptr(Size, ?TAG_PRIMARY_BOXED),
- Imm = hipe_rtl:mk_imm(1*WordSize+Offset),
- [Untag, hipe_rtl:mk_load(USize, Base, Imm)].
-
--spec bignum_sizeneed(non_neg_integer()) -> non_neg_integer().
-
-bignum_sizeneed(Size) ->
- case is_fixnum(1 bsl Size) of
- true ->
- 0;
- false ->
- WordSizeBits = hipe_rtl_arch:word_size() * 8,
- ((Size + (WordSizeBits-1)) div WordSizeBits) + 1
- end.
-
-bignum_sizeneed_code(SizeReg,FixNumLblName) ->
- WordSizeBits = hipe_rtl_arch:word_size() * 8,
- WordShifts = hipe_rtl_arch:log2_word_size() + 3,
- MaxFixNum = WordSizeBits - ?TAG_IMMED1_SIZE - 1,
- ResReg = hipe_rtl:mk_new_reg_gcsafe(),
- Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
- BigLbl = hipe_rtl:mk_new_label(),
- Code =
- [hipe_rtl:mk_branch(SizeReg, le, hipe_rtl:mk_imm(MaxFixNum),
- FixNumLblName, hipe_rtl:label_name(BigLbl)),
- BigLbl,
- hipe_rtl:mk_alu(Tmp1,SizeReg,add,hipe_rtl:mk_imm(WordSizeBits-1)),
- hipe_rtl:mk_alu(ResReg,Tmp1,srl,hipe_rtl:mk_imm(WordShifts)),
- hipe_rtl:mk_alu(ResReg,ResReg,add,hipe_rtl:mk_imm(1))],
- {ResReg,Code}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% MatchState Code
-
-create_matchstate(Max, BinSize, Base, Offset, Orig, Ms) ->
- WordSize = hipe_rtl_arch:word_size(),
- {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(),
- ByteSize = (Max+1)*WordSize + ?MS_SAVEOFFSET,
- SizeInWords = ((ByteSize div WordSize) - 1),
- Header = hipe_rtl:mk_imm(mk_header(SizeInWords, ?TAG_HEADER_BIN_MATCHSTATE)),
- [GetHPInsn,
- tag_boxed(Ms, HP),
- set_field_from_term({matchstate,thing_word}, Ms, Header),
- set_field_from_term({matchstate,{matchbuffer,orig}}, Ms, Orig),
- set_field_from_term({matchstate,{matchbuffer,base}}, Ms, Base),
- set_field_from_term({matchstate,{matchbuffer,binsize}}, Ms, BinSize),
- set_field_from_term({matchstate,{matchbuffer,offset}}, Ms, Offset),
- set_field_from_term({matchstate,{saveoffset, 0}}, Ms, Offset),
- hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(ByteSize)),
- PutHPInsn].
-
-convert_matchstate(Ms) ->
- WordSize = hipe_rtl_arch:word_size(),
- Header = hipe_rtl:mk_new_reg_gcsafe(),
- TmpSize = hipe_rtl:mk_new_reg_gcsafe(),
- SavedOffset = hipe_rtl:mk_new_reg_gcsafe(),
- Orig = hipe_rtl:mk_new_reg_gcsafe(),
- BinSize = hipe_rtl:mk_new_reg_gcsafe(),
- ByteSize = hipe_rtl:mk_new_reg_gcsafe(),
- BitSize = hipe_rtl:mk_new_reg_gcsafe(),
- ByteOffset = hipe_rtl:mk_new_reg_gcsafe(),
- BitOffset = hipe_rtl:mk_new_reg_gcsafe(),
- SizeInWords = hipe_rtl:mk_new_reg_gcsafe(),
- Hole = hipe_rtl:mk_new_reg_gcsafe(),
- BigIntHeader = hipe_rtl:mk_new_reg_gcsafe(),
- [get_field_from_term({matchstate, {matchbuffer, orig}}, Ms, Orig),
- get_field_from_term({matchstate, {matchbuffer, binsize}}, Ms, BinSize),
- get_field_from_term({matchstate, {saveoffset, 0}}, Ms, SavedOffset),
- get_field_from_term({matchstate, thing_word}, Ms, Header),
- hipe_rtl:mk_alu(TmpSize, BinSize, sub, SavedOffset),
- hipe_rtl:mk_alu(BitSize, TmpSize, 'and', hipe_rtl:mk_imm(7)),
- hipe_rtl:mk_alu(BitOffset, SavedOffset, 'and', hipe_rtl:mk_imm(7)),
- hipe_rtl:mk_alu(ByteSize, TmpSize, srl, hipe_rtl:mk_imm(3)),
- hipe_rtl:mk_alu(ByteOffset, SavedOffset, srl, hipe_rtl:mk_imm(3)),
- build_sub_binary(Ms, ByteSize, ByteOffset, BitSize, BitOffset,
- hipe_rtl:mk_imm(0), Orig),
- size_from_header(SizeInWords, Header),
- hipe_rtl:mk_alu(Hole, SizeInWords, sub, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
- mk_var_header(BigIntHeader, Hole, ?TAG_HEADER_POS_BIG),
- %% Matchstates can't be literals; so untagging with ?TAG_PRIMARY_BOXED is
- %% fine here
- hipe_rtl:mk_store(Ms, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE*WordSize
- -?TAG_PRIMARY_BOXED),
- BigIntHeader)].
-
-compare_matchstate(Max, Ms, LargeEnough, TooSmall) ->
- WordSize = hipe_rtl_arch:word_size(),
- ByteSize = (Max+1)*WordSize + ?MS_SAVEOFFSET,
- SizeInWords = ((ByteSize div WordSize) - 1),
- Header = hipe_rtl:mk_imm(mk_header(SizeInWords, ?TAG_HEADER_BIN_MATCHSTATE)),
- RealHeader = hipe_rtl:mk_new_reg_gcsafe(),
- %% Matchstates can't be literals; so untagging with ?TAG_PRIMARY_BOXED is fine
- %% here
- [hipe_rtl:mk_load(RealHeader, Ms, hipe_rtl:mk_imm(-?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_branch(RealHeader, ge, Header, LargeEnough, TooSmall)].
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Struct manipulation code
-
-get_field_offset({matchstate, thing_word}) ->
- ?MS_THING_WORD;
-get_field_offset({matchstate, matchbuffer}) ->
- ?MS_MATCHBUFFER;
-get_field_offset({matchstate, {matchbuffer, _} = Field}) ->
- ?MS_MATCHBUFFER + get_field_offset(Field);
-get_field_offset({matchstate, {saveoffset, N}} = Field) ->
- ?MS_SAVEOFFSET + N*get_field_size1(Field);
-get_field_offset({sub_binary, thing_word}) ->
- ?SUB_BIN_THING_WORD;
-get_field_offset({sub_binary, binsize}) ->
- ?SUB_BIN_BINSIZE;
-get_field_offset({sub_binary, bitsize}) ->
- ?SUB_BIN_BITSIZE;
-get_field_offset({sub_binary, offset}) ->
- ?SUB_BIN_OFFS;
-get_field_offset({sub_binary, bitoffset}) ->
- ?SUB_BIN_BITOFFS;
-get_field_offset({sub_binary, is_writable}) ->
- ?SUB_BIN_WRITABLE;
-get_field_offset({sub_binary, orig}) ->
- ?SUB_BIN_ORIG;
-get_field_offset({proc_bin, thing_word}) ->
- ?PROC_BIN_THING_WORD;
-get_field_offset({proc_bin, binsize}) ->
- ?PROC_BIN_BINSIZE;
-get_field_offset({proc_bin, next}) ->
- ?PROC_BIN_NEXT;
-get_field_offset({proc_bin, val}) ->
- ?PROC_BIN_VAL;
-get_field_offset({proc_bin, bytes}) ->
- ?PROC_BIN_BYTES;
-get_field_offset({proc_bin, flags}) ->
- ?PROC_BIN_FLAGS;
-get_field_offset({binary, orig_bytes}) ->
- ?BINARY_ORIG_BYTES;
-get_field_offset({binary, orig_size}) ->
- ?BINARY_ORIG_SIZE;
-get_field_offset({heap_bin, thing_word}) ->
- ?HEAP_BIN_THING_WORD;
-get_field_offset({heap_bin, binsize}) ->
- ?HEAP_BIN_SIZE;
-get_field_offset({heap_bin, {data, N}} = Field) ->
- ?HEAP_BIN_DATA+N*get_field_size1(Field);
-get_field_offset({matchbuffer, offset}) ->
- ?MB_OFFSET;
-get_field_offset({matchbuffer, orig}) ->
- ?MB_ORIG;
-get_field_offset({matchbuffer, base}) ->
- ?MB_BASE;
-get_field_offset({matchbuffer, binsize}) ->
- ?MB_SIZE.
-
-get_field_size(Field) ->
- WordSize = hipe_rtl_arch:word_size(),
- case get_field_size1(Field) of
- WordSize -> word;
- %% 4 -> int32; Seems not needed: covered by the previous case
- %% 2 -> int16; So far there are no 2 byte fields
- 1 -> byte
- end.
-
-get_field_size1({matchstate, thing_word}) ->
- ?MS_THING_WORD_SIZE;
-get_field_size1({matchstate, {matchbuffer, _} = Field}) ->
- get_field_size1(Field);
-get_field_size1({matchstate, {saveoffset, _N}}) ->
- ?MS_SAVEOFFSET_SIZE;
-get_field_size1({sub_binary, thing_word}) ->
- ?SUB_BIN_THING_WORD_SIZE;
-get_field_size1({sub_binary, binsize}) ->
- ?SUB_BIN_BINSIZE_SIZE;
-get_field_size1({sub_binary, bitsize}) ->
- ?SUB_BIN_BITSIZE_SIZE;
-get_field_size1({sub_binary, offset}) ->
- ?SUB_BIN_OFFS_SIZE;
-get_field_size1({sub_binary, bitoffset}) ->
- ?SUB_BIN_BITOFFS_SIZE;
-get_field_size1({sub_binary, is_writable}) ->
- ?SUB_BIN_WRITABLE_SIZE;
-get_field_size1({sub_binary, orig}) ->
- ?SUB_BIN_ORIG_SIZE;
-get_field_size1({proc_bin, thing_word}) ->
- ?PROC_BIN_THING_WORD_SIZE;
-get_field_size1({proc_bin, binsize}) ->
- ?PROC_BIN_BINSIZE_SIZE;
-get_field_size1({proc_bin, next}) ->
- ?PROC_BIN_NEXT_SIZE;
-get_field_size1({proc_bin, val}) ->
- ?PROC_BIN_VAL_SIZE;
-get_field_size1({proc_bin, bytes}) ->
- ?PROC_BIN_BYTES_SIZE;
-get_field_size1({proc_bin, flags}) ->
- ?PROC_BIN_FLAGS_SIZE;
-get_field_size1({binary, orig_bytes}) ->
- ?BINARY_ORIG_BYTES_SIZE;
-get_field_size1({binary, orig_size}) ->
- ?BINARY_ORIG_SIZE_SIZE;
-get_field_size1({heap_bin, thing_word}) ->
- ?HEAP_BIN_THING_WORD_SIZE;
-get_field_size1({heap_bin, binsize}) ->
- ?HEAP_BIN_SIZE_SIZE;
-get_field_size1({heap_bin, {data, _}}) ->
- ?HEAP_BIN_DATA_SIZE;
-get_field_size1({matchbuffer, offset}) ->
- ?MB_OFFSET_SIZE;
-get_field_size1({matchbuffer, orig}) ->
- ?MB_ORIG_SIZE;
-get_field_size1({matchbuffer, base}) ->
- ?MB_BASE_SIZE;
-get_field_size1({matchbuffer, binsize}) ->
- ?MB_SIZE_SIZE.
-
-get_field_addr_from_term(Struct, Term, Dst) ->
- {Base, Offset0, Untag} = untag_ptr(Term, ?TAG_PRIMARY_BOXED),
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct) + Offset0),
- [Untag, hipe_rtl:mk_alu(Dst, Base, add, Offset)].
-
-get_field_from_term(Struct, Term, Dst) ->
- {Base, Offset0, Untag} = untag_ptr(Term, ?TAG_PRIMARY_BOXED),
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct) + Offset0),
- Size = get_field_size(Struct),
- [Untag, hipe_rtl:mk_load(Dst, Base, Offset, Size, unsigned)].
-
-set_field_from_term(Struct, Term, Value) ->
- {Base, Offset0, Untag} = untag_ptr(Term, ?TAG_PRIMARY_BOXED),
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct) + Offset0),
- Size = get_field_size(Struct),
- [Untag, hipe_rtl:mk_store(Base, Offset, Value, Size)].
-
-get_field_from_pointer(Struct, Term, Dst) ->
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct)),
- Size = get_field_size(Struct),
- hipe_rtl:mk_load(Dst, Term, Offset, Size, unsigned).
-
-set_field_from_pointer(Struct, Term, Value) ->
- Offset = hipe_rtl:mk_imm(get_field_offset(Struct)),
- Size = get_field_size(Struct),
- hipe_rtl:mk_store(Term, Offset, Value, Size).
-
-extract_matchbuffer(Mb, Ms) ->
- What = {matchstate, matchbuffer},
- %% Matchstates can't be literals; so untagging with ?TAG_PRIMARY_BOXED is fine
- %% here
- Offset = hipe_rtl:mk_imm(get_field_offset(What) - ?TAG_PRIMARY_BOXED),
- hipe_rtl:mk_alu(Mb, Ms, add, Offset).
-
-extract_binary_bytes(Binary, Base) ->
- Offset = hipe_rtl:mk_imm(get_field_offset({binary, orig_bytes})),
- hipe_rtl:mk_alu(Base, Binary, add, Offset).
diff --git a/lib/hipe/sparc/Makefile b/lib/hipe/sparc/Makefile
deleted file mode 100644
index ac1230df7c..0000000000
--- a/lib/hipe/sparc/Makefile
+++ /dev/null
@@ -1,128 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-# Please keep this list sorted.
-MODULES=hipe_rtl_to_sparc \
- hipe_sparc \
- hipe_sparc_assemble \
- hipe_sparc_cfg \
- hipe_sparc_defuse \
- hipe_sparc_encode \
- hipe_sparc_finalise \
- hipe_sparc_frame \
- hipe_sparc_liveness_all \
- hipe_sparc_liveness_fpr \
- hipe_sparc_liveness_gpr \
- hipe_sparc_main \
- hipe_sparc_pp \
- hipe_sparc_ra \
- hipe_sparc_ra_finalise \
- hipe_sparc_ra_ls \
- hipe_sparc_ra_naive \
- hipe_sparc_ra_postconditions \
- hipe_sparc_ra_postconditions_fp \
- hipe_sparc_registers \
- hipe_sparc_subst
-
-HRL_FILES=hipe_sparc.hrl
-ERL_FILES=$(MODULES:%=%.erl)
-TARGET_FILES=$(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-# Please keep this list sorted.
-$(EBIN)/hipe_rtl_to_sparc.beam: ../rtl/hipe_rtl.hrl
-$(EBIN)/hipe_sparc_assemble.beam: ../main/hipe.hrl ../../kernel/src/hipe_ext_format.hrl ../rtl/hipe_literals.hrl ../misc/hipe_sdi.hrl
-$(EBIN)/hipe_sparc_cfg.beam: ../flow/cfg.hrl ../flow/cfg.inc
-$(EBIN)/hipe_sparc_frame.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_sparc_liveness_all.beam: ../flow/liveness.inc
-$(EBIN)/hipe_sparc_liveness_fpr.beam: ../flow/liveness.inc
-$(EBIN)/hipe_sparc_liveness_gpr.beam: ../flow/liveness.inc
-$(EBIN)/hipe_sparc_registers.beam: ../rtl/hipe_literals.hrl
-
-$(TARGET_FILES): hipe_sparc.hrl ../misc/hipe_consttab.hrl
diff --git a/lib/hipe/sparc/hipe_rtl_to_sparc.erl b/lib/hipe/sparc/hipe_rtl_to_sparc.erl
deleted file mode 100644
index d1a6b15508..0000000000
--- a/lib/hipe/sparc/hipe_rtl_to_sparc.erl
+++ /dev/null
@@ -1,907 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_rtl_to_sparc).
-
--export([translate/1]).
-
--include("../rtl/hipe_rtl.hrl").
-
-translate(RTL) ->
- hipe_gensym:init(sparc),
- hipe_gensym:set_var(sparc, hipe_sparc_registers:first_virtual()),
- hipe_gensym:set_label(sparc, hipe_gensym:get_label(rtl)),
- Map0 = vmap_empty(),
- {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),
- OldData = hipe_rtl:rtl_data(RTL),
- {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),
- {RegFormals, _} = split_args(Formals),
- Code =
- case RegFormals of
- [] -> Code0;
- _ -> [hipe_sparc:mk_label(hipe_gensym:get_next_label(sparc)) |
- move_formals(RegFormals, Code0)]
- end,
- IsClosure = hipe_rtl:rtl_is_closure(RTL),
- IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
- hipe_sparc:mk_defun(hipe_rtl:rtl_fun(RTL),
- Formals,
- IsClosure,
- IsLeaf,
- Code,
- NewData,
- [],
- []).
-
-conv_insn_list([H|T], Map, Data) ->
- {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),
- %% io:format("~w \n ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),
- {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),
- {NewH ++ NewT, NewData2};
-conv_insn_list([], _, Data) ->
- {[], Data}.
-
-conv_insn(I, Map, Data) ->
- case I of
- #alu{} -> conv_alu(I, Map, Data);
- #alub{} -> conv_alub(I, Map, Data);
- #call{} -> conv_call(I, Map, Data);
- #comment{} -> conv_comment(I, Map, Data);
- #enter{} -> conv_enter(I, Map, Data);
- #goto{} -> conv_goto(I, Map, Data);
- #label{} -> conv_label(I, Map, Data);
- #load{} -> conv_load(I, Map, Data);
- #load_address{} -> conv_load_address(I, Map, Data);
- #load_atom{} -> conv_load_atom(I, Map, Data);
- #move{} -> conv_move(I, Map, Data);
- #return{} -> conv_return(I, Map, Data);
- #store{} -> conv_store(I, Map, Data);
- #switch{} -> conv_switch(I, Map, Data); % XXX: only switch uses/updates Data
- #fconv{} -> conv_fconv(I, Map, Data);
- #fmove{} -> conv_fmove(I, Map, Data);
- #fload{} -> conv_fload(I, Map, Data);
- #fstore{} -> conv_fstore(I, Map, Data);
- #fp{} -> conv_fp_binary(I, Map, Data);
- #fp_unop{} -> conv_fp_unary(I, Map, Data);
- _ -> exit({?MODULE,conv_insn,I})
- end.
-
-conv_fconv(I, Map, Data) ->
- %% Dst := (double)Src, where Dst is FP reg and Src is GP reg or imm
- {Src, Map1} = conv_src(hipe_rtl:fconv_src(I), Map),
- {Dst, Map2} = conv_fpreg(hipe_rtl:fconv_dst(I), Map1),
- I2 = mk_fconv(Src, Dst),
- {I2, Map2, Data}.
-
-mk_fconv(Src, Dst) ->
- CSP = hipe_sparc:mk_temp(14, 'untagged'), % o6
- Offset = 100,
- mk_store('stw', Src, CSP, Offset) ++
- [hipe_sparc:mk_pseudo_fload(CSP, hipe_sparc:mk_simm13(Offset), Dst, true),
- hipe_sparc:mk_fp_unary('fitod', Dst, Dst)].
-
-conv_fmove(I, Map, Data) ->
- %% Dst := Src, where both Dst and Src are FP regs
- {Src, Map1} = conv_fpreg(hipe_rtl:fmove_src(I), Map),
- {Dst, Map2} = conv_fpreg(hipe_rtl:fmove_dst(I), Map1),
- I2 = mk_fmove(Src, Dst),
- {I2, Map2, Data}.
-
-mk_fmove(Src, Dst) ->
- [hipe_sparc:mk_pseudo_fmove(Src, Dst)].
-
-conv_fload(I, Map, Data) ->
- %% Dst := MEM[Base+Off], where Dst is FP reg
- {Base1, Map1} = conv_src(hipe_rtl:fload_src(I), Map),
- {Base2, Map2} = conv_src(hipe_rtl:fload_offset(I), Map1),
- {Dst, Map3} = conv_fpreg(hipe_rtl:fload_dst(I), Map2),
- I2 = mk_fload(Base1, Base2, Dst),
- {I2, Map3, Data}.
-
-mk_fload(Base1, Base2, Dst) ->
- case hipe_sparc:is_temp(Base1) of
- true ->
- case hipe_sparc:is_temp(Base2) of
- true ->
- mk_fload_rr(Base1, Base2, Dst);
- _ ->
- mk_fload_ri(Base1, Base2, Dst)
- end;
- _ ->
- case hipe_sparc:is_temp(Base2) of
- true ->
- mk_fload_ri(Base2, Base1, Dst);
- _ ->
- mk_fload_ii(Base1, Base2, Dst)
- end
- end.
-
-mk_fload_rr(Base1, Base2, Dst) ->
- Tmp = new_untagged_temp(),
- Disp = hipe_sparc:mk_simm13(0),
- [hipe_sparc:mk_alu('add', Base1, Base2, Tmp),
- hipe_sparc:mk_pseudo_fload(Tmp, Disp, Dst, false)].
-
-mk_fload_ii(Base1, Base2, Dst) ->
- io:format("~w: RTL fload with two immediates\n", [?MODULE]),
- Tmp = new_untagged_temp(),
- mk_set(Base1, Tmp, mk_fload_ri(Tmp, Base2, Dst)).
-
-mk_fload_ri(Base, Disp, Dst) ->
- hipe_sparc:mk_fload(Base, Disp, Dst, 'new').
-
-conv_fstore(I, Map, Data) ->
- %% MEM[Base+Off] := Src, where Src is FP reg
- {Base1, Map1} = conv_dst(hipe_rtl:fstore_base(I), Map),
- {Base2, Map2} = conv_src(hipe_rtl:fstore_offset(I), Map1),
- {Src, Map3} = conv_fpreg(hipe_rtl:fstore_src(I), Map2),
- I2 = mk_fstore(Src, Base1, Base2),
- {I2, Map3, Data}.
-
-mk_fstore(Src, Base1, Base2) ->
- case hipe_sparc:is_temp(Base2) of
- true ->
- mk_fstore_rr(Src, Base1, Base2);
- _ ->
- mk_fstore_ri(Src, Base1, Base2)
- end.
-
-mk_fstore_rr(Src, Base1, Base2) ->
- Tmp = new_untagged_temp(),
- Disp = hipe_sparc:mk_simm13(0),
- [hipe_sparc:mk_alu('add', Base1, Base2, Tmp),
- hipe_sparc:mk_pseudo_fstore(Src, Tmp, Disp)].
-
-mk_fstore_ri(Src, Base, Disp) ->
- hipe_sparc:mk_fstore(Src, Base, Disp, 'new').
-
-conv_fp_binary(I, Map, Data) ->
- {Src1, Map1} = conv_fpreg(hipe_rtl:fp_src1(I), Map),
- {Src2, Map2} = conv_fpreg(hipe_rtl:fp_src2(I), Map1),
- {Dst, Map3} = conv_fpreg(hipe_rtl:fp_dst(I), Map2),
- RtlFpOp = hipe_rtl:fp_op(I),
- I2 = mk_fp_binary(RtlFpOp, Src1, Src2, Dst),
- {I2, Map3, Data}.
-
-mk_fp_binary(RtlFpOp, Src1, Src2, Dst) ->
- FpBinOp =
- case RtlFpOp of
- 'fadd' -> 'faddd';
- 'fdiv' -> 'fdivd';
- 'fmul' -> 'fmuld';
- 'fsub' -> 'fsubd'
- end,
- [hipe_sparc:mk_fp_binary(FpBinOp, Src1, Src2, Dst)].
-
-conv_fp_unary(I, Map, Data) ->
- {Src, Map1} = conv_fpreg(hipe_rtl:fp_unop_src(I), Map),
- {Dst, Map2} = conv_fpreg(hipe_rtl:fp_unop_dst(I), Map1),
- RtlFpUnOp = hipe_rtl:fp_unop_op(I),
- I2 = mk_fp_unary(RtlFpUnOp, Src, Dst),
- {I2, Map2, Data}.
-
-mk_fp_unary(RtlFpUnOp, Src, Dst) ->
- FpUnOp =
- case RtlFpUnOp of
- 'fchs' -> 'fnegd'
- end,
- [hipe_sparc:mk_fp_unary(FpUnOp, Src, Dst)].
-
-conv_alu(I, Map, Data) ->
- %% dst = src1 aluop src2
- {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),
- {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),
- {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),
- AluOp = conv_aluop(hipe_rtl:alu_op(I)),
- {I2, _DidCommute} = mk_alu(AluOp, Src1, Src2, Dst),
- {I2, Map2, Data}.
-
-mk_alu(XAluOp, Src1, Src2, Dst) ->
- case hipe_sparc:is_temp(Src1) of
- true ->
- case hipe_sparc:is_temp(Src2) of
- true ->
- {mk_alu_rs(XAluOp, Src1, Src2, Dst),
- false};
- _ ->
- {mk_alu_ri(XAluOp, Src1, Src2, Dst),
- false}
- end;
- _ ->
- case hipe_sparc:is_temp(Src2) of
- true ->
- mk_alu_ir(XAluOp, Src1, Src2, Dst);
- _ ->
- {mk_alu_ii(XAluOp, Src1, Src2, Dst),
- false}
- end
- end.
-
-mk_alu_ii(XAluOp, Src1, Src2, Dst) ->
- io:format("~w: ALU with two immediates (~w ~w ~w ~w)\n",
- [?MODULE, XAluOp, Src1, Src2, Dst]),
- Tmp = new_untagged_temp(),
- mk_set(Src1, Tmp, mk_alu_ri(XAluOp, Tmp, Src2, Dst)).
-
-mk_alu_ir(XAluOp, Src1, Src2, Dst) ->
- case xaluop_commutes(XAluOp) of
- true ->
- {mk_alu_ri(XAluOp, Src2, Src1, Dst),
- true};
- _ ->
- Tmp = new_untagged_temp(),
- {mk_set(Src1, Tmp, mk_alu_rs(XAluOp, Tmp, Src2, Dst)),
- false}
- end.
-
-mk_alu_ri(XAluOp, Src1, Src2, Dst) ->
- case xaluop_is_shift(XAluOp) of
- true ->
- mk_shift_ri(XAluOp, Src1, Src2, Dst);
- false ->
- mk_arith_ri(XAluOp, Src1, Src2, Dst)
- end.
-
-mk_shift_ri(XShiftOp, Src1, Src2, Dst) when is_integer(Src2) ->
- if Src2 >= 0, Src2 < 32 -> % XXX: sparc64: < 64
- mk_alu_rs(XShiftOp, Src1, hipe_sparc:mk_uimm5(Src2), Dst);
- true ->
- exit({?MODULE,mk_shift_ri,Src2}) % excessive shifts are errors
- end.
-
-mk_arith_ri(XAluOp, Src1, Src2, Dst) when is_integer(Src2) ->
- if -4096 =< Src2, Src2 < 4096 ->
- mk_alu_rs(XAluOp, Src1, hipe_sparc:mk_simm13(Src2), Dst);
- true ->
- Tmp = new_untagged_temp(),
- mk_set(Src2, Tmp, mk_alu_rs(XAluOp, Src1, Tmp, Dst))
- end.
-
-mk_alu_rs(XAluOp, Src1, Src2, Dst) ->
- [hipe_sparc:mk_alu(xaluop_normalise(XAluOp), Src1, Src2, Dst)].
-
-conv_alub(I, Map, Data) ->
- %% dst = src1 aluop src2; if COND goto label
- HasDst = hipe_rtl:alub_has_dst(I),
- {Dst, Map0} =
- case HasDst of
- false -> {hipe_sparc:mk_g0(), Map};
- true -> conv_dst(hipe_rtl:alub_dst(I), Map)
- end,
- {Src1, Map1} = conv_src(hipe_rtl:alub_src1(I), Map0),
- {Src2, Map2} = conv_src(hipe_rtl:alub_src2(I), Map1),
- Cond = conv_cond(hipe_rtl:alub_cond(I)),
- RtlAlubOp = hipe_rtl:alub_op(I),
- I2 =
- case RtlAlubOp of
- 'mul' ->
- %% To check for overflow in 32x32->32 multiplication:
- %% smul Src1,Src2,Dst % Dst is lo32(Res), %y is %hi32(Res)
- %% rd %y,TmpHi
- %% sra Dst,31,TmpSign % fill TmpSign with sign of Dst
- %% subcc TmpSign,TmpHi,%g0
- %% [bne OverflowLabel]
- NewCond =
- case Cond of
- vs -> ne;
- vc -> eq
- end,
- TmpHi = hipe_sparc:mk_new_temp('untagged'),
- TmpSign = hipe_sparc:mk_new_temp('untagged'),
- G0 = hipe_sparc:mk_g0(),
- {I1, _DidCommute} = mk_alu('smul', Src1, Src2, Dst),
- I1 ++
- [hipe_sparc:mk_rdy(TmpHi),
- hipe_sparc:mk_alu('sra', Dst, hipe_sparc:mk_uimm5(31), TmpSign) |
- conv_alub2(G0, TmpSign, 'cmpcc', NewCond, TmpHi, I)];
- _ ->
- XAluOp =
- case (not HasDst) andalso RtlAlubOp =:= 'sub' of
- true -> 'cmpcc'; % == a subcc that commutes
- false -> conv_alubop_cc(RtlAlubOp)
- end,
- conv_alub2(Dst, Src1, XAluOp, Cond, Src2, I)
- end,
- {I2, Map2, Data}.
-
-conv_alub2(Dst, Src1, XAluOp, Cond, Src2, I) ->
- conv_alub_bp(Dst, Src1, XAluOp, Cond, Src2, I).
-
-conv_alub_bp(Dst, Src1, XAluOp, Cond, Src2, I) ->
- TrueLab = hipe_rtl:alub_true_label(I),
- FalseLab = hipe_rtl:alub_false_label(I),
- Pred = hipe_rtl:alub_pred(I),
- %% "Dst = Src1 AluOp Src2; if COND" becomes
- %% "Dst = Src1 AluOpCC Src22; if-COND(CC)"
- {I2, DidCommute} = mk_alu(XAluOp, Src1, Src2, Dst),
- NewCond =
- case DidCommute andalso XAluOp =:= 'cmpcc' of
- true -> commute_cond(Cond); % subcc does not commute; its conditions do
- false -> Cond
- end,
- I2 ++ mk_pseudo_bp(NewCond, TrueLab, FalseLab, Pred).
-
-conv_alubop_cc(RtlAlubOp) ->
- case RtlAlubOp of
- 'add' -> 'addcc';
- 'sub' -> 'subcc';
- %% mul: handled elsewhere
- 'or' -> 'orcc';
- 'and' -> 'andcc';
- 'xor' -> 'xorcc'
- %% no shift ops
- end.
-
-conv_call(I, Map, Data) ->
- {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),
- {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),
- {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),
- ContLab = hipe_rtl:call_continuation(I),
- ExnLab = hipe_rtl:call_fail(I),
- Linkage = hipe_rtl:call_type(I),
- I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage),
- {I2, Map2, Data}.
-
-mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- case hipe_sparc:is_prim(Fun) of
- true ->
- mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);
- false ->
- mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)
- end.
-
-mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->
- case hipe_sparc:prim_prim(Prim) of
- %% no SPARC-specific primops defined yet
- _ ->
- mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)
- end.
-
-mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- %% The backend does not support pseudo_calls without a
- %% continuation label, so we make sure each call has one.
- {RealContLab, Tail} =
- case mk_call_results(Dsts) of
- [] ->
- %% Avoid consing up a dummy basic block if the moves list
- %% is empty, as is typical for calls to suspend/0.
- %% This should be subsumed by a general "optimise the CFG"
- %% module, and could probably be removed.
- case ContLab of
- [] ->
- NewContLab = hipe_gensym:get_next_label(sparc),
- {NewContLab, [hipe_sparc:mk_label(NewContLab)]};
- _ ->
- {ContLab, []}
- end;
- Moves ->
- %% Change the call to continue at a new basic block.
- %% In this block move the result registers to the Dsts,
- %% then continue at the call's original continuation.
- NewContLab = hipe_gensym:get_next_label(sparc),
- case ContLab of
- [] ->
- %% This is just a fallthrough
- %% No jump back after the moves.
- {NewContLab,
- [hipe_sparc:mk_label(NewContLab) |
- Moves]};
- _ ->
- %% The call has a continuation. Jump to it.
- {NewContLab,
- [hipe_sparc:mk_label(NewContLab) |
- Moves ++
- [hipe_sparc:mk_b_label(ContLab)]]}
- end
- end,
- SDesc = hipe_sparc:mk_sdesc(ExnLab, 0, length(Args), {}),
- CallInsn = hipe_sparc:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage),
- {RegArgs,StkArgs} = split_args(Args),
- mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).
-
-mk_call_results(Dsts) ->
- case Dsts of
- [] -> [];
- [Dst] ->
- RV = hipe_sparc:mk_rv(),
- [hipe_sparc:mk_pseudo_move(RV, Dst)]
- end.
-
-mk_push_args(StkArgs, Tail) ->
- case length(StkArgs) of
- 0 ->
- Tail;
- NrStkArgs ->
- [hipe_sparc:mk_pseudo_call_prepare(NrStkArgs) |
- mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)]
- end.
-
-mk_store_args([Arg|Args], PrevOffset, Tail) ->
- Offset = PrevOffset - word_size(),
- {Src,FixSrc} =
- case hipe_sparc:is_temp(Arg) of
- true ->
- {Arg, []};
- _ ->
- Tmp = new_tagged_temp(),
- {Tmp, mk_set(Arg, Tmp)}
- end,
- %% XXX: sparc64: stx
- Store = hipe_sparc:mk_store('stw', Src, hipe_sparc:mk_sp(), hipe_sparc:mk_simm13(Offset)),
- mk_store_args(Args, Offset, FixSrc ++ [Store | Tail]);
-mk_store_args([], _, Tail) ->
- Tail.
-
-conv_comment(I, Map, Data) ->
- I2 = [hipe_sparc:mk_comment(hipe_rtl:comment_text(I))],
- {I2, Map, Data}.
-
-conv_enter(I, Map, Data) ->
- {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),
- {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),
- I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)),
- {I2, Map1, Data}.
-
-mk_enter(Fun, Args, Linkage) ->
- Arity = length(Args),
- {RegArgs,StkArgs} = split_args(Args),
- move_actuals(RegArgs,
- [hipe_sparc:mk_pseudo_tailcall_prepare(),
- hipe_sparc:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]).
-
-conv_goto(I, Map, Data) ->
- I2 = [hipe_sparc:mk_b_label(hipe_rtl:goto_label(I))],
- {I2, Map, Data}.
-
-conv_label(I, Map, Data) ->
- I2 = [hipe_sparc:mk_label(hipe_rtl:label_name(I))],
- {I2, Map, Data}.
-
-conv_load(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),
- {Base1, Map1} = conv_src(hipe_rtl:load_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:load_offset(I), Map1),
- LdOp = conv_ldop(hipe_rtl:load_size(I), hipe_rtl:load_sign(I)),
- {I2, _DidCommute} = mk_alu(LdOp, Base1, Base2, Dst),
- {I2, Map2, Data}.
-
-conv_ldop(LoadSize, LoadSign) ->
- case LoadSize of
- word -> 'lduw'; % XXX: sparc64: ldx
- int32 -> 'lduw'; % XXX: sparc64: lduw or ldsw
- int16 ->
- case LoadSign of
- signed -> 'ldsh';
- unsigned -> 'lduh'
- end;
- byte ->
- case LoadSign of
- signed -> 'ldsb';
- unsigned -> 'ldub'
- end
- end.
-
-conv_load_address(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map),
- Addr = hipe_rtl:load_address_addr(I),
- Type = hipe_rtl:load_address_type(I),
- Src = {Addr,Type},
- I2 = [hipe_sparc:mk_pseudo_set(Src, Dst)],
- {I2, Map0, Data}.
-
-conv_load_atom(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map),
- Src = hipe_rtl:load_atom_atom(I),
- I2 = [hipe_sparc:mk_pseudo_set(Src, Dst)],
- {I2, Map0, Data}.
-
-conv_move(I, Map, Data) ->
- {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0),
- I2 = mk_move(Src, Dst, []),
- {I2, Map1, Data}.
-
-mk_move(Src, Dst, Tail) ->
- case hipe_sparc:is_temp(Src) of
- true -> [hipe_sparc:mk_pseudo_move(Src, Dst) | Tail];
- _ -> mk_set(Src, Dst, Tail)
- end.
-
-conv_return(I, Map, Data) ->
- %% TODO: multiple-value returns
- {[Arg], Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map),
- I2 = mk_move(Arg, hipe_sparc:mk_rv(), [hipe_sparc:mk_pseudo_ret()]),
- {I2, Map0, Data}.
-
-conv_store(I, Map, Data) ->
- {Base1, Map0} = conv_src(hipe_rtl:store_base(I), Map),
- {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),
- {Base2, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),
- StOp = conv_stop(hipe_rtl:store_size(I)),
- I2 = mk_store(StOp, Src, Base1, Base2),
- {I2, Map2, Data}.
-
-conv_stop(StoreSize) ->
- case StoreSize of
- word -> 'stw'; % XXX: sparc64: stx
- int32 -> 'stw';
- byte -> 'stb'
- end.
-
-mk_store(StOp, Src, Base1, Base2) ->
- case hipe_sparc:is_temp(Src) of
- true ->
- mk_store2(StOp, Src, Base1, Base2);
- _ ->
- Tmp = new_untagged_temp(),
- mk_set(Src, Tmp, mk_store2(StOp, Tmp, Base1, Base2))
- end.
-
-mk_store2(StOp, Src, Base1, Base2) ->
- case hipe_sparc:is_temp(Base1) of
- true ->
- case hipe_sparc:is_temp(Base2) of
- true ->
- mk_store_rr(StOp, Src, Base1, Base2);
- _ ->
- mk_store_ri(StOp, Src, Base1, Base2)
- end;
- _ ->
- case hipe_sparc:is_temp(Base2) of
- true ->
- mk_store_ri(StOp, Src, Base2, Base1);
- _ ->
- mk_store_ii(StOp, Src, Base1, Base2)
- end
- end.
-
-mk_store_ii(StOp, Src, Base, Disp) ->
- Tmp = new_untagged_temp(),
- mk_set(Base, Tmp, mk_store_ri(StOp, Src, Tmp, Disp)).
-
-mk_store_ri(StOp, Src, Base, Disp) ->
- hipe_sparc:mk_store(StOp, Src, Base, Disp, 'new', []).
-
-mk_store_rr(StOp, Src, Base1, Base2) ->
- [hipe_sparc:mk_store(StOp, Src, Base1, Base2)].
-
-conv_switch(I, Map, Data) ->
- Labels = hipe_rtl:switch_labels(I),
- LMap = [{label,L} || L <- Labels],
- {NewData, JTabLab} =
- case hipe_rtl:switch_sort_order(I) of
- [] ->
- hipe_consttab:insert_block(Data, word, LMap);
- SortOrder ->
- hipe_consttab:insert_sorted_block(Data, word, LMap, SortOrder)
- end,
- %% no immediates allowed here
- {IndexR, Map1} = conv_dst(hipe_rtl:switch_src(I), Map),
- JTabR = new_untagged_temp(),
- OffsetR = new_untagged_temp(),
- DestR = new_untagged_temp(),
- I2 =
- [hipe_sparc:mk_pseudo_set({JTabLab,constant}, JTabR),
- %% XXX: sparc64: << 3
- hipe_sparc:mk_alu('sll', IndexR, hipe_sparc:mk_uimm5(2), OffsetR),
- %% XXX: sparc64: ldx
- hipe_sparc:mk_alu('lduw', JTabR, OffsetR, DestR),
- hipe_sparc:mk_jmp(DestR, hipe_sparc:mk_simm13(0), Labels)],
- {I2, Map1, NewData}.
-
-%%% Create a conditional branch.
-
-mk_pseudo_bp(Cond, TrueLabel, FalseLabel, Pred) ->
- [hipe_sparc:mk_pseudo_bp(Cond, TrueLabel, FalseLabel, Pred)].
-
-%%% Load an integer constant into a register.
-
-mk_set(Value, Dst) -> mk_set(Value, Dst, []).
-
-mk_set(Value, Dst, Tail) ->
- hipe_sparc:mk_set(Value, Dst, Tail).
-
-%%% Convert an RTL ALU op.
-
-conv_aluop(RtlAluOp) ->
- case RtlAluOp of
- 'add' -> 'add';
- 'sub' -> 'sub';
- 'mul' -> 'mulx';
- 'or' -> 'or';
- 'and' -> 'and';
- 'xor' -> 'xor';
- 'sll' -> 'sll'; % XXX: sparc64: sllx
- 'srl' -> 'srl'; % XXX: sparc64: srlx
- 'sra' -> 'sra' % XXX: sparc64: srax
- end.
-
-%%% Check if an extended SPARC AluOp commutes.
-
-xaluop_commutes(XAluOp) ->
- case XAluOp of
- %% 'cmp' -> true;
- 'cmpcc' -> true;
- 'add' -> true;
- 'addcc' -> true;
- 'and' -> true;
- 'andcc' -> true;
- 'or' -> true;
- 'orcc' -> true;
- 'xor' -> true;
- 'xorcc' -> true;
- 'sub' -> false;
- 'subcc' -> false;
- 'mulx' -> true;
- 'smul' -> true;
- 'sll' -> false;
- 'srl' -> false;
- 'sra' -> false;
- %% 'sllx' -> false;
- %% 'srlx' -> false;
- %% 'srax' -> false;
- 'ldsb' -> true;
- 'ldsh' -> true;
- %% 'ldsw' -> true;
- 'ldub' -> true;
- 'lduh' -> true;
- 'lduw' -> true
- %% 'ldx' -> true
- end.
-
-%%% Check if an extended SPARC AluOp is a shift.
-
-xaluop_is_shift(XAluOp) ->
- case XAluOp of
- 'add' -> false;
- 'addcc' -> false;
- 'and' -> false;
- 'andcc' -> false;
- 'cmpcc' -> false;
- 'ldsb' -> false;
- 'ldub' -> false;
- 'lduw' -> false;
- 'or' -> false;
- 'sll' -> true;
- %% 'sllx' -> true;
- 'smul' -> false;
- 'sra' -> true;
- %% 'srax' -> true;
- 'srl' -> true;
- %% 'srlx' -> true;
- 'sub' -> false;
- 'subcc' -> false;
- 'xor' -> false
- end.
-
-%%% Convert an extended SPARC AluOp back to a plain AluOp.
-%%% This just maps cmp{,cc} to sub{,cc}.
-
-xaluop_normalise(XAluOp) ->
- case XAluOp of
- 'add' -> 'add';
- 'addcc' -> 'addcc';
- 'and' -> 'and';
- 'andcc' -> 'andcc';
- %% 'cmp' -> 'sub';
- 'cmpcc' -> 'subcc';
- 'ldsb' -> 'ldsb';
- 'ldub' -> 'ldub';
- 'lduw' -> 'lduw';
- 'or' -> 'or';
- 'sll' -> 'sll';
- 'smul' -> 'smul';
- 'sra' -> 'sra';
- 'srl' -> 'srl';
- 'sub' -> 'sub';
- 'subcc' -> 'subcc';
- 'xor' -> 'xor'
- end.
-
-%%% Convert an RTL condition code.
-
-conv_cond(RtlCond) ->
- case RtlCond of
- eq -> 'e';
- ne -> 'ne';
- gt -> 'g';
- gtu -> 'gu'; % >u
- ge -> 'ge';
- geu -> 'geu'; % >=u
- lt -> 'l';
- ltu -> 'lu'; % <u
- le -> 'le';
- leu -> 'leu'; % <=u
- overflow -> 'vs';
- not_overflow -> 'vc'
- end.
-
-%%% Commute a SPARC condition code.
-
-commute_cond(Cond) -> % if x Cond y, then y commute_cond(Cond) x
- case Cond of
- 'e' -> 'e'; % ==, ==
- 'ne' -> 'ne'; % !=, !=
- 'g' -> 'l'; % >, <
- 'ge' -> 'le'; % >=, <=
- 'l' -> 'g'; % <, >
- 'le' -> 'ge'; % <=, >=
- 'gu' -> 'lu'; % >u, <u
- 'geu' -> 'leu'; % >=u, <=u
- 'lu' -> 'gu'; % <u, >u
- 'leu' -> 'geu' % <=u, >=u
- %% vs/vc: n/a
- end.
-
-%%% Split a list of formal or actual parameters into the
-%%% part passed in registers and the part passed on the stack.
-%%% The parameters passed in registers are also tagged with
-%%% the corresponding registers.
-
-split_args(Args) ->
- split_args(0, hipe_sparc_registers:nr_args(), Args, []).
-
-split_args(I, N, [Arg|Args], RegArgs) when I < N ->
- Reg = hipe_sparc_registers:arg(I),
- Temp = hipe_sparc:mk_temp(Reg, 'tagged'),
- split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]);
-split_args(_, _, StkArgs, RegArgs) ->
- {RegArgs, StkArgs}.
-
-%%% Convert a list of actual parameters passed in
-%%% registers (from split_args/1) to a list of moves.
-
-move_actuals([{Src,Dst}|Actuals], Rest) ->
- move_actuals(Actuals, mk_move(Src, Dst, Rest));
-move_actuals([], Rest) ->
- Rest.
-
-%%% Convert a list of formal parameters passed in
-%%% registers (from split_args/1) to a list of moves.
-
-move_formals([{Dst,Src}|Formals], Rest) ->
- move_formals(Formals, [hipe_sparc:mk_pseudo_move(Src, Dst) | Rest]);
-move_formals([], Rest) ->
- Rest.
-
-%%% Convert a 'fun' operand (MFA, prim, or temp)
-
-conv_fun(Fun, Map) ->
- case hipe_rtl:is_var(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- case hipe_rtl:is_reg(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- if is_atom(Fun) ->
- {hipe_sparc:mk_prim(Fun), Map};
- true ->
- {conv_mfa(Fun), Map}
- end
- end
- end.
-
-%%% Convert an MFA operand.
-
-conv_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
- hipe_sparc:mk_mfa(M, F, A).
-
-%%% Convert an RTL source operand (imm/var/reg).
-%%% Returns a temp or a naked integer.
-
-conv_src(Opnd, Map) ->
- case hipe_rtl:is_imm(Opnd) of
- true ->
- Value = hipe_rtl:imm_value(Opnd),
- if is_integer(Value) ->
- {Value, Map}
- end;
- false ->
- conv_dst(Opnd, Map)
- end.
-
-conv_src_list([O|Os], Map) ->
- {V, Map1} = conv_src(O, Map),
- {Vs, Map2} = conv_src_list(Os, Map1),
- {[V|Vs], Map2};
-conv_src_list([], Map) ->
- {[], Map}.
-
-%%% Convert an RTL destination operand (var/reg).
-
-conv_fpreg(Opnd, Map) ->
- true = hipe_rtl:is_fpreg(Opnd),
- conv_dst(Opnd, Map).
-
-conv_dst(Opnd, Map) ->
- {Name, Type} =
- case hipe_rtl:is_var(Opnd) of
- true ->
- {hipe_rtl:var_index(Opnd), 'tagged'};
- false ->
- case hipe_rtl:is_fpreg(Opnd) of
- true ->
- {hipe_rtl:fpreg_index(Opnd), 'double'};
- false ->
- {hipe_rtl:reg_index(Opnd), 'untagged'}
- end
- end,
- IsPrecoloured =
- case Type of
- 'double' -> false; %hipe_sparc_registers:is_precoloured_fpr(Name);
- _ -> hipe_sparc_registers:is_precoloured_gpr(Name)
- end,
- case IsPrecoloured of
- true ->
- {hipe_sparc:mk_temp(Name, Type), Map};
- false ->
- case vmap_lookup(Map, Opnd) of
- {value, NewTemp} ->
- {NewTemp, Map};
- _ ->
- NewTemp = hipe_sparc:mk_new_temp(Type),
- {NewTemp, vmap_bind(Map, Opnd, NewTemp)}
- end
- end.
-
-conv_dst_list([O|Os], Map) ->
- {Dst, Map1} = conv_dst(O, Map),
- {Dsts, Map2} = conv_dst_list(Os, Map1),
- {[Dst|Dsts], Map2};
-conv_dst_list([], Map) ->
- {[], Map}.
-
-conv_formals(Os, Map) ->
- conv_formals(hipe_sparc_registers:nr_args(), Os, Map, []).
-
-conv_formals(N, [O|Os], Map, Res) ->
- Type =
- case hipe_rtl:is_var(O) of
- true -> 'tagged';
- _ -> 'untagged'
- end,
- Dst =
- if N > 0 -> hipe_sparc:mk_new_temp(Type); % allocatable
- true -> hipe_sparc:mk_new_nonallocatable_temp(Type)
- end,
- Map1 = vmap_bind(Map, O, Dst),
- conv_formals(N-1, Os, Map1, [Dst|Res]);
-conv_formals(_, [], Map, Res) ->
- {lists:reverse(Res), Map}.
-
-%%% new_untagged_temp -- conjure up an untagged scratch reg
-
-new_untagged_temp() ->
- hipe_sparc:mk_new_temp('untagged').
-
-%%% new_tagged_temp -- conjure up a tagged scratch reg
-
-new_tagged_temp() ->
- hipe_sparc:mk_new_temp('tagged').
-
-%%% Map from RTL var/reg operands to temps.
-
-vmap_empty() ->
- gb_trees:empty().
-
-vmap_lookup(Map, Key) ->
- gb_trees:lookup(Key, Map).
-
-vmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-word_size() ->
- hipe_rtl_arch:word_size().
diff --git a/lib/hipe/sparc/hipe_sparc.erl b/lib/hipe/sparc/hipe_sparc.erl
deleted file mode 100644
index 22e0761b69..0000000000
--- a/lib/hipe/sparc/hipe_sparc.erl
+++ /dev/null
@@ -1,415 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc).
--export([
- mk_temp/2,
- mk_new_temp/1,
- mk_new_nonallocatable_temp/1,
- is_temp/1,
- temp_reg/1,
- temp_type/1,
- temp_is_allocatable/1,
- temp_is_precoloured/1,
-
- mk_g0/0,
- mk_ra/0,
- mk_rv/0,
- mk_sp/0,
- mk_temp1/0,
- mk_temp2/0,
-
- mk_simm13/1,
- mk_uimm5/1,
-
- mk_mfa/3,
-
- mk_prim/1,
- is_prim/1,
- prim_prim/1,
-
- mk_sdesc/4,
-
- mk_alu/4,
- mk_mov/2,
- mk_load/6,
-
- mk_bp/3,
- mk_b_label/1,
-
- %% mk_br/4,
-
- mk_call_rec/3,
-
- mk_call_tail/2,
-
- mk_comment/1,
-
- mk_label/1,
- is_label/1,
- label_label/1,
-
- mk_jmp/3,
- mk_jmpl/2,
-
- mk_pseudo_bp/4,
- negate_cond/1,
-
- %% mk_pseudo_br/5,
- %% negate_rcond/1,
-
- mk_pseudo_call/4,
- pseudo_call_contlab/1,
- pseudo_call_funv/1,
- pseudo_call_linkage/1,
- pseudo_call_sdesc/1,
-
- mk_pseudo_call_prepare/1,
- pseudo_call_prepare_nrstkargs/1,
-
- mk_pseudo_move/2,
- is_pseudo_move/1,
- pseudo_move_dst/1,
- pseudo_move_src/1,
-
- mk_pseudo_ret/0,
-
- mk_pseudo_set/2,
-
- mk_pseudo_spill_move/3,
- is_pseudo_spill_move/1,
-
- mk_pseudo_tailcall/4,
- pseudo_tailcall_funv/1,
- pseudo_tailcall_linkage/1,
- pseudo_tailcall_stkargs/1,
-
- mk_pseudo_tailcall_prepare/0,
-
- mk_rdy/1,
-
- %% mk_sethi/2,
- mk_nop/0,
- mk_set/2,
- mk_set/3,
- mk_addi/4,
-
- mk_store/4,
- mk_store/6,
-
- mk_fp_binary/4,
-
- mk_fp_unary/3,
-
- mk_pseudo_fload/4,
- mk_fload/4,
-
- mk_pseudo_fmove/2,
- is_pseudo_fmove/1,
- pseudo_fmove_src/1,
- pseudo_fmove_dst/1,
-
- mk_pseudo_spill_fmove/3,
- is_pseudo_spill_fmove/1,
-
- mk_pseudo_fstore/3,
- mk_fstore/4,
-
- mk_defun/8,
- defun_code/1,
- defun_data/1,
- defun_formals/1,
- defun_is_closure/1,
- defun_is_leaf/1,
- defun_mfa/1,
- defun_var_range/1
- ]).
-
--include("hipe_sparc.hrl").
-
-mk_temp(Reg, Type, Allocatable) ->
- #sparc_temp{reg=Reg, type=Type, allocatable=Allocatable}.
-mk_temp(Reg, Type) -> mk_temp(Reg, Type, true).
-mk_new_temp(Type, Allocatable) ->
- mk_temp(hipe_gensym:get_next_var(sparc), Type, Allocatable).
-mk_new_temp(Type) -> mk_new_temp(Type, true).
-mk_new_nonallocatable_temp(Type) -> mk_new_temp(Type, false).
-is_temp(X) -> case X of #sparc_temp{} -> true; _ -> false end.
-temp_reg(#sparc_temp{reg=Reg}) -> Reg.
-temp_type(#sparc_temp{type=Type}) -> Type.
-temp_is_allocatable(#sparc_temp{allocatable=A}) -> A.
-temp_is_precoloured(#sparc_temp{reg=Reg,type=Type}) ->
- case Type of
- %% 'double' -> hipe_sparc_registers:is_precoloured_fpr(Reg);
- _ -> hipe_sparc_registers:is_precoloured_gpr(Reg)
- end.
-
-mk_g0() -> mk_temp(hipe_sparc_registers:g0(), 'untagged').
-mk_ra() -> mk_temp(hipe_sparc_registers:return_address(), 'untagged').
-mk_rv() -> mk_temp(hipe_sparc_registers:return_value(), 'tagged').
-mk_sp() -> mk_temp(hipe_sparc_registers:stack_pointer(), 'untagged').
-mk_temp1() -> mk_temp(hipe_sparc_registers:temp1(), 'untagged').
-mk_temp2() -> mk_temp(hipe_sparc_registers:temp2(), 'untagged').
-
-mk_simm13(Value) -> #sparc_simm13{value=Value}.
-mk_uimm5(Value) -> #sparc_uimm5{value=Value}.
-mk_uimm22(Value) -> #sparc_uimm22{value=Value}.
-
-mk_mfa(M, F, A) -> #sparc_mfa{m=M, f=F, a=A}.
-
-mk_prim(Prim) -> #sparc_prim{prim=Prim}.
-is_prim(X) -> case X of #sparc_prim{} -> true; _ -> false end.
-prim_prim(#sparc_prim{prim=Prim}) -> Prim.
-
-mk_sdesc(ExnLab, FSize, Arity, Live) ->
- #sparc_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}.
-
-mk_alu(AluOp, Src1, Src2, Dst) ->
- #alu{aluop=AluOp, src1=Src1, src2=Src2, dst=Dst}.
-mk_mov(Src, Dst) -> mk_alu('or', mk_g0(), Src, Dst).
-
-mk_bp(Cond, Label, Pred) -> #bp{'cond'=Cond, label=Label, pred=Pred}.
-mk_b_label(Label) -> mk_bp('a', Label, 1.0).
-
--ifdef(notdef). % XXX: only for sparc64, alas
-mk_br(RCond, Src, Label, Pred) ->
- #br{rcond=RCond, src=Src, label=Label, pred=Pred}.
--endif.
-
-mk_call_rec(Fun, SDesc, Linkage) ->
- #call_rec{'fun'=Fun, sdesc=SDesc, linkage=Linkage}.
-
-mk_call_tail(Fun, Linkage) -> #call_tail{'fun'=Fun, linkage=Linkage}.
-
-mk_comment(Term) -> #comment{term=Term}.
-
-mk_label(Label) -> #label{label=Label}.
-is_label(I) -> case I of #label{} -> true; _ -> false end.
-label_label(#label{label=Label}) -> Label.
-
-mk_jmp(Src1, Src2, Labels) -> #jmp{src1=Src1, src2=Src2, labels=Labels}.
-
-mk_jmpl(Src, SDesc) -> #jmpl{src=Src, sdesc=SDesc}.
-
-mk_pseudo_bp(Cond, TrueLab, FalseLab, Pred) ->
- if Pred >= 0.5 ->
- mk_pseudo_bp_simple(negate_cond(Cond), FalseLab,
- TrueLab, 1.0-Pred);
- true ->
- mk_pseudo_bp_simple(Cond, TrueLab, FalseLab, Pred)
- end.
-
-mk_pseudo_bp_simple(Cond, TrueLab, FalseLab, Pred) when Pred =< 0.5 ->
- #pseudo_bp{'cond'=Cond, true_label=TrueLab,
- false_label=FalseLab, pred=Pred}.
-
-negate_cond(Cond) ->
- case Cond of
- 'l' -> 'ge'; % <, >=
- 'ge' -> 'l'; % >=, <
- 'g' -> 'le'; % >, <=
- 'le' -> 'g'; % <=, >
- 'e' -> 'ne'; % ==, !=
- 'ne' -> 'e'; % !=, ==
- 'gu' -> 'leu'; % >u, <=u
- 'leu'-> 'gu'; % <=u, >u
- 'geu'-> 'lu'; % >=u, <u
- 'lu' -> 'geu'; % <u, >=u
- 'vs' -> 'vc'; % overflow, not_overflow
- 'vc' -> 'vs' % not_overflow, overflow
- end.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-mk_pseudo_br(RCond, Src, TrueLab, FalseLab, Pred) ->
- if Pred >= 0.5 ->
- mk_pseudo_br_simple(negate_rcond(RCond), Src, FalseLab,
- TrueLab, 1.0-Pred);
- true ->
- mk_pseudo_br_simple(RCond, Src, TrueLab, FalseLab, Pred)
- end.
-
-mk_pseudo_br_simple(RCond, Src, TrueLab, FalseLab, Pred) when Pred =< 0.5 ->
- #pseudo_br{rcond=RCond, src=Src, true_label=TrueLab,
- false_label=FalseLab, pred=Pred}.
-
-negate_rcond(RCond) ->
- case RCond of
- 'z' -> 'nz'; % ==, !=
- 'nz' -> 'z'; % !=, ==
- 'gz' -> 'lez'; % >, <=
- 'lez' -> 'gz'; % <=, >
- 'gez' -> 'lz'; % >=, <
- 'lz' -> 'gez' % <, >=
- end.
--endif.
-
-mk_pseudo_call(FunV, SDesc, ContLab, Linkage) ->
- #pseudo_call{funv=FunV, sdesc=SDesc, contlab=ContLab, linkage=Linkage}.
-pseudo_call_funv(#pseudo_call{funv=FunV}) -> FunV.
-pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab.
-pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage.
-pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc.
-
-mk_pseudo_call_prepare(NrStkArgs) ->
- #pseudo_call_prepare{nrstkargs=NrStkArgs}.
-pseudo_call_prepare_nrstkargs(#pseudo_call_prepare{nrstkargs=NrStkArgs}) ->
- NrStkArgs.
-
-mk_pseudo_move(Src, Dst) -> #pseudo_move{src=Src, dst=Dst}.
-is_pseudo_move(I) -> case I of #pseudo_move{} -> true; _ -> false end.
-pseudo_move_dst(#pseudo_move{dst=Dst}) -> Dst.
-pseudo_move_src(#pseudo_move{src=Src}) -> Src.
-
-mk_pseudo_ret() -> #pseudo_ret{}.
-
-mk_pseudo_set(Imm, Dst) -> #pseudo_set{imm=Imm, dst=Dst}.
-
-mk_pseudo_spill_move(Src, Temp, Dst) ->
- #pseudo_spill_move{src=Src, temp=Temp, dst=Dst}.
-is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move).
-
-mk_pseudo_tailcall(FunV, Arity, StkArgs, Linkage) ->
- #pseudo_tailcall{funv=FunV, arity=Arity, stkargs=StkArgs, linkage=Linkage}.
-pseudo_tailcall_funv(#pseudo_tailcall{funv=FunV}) -> FunV.
-pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage.
-pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs.
-
-mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}.
-
-mk_rdy(Dst) -> #rdy{dst=Dst}.
-
-mk_sethi(UImm22, Dst) -> #sethi{uimm22=UImm22, dst=Dst}.
-mk_nop() -> mk_sethi(mk_uimm22(0), mk_g0()).
-
-%%% Load an integer constant into a register.
-mk_set(Value, Dst) -> mk_set(Value, Dst, []).
-
-mk_set(Value, Dst, Tail) ->
- if -4096 =< Value, Value < 4096 ->
- [mk_alu('or', mk_g0(), mk_simm13(Value), Dst) | Tail];
- true ->
- Hi22 = mk_uimm22((Value bsr 10) band 16#003FFFFF),
- case (Value band 16#3FF) of
- 0 ->
- [mk_sethi(Hi22, Dst) | Tail];
- Lo10 ->
- [mk_sethi(Hi22, Dst),
- mk_alu('or', Dst, mk_simm13(Lo10), Dst) |
- Tail]
- end
- end.
-
-%%% Add an integer constant. Dst may equal Src,
-%%% in which case temp2 may be clobbered.
-mk_addi(Src, Value, Dst, Tail) ->
- if -4096 =< Value, Value < 4096 ->
- [mk_alu('add', Src, mk_simm13(Value), Dst) | Tail];
- true ->
- Tmp =
- begin
- DstReg = temp_reg(Dst),
- SrcReg = temp_reg(Src),
- if DstReg =:= SrcReg -> mk_temp2();
- true -> Dst
- end
- end,
- mk_set(Value, Tmp, [mk_alu('add', Src, Tmp, Dst) | Tail])
- end.
-
-mk_store(StOp, Src, Base, Disp) ->
- #store{stop=StOp, src=Src, base=Base, disp=Disp}.
-
-mk_store(StOp, Src, Base, Offset, Scratch, Rest) when is_integer(Offset) ->
- if -4096 =< Offset, Offset < 4096 ->
- [mk_store(StOp, Src, Base, mk_simm13(Offset)) | Rest];
- true ->
- Index = mk_scratch(Scratch),
- mk_set(Offset, Index, [mk_store(StOp, Src, Base, Index) | Rest])
- end.
-
-mk_load(LdOp, Base, Disp, Dst) ->
- mk_alu(LdOp, Base, Disp, Dst).
-
-mk_load(LdOp, Base, Offset, Dst, Scratch, Rest) when is_integer(Offset) ->
- if -4096 =< Offset, Offset < 4096 ->
- [mk_load(LdOp, Base, mk_simm13(Offset), Dst) | Rest];
- true ->
- Index =
- begin
- DstReg = temp_reg(Dst),
- BaseReg = temp_reg(Base),
- if DstReg =/= BaseReg -> Dst;
- true -> mk_scratch(Scratch)
- end
- end,
- mk_set(Offset, Index, [mk_load(LdOp, Base, Index, Dst) | Rest])
- end.
-
-mk_scratch(Scratch) ->
- case Scratch of
- 'temp2' -> mk_temp2();
- 'new' -> mk_new_temp('untagged')
- end.
-
-mk_fp_binary(FpBinOp, Src1, Src2, Dst) ->
- #fp_binary{fp_binop=FpBinOp, src1=Src1, src2=Src2, dst=Dst}.
-
-mk_fp_unary(FpUnOp, Src, Dst) -> #fp_unary{fp_unop=FpUnOp, src=Src, dst=Dst}.
-
-mk_pseudo_fload(Base, Disp, Dst, IsSingle) ->
- #pseudo_fload{base=Base, disp=Disp, dst=Dst, is_single=IsSingle}.
-
-mk_fload(Base, Disp, Dst, Scratch) when is_integer(Disp) ->
- if -4096 =< Disp, Disp < (4096-4) ->
- [mk_pseudo_fload(Base, mk_simm13(Disp), Dst, false)];
- true ->
- Tmp = mk_scratch(Scratch),
- mk_set(Disp, Tmp,
- [mk_alu('add', Tmp, Base, Tmp),
- mk_pseudo_fload(Tmp, mk_simm13(0), Dst, false)])
- end.
-
-mk_pseudo_fmove(Src, Dst) -> #pseudo_fmove{src=Src, dst=Dst}.
-is_pseudo_fmove(I) -> case I of #pseudo_fmove{} -> true; _ -> false end.
-pseudo_fmove_src(#pseudo_fmove{src=Src}) -> Src.
-pseudo_fmove_dst(#pseudo_fmove{dst=Dst}) -> Dst.
-
-mk_pseudo_spill_fmove(Src, Temp, Dst) ->
- #pseudo_spill_fmove{src=Src, temp=Temp, dst=Dst}.
-is_pseudo_spill_fmove(I) -> is_record(I, pseudo_spill_fmove).
-
-mk_pseudo_fstore(Src, Base, Disp) ->
- #pseudo_fstore{src=Src, base=Base, disp=Disp}.
-
-mk_fstore(Src, Base, Disp, Scratch) when is_integer(Disp) ->
- if -4096 =< Disp, Disp < (4096-4) ->
- [mk_pseudo_fstore(Src, Base, hipe_sparc:mk_simm13(Disp))];
- true ->
- Tmp = mk_scratch(Scratch),
- mk_set(Disp, Tmp,
- [mk_alu('add', Tmp, Base, Tmp),
- mk_pseudo_fstore(Src, Tmp, mk_simm13(0))])
- end.
-
-mk_defun(MFA, Formals, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) ->
- #defun{mfa=MFA, formals=Formals, code=Code, data=Data,
- isclosure=IsClosure, isleaf=IsLeaf,
- var_range=VarRange, label_range=LabelRange}.
-defun_code(#defun{code=Code}) -> Code.
-defun_data(#defun{data=Data}) -> Data.
-defun_formals(#defun{formals=Formals}) -> Formals.
-defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure.
-defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf.
-defun_mfa(#defun{mfa=MFA}) -> MFA.
-defun_var_range(#defun{var_range=VarRange}) -> VarRange.
diff --git a/lib/hipe/sparc/hipe_sparc.hrl b/lib/hipe/sparc/hipe_sparc.hrl
deleted file mode 100644
index f60e516e59..0000000000
--- a/lib/hipe/sparc/hipe_sparc.hrl
+++ /dev/null
@@ -1,112 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
-%%%--------------------------------------------------------------------
-%%% Basic Values:
-%%%
-%%% temp ::= #sparc_temp{reg, type, allocatable}
-%%% reg ::= <token from hipe_sparc_registers>
-%%% type ::= tagged | untagged | double
-%%% allocatable ::= true | false
-%%%
-%%% sdesc ::= #sparc_sdesc{exnlab, fsize, arity, live}
-%%% exnlab ::= [] | label
-%%% fsize ::= int32 (frame size in words)
-%%% live ::= <tuple of int32> (word offsets)
-%%% arity ::= uint8
-%%%
-%%% mfa ::= #sparc_mfa{atom, atom, arity}
-%%% prim ::= #sparc_prim{atom}
-
--record(sparc_mfa, {m::atom(), f::atom(), a::arity()}).
--record(sparc_prim, {prim}).
--record(sparc_sdesc, {exnlab, fsize, arity::arity(), live}).
--record(sparc_temp, {reg, type, allocatable}).
--record(sparc_simm13, {value}).
--record(sparc_uimm5, {value}).
--record(sparc_uimm6, {value}). % shift counts in 64-bit mode
--record(sparc_uimm22, {value}).
-
-%%% Instruction Operands:
-%%%
-%%% aluop ::= add | addcc | and | andcc | or | orcc
-%%% | xor | xorcc | sub | subcc | mulx | smul
-%%% | sll | srl | sra | sllx | srlx | srax
-%%% | ldsb | ldsh | ldsw | ldub | lduh | lduw | ldx
-%%% (HW has andn{,cc}, orn{,cc}, xnor{,cc}, addc{,cc},
-%%% and subc{,cc}, but we don't use them)
-%%% cond ::= n | e | le | l | leu | lu | neg | vs |
-%%% | a | ne | g | ge | gu | geu | pos | vc
-%%% rcond ::= z | lez | lz | nz | gz | gez
-%%% stop ::= stb | stw | stx (HW has sth, but we don't use it)
-%%%
-%%% immediate ::= int32 | atom | {label, label_type}
-%%% label_type ::= constant | closure | c_const
-%%%
-%%% dst ::= temp
-%%% src ::= temp
-%%% src1 ::= temp
-%%% src2 ::= temp
-%%% | simm13 (only in alu.src2, jmp.src2, jmpl.src2)
-%%% base ::= src1
-%%% disp ::= src2
-%%%
-%%% fun ::= mfa | prim
-%%% funv ::= fun | temp
-%%%
-%%% fp_binop ::= faddd | fdivd | fmuld | fsubd
-%%% fp_unop ::= fitod | fmovd | fnegd
-
-%%% Instructions:
-
--record(alu, {aluop, src1, src2, dst}).
--record(bp, {'cond', label, pred}). % local jump on %icc
--ifdef(notdef). % XXX: only for sparc64, alas
--record(br, {rcond, src, label, pred}). % local jump on register
--endif.
--record(call_rec, {'fun', sdesc, linkage}). % known recursive call
--record(call_tail, {'fun', linkage}). % known tailcall
--record(comment, {term}).
--record(jmp, {src1, src2, labels}). % return, switch, or computed tailcall
--record(jmpl, {src, sdesc}). % computed recursive call (jmpl [src+0],%o7)
--record(label, {label}).
--record(pseudo_bp, {'cond', true_label, false_label, pred}).
-%%-record(pseudo_br, {rcond, src, true_label, false_label, pred}).
--record(pseudo_call, {funv, sdesc, contlab, linkage}).
--record(pseudo_call_prepare, {nrstkargs}).
--record(pseudo_move, {src, dst}).
--record(pseudo_ret, {}).
--record(pseudo_set, {imm, dst}).
--record(pseudo_spill_fmove, {src, temp, dst}).
--record(pseudo_spill_move, {src, temp, dst}).
--record(pseudo_tailcall, {funv, arity, stkargs, linkage}).
--record(pseudo_tailcall_prepare, {}).
--record(rdy, {dst}).
--record(sethi, {uimm22, dst}).
--record(store, {stop, src, base, disp}).
--record(fp_binary, {fp_binop, src1, src2, dst}).
--record(fp_unary, {fp_unop, src, dst}).
--record(pseudo_fload, {base, disp, dst, is_single}).
--record(pseudo_fmove, {src, dst}).
--record(pseudo_fstore, {src, base, disp}).
-
-%%% Function definitions.
-
--include("../misc/hipe_consttab.hrl").
-
--record(defun, {mfa :: mfa(), formals, code,
- data :: hipe_consttab(),
- isclosure :: boolean(),
- isleaf :: boolean(),
- var_range, label_range}).
diff --git a/lib/hipe/sparc/hipe_sparc_assemble.erl b/lib/hipe/sparc/hipe_sparc_assemble.erl
deleted file mode 100644
index 2b82f41d23..0000000000
--- a/lib/hipe/sparc/hipe_sparc_assemble.erl
+++ /dev/null
@@ -1,540 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_assemble).
--export([assemble/4]).
-
--include("../main/hipe.hrl"). % for VERSION_STRING, when_option
--include("hipe_sparc.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../rtl/hipe_literals.hrl").
--include("../misc/hipe_sdi.hrl").
--undef(ASSERT).
--define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).
-
-assemble(CompiledCode, Closures, Exports, Options) ->
- print("****************** Assembling *******************\n", [], Options),
- %%
- Code = [{MFA,
- hipe_sparc:defun_code(Defun),
- hipe_sparc:defun_data(Defun)}
- || {MFA, Defun} <- CompiledCode],
- %%
- {ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code),
- %%
- {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =
- encode(translate(Code, ConstMap), Options),
- print("Total num bytes=~w\n", [CodeSize], Options),
- %%
- SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
- SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
- ConstAlign, ConstSize,
- SC,
- DataRelocs, % nee LM, LabelMap
- SSE,
- CodeSize,CodeBinary,SlimRefs,
- 0,[] % ColdCodeSize, SlimColdRefs
- ]),
- %%
- Bin.
-
-%%%
-%%% Assembly Pass 1.
-%%% Process initial {MFA,Code,Data} list.
-%%% Translate each MFA's body, choosing operand & instruction kinds.
-%%%
-%%% Assembly Pass 2.
-%%% Perform short/long form optimisation for jumps.
-%%%
-%%% Result is {MFA,NewCode,CodeSize,LabelMap} list.
-%%%
-
-translate(Code, ConstMap) ->
- translate_mfas(Code, ConstMap, []).
-
-translate_mfas([{MFA,Insns,_Data}|Code], ConstMap, NewCode) ->
- {NewInsns,CodeSize,LabelMap} =
- translate_insns(Insns, MFA, ConstMap, hipe_sdi:pass1_init(), 0, []),
- translate_mfas(Code, ConstMap, [{MFA,NewInsns,CodeSize,LabelMap}|NewCode]);
-translate_mfas([], _ConstMap, NewCode) ->
- lists:reverse(NewCode).
-
-translate_insns([I|Insns], MFA, ConstMap, SdiPass1, Address, NewInsns) ->
- NewIs = translate_insn(I, MFA, ConstMap),
- add_insns(NewIs, Insns, MFA, ConstMap, SdiPass1, Address, NewInsns);
-translate_insns([], _MFA, _ConstMap, SdiPass1, Address, NewInsns) ->
- {LabelMap,CodeSizeIncr} = hipe_sdi:pass2(SdiPass1),
- {lists:reverse(NewInsns), Address+CodeSizeIncr, LabelMap}.
-
-add_insns([I|Is], Insns, MFA, ConstMap, SdiPass1, Address, NewInsns) ->
- NewSdiPass1 =
- case I of
- {'.label',L,_} ->
- hipe_sdi:pass1_add_label(SdiPass1, Address, L);
- {bp_sdi,{_,_,{label,L}},_} -> % BP has 19-bit offset
- SdiInfo = #sdi_info{incr=(12-4),lb=-16#40000*4,ub=16#3FFFF*4},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo);
- %% {br_sdi,_,_} -> add_insns_br(I, SdiPass1, Address);
- _ ->
- SdiPass1
- end,
- Address1 = Address + insn_size(I),
- add_insns(Is, Insns, MFA, ConstMap, NewSdiPass1, Address1, [I|NewInsns]);
-add_insns([], Insns, MFA, ConstMap, SdiPass1, Address, NewInsns) ->
- translate_insns(Insns, MFA, ConstMap, SdiPass1, Address, NewInsns).
-
--ifdef(notdef). % XXX: only for sparc64, alas
-add_insns_br(I, SdiPass1, Address) -> % BR has 16-bit offset
- {br_sdi,{_,_,_,{label,L}},_} = I,
- SdiInfo = #sdi_info{incr=(12-4),lb=-16#8000*4,ub=16#7FFF*4},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo).
--endif.
-
-insn_size(I) ->
- case I of
- {'.label',_,_} -> 0;
- {'.reloc',_,_} -> 0;
- _ -> 4 % b{p,r}_sdi included in this case
- end.
-
-translate_insn(I, MFA, ConstMap) -> % -> [{Op,Opnd,OrigI}]
- case I of
- #alu{} -> do_alu(I);
- #bp{} -> do_bp(I);
- %% #br{} -> do_br(I);
- #call_rec{} -> do_call_rec(I);
- #call_tail{} -> do_call_tail(I);
- #comment{} -> [];
- #jmp{} -> do_jmp(I);
- #jmpl{} -> do_jmpl(I);
- #label{} -> do_label(I);
- %% pseudo_bp: eliminated before assembly
- %% pseudo_br: eliminated before assembly
- %% pseudo_call: eliminated before assembly
- %% pseudo_call_prepare: eliminated before assembly
- %% pseudo_move: eliminated before assembly
- %% pseudo_ret: eliminated before assembly
- #pseudo_set{} -> do_pseudo_set(I, MFA, ConstMap);
- %% pseudo_tailcall: eliminated before assembly
- %% pseudo_tailcall_prepare: eliminated before assembly
- #rdy{} -> do_rdy(I);
- #sethi{} -> do_sethi(I);
- #store{} -> do_store(I);
- #fp_binary{} -> do_fp_binary(I);
- #fp_unary{} -> do_fp_unary(I);
- #pseudo_fload{} -> do_pseudo_fload(I);
- %% #pseudo_fmove: eliminated before assembly
- #pseudo_fstore{} -> do_pseudo_fstore(I);
- _ -> exit({?MODULE,translate_insn,I})
- end.
-
-do_alu(I) ->
- #alu{aluop=AluOp,src1=Src1,src2=Src2,dst=Dst} = I,
- NewDst = do_reg(Dst),
- NewSrc1 = do_reg(Src1),
- NewSrc2 = do_reg_or_imm(Src2),
- [{AluOp, {NewSrc1,NewSrc2,NewDst}, I}].
-
-do_bp(I) ->
- #bp{'cond'=Cond,pred=Pred,label=Label} = I,
- NewLabel = {label,Label},
- case Cond of
- 'a' ->
- [{ba, NewLabel, I}]; % 3 more offset bits
- _ ->
- NewCond = {'cond',Cond},
- NewPred = {pred,Pred},
- [{bp_sdi, {NewCond,NewPred,NewLabel}, I}]
- end.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-do_br(I) ->
- #br{rcond=RCond,pred=Pred,src=Src,label=Label} = I,
- NewRCond = {rcond,RCond},
- NewPred = {pred,Pred},
- NewSrc = do_reg(Src),
- NewLabel = {label,Label},
- [{br_sdi, {NewRCond,NewPred,NewSrc,NewLabel}, I}].
--endif.
-
-do_call_rec(I) ->
- #call_rec{'fun'=Fun,sdesc=SDesc,linkage=Linkage} = I,
- [{'.reloc', {call,Fun,Linkage}, #comment{term='fun'}},
- {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}},
- {call, {disp30,0}, I}].
-
-do_call_tail(I) ->
- #call_tail{'fun'=Fun,linkage=Linkage} = I,
- [{'.reloc', {call,Fun,Linkage}, #comment{term='fun'}},
- {call, {disp30,0}, I}].
-
-do_jmp(I) ->
- #jmp{src1=Src1,src2=Src2} = I,
- NewSrc1 = do_reg(Src1),
- NewSrc2 = do_reg_or_imm(Src2),
- NewDst = {r,0},
- [{jmpl, {NewSrc1,NewSrc2,NewDst}, I}].
-
-do_jmpl(I) ->
- #jmpl{src=Src,sdesc=SDesc} = I,
- NewSrc1 = do_reg(Src),
- NewSrc2 = {simm13,0},
- NewDst = {r,15}, % %o7
- [{'.reloc', {sdesc,SDesc}, #comment{term=sdesc}},
- {jmpl, {NewSrc1,NewSrc2,NewDst}, I}].
-
-do_label(I) ->
- #label{label=Label} = I,
- [{'.label', Label, I}].
-
-do_pseudo_set(I, MFA, ConstMap) ->
- #pseudo_set{imm=Imm,dst=Dst} = I,
- RelocData =
- case Imm of
- Atom when is_atom(Atom) ->
- {load_atom, Atom};
-%%% {mfa,MFAorPrim,Linkage} ->
-%%% Tag =
-%%% case Linkage of
-%%% remote -> remote_function;
-%%% not_remote -> local_function
-%%% end,
-%%% {load_address, {Tag,untag_mfa_or_prim(MFAorPrim)}};
- {Label,constant} ->
- ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
- {load_address, {constant,ConstNo}};
- {Label,closure} ->
- {load_address, {closure,Label}};
- {Label,c_const} ->
- {load_address, {c_const,Label}}
- end,
- NewDst = do_reg(Dst),
- [{'.reloc', RelocData, #comment{term=reloc}},
- {sethi, {{uimm22,0},NewDst}, I},
- {'or', {NewDst,{simm13,0},NewDst}, I}].
-
-do_rdy(I) ->
- #rdy{dst=Dst} = I,
- NewDst = do_reg(Dst),
- [{rd, {y,NewDst}, I}].
-
-do_sethi(I) ->
- #sethi{uimm22=#sparc_uimm22{value=UImm22},dst=Dst} = I,
- NewUImm22 = {uimm22,UImm22},
- NewDst = do_reg(Dst),
- [{sethi, {NewUImm22,NewDst}, I}].
-
-do_store(I) ->
- #store{stop=StOp,src=Src,base=Base,disp=Disp} = I,
- NewSrc = do_reg(Src),
- NewBase = do_reg(Base),
- NewDisp = do_reg_or_imm(Disp),
- [{StOp, {NewSrc,NewBase,NewDisp}, I}].
-
-do_fp_binary(I) ->
- #fp_binary{fp_binop=FpBinOp,src1=Src1,src2=Src2,dst=Dst} = I,
- NewSrc1 = do_fpreg(Src1),
- NewSrc2 = do_fpreg(Src2),
- NewDst = do_fpreg(Dst),
- [{FpBinOp, {NewSrc1,NewSrc2,NewDst}, I}].
-
-do_fp_unary(I) ->
- #fp_unary{fp_unop=FpUnOp,src=Src,dst=Dst} = I,
- NewSrc = do_fpreg(Src),
- NewDst = do_fpreg(Dst),
- [{FpUnOp, {NewSrc,NewDst}, I}].
-
-do_pseudo_fload(I) ->
- #pseudo_fload{base=Base,disp=Disp,dst=Dst,is_single=IsSingle} = I,
- NewBase = do_reg(Base),
- #sparc_simm13{value=RawDisp} = Disp,
- {fr,RawDst} = FrRawDst = do_fpreg(Dst),
- case IsSingle of
- true ->
- [{'ldf', {NewBase,{simm13,RawDisp},FrRawDst}, I}];
- _ ->
- [{'ldf', {NewBase,{simm13,RawDisp},FrRawDst}, I},
- {'ldf', {NewBase,{simm13,RawDisp+4},{fr,RawDst+1}}, I}]
- end.
-
-do_pseudo_fstore(I) ->
- #pseudo_fstore{src=Src,base=Base,disp=Disp} = I,
- {fr,RawSrc} = FrRawSrc = do_fpreg(Src),
- NewBase = do_reg(Base),
- #sparc_simm13{value=RawDisp} = Disp,
- [{'stf', {FrRawSrc,NewBase,{simm13,RawDisp}}, I},
- {'stf', {{fr,RawSrc+1},NewBase,{simm13,RawDisp+4}}, I}].
-
-%% map a virtual double-precision fp reg in [0,15] to its
-%% corresponding single-precision fp reg in [0,2,4,...,28,30]
-do_fpreg(#sparc_temp{reg=Reg,type='double'})
- when is_integer(Reg), 0 =< Reg, Reg < 16 ->
- {fr,2*Reg}.
-
-do_reg(#sparc_temp{reg=Reg,type=Type})
- when is_integer(Reg), 0 =< Reg, Reg < 32, Type =/= 'double' ->
- {r,Reg}.
-
-do_reg_or_imm(Src) ->
- case Src of
- #sparc_temp{} ->
- do_reg(Src);
- #sparc_simm13{value=Value} when is_integer(Value), -4096 =< Value, Value =< 4095 ->
- {simm13, Value band 16#1fff};
- #sparc_uimm5{value=Value} when is_integer(Value), 0 =< Value, Value =< 31 ->
- {uimm5, Value};
- #sparc_uimm6{value=Value} when is_integer(Value), 0 =< Value, Value =< 63 ->
- {uimm6, Value}
- end.
-
-%%%
-%%% Assembly Pass 3.
-%%% Process final {MFA,Code,CodeSize,LabelMap} list from pass 2.
-%%% Translate to a single binary code segment.
-%%% Collect relocation patches.
-%%% Build ExportMap (MFA-to-address mapping).
-%%% Combine LabelMaps to a single one (for mk_data_relocs/2 compatibility).
-%%% Return {CombinedCodeSize,BinaryCode,Relocs,CombinedLabelMap,ExportMap}.
-%%%
-
-encode(Code, Options) ->
- CodeSize = compute_code_size(Code, 0),
- ExportMap = build_export_map(Code, 0, []),
- {AccCode,Relocs} = encode_mfas(Code, 0, [], [], Options),
- CodeBinary = list_to_binary(lists:reverse(AccCode)),
- ?ASSERT(CodeSize =:= byte_size(CodeBinary)),
- CombinedLabelMap = combine_label_maps(Code, 0, gb_trees:empty()),
- {CodeSize,CodeBinary,Relocs,CombinedLabelMap,ExportMap}.
-
-compute_code_size([{_MFA,_Insns,CodeSize,_LabelMap}|Code], Size) ->
- compute_code_size(Code, Size+CodeSize);
-compute_code_size([], Size) -> Size.
-
-build_export_map([{{M,F,A},_Insns,CodeSize,_LabelMap}|Code], Address, ExportMap) ->
- build_export_map(Code, Address+CodeSize, [{Address,M,F,A}|ExportMap]);
-build_export_map([], _Address, ExportMap) -> ExportMap.
-
-combine_label_maps([{MFA,_Insns,CodeSize,LabelMap}|Code], Address, CLM) ->
- NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
- combine_label_maps(Code, Address+CodeSize, NewCLM);
-combine_label_maps([], _Address, CLM) -> CLM.
-
-merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
- NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
- merge_label_map(Rest, MFA, Address, NewCLM);
-merge_label_map([], _MFA, _Address, CLM) -> CLM.
-
-encode_mfas([{MFA,Insns,CodeSize,LabelMap}|Code], Address, AccCode, Relocs, Options) ->
- print("Generating code for: ~w\n", [MFA], Options),
- print("Offset | Opcode | Instruction\n", [], Options),
- {Address1,Relocs1,AccCode1} =
- encode_insns(Insns, Address, Address, LabelMap, Relocs, AccCode, Options),
- ExpectedAddress = Address + CodeSize,
- ?ASSERT(Address1 =:= ExpectedAddress),
- print("Finished.\n", [], Options),
- encode_mfas(Code, Address1, AccCode1, Relocs1, Options);
-encode_mfas([], _Address, AccCode, Relocs, _Options) ->
- {AccCode,Relocs}.
-
-encode_insns([I|Insns], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case I of
- {'.label',L,_} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ?ASSERT(Address =:= LabelAddress), % sanity check
- print_insn(Address, [], I, Options),
- encode_insns(Insns, Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- {'.reloc',Data,_} ->
- Reloc = encode_reloc(Data, Address, FunAddress, LabelMap),
- encode_insns(Insns, Address, FunAddress, LabelMap, [Reloc|Relocs], AccCode, Options);
- {bp_sdi,_,_} ->
- encode_insns(fix_bp_sdi(I, Insns, Address, FunAddress, LabelMap),
- Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- %% {br_sdi,_,_} ->
- %% encode_insns(fix_br_sdi(I, Insns, Address, FunAddress, LabelMap),
- %% Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- _ ->
- {Op,Arg,_} = fix_jumps(I, Address, FunAddress, LabelMap),
- Word = hipe_sparc_encode:insn_encode(Op, Arg),
- print_insn(Address, Word, I, Options),
- Segment = <<Word:32/integer-big>>,
- NewAccCode = [Segment|AccCode],
- encode_insns(Insns, Address+4, FunAddress, LabelMap, Relocs, NewAccCode, Options)
- end;
-encode_insns([], Address, _FunAddress, _LabelMap, Relocs, AccCode, _Options) ->
- {Address,Relocs,AccCode}.
-
-encode_reloc(Data, Address, FunAddress, LabelMap) ->
- case Data of
- {call,MFAorPrim,Linkage} ->
- %% call_rec and call_tail are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case Linkage of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- {PatchTypeExt, Address, untag_mfa_or_prim(MFAorPrim)};
- {load_atom,Atom} ->
- {?LOAD_ATOM, Address, Atom};
- {load_address,X} ->
- {?LOAD_ADDRESS, Address, X};
- {sdesc,SDesc} ->
- #sparc_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live} = SDesc,
- ExnRA =
- case ExnLab of
- [] -> []; % don't cons up a new one
- ExnLab -> gb_trees:get(ExnLab, LabelMap) + FunAddress
- end,
- {?SDESC, Address,
- ?STACK_DESC(ExnRA, FSize, Arity, Live)}
- end.
-
-untag_mfa_or_prim(#sparc_mfa{m=M,f=F,a=A}) -> {M,F,A};
-untag_mfa_or_prim(#sparc_prim{prim=Prim}) -> Prim.
-
-fix_bp_sdi(I, Insns, InsnAddress, FunAddress, LabelMap) ->
- {bp_sdi,Opnds,OrigI} = I,
- {{'cond',Cond},{pred,Pred},Label} = Opnds,
- {label,L} = Label,
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- BD = (LabelAddress - InsnAddress) div 4,
- if BD >= -16#40000, BD =< 16#3FFFF ->
- [{bp, Opnds, OrigI} | Insns];
- true ->
- %% bp<cond>,<pred> L; Delay
- %% -->
- %% bp<!cond>,<!pred> 1f; Delay; ba L; nop; 1:
- [Delay|Rest] = Insns,
- NewCond = hipe_sparc:negate_cond(Cond),
- NewPred = 1.0 - Pred,
- [{bp,
- {{'cond',NewCond},{pred,NewPred},'.+16'},
- #bp{'cond'=NewCond,pred=NewPred,label='.+16'}}, % pp will be ugly
- Delay, % should be a NOP
- {ba, Label, #bp{'cond'='a',pred=1.0,label=L}},
- {sethi, {{uimm22,0},{r,0}}, #comment{term=nop}} |
- Rest]
- end.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-fix_br_sdi(I, Insns, InsnAddress, FunAddress, LabelMap) ->
- {br_sdi,Opnds,OrigI} = I,
- {{rcond,RCond},{pred,Pred},Src,{label,L}} = Opnds,
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- BD = (LabelAddress - InsnAddress) div 4,
- if BD >= -16#8000, BD =< 16#7FFF ->
- [{br, Opnds, OrigI} | Insns];
- true ->
- %% br<rcond>,<pred> reg, L; Delay
- %% -->
- %% br<!rcond>,<!pred> reg, 1f; Delay; ba L; nop; 1:
- [Delay|Rest] = Insns,
- {reg,SrcReg} = Src,
- NewRCond = hipe_sparc:negate_rcond(RCond),
- NewPred = 1.0 - Pred,
- [{br,
- {{rcond,NewRCond},{pred,NewPred},Src,'.+16'},
- #br{rcond=NewRCond,pred=NewPred,src=SrcReg,label='.+16'}}, % pp will be ugly
- Delay, % should be a NOP
- {ba, {label,L}, #bp{'cond'='a',pred=1.0,label=L}},
- {sethi, {{uimm22,0},{r,0}}, #comment{term=nop}} |
- Rest]
- end.
--endif.
-
-fix_jumps(I, InsnAddress, FunAddress, LabelMap) ->
- case I of
- {ba, {label,L}, OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- BD = (LabelAddress - InsnAddress) div 4,
- %% ensure BD fits in a 22 bit sign-extended field
- ?ASSERT(BD =< 16#1FFFFF),
- ?ASSERT(BD >= -16#200000),
- {ba, {disp22,BD band 16#3FFFFF}, OrigI};
- {bp, {Cond,Pred,Target}, OrigI} ->
- LabelAddress =
- case Target of
- {label,L} -> gb_trees:get(L, LabelMap) + FunAddress;
- '.+16' -> InsnAddress + 16
- end,
- BD = (LabelAddress - InsnAddress) div 4,
- %% ensure BD fits in a 19 bit sign-extended field
- ?ASSERT(BD =< 16#3FFFF),
- ?ASSERT(BD >= -16#40000),
- {bp, {Cond,px(Pred),{disp19,BD band 16#7FFFF}}, OrigI};
- %% {br, _, _} -> fix_br(I, InsnAddress, FunAddress, LabelMap);
- _ -> I
- end.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-fix_br(I, InsnAddress, FunAddress, LabelMap) ->
- {br, {RCond,Pred,Src,Target}, OrigI} = I,
- LabelAddress =
- case Target of
- {label,L} -> gb_trees:get(L, LabelMap) + FunAddress;
- '.+16' -> InsnAddress + 16
- end,
- BD = (LabelAddress - InsnAddress) div 4,
- %% ensure BD fits in a 16 bit sign-extended field
- ?ASSERT(BD =< 16#7FFF),
- ?ASSERT(BD >= -16#8000),
- {br, {RCond,px(Pred),Src,{disp16,BD band 16#FFFF}}, OrigI}.
--endif.
-
-px({pred,Pred}) -> % XXX: use pt/pn throughout entire backend
- {pred, if Pred >= 0.5 -> 'pt'; true -> 'pn' end}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%
-%%% Assembly listing support (pp_asm option).
-%%%
-
-print(String, Arglist, Options) ->
- ?when_option(pp_asm, Options, io:format(String, Arglist)).
-
-print_insn(Address, Word, I, Options) ->
- ?when_option(pp_asm, Options, print_insn_2(Address, Word, I)).
-
-print_insn_2(Address, Word, {_,_,OrigI}) ->
- io:format("~8.16.0b | ", [Address]),
- print_code_list(word_to_bytes(Word), 0),
- hipe_sparc_pp:pp_insn(OrigI).
-
-word_to_bytes(W) ->
- case W of
- [] -> []; % label or other pseudo instruction
- _ -> [(W bsr 24) band 16#FF, (W bsr 16) band 16#FF,
- (W bsr 8) band 16#FF, W band 16#FF]
- end.
-
-print_code_list([Byte|Rest], Len) ->
- print_byte(Byte),
- print_code_list(Rest, Len+1);
-print_code_list([], Len) ->
- fill_spaces(8-(Len*2)),
- io:format(" | ").
-
-print_byte(Byte) ->
- io:format("~2.16.0b", [Byte band 16#FF]).
-
-fill_spaces(N) when N > 0 ->
- io:format(" "),
- fill_spaces(N-1);
-fill_spaces(0) ->
- [].
diff --git a/lib/hipe/sparc/hipe_sparc_cfg.erl b/lib/hipe/sparc/hipe_sparc_cfg.erl
deleted file mode 100644
index 45c8e887b5..0000000000
--- a/lib/hipe/sparc/hipe_sparc_cfg.erl
+++ /dev/null
@@ -1,155 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_cfg).
-
--export([init/1,
- labels/1, start_label/1,
- succ/2,
- map_bbs/2, fold_bbs/3,
- bb/2, bb_add/3]).
--export([postorder/1, reverse_postorder/1]).
--export([linearise/1]).
--export([params/1]).
--export([arity/1]). % for linear scan
--export([redirect_jmp/3, branch_preds/1]).
-
--define(SPARC_CFG, true). % needed for cfg.inc
-
--include("../main/hipe.hrl").
--include("hipe_sparc.hrl").
--include("../flow/cfg.hrl").
--include("../flow/cfg.inc").
-
-%%----------------------------------------------------------------------------
-%% CFG interface to SPARC
-%%----------------------------------------------------------------------------
-
-init(Defun) ->
- Code = hipe_sparc:defun_code(Defun),
- StartLab = hipe_sparc:label_label(hd(Code)),
- Data = hipe_sparc:defun_data(Defun),
- IsClosure = hipe_sparc:defun_is_closure(Defun),
- Name = hipe_sparc:defun_mfa(Defun),
- IsLeaf = hipe_sparc:defun_is_leaf(Defun),
- Formals = hipe_sparc:defun_formals(Defun),
- CFG = mk_empty_cfg(Name, StartLab, Data, IsClosure, IsLeaf, Formals),
- take_bbs(Code, CFG).
-
-is_branch(I) ->
- case I of
- #bp{'cond'='a'} -> true;
- %% not br
- #call_tail{} -> true;
- #jmp{} -> true;
- %% not jmpl
- #pseudo_bp{} -> true;
- %% #pseudo_br{} -> true;
- #pseudo_call{} -> true;
- #pseudo_ret{} -> true;
- #pseudo_tailcall{} -> true;
- _ -> false
- end.
-
-branch_successors(Branch) ->
- case Branch of
- #bp{'cond'='a',label=Label} -> [Label];
- #call_tail{} -> [];
- #jmp{labels=Labels} -> Labels;
- #pseudo_bp{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
- %% #pseudo_br{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
- #pseudo_call{contlab=ContLab, sdesc=#sparc_sdesc{exnlab=ExnLab}} ->
- case ExnLab of
- [] -> [ContLab];
- _ -> [ContLab,ExnLab]
- end;
- #pseudo_ret{} -> [];
- #pseudo_tailcall{} -> []
- end.
-
-branch_preds(Branch) ->
- case Branch of
- #jmp{labels=Labels} ->
- Prob = 1.0/length(Labels),
- [{L, Prob} || L <- Labels];
- #pseudo_bp{true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
- [{FalseLab, 1.0-Pred}, {TrueLab, Pred}];
- #pseudo_call{contlab=ContLab, sdesc=#sparc_sdesc{exnlab=[]}} ->
- %% A function can still cause an exception, even if we won't catch it
- [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}];
- #pseudo_call{contlab=ContLab, sdesc=#sparc_sdesc{exnlab=ExnLab}} ->
- CallExnPred = hipe_bb_weights:call_exn_pred(),
- [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}];
- _ ->
- case branch_successors(Branch) of
- [] -> [];
- [Single] -> [{Single, 1.0}]
- end
- end.
-
--ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
-fails_to(_Instr) -> [].
--endif.
-
-redirect_jmp(I, Old, New) ->
- case I of
- #bp{'cond'='a',label=Label} ->
- if Old =:= Label -> I#bp{label=New};
- true -> I
- end;
- #pseudo_bp{true_label=TrueLab, false_label=FalseLab} ->
- I1 = if Old =:= TrueLab -> I#pseudo_bp{true_label=New};
- true -> I
- end,
- if Old =:= FalseLab -> I1#pseudo_bp{false_label=New};
- true -> I1
- end;
- #pseudo_call{contlab=ContLab0, sdesc=SDesc0} ->
- SDesc = case SDesc0 of
- #sparc_sdesc{exnlab=Old} -> SDesc0#sparc_sdesc{exnlab=New};
- #sparc_sdesc{exnlab=_} -> SDesc0
- end,
- ContLab = if Old =:= ContLab0 -> New;
- true -> ContLab0
- end,
- I#pseudo_call{sdesc=SDesc, contlab=ContLab}
- end.
-
-mk_goto(Label) ->
- hipe_sparc:mk_b_label(Label).
-
-is_label(I) ->
- hipe_sparc:is_label(I).
-
-label_name(Label) ->
- hipe_sparc:label_label(Label).
-
-mk_label(Name) ->
- hipe_sparc:mk_label(Name).
-
-linearise(CFG) -> % -> defun, not insn list
- MFA = function(CFG),
- Formals = params(CFG),
- Code = linearize_cfg(CFG),
- Data = data(CFG),
- VarRange = hipe_gensym:var_range(sparc),
- LabelRange = hipe_gensym:label_range(sparc),
- IsClosure = is_closure(CFG),
- IsLeaf = is_leaf(CFG),
- hipe_sparc:mk_defun(MFA, Formals, IsClosure, IsLeaf,
- Code, Data, VarRange, LabelRange).
-
-arity(CFG) ->
- {_M, _F, A} = function(CFG),
- A.
diff --git a/lib/hipe/sparc/hipe_sparc_defuse.erl b/lib/hipe/sparc/hipe_sparc_defuse.erl
deleted file mode 100644
index 4d4b11e301..0000000000
--- a/lib/hipe/sparc/hipe_sparc_defuse.erl
+++ /dev/null
@@ -1,154 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_defuse).
--export([insn_def_all/1, insn_use_all/1]).
--export([insn_def_gpr/1, insn_use_gpr/1]).
--export([insn_def_fpr/1, insn_use_fpr/1]).
--export([insn_defs_all_gpr/1, insn_defs_all_fpr/1]).
--include("hipe_sparc.hrl").
-
-%%%
-%%% Defs and uses for both general-purpose and floating-point registers.
-%%% This is needed for the frame module, alas.
-%%%
-insn_def_all(I) ->
- addtemps(insn_def_fpr(I), insn_def_gpr(I)).
-
-insn_use_all(I) ->
- addtemps(insn_use_fpr(I), insn_use_gpr(I)).
-
-%%%
-%%% Defs and uses for general-purpose (integer) registers only.
-%%%
-insn_def_gpr(I) ->
- case I of
- #alu{dst=Dst} -> [Dst];
- %% #jmpl{} -> [hipe_sparc:mk_ra()]; % XXX: can jmpl occur this early?
- #pseudo_call{} -> call_clobbered_gpr();
- #pseudo_move{dst=Dst} -> [Dst];
- #pseudo_set{dst=Dst} -> [Dst];
- #pseudo_spill_move{temp=Temp, dst=Dst} -> [Temp, Dst];
- #pseudo_tailcall_prepare{} -> tailcall_clobbered_gpr();
- #rdy{dst=Dst} -> [Dst];
- #sethi{dst=Dst} -> [Dst];
- _ -> []
- end.
-
-insn_defs_all_gpr(I) ->
- case I of
- #pseudo_call{} -> true;
- _ -> false
- end.
-
-call_clobbered_gpr() ->
- [hipe_sparc:mk_temp(R, T)
- || {R,T} <- hipe_sparc_registers:call_clobbered() ++ all_fp_pseudos()].
-
-all_fp_pseudos() -> []. % XXX: for now
-
-tailcall_clobbered_gpr() ->
- [hipe_sparc:mk_temp(R, T)
- || {R,T} <- hipe_sparc_registers:tailcall_clobbered() ++ all_fp_pseudos()].
-
-insn_use_gpr(I) ->
- case I of
- #alu{src1=Src1,src2=Src2} -> addsrc(Src2, [Src1]);
- %% #br{src=Src} -> [Src]; % XXX: can br occur this early?
- #jmp{src1=Src1,src2=Src2} -> addsrc(Src2, [Src1]);
- %% #jmpl{src=Src} -> [Src]; % XXX: can jmpl occur this early?
- %% #pseudo_br{src=Src} -> [Src];
- #pseudo_call{funv=FunV,sdesc=#sparc_sdesc{arity=Arity}} ->
- funv_use(FunV, arity_use_gpr(Arity));
- #pseudo_move{src=Src} -> [Src];
- #pseudo_ret{} -> [hipe_sparc:mk_rv()];
- #pseudo_spill_move{src=Src} -> [Src];
- #pseudo_tailcall{funv=FunV,arity=Arity,stkargs=StkArgs} ->
- addsrcs(StkArgs, addtemps(tailcall_clobbered_gpr(), funv_use(FunV, arity_use_gpr(Arity))));
- #store{src=Src,base=Base,disp=Disp} ->
- addtemp(Src, addsrc(Disp, [Base]));
- #pseudo_fload{base=Base} -> [Base];
- #pseudo_fstore{base=Base} -> [Base];
- _ -> []
- end.
-
-arity_use_gpr(Arity) ->
- [hipe_sparc:mk_temp(R, 'tagged')
- || R <- hipe_sparc_registers:args(Arity)].
-
-funv_use(FunV, Set) ->
- case FunV of
- #sparc_temp{} -> addtemp(FunV, Set);
- _ -> Set
- end.
-
-addsrcs([Arg|Args], Set) ->
- addsrcs(Args, addsrc(Arg, Set));
-addsrcs([], Set) ->
- Set.
-
-addsrc(Src, Set) ->
- case Src of
- #sparc_temp{} -> addtemp(Src, Set);
- _ -> Set
- end.
-
-%%%
-%%% Defs and uses for floating-point registers only.
-%%%
-insn_def_fpr(I) ->
- case I of
- #pseudo_call{} -> call_clobbered_fpr();
- #fp_binary{dst=Dst} -> [Dst];
- #fp_unary{dst=Dst} -> [Dst];
- #pseudo_fload{dst=Dst} -> [Dst];
- #pseudo_fmove{dst=Dst} -> [Dst];
- #pseudo_spill_fmove{temp=Temp, dst=Dst} -> [Temp, Dst];
- _ -> []
- end.
-
-insn_defs_all_fpr(I) ->
- case I of
- #pseudo_call{} -> true;
- _ -> false
- end.
-
-call_clobbered_fpr() ->
- [hipe_sparc:mk_temp(R, 'double') || R <- hipe_sparc_registers:allocatable_fpr()].
-
-insn_use_fpr(I) ->
- case I of
- #fp_binary{src1=Src1,src2=Src2} -> addtemp(Src1, [Src2]);
- #fp_unary{src=Src} -> [Src];
- #pseudo_fmove{src=Src} -> [Src];
- #pseudo_fstore{src=Src} -> [Src];
- #pseudo_spill_fmove{src=Src} -> [Src];
- _ -> []
- end.
-
-%%%
-%%% Auxiliary operations on sets of temps
-%%% These sets are small. No point using gb_trees, right?
-%%%
-
-addtemps([Arg|Args], Set) ->
- addtemps(Args, addtemp(Arg, Set));
-addtemps([], Set) ->
- Set.
-
-addtemp(Temp, Set) ->
- case lists:member(Temp, Set) of
- false -> [Temp|Set];
- _ -> Set
- end.
diff --git a/lib/hipe/sparc/hipe_sparc_encode.erl b/lib/hipe/sparc/hipe_sparc_encode.erl
deleted file mode 100644
index f0ee2d1647..0000000000
--- a/lib/hipe/sparc/hipe_sparc_encode.erl
+++ /dev/null
@@ -1,471 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Encode symbolic SPARC instructions to binary form.
-%%% Copyright (C) 2007-2008 Mikael Pettersson
-
--module(hipe_sparc_encode).
-
--export([insn_encode/2]).
-
-%%-define(TESTING,1).
--ifdef(TESTING).
--export([dotest/0, dotest/1]).
--endif.
-
--define(ASSERT(G),
- if G -> [];
- true -> exit({assertion_failed,?MODULE,?LINE,??G})
- end).
-
-bf(LeftBit, RightBit, Value) ->
- ?ASSERT(32 > LeftBit),
- ?ASSERT(LeftBit >= RightBit),
- ?ASSERT(RightBit >= 0),
- ?ASSERT(Value >= 0),
- ?ASSERT(Value < (1 bsl ((LeftBit - RightBit) + 1))),
- Value bsl RightBit.
-
--define(BF(LB,RB,V), bf(LB,RB,V)).
--define(BIT(Pos,Val), ?BF(Pos,Pos,Val)).
-%%-define(BITS(N,Val), ?BF(N,0,Val)).
-
-%%%
-%%% Instruction Formats
-%%%
-
-format1(Disp30) ->
- ?BIT(30,1) bor ?BF(29,0,Disp30).
-
-format2a(Rd, Op2, Imm22) ->
- ?BF(29,25,Rd) bor ?BF(24,22,Op2) bor ?BF(21,0,Imm22).
-
-format2b(A, Cond, Op2, Disp22) ->
- ?BIT(29,A) bor ?BF(28,25,Cond) bor ?BF(24,22,Op2) bor ?BF(21,0,Disp22).
-
-format2c(A, Cond, Op2, CC1, CC0, P, Disp19) ->
- ?BIT(29,A) bor ?BF(28,25,Cond) bor ?BF(24,22,Op2) bor ?BIT(21,CC1)
- bor ?BIT(20,CC0) bor ?BIT(19,P) bor ?BF(18,0,Disp19).
-
-format2d(A, RCond, Op2, P, Rs1, Disp16) ->
- D16Hi = Disp16 bsr 14,
- D16Lo = Disp16 band 16#3FFF,
- ?BIT(29,A) bor ?BF(27,25,RCond) bor ?BF(24,22,Op2) bor ?BF(21,20,D16Hi)
- bor ?BIT(19,P) bor ?BF(18,14,Rs1) bor ?BF(13,0,D16Lo).
-
-format3common(Op, Rd, Op3, Rs1) -> % format 3, bits 31..14
- ?BF(31,30,Op) bor ?BF(29,25,Rd) bor ?BF(24,19,Op3) bor ?BF(18,14,Rs1).
-
-format3a(Op, Rd, Op3, Rs1, Rs2) ->
- format3common(Op, Rd, Op3, Rs1) bor ?BF(4,0,Rs2).
-
-format3ax(Op, Rd, Op3, Rs1, Rs2) ->
- format3a(Op, Rd, Op3, Rs1, Rs2) bor ?BIT(12,1).
-
-format3b(Op, Rd, Op3, Rs1, Simm13) ->
- format3common(Op, Rd, Op3, Rs1) bor ?BIT(13,1) bor ?BF(12,0,Simm13).
-
-format3b32(Op, Rd, Op3, Rs1, Shcnt32) ->
- format3a(Op, Rd, Op3, Rs1, Shcnt32) bor ?BIT(13,1).
-
-format3b64(Op, Rd, Op3, Rs1, Shcnt64) ->
- format3common(Op, Rd, Op3, Rs1) bor ?BIT(13,1) bor ?BF(5,0,Shcnt64).
-
-format3ab(Op, {r,Rd}, Op3, {r,Rs1}, Src2) ->
- case Src2 of
- {r,Rs2} ->
- format3a(Op, Rd, Op3, Rs1, Rs2);
- {simm13,Simm13} ->
- format3b(Op, Rd, Op3, Rs1, Simm13)
- end.
-
-format3ab({Rs1,Src2,Rd}, Op3, Op) -> format3ab(Op, Rd, Op3, Rs1, Src2).
-
--ifdef(notdef).
-format3c(Op, Rd, Op3, Rs1, Opf, Rs2) ->
- format3h(Op, Rd, Op3, Rs1) bor (Opf bsl 5) bor Rs2.
-
-format3d(Op, Rd, Op3, Rs1, I, Rs2) ->
- format3h(Op, Rd, Op3, Rs1) bor (I bsl 13) bor Rs2.
--endif.
-
-%%%
-%%% Instruction Operands
-%%%
-
-'cond'(Cond) ->
- case Cond of
- 'n' -> 2#0000;
- 'e' -> 2#0001;
- 'le' -> 2#0010;
- 'l' -> 2#0011;
- 'leu' -> 2#0100;
- 'lu' -> 2#0101; % a.k.a. 'cs'
- 'neg' -> 2#0110;
- 'vs' -> 2#0111;
- 'a' -> 2#1000;
- 'ne' -> 2#1001;
- 'g' -> 2#1010;
- 'ge' -> 2#1011;
- 'gu' -> 2#1100;
- 'geu' -> 2#1101; % a.k.a. 'cc'
- 'pos' -> 2#1110;
- 'vc' -> 2#1111
- end.
-
-rcond(RCond) ->
- case RCond of
- 'z' -> 2#001;
- 'lez' -> 2#010;
- 'lz' -> 2#011;
- 'nz' -> 2#101;
- 'gz' -> 2#110;
- 'gez' -> 2#111
- end.
-
-pred(Pred) ->
- case Pred of
- 'pt' -> 1;
- 'pn' -> 0
- end.
-
-%%%
-%%% Branch Instructions
-%%%
-
-call({disp30,Disp30}) ->
- format1(Disp30).
-
-ba({disp22,Disp22}) -> % V7 Bicc, only used for unconditional branches
- format2b(0, 'cond'('a'), 2#010, Disp22).
-
-bp({{'cond',Cond},{pred,Pred},{disp19,Disp19}}) ->
- %% XXX: sparc64 will need CC1=1 here
- format2c(0, 'cond'(Cond), 2#001, 0, 0, pred(Pred), Disp19).
-
-br({{rcond,RCond},{pred,Pred},{r,Rs1},{disp16,Disp16}}) ->
- format2d(0, rcond(RCond), 2#011, pred(Pred), Rs1, Disp16).
-
-%%%
-%%% Integer Arithmetic Instructions
-%%%
-
-alu(Opnds, Op3) -> format3ab(Opnds, Op3, 2#10).
-
-add(Opnds) -> alu(Opnds, 2#000000).
-addcc(Opnds) -> alu(Opnds, 2#010000).
-%%addc(Opnds) -> alu(Opnds, 2#001000).
-%%addccc(Opnds) -> alu(Opnds, 2#011000).
-
-sub(Opnds) -> alu(Opnds, 2#000100).
-subcc(Opnds) -> alu(Opnds, 2#010100).
-%%subc(Opnds) -> alu(Opnds, 2#001100). % XXX: hipe_sparc_op has bug here
-%%subccc(Opnds) -> alu(Opnds, 2#011100). % XXX: hipe_sparc_op has bug here
-
-%%taddcc(Opnds) -> alu(Opnds, 2#100000).
-%%taddcctv(Opnds) -> alu(Opnds, 2#100010).
-
-%%tsubcc(Opnds) -> alu(Opnds, 2#100001).
-%%tsubcctv(Opnds) -> alu(Opnds, 2#100011).
-
-mulx(Opnds) -> alu(Opnds, 2#001001).
-%%sdivx(Opnds) -> alu(Opnds, 2#101101).
-%%udivx(Opnds) -> alu(Opnds, 2#001101).
-
-%%umul(Opnds) -> alu(Opnds, 2#001010).
-smul(Opnds) -> alu(Opnds, 2#001011).
-%%umulcc(Opnds) -> alu(Opnds, 2#011010).
-%%smulcc(Opnds) -> alu(Opnds, 2#011011).
-
-'and'(Opnds) -> alu(Opnds, 2#000001).
-andcc(Opnds) -> alu(Opnds, 2#010001).
-%%andn(Opnds) -> alu(Opnds, 2#000101).
-%%andncc(Opnds) -> alu(Opnds, 2#010101).
-
-'or'(Opnds) -> alu(Opnds, 2#000010).
-orcc(Opnds) -> alu(Opnds, 2#010010).
-%%orn(Opnds) -> alu(Opnds, 2#000110).
-%%orncc(Opnds) -> alu(Opnds, 2#010110).
-
-'xor'(Opnds) -> alu(Opnds, 2#000011).
-xorcc(Opnds) -> alu(Opnds, 2#010011).
-%%xnor(Opnds) -> alu(Opnds, 2#000111).
-%%xnorcc(Opnds) -> alu(Opnds, 2#010111).
-
-shift32({{r,Rs1},Src2,{r,Rd}}, Op3) ->
- case Src2 of
- {r,Rs2} ->
- format3a(2#10, Rd, Op3, Rs1, Rs2);
- {uimm5,Shcnt32} ->
- format3b32(2#10, Rd, Op3, Rs1, Shcnt32)
- end.
-
-shift64({{r,Rs1},Src2,{r,Rd}}, Op3) ->
- case Src2 of
- {r,Rs2} ->
- format3ax(2#10, Rd, Op3, Rs1, Rs2);
- {uimm6,Shcnt64} ->
- format3b64(2#10, Rd, Op3, Rs1, Shcnt64)
- end.
-
-sll(Opnds) -> shift32(Opnds, 2#100101).
-sllx(Opnds) -> shift64(Opnds, 2#100101).
-srl(Opnds) -> shift32(Opnds, 2#100110).
-srlx(Opnds) -> shift64(Opnds, 2#100110).
-sra(Opnds) -> shift32(Opnds, 2#100111).
-srax(Opnds) -> shift64(Opnds, 2#100111).
-
-jmpl(Opnds) -> alu(Opnds, 2#111000).
-
-rd({y,{r,Rd}}) -> format3a(2#10, Rd, 2#101000, 0, 0).
-
-sethi({{uimm22,UImm22},{r,Rd}}) -> format2a(Rd, 2#100, UImm22).
-
-ld(Opnds, Op3) -> format3ab(Opnds, Op3, 2#11).
-
-ldsb(Opnds) -> ld(Opnds, 2#001001).
-ldsh(Opnds) -> ld(Opnds, 2#001010).
-ldsw(Opnds) -> ld(Opnds, 2#001000).
-ldub(Opnds) -> ld(Opnds, 2#000001).
-lduh(Opnds) -> ld(Opnds, 2#000010).
-lduw(Opnds) -> ld(Opnds, 2#000000).
-ldx(Opnds) -> ld(Opnds, 2#001011).
-%%ldd(Opnds) -> ld(Opnds, 2#000011).
-
-st({Rd,Rs1,Src2}, Op3) -> format3ab(2#11, Rd, Op3, Rs1, Src2).
-
-stb(Opnds) -> st(Opnds, 2#000101).
-%%sth(Opnds) -> st(Opnds, 2#000110).
-stw(Opnds) -> st(Opnds, 2#000100).
-stx(Opnds) -> st(Opnds, 2#001110).
-%%std(Opnds) -> st(Opnds, 2#000111).
-
-%%%
-%%% Floating-Point Instructions
-%%%
-
-format3f(Rd, Rs1, Opf, Rs2) ->
- format3a(2#10, Rd, 2#110100, Rs1, Rs2) bor ?BF(13,5,Opf).
-
-fpop1binary(Opf, {{fr,Rs1},{fr,Rs2},{fr,Rd}}) ->
- format3f(Rd, Rs1, Opf, Rs2).
-
-faddd(Opnds) -> fpop1binary(2#001000010, Opnds).
-fdivd(Opnds) -> fpop1binary(2#001001110, Opnds).
-fmuld(Opnds) -> fpop1binary(2#001001010, Opnds).
-fsubd(Opnds) -> fpop1binary(2#001000110, Opnds).
-
-fpop1unary(Opf, {{fr,Rs2},{fr,Rd}}) ->
- format3f(Rd, 0, Opf, Rs2).
-
-fitod(Opnds) -> fpop1unary(2#011001000, Opnds).
-fmovd(Opnds) -> fpop1unary(2#000000010, Opnds).
-fnegd(Opnds) -> fpop1unary(2#000000110, Opnds).
-
-ldf({{r,Rs1},{simm13,Simm13},{fr,Rd}}) ->
- format3b(2#11, Rd, 2#100000, Rs1, Simm13).
-
-stf({{fr,Rd},{r,Rs1},{simm13,Simm13}}) ->
- format3b(2#11, Rd, 2#100100, Rs1, Simm13).
-
--ifdef(notdef).
-fpop1(Rs1,Opf,Rs2,Rd) -> format3a(2#10, Rd, 2#110100, Rs1, Opf, Rs2).
-%% fpop2(Rs1,Opf,Rs2,Rd) -> format3a(2#10, Rd, 2#110101, Rs1, Opf, Rs2).
-
-%% fxtos(Rs2, Rd) -> fpop1(0,2#010000100,Rs2,Rd).
-%% fxtod(Rs2, Rd) -> fpop1(0,2#010001000,Rs2,Rd).
-%% fxtoq(Rs2, Rd) -> fpop1(0,2#010001100,Rs2,Rd).
-fitos(Rs2, Rd) -> fpop1(0,2#011000100,Rs2,Rd).
-fitoq(Rs2, Rd) -> fpop1(0,2#011001100,Rs2,Rd).
-
-%% fstox(Rs2, Rd) -> fpop1(0,2#010000001,Rs2,Rd).
-%% fdtox(Rs2, Rd) -> fpop1(0,2#010000010,Rs2,Rd).
-%% fqtox(Rs2, Rd) -> fpop1(0,2#010000011,Rs2,Rd).
-%% fstoi(Rs2, Rd) -> fpop1(0,2#011010001,Rs2,Rd).
-%% fdtoi(Rs2, Rd) -> fpop1(0,2#011010010,Rs2,Rd).
-%% fqtoi(Rs2, Rd) -> fpop1(0,2#011010011,Rs2,Rd).
-
-%% fstod(Rs2, Rd) -> fpop1(0,2#011001001,Rs2,Rd).
-%% fstoq(Rs2, Rd) -> fpop1(0,2#011001101,Rs2,Rd).
-%% fdtos(Rs2, Rd) -> fpop1(0,2#011000110,Rs2,Rd).
-%% fdtoq(Rs2, Rd) -> fpop1(0,2#011001110,Rs2,Rd).
-%% fqtos(Rs2, Rd) -> fpop1(0,2#011000111,Rs2,Rd).
-%% fqtod(Rs2, Rd) -> fpop1(0,2#011001011,Rs2,Rd).
-
-fmovs(Rs2, Rd) -> fpop1(0,2#000000001,Rs2,Rd).
-fnegs(Rs2, Rd) -> fpop1(0,2#000000101,Rs2,Rd).
-fabss(Rs2, Rd) -> fpop1(0,2#000001001,Rs2,Rd).
-fabsd(Rs2, Rd) -> fpop1(0,2#000001010,Rs2,Rd).
-fmovq(Rs2, Rd) -> fpop1(0,2#000000011,Rs2,Rd).
-fnegq(Rs2, Rd) -> fpop1(0,2#000000111,Rs2,Rd).
-fabsq(Rs2, Rd) -> fpop1(0,2#000001011,Rs2,Rd).
-
-%% fsqrts(Rs2, Rd) -> fpop1(0,2#000101001,Rs2,Rd).
-%% fsqrtd(Rs2, Rd) -> fpop1(0,2#000101010,Rs2,Rd).
-%% fsqrtq(Rs2, Rd) -> fpop1(0,2#000101011,Rs2,Rd).
-
-fadds(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000001,Rs2,Rd).
-faddq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000011,Rs2,Rd).
-fsubs(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000101,Rs2,Rd).
-fsubq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001000111,Rs2,Rd).
-
-fmuls(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001001,Rs2,Rd).
-fmulq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001011,Rs2,Rd).
-%% fsmuld(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001101001,Rs2,Rd).
-%% fdmulq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001101110,Rs2,Rd).
-fdivs(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001101,Rs2,Rd).
-fdivq(Rs1, Rs2, Rd) -> fpop1(Rs1,2#001001111,Rs2,Rd).
-
-%% Uses fcc0
-%% fcmps(Rs1, Rs2) -> fpop2(Rs1,2#001010001,Rs2,0).
-%% fcmpd(Rs1, Rs2) -> fpop2(Rs1,2#001010010,Rs2,0).
-%% fcmpq(Rs1, Rs2) -> fpop2(Rs1,2#001010011,Rs2,0).
-%% fcmpes(Rs1, Rs2) -> fpop2(Rs1,2#001010101,Rs2,0).
-%% fcmped(Rs1, Rs2) -> fpop2(Rs1,2#001010110,Rs2,0).
-%% fcmpeq(Rs1, Rs2) -> fpop2(Rs1,2#001010111,Rs2,0).
-
-%% fcmps(N, Rs1, Rs2) -> fpcn(N,2#001010001,Rs1,Rs2).
-%% fcmpd(N, Rs1, Rs2) -> fpcn(N,2#001010010,Rs1,Rs2).
-%% fcmpq(N, Rs1, Rs2) -> fpcn(N,2#001010011,Rs1,Rs2).
-%% fcmpes(N, Rs1, Rs2) -> fpcn(N,2#001010101,Rs1,Rs2).
-%% fcmped(N, Rs1, Rs2) -> fpcn(N,2#001010110,Rs1,Rs2).
-%% fcmpeq(N, Rs1, Rs2) -> fpcn(N,2#001010111,Rs1,Rs2).
-
-stfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100100, Rs1, Offset).
-stdf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100111, Rs1, 0, Rs2).
-stdfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100111, Rs1, Offset).
-stqf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100110, Rs1, 0, Rs2).
-stqfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100110, Rs1, Offset).
-%% stfsr(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100101, Rs1, 0, Rs2).
-%% stfsri(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100101, Rs1, Offset).
-
-ldfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100000, Rs1, Offset).
-lddf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100011, Rs1, 0, Rs2).
-lddfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100011, Rs1, Offset).
-ldqf(Rd, Rs1, Rs2) -> format3a(2#11, Rd, 2#100010, Rs1, 0, Rs2).
-ldqfi(Rd, Rs1, Offset) -> format3b(2#11, Rd, 2#100010, Rs1, Offset).
-%% ldxfsr(Rs1, Rs2) -> format3a(2#11, 1, 2#100001, Rs1, 0, Rs2).
-%% ldxfsri(Rs1, Offset) -> format3b(2#11, 1, 2#100001, Rs1, Offset).
-
-%% fpcn(N, Opf, Rs1, Rs2) ->
-%% case N of
-%% 0 -> fpc0(Opf, Rs1, Rs2);
-%% 1 -> fpc1(Opf, Rs1, Rs2);
-%% 2 -> fpc2(Opf, Rs1, Rs2);
-%% 3 -> fpc3(Opf, Rs1, Rs2)
-%% end.
-
-%% fpc0(Opf, Rs1, Rs2) -> format3c(2#10, 2#00000, 2#110101, Rs1, Opf, Rs2).
-%% fpc1(Opf, Rs1, Rs2) -> format3c(2#10, 2#00001, 2#110101, Rs1, Opf, Rs2).
-%% fpc2(Opf, Rs1, Rs2) -> format3c(2#10, 2#00010, 2#110101, Rs1, Opf, Rs2).
-%% fpc3(Opf, Rs1, Rs2) -> format3c(2#10, 2#00011, 2#110101, Rs1, Opf, Rs2).
--endif. % FP insns
-
-%%%
-%%% Main Encode Dispatch
-%%%
-
-insn_encode(Op, Opnds) ->
- case Op of
- 'add' -> add(Opnds);
- 'addcc' -> addcc(Opnds);
- 'and' -> 'and'(Opnds);
- 'andcc' -> andcc(Opnds);
- 'ba' -> ba(Opnds);
- 'bp' -> bp(Opnds);
- 'br' -> br(Opnds);
- 'call' -> call(Opnds);
- 'jmpl' -> jmpl(Opnds);
- 'ldsb' -> ldsb(Opnds);
- 'ldsh' -> ldsh(Opnds);
- 'ldsw' -> ldsw(Opnds);
- 'ldub' -> ldub(Opnds);
- 'lduh' -> lduh(Opnds);
- 'lduw' -> lduw(Opnds);
- 'ldx' -> ldx(Opnds);
- 'mulx' -> mulx(Opnds);
- 'or' -> 'or'(Opnds);
- 'orcc' -> orcc(Opnds);
- 'rd' -> rd(Opnds);
- 'sethi' -> sethi(Opnds);
- 'sll' -> sll(Opnds);
- 'sllx' -> sllx(Opnds);
- 'smul' -> smul(Opnds);
- 'sra' -> sra(Opnds);
- 'srax' -> srax(Opnds);
- 'srl' -> srl(Opnds);
- 'srlx' -> srlx(Opnds);
- 'stb' -> stb(Opnds);
- 'stw' -> stw(Opnds);
- 'stx' -> stx(Opnds);
- 'sub' -> sub(Opnds);
- 'subcc' -> subcc(Opnds);
- 'xor' -> 'xor'(Opnds);
- 'xorcc' -> xorcc(Opnds);
- 'faddd' -> faddd(Opnds);
- 'fdivd' -> fdivd(Opnds);
- 'fmuld' -> fmuld(Opnds);
- 'fsubd' -> fsubd(Opnds);
- 'fitod' -> fitod(Opnds);
- 'fmovd' -> fmovd(Opnds);
- 'fnegd' -> fnegd(Opnds);
- 'ldf' -> ldf(Opnds);
- 'stf' -> stf(Opnds);
- _ -> exit({?MODULE,insn_encode,Op})
- end.
-
-%%%
-%%% Testing Interface
-%%%
-
--ifdef(TESTING).
-
-say(OS, Str) ->
- file:write(OS, Str).
-
-hex_digit(Dig0) ->
- Dig = Dig0 band 16#F,
- if Dig >= 16#A -> $A + (Dig - 16#A);
- true -> $0 + Dig
- end.
-
-say_byte(OS, Byte) ->
- say(OS, [hex_digit(Byte bsr 4)]),
- say(OS, [hex_digit(Byte)]).
-
-say_word(OS, Word) ->
- say(OS, "0x"),
- say_byte(OS, Word bsr 24),
- say_byte(OS, Word bsr 16),
- say_byte(OS, Word bsr 8),
- say_byte(OS, Word).
-
-t(OS, Op, Opnds) ->
- Word = insn_encode(Op, Opnds),
- say(OS, "\t.long "),
- say_word(OS, Word),
- say(OS, "\n").
-
-dotest1(OS) ->
- say(OS, "\t.text\n\t.align 4\n"),
- [].
-
-dotest() -> dotest1(group_leader()).
-
-dotest(File) ->
- {ok,OS} = file:open(File, [write]),
- dotest1(OS),
- file:close(OS).
-
--endif.
diff --git a/lib/hipe/sparc/hipe_sparc_finalise.erl b/lib/hipe/sparc/hipe_sparc_finalise.erl
deleted file mode 100644
index 3634a4d14c..0000000000
--- a/lib/hipe/sparc/hipe_sparc_finalise.erl
+++ /dev/null
@@ -1,132 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_finalise).
--export([finalise/1]).
--include("hipe_sparc.hrl").
-
-finalise(Defun) ->
- #defun{code=Code0} = Defun,
- Code1 = peep(expand(Code0)),
- Defun#defun{code=Code1}.
-
-expand(Insns) ->
- expand_list(Insns, []).
-
-expand_list([I|Insns], Accum) ->
- expand_list(Insns, expand_insn(I, Accum));
-expand_list([], Accum) ->
- lists:reverse(Accum).
-
-expand_insn(I, Accum) ->
- case I of
- #bp{'cond'='a'} ->
- [hipe_sparc:mk_nop(),
- I |
- Accum];
- #call_rec{} ->
- [hipe_sparc:mk_nop(),
- I |
- Accum];
- #call_tail{} ->
- RA = hipe_sparc:mk_ra(),
- TempRA = hipe_sparc:mk_temp1(),
- [hipe_sparc:mk_mov(TempRA, RA),
- I, % becomes a call, which clobbers RA
- hipe_sparc:mk_mov(RA, TempRA) |
- Accum];
- #jmp{} ->
- [hipe_sparc:mk_nop(),
- I |
- Accum];
- #pseudo_bp{'cond'=Cond,true_label=TrueLab,false_label=FalseLab, pred=Pred} ->
- [hipe_sparc:mk_nop(),
- hipe_sparc:mk_b_label(FalseLab),
- hipe_sparc:mk_nop(),
- hipe_sparc:mk_bp(Cond, TrueLab, Pred) |
- Accum];
- %% #pseudo_br{} -> expand_pseudo_br(I, Accum);
- #pseudo_call{funv=FunV,sdesc=SDesc,contlab=ContLab,linkage=Linkage} ->
- [hipe_sparc:mk_nop(),
- hipe_sparc:mk_b_label(ContLab),
- hipe_sparc:mk_nop(),
- case FunV of
- #sparc_temp{} ->
- hipe_sparc:mk_jmpl(FunV, SDesc);
- _ ->
- hipe_sparc:mk_call_rec(FunV, SDesc, Linkage)
- end |
- Accum];
- #pseudo_ret{} ->
- RA = hipe_sparc:mk_ra(),
- [hipe_sparc:mk_nop(),
- hipe_sparc:mk_jmp(RA, hipe_sparc:mk_simm13(8), []) |
- Accum];
- #pseudo_tailcall_prepare{} ->
- Accum;
- _ ->
- XXX =
- case I of
- #alu{} -> true;
- #comment{} -> true;
- #label{} -> true;
- #pseudo_set{} -> true;
- #rdy{} -> true;
- #sethi{} -> true;
- #store{} -> true;
- #bp{} -> false;
- %% #br{} -> false;
- #call_rec{} -> false;
- #call_tail{} -> false;
- #jmp{} -> false;
- #jmpl{} -> false;
- #pseudo_bp{} -> false;
- %% #pseudo_br{} -> false;
- #pseudo_call{} -> false;
- #pseudo_call_prepare{} -> false;
- #pseudo_move{} -> false;
- #pseudo_ret{} -> false;
- #pseudo_tailcall{} -> false;
- #pseudo_tailcall_prepare{} -> false;
- #fp_binary{} -> true;
- #fp_unary{} -> true;
- #pseudo_fload{} -> true;
- #pseudo_fstore{} -> true
- end,
- case XXX of
- true -> [];
- false -> exit({?MODULE,expand_insn,I})
- end,
- [I|Accum]
- end.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-expand_pseudo_br(I, Accum) ->
- #pseudo_br{rcond=RCond,src=Src,true_label=TrueLab,false_label=FalseLab, pred=Pred} = I,
- [hipe_sparc:mk_nop(),
- hipe_sparc:mk_b_label(FalseLab),
- hipe_sparc:mk_nop(),
- hipe_sparc:mk_br(RCond, Src, TrueLab, Pred) |
- Accum].
--endif.
-
-peep(Insns) ->
- peep_list(Insns, []).
-
-peep_list([#bp{'cond'='a',label=Label}, #sethi{uimm22=#sparc_uimm22{value=0},dst=#sparc_temp{reg=0}} | (Insns = [#label{label=Label}|_])], Accum) ->
- peep_list(Insns, Accum);
-peep_list([I|Insns], Accum) ->
- peep_list(Insns, [I|Accum]);
-peep_list([], Accum) ->
- lists:reverse(Accum).
diff --git a/lib/hipe/sparc/hipe_sparc_frame.erl b/lib/hipe/sparc/hipe_sparc_frame.erl
deleted file mode 100644
index 1f2a259ca1..0000000000
--- a/lib/hipe/sparc/hipe_sparc_frame.erl
+++ /dev/null
@@ -1,674 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_frame).
--export([frame/1]).
-
--include("hipe_sparc.hrl").
--include("../rtl/hipe_literals.hrl").
-
-frame(CFG) ->
- Formals = fix_formals(hipe_sparc_cfg:params(CFG)),
- Temps0 = all_temps(CFG, Formals),
- MinFrame = defun_minframe(CFG),
- Temps = ensure_minframe(MinFrame, Temps0),
- ClobbersRA = clobbers_ra(CFG),
- Liveness = hipe_sparc_liveness_all:analyse(CFG),
- do_body(CFG, Liveness, Formals, Temps, ClobbersRA).
-
-fix_formals(Formals) ->
- fix_formals(hipe_sparc_registers:nr_args(), Formals).
-
-fix_formals(0, Rest) -> Rest;
-fix_formals(N, [_|Rest]) -> fix_formals(N-1, Rest);
-fix_formals(_, []) -> [].
-
-do_body(CFG0, Liveness, Formals, Temps, ClobbersRA) ->
- Context = mk_context(Liveness, Formals, Temps, ClobbersRA),
- CFG1 = do_blocks(CFG0, Context),
- do_prologue(CFG1, Context).
-
-do_blocks(CFG, Context) ->
- Labels = hipe_sparc_cfg:labels(CFG),
- do_blocks(Labels, CFG, Context).
-
-do_blocks([Label|Labels], CFG, Context) ->
- Liveness = context_liveness(Context),
- LiveOut = hipe_sparc_liveness_all:liveout(Liveness, Label),
- Block = hipe_sparc_cfg:bb(CFG, Label),
- Code = hipe_bb:code(Block),
- NewCode = do_block(Code, LiveOut, Context),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- NewCFG = hipe_sparc_cfg:bb_add(CFG, Label, NewBlock),
- do_blocks(Labels, NewCFG, Context);
-do_blocks([], CFG, _) ->
- CFG.
-
-do_block(Insns, LiveOut, Context) ->
- do_block(Insns, LiveOut, Context, context_framesize(Context), []).
-
-do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) ->
- {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0),
- do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode));
-do_block([], _, Context, FPoff, RevCode) ->
- FPoff0 = context_framesize(Context),
- if FPoff =:= FPoff0 -> [];
- true -> exit({?MODULE,do_block,FPoff})
- end,
- lists:reverse(RevCode, []).
-
-do_insn(I, LiveOut, Context, FPoff) ->
- case I of
- #pseudo_call{} ->
- do_pseudo_call(I, LiveOut, Context, FPoff);
- #pseudo_call_prepare{} ->
- do_pseudo_call_prepare(I, FPoff);
- #pseudo_move{} ->
- {do_pseudo_move(I, Context, FPoff), FPoff};
- #pseudo_ret{} ->
- {do_pseudo_ret(I, Context, FPoff), context_framesize(Context)};
- #pseudo_tailcall{} ->
- {do_pseudo_tailcall(I, Context), context_framesize(Context)};
- #pseudo_fmove{} ->
- {do_pseudo_fmove(I, Context, FPoff), FPoff};
- #pseudo_spill_move{} ->
- {do_pseudo_spill_move(I, Context, FPoff), FPoff};
- #pseudo_spill_fmove{} ->
- {do_pseudo_spill_fmove(I, Context, FPoff), FPoff};
- _ ->
- {[I], FPoff}
- end.
-
-%%%
-%%% Moves, with Dst or Src possibly a pseudo
-%%%
-
-do_pseudo_move(I, Context, FPoff) ->
- Dst = hipe_sparc:pseudo_move_dst(I),
- Src = hipe_sparc:pseudo_move_src(I),
- case temp_is_pseudo(Dst) of
- true ->
- Offset = pseudo_offset(Dst, FPoff, Context),
- mk_store(Src, hipe_sparc:mk_sp(), Offset, []);
- _ ->
- case temp_is_pseudo(Src) of
- true ->
- Offset = pseudo_offset(Src, FPoff, Context),
- mk_load(hipe_sparc:mk_sp(), Offset, Dst, []);
- _ ->
- case hipe_sparc:temp_reg(Dst) =:= hipe_sparc:temp_reg(Src) of
- true -> [];
- false -> [hipe_sparc:mk_mov(Src, Dst)]
- end
- end
- end.
-
-do_pseudo_spill_move(I, Context, FPoff) ->
- #pseudo_spill_move{src=Src,temp=Temp,dst=Dst} = I,
- case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of
- false -> % Register allocator changed its mind, turn back to move
- do_pseudo_move(hipe_sparc:mk_pseudo_move(Src, Dst), Context, FPoff);
- true ->
- SrcOffset = pseudo_offset(Src, FPoff, Context),
- DstOffset = pseudo_offset(Dst, FPoff, Context),
- case SrcOffset =:= DstOffset of
- true -> []; % omit move-to-self
- false ->
- mk_load(hipe_sparc:mk_sp(), SrcOffset, Temp,
- mk_store(Temp, hipe_sparc:mk_sp(), DstOffset, []))
- end
- end.
-
-do_pseudo_fmove(I, Context, FPoff) ->
- Dst = hipe_sparc:pseudo_fmove_dst(I),
- Src = hipe_sparc:pseudo_fmove_src(I),
- case temp_is_pseudo(Dst) of
- true ->
- Offset = pseudo_offset(Dst, FPoff, Context),
- mk_fstore(Src, hipe_sparc:mk_sp(), Offset);
- _ ->
- case temp_is_pseudo(Src) of
- true ->
- Offset = pseudo_offset(Src, FPoff, Context),
- mk_fload(hipe_sparc:mk_sp(), Offset, Dst);
- _ ->
- [hipe_sparc:mk_fp_unary('fmovd', Src, Dst)]
- end
- end.
-
-do_pseudo_spill_fmove(I, Context, FPoff) ->
- #pseudo_spill_fmove{src=Src,temp=Temp,dst=Dst} = I,
- case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of
- false -> % Register allocator changed its mind, turn back to fmove
- do_pseudo_fmove(hipe_sparc:mk_pseudo_fmove(Src, Dst), Context, FPoff);
- true ->
- SrcOffset = pseudo_offset(Src, FPoff, Context),
- DstOffset = pseudo_offset(Dst, FPoff, Context),
- case SrcOffset =:= DstOffset of
- true -> []; % omit move-to-self
- false ->
- mk_fload(hipe_sparc:mk_sp(), SrcOffset, Temp)
- ++ mk_fstore(Temp, hipe_sparc:mk_sp(), DstOffset)
- end
- end.
-
-pseudo_offset(Temp, FPoff, Context) ->
- FPoff + context_offset(Context, Temp).
-
-%%%
-%%% Return - deallocate frame and emit 'ret $N' insn.
-%%%
-
-do_pseudo_ret(I, Context, FPoff) ->
- %% XXX: typically only one instruction between
- %% the move-to-RA and the jmp-via-RA, ouch
- restore_ra(FPoff, Context,
- adjust_sp(FPoff + word_size() * context_arity(Context),
- [I])).
-
-restore_ra(FPoff, Context, Rest) ->
- case context_clobbers_ra(Context) of
- false -> Rest;
- true ->
- RA = hipe_sparc:mk_ra(),
- mk_load(hipe_sparc:mk_sp(), FPoff - word_size(), RA, Rest)
- end.
-
-adjust_sp(N, Rest) ->
- if N =:= 0 ->
- Rest;
- true ->
- SP = hipe_sparc:mk_sp(),
- hipe_sparc:mk_addi(SP, N, SP, Rest)
- end.
-
-%%%
-%%% Recursive calls.
-%%%
-
-do_pseudo_call_prepare(I, FPoff0) ->
- %% Create outgoing arguments area on the stack.
- NrStkArgs = hipe_sparc:pseudo_call_prepare_nrstkargs(I),
- Offset = NrStkArgs * word_size(),
- {adjust_sp(-Offset, []), FPoff0 + Offset}.
-
-do_pseudo_call(I, LiveOut, Context, FPoff0) ->
- #sparc_sdesc{exnlab=ExnLab,arity=OrigArity} = hipe_sparc:pseudo_call_sdesc(I),
- FunV = hipe_sparc:pseudo_call_funv(I),
- LiveTemps = [Temp || Temp <- LiveOut, temp_is_pseudo(Temp)],
- SDesc = mk_sdesc(ExnLab, Context, LiveTemps),
- ContLab = hipe_sparc:pseudo_call_contlab(I),
- Linkage = hipe_sparc:pseudo_call_linkage(I),
- CallCode = [hipe_sparc:mk_pseudo_call(FunV, SDesc, ContLab, Linkage)],
- StkArity = erlang:max(0, OrigArity - hipe_sparc_registers:nr_args()),
- context_need_stack(Context, stack_need(FPoff0, StkArity, FunV)),
- ArgsBytes = word_size() * StkArity,
- {CallCode, FPoff0 - ArgsBytes}.
-
-stack_need(FPoff, StkArity, FunV) ->
- case FunV of
- #sparc_prim{} -> FPoff;
- #sparc_mfa{m=M,f=F,a=A} ->
- case erlang:is_builtin(M, F, A) of
- true -> FPoff;
- false -> stack_need_general(FPoff, StkArity)
- end;
- _ -> stack_need_general(FPoff, StkArity)
- end.
-
-stack_need_general(FPoff, StkArity) ->
- erlang:max(FPoff, FPoff + (?SPARC_LEAF_WORDS - StkArity) * word_size()).
-
-%%%
-%%% Create stack descriptors for call sites.
-%%%
-
-mk_sdesc(ExnLab, Context, Temps) -> % for normal calls
- Temps0 = only_tagged(Temps),
- Live = mk_live(Context, Temps0),
- Arity = context_arity(Context),
- FSize = context_framesize(Context),
- hipe_sparc:mk_sdesc(ExnLab, (FSize div word_size())-1, Arity,
- list_to_tuple(Live)).
-
-only_tagged(Temps)->
- [X || X <- Temps, hipe_sparc:temp_type(X) =:= 'tagged'].
-
-mk_live(Context, Temps) ->
- lists:sort([temp_to_slot(Context, Temp) || Temp <- Temps]).
-
-temp_to_slot(Context, Temp) ->
- (context_framesize(Context) + context_offset(Context, Temp))
- div word_size().
-
-mk_minimal_sdesc(Context) -> % for inc_stack_0 calls
- hipe_sparc:mk_sdesc([], 0, context_arity(Context), {}).
-
-%%%
-%%% Tailcalls.
-%%%
-
-do_pseudo_tailcall(I, Context) -> % always at FPoff=context_framesize(Context)
- Arity = context_arity(Context),
- Args = hipe_sparc:pseudo_tailcall_stkargs(I),
- FunV = hipe_sparc:pseudo_tailcall_funv(I),
- Linkage = hipe_sparc:pseudo_tailcall_linkage(I),
- {Insns, FPoff1} = do_tailcall_args(Args, Context),
- context_need_stack(Context, FPoff1),
- StkArity = length(Args),
- FPoff2 = FPoff1 + (Arity - StkArity) * word_size(),
- context_need_stack(Context, stack_need(FPoff2, StkArity, FunV)),
- I2 =
- case FunV of
- #sparc_temp{} ->
- hipe_sparc:mk_jmp(FunV, hipe_sparc:mk_simm13(0), []);
- Fun ->
- hipe_sparc:mk_call_tail(Fun, Linkage)
- end,
- %% XXX: break out the RA restore, just like for pseudo_ret?
- restore_ra(context_framesize(Context), Context,
- Insns ++ adjust_sp(FPoff2, [I2])).
-
-do_tailcall_args(Args, Context) ->
- FPoff0 = context_framesize(Context),
- Arity = context_arity(Context),
- FrameTop = word_size()*Arity,
- DangerOff = FrameTop - word_size()*length(Args),
- %%
- Moves = mk_moves(Args, FrameTop, []),
- %%
- {Stores, Simple, Conflict} =
- split_moves(Moves, Context, DangerOff, [], [], []),
- %% sanity check (shouldn't trigger any more)
- if DangerOff < -FPoff0 ->
- exit({?MODULE,do_tailcall_args,DangerOff,-FPoff0});
- true -> []
- end,
- FPoff1 = FPoff0,
- %%
- {Pushes, Pops, FPoff2} = split_conflict(Conflict, FPoff1, [], []),
- %%
- TempReg = hipe_sparc_registers:temp1(),
- %%
- {adjust_sp(-(FPoff2 - FPoff1),
- simple_moves(Pushes, FPoff2, TempReg,
- store_moves(Stores, FPoff2, TempReg,
- simple_moves(Simple, FPoff2, TempReg,
- simple_moves(Pops, FPoff2, TempReg,
- []))))),
- FPoff2}.
-
-mk_moves([Arg|Args], Off, Moves) ->
- Off1 = Off - word_size(),
- mk_moves(Args, Off1, [{Arg,Off1}|Moves]);
-mk_moves([], _, Moves) ->
- Moves.
-
-split_moves([Move|Moves], Context, DangerOff, Stores, Simple, Conflict) ->
- {Src,DstOff} = Move,
- case src_is_pseudo(Src) of
- false ->
- split_moves(Moves, Context, DangerOff, [Move|Stores],
- Simple, Conflict);
- true ->
- SrcOff = context_offset(Context, Src),
- Type = typeof_temp(Src),
- if SrcOff =:= DstOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, Conflict);
- SrcOff >= DangerOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, [{SrcOff,DstOff,Type}|Conflict]);
- true ->
- split_moves(Moves, Context, DangerOff, Stores,
- [{SrcOff,DstOff,Type}|Simple], Conflict)
- end
- end;
-split_moves([], _, _, Stores, Simple, Conflict) ->
- {Stores, Simple, Conflict}.
-
-split_conflict([{SrcOff,DstOff,Type}|Conflict], FPoff, Pushes, Pops) ->
- FPoff1 = FPoff + word_size(),
- Push = {SrcOff,-FPoff1,Type},
- Pop = {-FPoff1,DstOff,Type},
- split_conflict(Conflict, FPoff1, [Push|Pushes], [Pop|Pops]);
-split_conflict([], FPoff, Pushes, Pops) ->
- {lists:reverse(Pushes), Pops, FPoff}.
-
-simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) ->
- Temp = hipe_sparc:mk_temp(TempReg, Type),
- SP = hipe_sparc:mk_sp(),
- LoadOff = FPoff+SrcOff,
- StoreOff = FPoff+DstOff,
- simple_moves(Moves, FPoff, TempReg,
- mk_load(SP, LoadOff, Temp,
- mk_store(Temp, SP, StoreOff,
- Rest)));
-simple_moves([], _, _, Rest) ->
- Rest.
-
-store_moves([{Src,DstOff}|Moves], FPoff, TempReg, Rest) ->
- %% Type = typeof_temp(Src),
- SP = hipe_sparc:mk_sp(),
- StoreOff = FPoff+DstOff,
- {NewSrc,FixSrc} =
- case hipe_sparc:is_temp(Src) of
- true ->
- {Src, []};
- _ ->
- Temp = hipe_sparc:mk_temp(TempReg, 'untagged'),
- {Temp, hipe_sparc:mk_set(Src, Temp)}
- end,
- store_moves(Moves, FPoff, TempReg,
- FixSrc ++ mk_store(NewSrc, SP, StoreOff, Rest));
-store_moves([], _, _, Rest) ->
- Rest.
-
-%%%
-%%% Contexts
-%%%
-
--record(context, {liveness, framesize, arity, map, clobbers_ra, ref_maxstack}).
-
-mk_context(Liveness, Formals, Temps, ClobbersRA) ->
- {Map, MinOff} = mk_temp_map(Formals, ClobbersRA, Temps),
- FrameSize = (-MinOff),
- RefMaxStack = hipe_bifs:ref(FrameSize),
- #context{liveness=Liveness,
- framesize=FrameSize, arity=length(Formals),
- map=Map, clobbers_ra=ClobbersRA, ref_maxstack=RefMaxStack}.
-
-context_need_stack(#context{ref_maxstack=RM}, N) ->
- M = hipe_bifs:ref_get(RM),
- if N > M -> hipe_bifs:ref_set(RM, N);
- true -> []
- end.
-
-context_maxstack(#context{ref_maxstack=RM}) ->
- hipe_bifs:ref_get(RM).
-
-context_arity(#context{arity=Arity}) ->
- Arity.
-
-context_framesize(#context{framesize=FrameSize}) ->
- FrameSize.
-
-context_liveness(#context{liveness=Liveness}) ->
- Liveness.
-
-context_offset(#context{map=Map}, Temp) ->
- tmap_lookup(Map, Temp).
-
-context_clobbers_ra(#context{clobbers_ra=ClobbersRA}) -> ClobbersRA.
-
-mk_temp_map(Formals, ClobbersRA, Temps) ->
- {Map, 0} = enter_vars(Formals, word_size() * length(Formals),
- tmap_empty()),
- TempsList = tset_to_list(Temps),
- AllTemps =
- case ClobbersRA of
- false -> TempsList;
- true ->
- RA = hipe_sparc:mk_new_temp('untagged'),
- [RA|TempsList]
- end,
- enter_vars(AllTemps, 0, Map).
-
-enter_vars([V|Vs], PrevOff, Map) ->
- Off =
- case hipe_sparc:temp_type(V) of
- 'double' -> PrevOff - 2*word_size(); % XXX: sparc64: 1*word_size()
- _ -> PrevOff - word_size()
- end,
- enter_vars(Vs, Off, tmap_bind(Map, V, Off));
-enter_vars([], Off, Map) ->
- {Map, Off}.
-
-tmap_empty() ->
- gb_trees:empty().
-
-tmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-tmap_lookup(Map, Key) ->
- gb_trees:get(Key, Map).
-
-%%%
-%%% do_prologue: prepend stack frame allocation code.
-%%%
-%%% NewStart:
-%%% temp1 = *(P + P_SP_LIMIT)
-%%% temp2 = SP - MaxStack
-%%% cmp temp2, temp1
-%%% if (ltu) goto IncStack else goto AllocFrame
-%%% AllocFrame:
-%%% SP = temp2 [if FrameSize == MaxStack]
-%%% SP -= FrameSize [if FrameSize != MaxStack]
-%%% *(SP + FrameSize-WordSize) = RA [if ClobbersRA]
-%%% goto OldStart
-%%% OldStart:
-%%% ...
-%%% IncStack:
-%%% temp1 = RA
-%%% call inc_stack; nop
-%%% RA = temp1
-%%% goto NewStart
-
-do_prologue(CFG, Context) ->
- MaxStack = context_maxstack(Context),
- if MaxStack > 0 ->
- FrameSize = context_framesize(Context),
- OldStartLab = hipe_sparc_cfg:start_label(CFG),
- NewStartLab = hipe_gensym:get_next_label(sparc),
- %%
- P = hipe_sparc:mk_temp(hipe_sparc_registers:proc_pointer(), 'untagged'),
- Temp1 = hipe_sparc:mk_temp1(),
- SP = hipe_sparc:mk_sp(),
- %%
- RA = hipe_sparc:mk_ra(),
- ClobbersRA = context_clobbers_ra(Context),
- GotoOldStartCode = [hipe_sparc:mk_b_label(OldStartLab)],
- AllocFrameCodeTail =
- case ClobbersRA of
- false -> GotoOldStartCode;
- true -> mk_store(RA, SP, FrameSize-word_size(), GotoOldStartCode)
- end,
- %%
- Arity = context_arity(Context),
- Guaranteed = erlang:max(0, (?SPARC_LEAF_WORDS - Arity) * word_size()),
- %%
- {CFG1,NewStartCode} =
- if MaxStack =< Guaranteed ->
- %% io:format("~w: MaxStack ~w =< Guaranteed ~w :-)\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameCode = adjust_sp(-FrameSize, AllocFrameCodeTail),
- NewStartCode0 = AllocFrameCode, % no mflr needed
- {CFG,NewStartCode0};
- true ->
- %% io:format("~w: MaxStack ~w > Guaranteed ~w :-(\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameLab = hipe_gensym:get_next_label(sparc),
- IncStackLab = hipe_gensym:get_next_label(sparc),
- Temp2 = hipe_sparc:mk_temp2(),
- %%
- NewStartCodeTail2 =
- [hipe_sparc:mk_pseudo_bp('lu', IncStackLab, AllocFrameLab, 0.01)],
- NewStartCodeTail1 = NewStartCodeTail2, % no mflr needed
- NewStartCode0 =
- mk_load(P, ?P_NSP_LIMIT, Temp1,
- hipe_sparc:mk_addi(SP, -MaxStack, Temp2,
- [hipe_sparc:mk_alu('subcc', Temp2, Temp1, hipe_sparc:mk_g0()) |
- NewStartCodeTail1])),
- %%
- AllocFrameCode =
- if MaxStack =:= FrameSize ->
- %% io:format("~w: MaxStack =:= FrameSize =:= ~w :-)\n", [?MODULE,MaxStack]),
- [hipe_sparc:mk_mov(Temp2, SP) |
- AllocFrameCodeTail];
- true ->
- %% io:format("~w: MaxStack ~w =/= FrameSize ~w :-(\n", [?MODULE,MaxStack,FrameSize]),
- adjust_sp(-FrameSize, AllocFrameCodeTail)
- end,
- %%
- IncStackCodeTail =
- [hipe_sparc:mk_call_rec(hipe_sparc:mk_prim('inc_stack_0'),
- mk_minimal_sdesc(Context), not_remote),
- hipe_sparc:mk_mov(Temp1, RA),
- hipe_sparc:mk_b_label(NewStartLab)],
- IncStackCode =
- [hipe_sparc:mk_mov(RA, Temp1) | IncStackCodeTail], % mflr always needed
- %%
- CFG0a = hipe_sparc_cfg:bb_add(CFG, AllocFrameLab,
- hipe_bb:mk_bb(AllocFrameCode)),
- CFG0b = hipe_sparc_cfg:bb_add(CFG0a, IncStackLab,
- hipe_bb:mk_bb(IncStackCode)),
- %%
- {CFG0b,NewStartCode0}
- end,
- %%
- CFG2 = hipe_sparc_cfg:bb_add(CFG1, NewStartLab,
- hipe_bb:mk_bb(NewStartCode)),
- hipe_sparc_cfg:start_label_update(CFG2, NewStartLab);
- true ->
- CFG
- end.
-
-%%% Create a load instruction.
-%%% May clobber Dst early for large offsets. In principle we could
-%%% clobber TEMP2 if Dst =:= Base, but Dst =/= Base here in frame.
-
-mk_load(Base, Offset, Dst, Rest) ->
- LdOp = 'lduw', % XXX: sparc64: ldx
- hipe_sparc:mk_load(LdOp, Base, Offset, Dst, 'error', Rest).
-
-mk_fload(Base, Offset, Dst) ->
- hipe_sparc:mk_fload(Base, Offset, Dst, 'temp2').
-
-%%% Create a store instruction.
-%%% May clobber TEMP2 for large offsets.
-
-mk_store(Src, Base, Offset, Rest) ->
- StOp = 'stw', % XXX: sparc64: stx
- hipe_sparc:mk_store(StOp, Src, Base, Offset, 'temp2', Rest).
-
-mk_fstore(Src, Base, Offset) ->
- hipe_sparc:mk_fstore(Src, Base, Offset, 'temp2').
-
-%%% typeof_temp -- what's temp's type?
-
-typeof_temp(Temp) ->
- hipe_sparc:temp_type(Temp).
-
-%%% Check if an operand is a pseudo-Temp.
-
-src_is_pseudo(Src) ->
- hipe_sparc:is_temp(Src) andalso temp_is_pseudo(Src).
-
-temp_is_pseudo(Temp) ->
- not(hipe_sparc:temp_is_precoloured(Temp)).
-
-%%%
-%%% Detect if a Defun's body clobbers RA.
-%%%
-
-clobbers_ra(CFG) ->
- any_insn(fun(#pseudo_call{}) -> true;
- (_) -> false
- end, CFG).
-
-any_insn(Pred, CFG) ->
- %% Abuse fold to do an efficient "any"-operation using nonlocal control flow
- FoundSatisfying = make_ref(),
- try fold_insns(fun (I, _) ->
- case Pred(I) of
- true -> throw(FoundSatisfying);
- false -> false
- end
- end, false, CFG)
- of _ -> false
- catch FoundSatisfying -> true
- end.
-
-%%%
-%%% Build the set of all temps used in a Defun's body.
-%%%
-
-all_temps(CFG, Formals) ->
- S0 = fold_insns(fun find_temps/2, tset_empty(), CFG),
- S1 = tset_del_list(S0, Formals),
- tset_filter(S1, fun(T) -> temp_is_pseudo(T) end).
-
-find_temps(I, S0) ->
- S1 = tset_add_list(S0, hipe_sparc_defuse:insn_def_all(I)),
- tset_add_list(S1, hipe_sparc_defuse:insn_use_all(I)).
-
-fold_insns(Fun, InitAcc, CFG) ->
- hipe_sparc_cfg:fold_bbs(
- fun(_, BB, Acc0) -> lists:foldl(Fun, Acc0, hipe_bb:code(BB)) end,
- InitAcc, CFG).
-
-tset_empty() ->
- gb_sets:new().
-
-tset_size(S) ->
- gb_sets:size(S).
-
-tset_insert(S, T) ->
- gb_sets:add_element(T, S).
-
-tset_add_list(S, Ts) ->
- gb_sets:union(S, gb_sets:from_list(Ts)).
-
-tset_del_list(S, Ts) ->
- gb_sets:subtract(S, gb_sets:from_list(Ts)).
-
-tset_filter(S, F) ->
- gb_sets:filter(F, S).
-
-tset_to_list(S) ->
- gb_sets:to_list(S).
-
-%%%
-%%% Compute minimum permissible frame size, ignoring spilled temps.
-%%% This is done to ensure that we won't have to adjust the frame size
-%%% in the middle of a tailcall.
-%%%
-
-defun_minframe(CFG) ->
- MaxTailArity = fold_insns(fun insn_mta/2, 0, CFG),
- MyArity = length(fix_formals(hipe_sparc_cfg:params(CFG))),
- erlang:max(MaxTailArity - MyArity, 0).
-
-insn_mta(I, MTA) ->
- case I of
- #pseudo_tailcall{arity=Arity} ->
- erlang:max(MTA, Arity - hipe_sparc_registers:nr_args());
- _ -> MTA
- end.
-
-%%%
-%%% Ensure that we have enough temps to satisfy the minimum frame size,
-%%% if necessary by prepending unused dummy temps.
-%%%
-
-ensure_minframe(MinFrame, Temps) ->
- ensure_minframe(MinFrame, tset_size(Temps), Temps).
-
-ensure_minframe(MinFrame, Frame, Temps) ->
- if MinFrame > Frame ->
- Temp = hipe_sparc:mk_new_temp('untagged'),
- ensure_minframe(MinFrame, Frame+1, tset_insert(Temps, Temp));
- true -> Temps
- end.
-
-word_size() ->
- hipe_rtl_arch:word_size().
diff --git a/lib/hipe/sparc/hipe_sparc_liveness_all.erl b/lib/hipe/sparc/hipe_sparc_liveness_all.erl
deleted file mode 100644
index f67b6c0fca..0000000000
--- a/lib/hipe/sparc/hipe_sparc_liveness_all.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_liveness_all).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_sparc.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_sparc_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_sparc_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_sparc_cfg:succ(CFG, L).
-uses(Insn) -> hipe_sparc_defuse:insn_use_all(Insn).
-defines(Insn) -> hipe_sparc_defuse:insn_def_all(Insn).
-liveout_no_succ() ->
- ordsets:from_list(lists:map(fun({Reg,Type}) ->
- hipe_sparc:mk_temp(Reg, Type)
- end,
- hipe_sparc_registers:live_at_return())).
diff --git a/lib/hipe/sparc/hipe_sparc_liveness_fpr.erl b/lib/hipe/sparc/hipe_sparc_liveness_fpr.erl
deleted file mode 100644
index bd2c0c75ee..0000000000
--- a/lib/hipe/sparc/hipe_sparc_liveness_fpr.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_liveness_fpr).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_sparc.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_sparc_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_sparc_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_sparc_cfg:succ(CFG, L).
-uses(Insn) -> hipe_sparc_defuse:insn_use_fpr(Insn).
-defines(Insn) -> hipe_sparc_defuse:insn_def_fpr(Insn).
-liveout_no_succ() -> [].
diff --git a/lib/hipe/sparc/hipe_sparc_liveness_gpr.erl b/lib/hipe/sparc/hipe_sparc_liveness_gpr.erl
deleted file mode 100644
index 848148e301..0000000000
--- a/lib/hipe/sparc/hipe_sparc_liveness_gpr.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_liveness_gpr).
--export([analyse/1]).
--export([liveout/2]).
-
--include("hipe_sparc.hrl").
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_sparc_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_sparc_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_sparc_cfg:succ(CFG, L).
-uses(Insn) -> hipe_sparc_defuse:insn_use_gpr(Insn).
-defines(Insn) -> hipe_sparc_defuse:insn_def_gpr(Insn).
-liveout_no_succ() ->
- ordsets:from_list(lists:map(fun({Reg,Type}) ->
- hipe_sparc:mk_temp(Reg, Type)
- end,
- hipe_sparc_registers:live_at_return())).
diff --git a/lib/hipe/sparc/hipe_sparc_main.erl b/lib/hipe/sparc/hipe_sparc_main.erl
deleted file mode 100644
index ea05721f60..0000000000
--- a/lib/hipe/sparc/hipe_sparc_main.erl
+++ /dev/null
@@ -1,54 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_main).
--export([rtl_to_sparc/3]).
-
-rtl_to_sparc(MFA, RTL, Options) ->
- Defun1 = hipe_rtl_to_sparc:translate(RTL),
- CFG1 = hipe_sparc_cfg:init(Defun1),
- %% io:format("~w: after translate\n", [?MODULE]),
- %% hipe_sparc_pp:pp(Defun1),
- CFG2 = hipe_sparc_ra:ra(CFG1, Options),
- %% io:format("~w: after regalloc\n", [?MODULE]),
- %% hipe_sparc_pp:pp(hipe_sparc_cfg:linearise(CFG2)),
- CFG3 = hipe_sparc_frame:frame(CFG2),
- Defun3 = hipe_sparc_cfg:linearise(CFG3),
- %% io:format("~w: after frame\n", [?MODULE]),
- %% hipe_sparc_pp:pp(Defun3),
- Defun4 = hipe_sparc_finalise:finalise(Defun3),
- %% io:format("~w: after finalise\n", [?MODULE]),
- pp(Defun4, MFA, Options),
- {native, sparc, {unprofiled, Defun4}}.
-
-pp(Defun, MFA, Options) ->
- case proplists:get_value(pp_native, Options) of
- true ->
- hipe_sparc_pp:pp(Defun);
- {only,Lst} when is_list(Lst) ->
- case lists:member(MFA,Lst) of
- true ->
- hipe_sparc_pp:pp(Defun);
- false ->
- ok
- end;
- {only,MFA} ->
- hipe_sparc_pp:pp(Defun);
- {file,FileName} ->
- {ok, File} = file:open(FileName, [write,append]),
- hipe_sparc_pp:pp(File, Defun),
- ok = file:close(File);
- _ ->
- ok
- end.
diff --git a/lib/hipe/sparc/hipe_sparc_pp.erl b/lib/hipe/sparc/hipe_sparc_pp.erl
deleted file mode 100644
index d893094eb7..0000000000
--- a/lib/hipe/sparc/hipe_sparc_pp.erl
+++ /dev/null
@@ -1,336 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_pp).
--export([pp/1, pp/2, pp_insn/1]).
--include("hipe_sparc.hrl").
-
-pp(Defun) ->
- pp(standard_io, Defun).
-
-pp(Dev, #defun{mfa={M,F,A}, code=Code, data=Data}) ->
- Fname = atom_to_list(M)++"_"++atom_to_list(F)++"_"++integer_to_list(A),
- io:format(Dev, "\t.text\n", []),
- io:format(Dev, "\t.align 4\n", []),
- io:format(Dev, "\t.global ~s\n", [Fname]),
- io:format(Dev, "~s:\n", [Fname]),
- pp_insns(Dev, Code, Fname),
- io:format(Dev, "\t.rodata\n", []),
- io:format(Dev, "\t.align 4\n", []),
- hipe_data_pp:pp(Dev, Data, sparc, Fname),
- io:format(Dev, "\n", []).
-
-pp_insns(Dev, [I|Is], Fname) ->
- pp_insn(Dev, I, Fname),
- pp_insns(Dev, Is, Fname);
-pp_insns(_, [], _) ->
- [].
-
-pp_insn(I) ->
- pp_insn(standard_io, I, "").
-
-pp_insn(Dev, I, Pre) ->
- case I of
- #alu{aluop=AluOp, dst=Dst, src1=Src1, src2=Src2} ->
- io:format(Dev, "\t~s ", [alu_op_name(AluOp)]),
- case aluop_is_ldop(AluOp) of
- true ->
- io:format(Dev, "[", []),
- pp_temp(Dev, Src1),
- io:format(Dev, " + ", []),
- pp_src(Dev, Src2),
- io:format(Dev, "]", []);
- false ->
- pp_temp(Dev, Src1),
- io:format(Dev, ", ", []),
- pp_src(Dev, Src2)
- end,
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #bp{'cond'=Cond, label=Label, pred=Pred} ->
- io:format(Dev, "\tb~w,~w .~s_~w\n",
- [cond_name(Cond), pred_name(Pred), Pre, Label]);
- %% #br{} -> pp_br(Dev, I, Pre);
- #call_rec{'fun'=Fun, sdesc=SDesc, linkage=Linkage} ->
- io:format(Dev, "\tcall ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " #", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #call_tail{'fun'=Fun, linkage=Linkage} ->
- io:format(Dev, "\tb ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " # ~w\n", [Linkage]);
- #comment{term=Term} ->
- io:format(Dev, "\t# ~p\n", [Term]);
- #jmp{src1=Src1, src2=Src2, labels=Labels} ->
- io:format(Dev, "\tjmp [", []),
- pp_temp(Dev, Src1),
- io:format(Dev, " + ", []),
- pp_src(Dev, Src2),
- io:format(Dev, "]", []),
- case Labels of
- [] -> [];
- _ ->
- io:format(Dev, " #", []),
- pp_labels(Dev, Labels, Pre)
- end,
- io:format(Dev, "\n", []);
- #jmpl{src=Src, sdesc=SDesc} ->
- io:format(Dev, "\tjmpl [", []),
- pp_temp(Dev, Src),
- io:format(Dev, " + 0], %o7 # ", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, "\n", []);
- #label{label=Label} ->
- io:format(Dev, ".~s_~w:~n", [Pre, Label]);
- #pseudo_bp{'cond'=Cond, true_label=TrueLab, false_label=FalseLab, pred=Pred} ->
- io:format(Dev, "\tpseudo_b~w,~w .~s_~w # .~s_~w\n",
- [cond_name(Cond), pred_name(Pred), Pre, TrueLab, Pre, FalseLab]);
- %% #pseudo_br{} -> pp_pseudo_br(Dev, I, Pre);
- #pseudo_call{funv=FunV, sdesc=SDesc, contlab=ContLab, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_call ", []),
- pp_funv(Dev, FunV),
- io:format(Dev, " # contlab .~s_~w", [Pre, ContLab]),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #pseudo_call_prepare{nrstkargs=NrStkArgs} ->
- SP = hipe_sparc_registers:reg_name_gpr(hipe_sparc_registers:stack_pointer()),
- io:format(Dev, "\tsub ~s, ~w, ~s # pseudo_call_prepare\n",
- [SP, 4*NrStkArgs, SP]);
- #pseudo_move{src=Src, dst=Dst} ->
- io:format(Dev, "\tpseudo_move ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #pseudo_ret{} ->
- io:format(Dev, "\tpseudo_ret\n", []);
- #pseudo_set{imm=Imm, dst=Dst} ->
- io:format(Dev, "\tpseudo_set ", []),
- pp_imm(Dev, Imm),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #pseudo_tailcall{funv=FunV, arity=Arity, stkargs=StkArgs, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_tailcall ", []),
- pp_funv(Dev, FunV),
- io:format(Dev, "/~w (", [Arity]),
- pp_args(Dev, StkArgs),
- io:format(Dev, ") ~w\n", [Linkage]);
- #pseudo_tailcall_prepare{} ->
- io:format(Dev, "\tpseudo_tailcall_prepare\n", []);
- #rdy{dst=Dst} ->
- io:format(Dev, "\trd %y, ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #sethi{dst=Dst, uimm22=#sparc_uimm22{value=Value}} ->
- io:format(Dev, "\tsethi ", []),
- pp_hex(Dev, Value),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #store{stop=StOp, src=Src, base=Base, disp=Disp} ->
- io:format(Dev, "\t~s ", [stop_name(StOp)]),
- pp_temp(Dev, Src),
- io:format(Dev, ", [", []),
- pp_temp(Dev, Base),
- io:format(Dev, " + ", []),
- pp_src(Dev, Disp),
- io:format(Dev, "]\n", []);
- #fp_binary{fp_binop=FpBinOp, src1=Src1, src2=Src2, dst=Dst} ->
- io:format(Dev, "\t~s ", [FpBinOp]),
- pp_temp(Dev, Src1),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Src2),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #fp_unary{fp_unop=FpUnOp, src=Src, dst=Dst} ->
- io:format(Dev, "\t~s ", [FpUnOp]),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #pseudo_fload{base=Base, disp=Disp, dst=Dst, is_single=IsSingle} ->
- io:format(Dev, "\t~s [",
- [case IsSingle of
- true -> 'ldf';
- _ -> 'pseudo_fload' end]),
- pp_temp(Dev, Base),
- io:format(Dev, " + ", []),
- pp_simm13(Dev, Disp),
- io:format(Dev, "], ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #pseudo_fmove{src=Src, dst=Dst} ->
- io:format(Dev, "\tpseudo_fmove ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Dst),
- io:format(Dev, "\n", []);
- #pseudo_fstore{src=Src, base=Base, disp=Disp} ->
- io:format(Dev, "\tpseudo_fstore ", []),
- pp_temp(Dev, Src),
- io:format(Dev, ", [", []),
- pp_temp(Dev, Base),
- io:format(Dev, " + ", []),
- pp_simm13(Dev, Disp),
- io:format(Dev, "]\n", []);
- _ ->
- exit({?MODULE, pp_insn, I})
- end.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-pp_br(Dev, I, Pre) ->
- #br{rcond=RCond, src=Src, label=Label, pred=Pred} = I,
- io:format(Dev, "\tbr~w,~w ", [rcond_name(RCond), pred_name(Pred)]),
- pp_temp(Dev, Src),
- io:format(Dev, ", .~s_~w\n", [Pre, Label]).
-
-pp_pseudo_br(Dev, I, Pre) ->
- #pseudo_br{rcond=RCond, src=Src, true_label=TrueLab, false_label=FalseLab, pred=Pred} = I,
- io:format(Dev, "\tpseudo_br~w,~w ", [rcond_name(RCond), pred_name(Pred)]),
- pp_src(Dev, Src),
- io:format(Dev, ", .~s_~w # .~s_~w\n", [Pre, TrueLab, Pre, FalseLab]).
--endif.
-
-to_hex(N) ->
- io_lib:format("~.16x", [N, "0x"]).
-
-pp_sdesc(Dev, Pre, #sparc_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live}) ->
- pp_sdesc_exnlab(Dev, Pre, ExnLab),
- io:format(Dev, " ~s ~w [", [to_hex(FSize), Arity]),
- pp_sdesc_live(Dev, Live),
- io:format(Dev, "]", []).
-
-pp_sdesc_exnlab(Dev, _, []) -> io:format(Dev, " []", []);
-pp_sdesc_exnlab(Dev, Pre, ExnLab) -> io:format(Dev, " .~s_~w", [Pre, ExnLab]).
-
-pp_sdesc_live(_, {}) -> [];
-pp_sdesc_live(Dev, Live) -> pp_sdesc_live(Dev, Live, 1).
-
-pp_sdesc_live(Dev, Live, I) ->
- io:format(Dev, "~s", [to_hex(element(I, Live))]),
- if I < tuple_size(Live) ->
- io:format(Dev, ",", []),
- pp_sdesc_live(Dev, Live, I+1);
- true -> []
- end.
-
-pp_labels(Dev, [Label|Labels], Pre) ->
- io:format(Dev, " .~s_~w", [Pre, Label]),
- pp_labels(Dev, Labels, Pre);
-pp_labels(_, [], _) ->
- [].
-
-pp_fun(Dev, Fun) ->
- case Fun of
- #sparc_mfa{m=M, f=F, a=A} ->
- io:format(Dev, "~w:~w/~w", [M, F, A]);
- #sparc_prim{prim=Prim} ->
- io:format(Dev, "~w", [Prim])
- end.
-
-pp_funv(Dev, FunV) ->
- case FunV of
- #sparc_temp{} ->
- pp_temp(Dev, FunV);
- Fun ->
- pp_fun(Dev, Fun)
- end.
-
-alu_op_name(Op) -> Op.
-
-aluop_is_ldop(AluOp) ->
- case AluOp of
- 'ldsb' -> true;
- 'ldsh' -> true;
- 'ldsw' -> true;
- 'ldub' -> true;
- 'lduh' -> true;
- 'lduw' -> true;
- 'ldx' -> true;
- _ -> false
- end.
-
-cond_name(Cond) -> Cond.
-%%rcond_name(RCond) -> RCond.
-
-pred_name(Pred) ->
- if Pred >= 0.5 -> 'pt';
- true -> 'pn'
- end.
-
-stop_name(StOp) -> StOp.
-
-pp_temp(Dev, Temp=#sparc_temp{reg=Reg, type=Type}) ->
- case hipe_sparc:temp_is_precoloured(Temp) of
- true ->
- Name =
- case Type of
- double -> hipe_sparc_registers:reg_name_fpr(Reg);
- _ -> hipe_sparc_registers:reg_name_gpr(Reg)
- end,
- io:format(Dev, "~s", [Name]);
- false ->
- Tag =
- case Type of
- double -> "f";
- tagged -> "t";
- untagged -> "u"
- end,
- io:format(Dev, "~s~w", [Tag, Reg])
- end.
-
-pp_hex(Dev, Value) -> io:format(Dev, "~s", [to_hex(Value)]).
-pp_simm13(Dev, #sparc_simm13{value=Value}) -> pp_hex(Dev, Value).
-pp_uimm5(Dev, #sparc_uimm5{value=Value}) -> pp_hex(Dev, Value).
-
-pp_imm(Dev, Value) ->
- if is_integer(Value) -> pp_hex(Dev, Value);
- true -> io:format(Dev, "~w", [Value])
- end.
-
-pp_src(Dev, Src) ->
- case Src of
- #sparc_temp{} ->
- pp_temp(Dev, Src);
- #sparc_simm13{} ->
- pp_simm13(Dev, Src);
- #sparc_uimm5{} -> % XXX: sparc64: uimm6
- pp_uimm5(Dev, Src)
- end.
-
-pp_arg(Dev, Arg) ->
- case Arg of
- #sparc_temp{} ->
- pp_temp(Dev, Arg);
- _ ->
- pp_hex(Dev, Arg)
- end.
-
-pp_args(Dev, [A|As]) ->
- pp_arg(Dev, A),
- pp_comma_args(Dev, As);
-pp_args(_, []) ->
- [].
-
-pp_comma_args(Dev, [A|As]) ->
- io:format(Dev, ", ", []),
- pp_arg(Dev, A),
- pp_comma_args(Dev, As);
-pp_comma_args(_, []) ->
- [].
diff --git a/lib/hipe/sparc/hipe_sparc_ra.erl b/lib/hipe/sparc/hipe_sparc_ra.erl
deleted file mode 100644
index ba1a9aa3d8..0000000000
--- a/lib/hipe/sparc/hipe_sparc_ra.erl
+++ /dev/null
@@ -1,53 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_ra).
--export([ra/2]).
-
-ra(CFG0, Options) ->
- %% hipe_sparc_pp:pp(hipe_sparc_cfg:linearise(CFG0)),
- {CFG1, _FPLiveness1, Coloring_fp, SpillIndex}
- = case proplists:get_bool(inline_fp, Options) of
- true ->
- FPLiveness0 = hipe_sparc_specific_fp:analyze(CFG0, no_context),
- hipe_regalloc_loop:ra_fp(CFG0, FPLiveness0, Options,
- hipe_coalescing_regalloc,
- hipe_sparc_specific_fp, no_context);
- false ->
- {CFG0,undefined,[],0}
- end,
- %% hipe_sparc_pp:pp(hipe_sparc_cfg:linearise(CFG1)),
- GPLiveness1 = hipe_sparc_specific:analyze(CFG1, no_context),
- {CFG2, _GPLiveness2, Coloring}
- = case proplists:get_value(regalloc, Options, coalescing) of
- coalescing ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_coalescing_regalloc);
- optimistic ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_optimistic_regalloc);
- graph_color ->
- ra(CFG1, GPLiveness1, SpillIndex, Options, hipe_graph_coloring_regalloc);
- linear_scan ->
- hipe_sparc_ra_ls:ra(CFG1, GPLiveness1, SpillIndex, Options);
- naive ->
- hipe_sparc_ra_naive:ra(CFG1, GPLiveness1, Coloring_fp, Options);
- _ ->
- exit({unknown_regalloc_compiler_option,
- proplists:get_value(regalloc,Options)})
- end,
- %% hipe_sparc_pp:pp(hipe_sparc_cfg:linearise(CFG2)),
- hipe_sparc_ra_finalise:finalise(CFG2, Coloring, Coloring_fp).
-
-ra(CFG, Liveness, SpillIndex, Options, RegAllocMod) ->
- hipe_regalloc_loop:ra(CFG, Liveness, SpillIndex, Options, RegAllocMod,
- hipe_sparc_specific, no_context).
diff --git a/lib/hipe/sparc/hipe_sparc_ra_finalise.erl b/lib/hipe/sparc/hipe_sparc_ra_finalise.erl
deleted file mode 100644
index a724821992..0000000000
--- a/lib/hipe/sparc/hipe_sparc_ra_finalise.erl
+++ /dev/null
@@ -1,264 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_ra_finalise).
--export([finalise/3]).
--include("hipe_sparc.hrl").
-
-finalise(CFG, TempMap, FPMap0) ->
- {_, SpillLimit} = hipe_gensym:var_range(sparc),
- Map = mk_ra_map(TempMap, SpillLimit),
- FPMap1 = mk_ra_map_fp(FPMap0, SpillLimit),
- hipe_sparc_cfg:map_bbs(fun(_Lbl, BB) -> ra_bb(BB, Map, FPMap1) end, CFG).
-
-ra_bb(BB, Map, FpMap) ->
- hipe_bb:code_update(BB, ra_code(hipe_bb:code(BB), Map, FpMap, [])).
-
-ra_code([I|Insns], Map, FPMap, Accum) ->
- ra_code(Insns, Map, FPMap, [ra_insn(I, Map, FPMap) | Accum]);
-ra_code([], _Map, _FPMap, Accum) ->
- lists:reverse(Accum).
-
-ra_insn(I, Map, FPMap) ->
- case I of
- #alu{} -> ra_alu(I, Map);
- #jmp{} -> ra_jmp(I, Map);
- %% #pseudo_br{} -> ra_pseudo_br(I, Map);
- #pseudo_call{} -> ra_pseudo_call(I, Map);
- #pseudo_move{} -> ra_pseudo_move(I, Map);
- #pseudo_set{} -> ra_pseudo_set(I, Map);
- #pseudo_spill_move{} -> ra_pseudo_spill_move(I, Map);
- #pseudo_tailcall{} -> ra_pseudo_tailcall(I, Map);
- #rdy{} -> ra_rdy(I, Map);
- #sethi{} -> ra_sethi(I, Map);
- #store{} -> ra_store(I, Map);
- #fp_binary{} -> ra_fp_binary(I, FPMap);
- #fp_unary{} -> ra_fp_unary(I, FPMap);
- #pseudo_fload{} -> ra_pseudo_fload(I, Map, FPMap);
- #pseudo_fmove{} -> ra_pseudo_fmove(I, FPMap);
- #pseudo_fstore{} -> ra_pseudo_fstore(I, Map, FPMap);
- #pseudo_spill_fmove{} -> ra_pseudo_spill_fmove(I, FPMap);
- _ -> I
- end.
-
-ra_alu(I=#alu{src1=Src1,src2=Src2,dst=Dst}, Map) ->
- NewSrc1 = ra_temp(Src1, Map),
- NewSrc2 = ra_src(Src2, Map),
- NewDst = ra_temp(Dst, Map),
- I#alu{src1=NewSrc1,src2=NewSrc2,dst=NewDst}.
-
-ra_jmp(I=#jmp{src1=Src1,src2=Src2}, Map) ->
- NewSrc1 = ra_temp(Src1, Map),
- NewSrc2 = ra_src(Src2, Map),
- I#jmp{src1=NewSrc1,src2=NewSrc2}.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-ra_pseudo_br(I=#pseudo_br{src=Src}, Map) ->
- NewSrc = ra_temp(Src, Map),
- I#pseudo_br{src=NewSrc}.
--endif.
-
-ra_pseudo_call(I=#pseudo_call{funv=FunV}, Map) ->
- NewFunV = ra_funv(FunV, Map),
- I#pseudo_call{funv=NewFunV}.
-
-ra_pseudo_move(I=#pseudo_move{src=Src,dst=Dst}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewDst = ra_temp(Dst, Map),
- I#pseudo_move{src=NewSrc,dst=NewDst}.
-
-ra_pseudo_set(I=#pseudo_set{dst=Dst}, Map) ->
- NewDst = ra_temp(Dst, Map),
- I#pseudo_set{dst=NewDst}.
-
-ra_pseudo_spill_move(I=#pseudo_spill_move{src=Src,temp=Temp,dst=Dst}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewTemp = ra_temp(Temp, Map),
- NewDst = ra_temp(Dst, Map),
- I#pseudo_spill_move{src=NewSrc,temp=NewTemp,dst=NewDst}.
-
-ra_pseudo_tailcall(I=#pseudo_tailcall{funv=FunV,stkargs=StkArgs}, Map) ->
- NewFunV = ra_funv(FunV, Map),
- NewStkArgs = ra_args(StkArgs, Map),
- I#pseudo_tailcall{funv=NewFunV,stkargs=NewStkArgs}.
-
-ra_rdy(I=#rdy{dst=Dst}, Map) ->
- NewDst = ra_temp(Dst, Map),
- I#rdy{dst=NewDst}.
-
-ra_sethi(I=#sethi{dst=Dst}, Map) ->
- NewDst = ra_temp(Dst, Map),
- I#sethi{dst=NewDst}.
-
-ra_store(I=#store{src=Src,base=Base,disp=Disp}, Map) ->
- NewSrc = ra_temp(Src, Map),
- NewBase = ra_temp(Base, Map),
- NewDisp = ra_src(Disp, Map),
- I#store{src=NewSrc,base=NewBase,disp=NewDisp}.
-
-ra_fp_binary(I=#fp_binary{src1=Src1,src2=Src2,dst=Dst}, FPMap) ->
- NewSrc1 = ra_temp_fp(Src1, FPMap),
- NewSrc2 = ra_temp_fp(Src2, FPMap),
- NewDst = ra_temp_fp(Dst, FPMap),
- I#fp_binary{src1=NewSrc1,src2=NewSrc2,dst=NewDst}.
-
-ra_fp_unary(I=#fp_unary{src=Src,dst=Dst}, FPMap) ->
- NewSrc = ra_temp_fp(Src, FPMap),
- NewDst = ra_temp_fp(Dst, FPMap),
- I#fp_unary{src=NewSrc,dst=NewDst}.
-
-ra_pseudo_fload(I=#pseudo_fload{base=Base,dst=Dst}, Map, FPMap) ->
- NewBase = ra_temp(Base, Map),
- NewDst = ra_temp_fp(Dst, FPMap),
- I#pseudo_fload{base=NewBase,dst=NewDst}.
-
-ra_pseudo_fmove(I=#pseudo_fmove{src=Src,dst=Dst}, FPMap) ->
- NewSrc = ra_temp_fp(Src, FPMap),
- NewDst = ra_temp_fp(Dst, FPMap),
- I#pseudo_fmove{src=NewSrc,dst=NewDst}.
-
-ra_pseudo_spill_fmove(I=#pseudo_spill_fmove{src=Src,temp=Temp,dst=Dst},
- FPMap) ->
- NewSrc = ra_temp_fp(Src, FPMap),
- NewTemp = ra_temp_fp(Temp, FPMap),
- NewDst = ra_temp_fp(Dst, FPMap),
- I#pseudo_spill_fmove{src=NewSrc,temp=NewTemp,dst=NewDst}.
-
-ra_pseudo_fstore(I=#pseudo_fstore{src=Src,base=Base}, Map, FPMap) ->
- NewSrc = ra_temp_fp(Src, FPMap),
- NewBase = ra_temp(Base, Map),
- I#pseudo_fstore{src=NewSrc,base=NewBase}.
-
-%%% Tailcall stack arguments.
-
-ra_args([Arg|Args], Map) ->
- [ra_temp_or_imm(Arg, Map) | ra_args(Args, Map)];
-ra_args([], _) ->
- [].
-
-ra_temp_or_imm(Arg, Map) ->
- case hipe_sparc:is_temp(Arg) of
- true ->
- ra_temp(Arg, Map);
- false ->
- Arg
- end.
-
-%%% FunV, Src, and Temp operands.
-
-ra_funv(FunV, Map) ->
- case FunV of
- #sparc_temp{} -> ra_temp(FunV, Map);
- _ -> FunV
- end.
-
-ra_src(Src, Map) ->
- case Src of
- #sparc_temp{} -> ra_temp(Src, Map);
- _ -> Src
- end.
-
-ra_temp_fp(Temp, FPMap) ->
- Reg = hipe_sparc:temp_reg(Temp),
- double = hipe_sparc:temp_type(Temp),
- case hipe_sparc_registers:is_precoloured_fpr(Reg) of
- true -> Temp;
- _ -> ra_temp_common(Reg, Temp, FPMap)
- end.
-
-ra_temp(Temp, Map) ->
- Reg = hipe_sparc:temp_reg(Temp),
- case hipe_sparc:temp_type(Temp) of
- 'double' ->
- exit({?MODULE,ra_temp,Temp});
- _ ->
- case hipe_sparc_registers:is_precoloured_gpr(Reg) of
- true -> Temp;
- _ -> ra_temp_common(Reg, Temp, Map)
- end
- end.
-
-ra_temp_common(Reg, Temp, Map) ->
- case gb_trees:lookup(Reg, Map) of
- {value, NewReg} -> Temp#sparc_temp{reg=NewReg};
- _ -> Temp
- end.
-
-mk_ra_map(TempMap, SpillLimit) ->
- %% Build a partial map from pseudo to reg or spill.
- %% Spills are represented as pseudos with indices above SpillLimit.
- %% (I'd prefer to use negative indices, but that breaks
- %% hipe_sparc_registers:is_precoloured/1.)
- %% The frame mapping proper is unchanged, since spills look just like
- %% ordinary (un-allocated) pseudos.
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit, is_precoloured_gpr),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- TempMap).
-
-conv_ra_maplet(MapLet = {From,To}, SpillLimit, IsPrecoloured) ->
- %% From should be a pseudo, or a hard reg mapped to itself.
- if is_integer(From), From =< SpillLimit ->
- case hipe_sparc_registers:IsPrecoloured(From) of
- false -> [];
- _ ->
- case To of
- {reg, From} -> [];
- _ -> exit({?MODULE,conv_ra_maplet,MapLet})
- end
- end;
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of From check
- case To of
- {reg, NewReg} ->
- %% NewReg should be a hard reg, or a pseudo mapped
- %% to itself (formals are handled this way).
- if is_integer(NewReg) ->
- case hipe_sparc_registers:IsPrecoloured(NewReg) of
- true -> [];
- _ -> if From =:= NewReg -> [];
- true ->
- exit({?MODULE,conv_ra_maplet,MapLet})
- end
- end;
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of NewReg check
- {From, NewReg};
- {spill, SpillIndex} ->
- %% SpillIndex should be >= 0.
- if is_integer(SpillIndex), SpillIndex >= 0 -> [];
- true -> exit({?MODULE,conv_ra_maplet,MapLet})
- end,
- %% end of SpillIndex check
- ToTempNum = SpillLimit+SpillIndex+1,
- MaxTempNum = hipe_gensym:get_var(sparc),
- if MaxTempNum >= ToTempNum -> ok;
- true -> hipe_gensym:set_var(sparc, ToTempNum)
- end,
- {From, ToTempNum};
- _ -> exit({?MODULE,conv_ra_maplet,MapLet})
- end.
-
-mk_ra_map_fp(FPMap, SpillLimit) ->
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit,
- is_precoloured_fpr),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- FPMap).
diff --git a/lib/hipe/sparc/hipe_sparc_ra_ls.erl b/lib/hipe/sparc/hipe_sparc_ra_ls.erl
deleted file mode 100644
index 1b8659ab70..0000000000
--- a/lib/hipe/sparc/hipe_sparc_ra_ls.erl
+++ /dev/null
@@ -1,49 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% Linear Scan register allocator for SPARC
-
--module(hipe_sparc_ra_ls).
--export([ra/4]).
-
-ra(CFG, Liveness, SpillIndex, Options) ->
- SpillLimit = hipe_sparc_specific:number_of_temporaries(CFG, no_context),
- alloc(CFG, Liveness, SpillIndex, SpillLimit, Options).
-
-alloc(CFG, Liveness, SpillIndex, SpillLimit, Options) ->
- {Coloring, _NewSpillIndex} =
- regalloc(
- CFG, Liveness,
- hipe_sparc_registers:allocatable_gpr()--
- [hipe_sparc_registers:temp3(),
- hipe_sparc_registers:temp2(),
- hipe_sparc_registers:temp1()],
- [hipe_sparc_cfg:start_label(CFG)],
- SpillIndex, SpillLimit, Options,
- hipe_sparc_specific, no_context),
- {NewCFG, _DidSpill} =
- hipe_sparc_ra_postconditions:check_and_rewrite(
- CFG, Coloring, 'linearscan'),
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_sparc_specific, no_context),
- {TempMap2,_NewSpillIndex2} =
- hipe_spillmin:stackalloc(CFG, Liveness, [], SpillIndex, Options,
- hipe_sparc_specific, no_context, TempMap),
- Coloring2 =
- hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), TempMap2),
- {NewCFG, Liveness, Coloring2}.
-
-regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options,
- TgtMod, TgtCtx) ->
- hipe_ls_regalloc:regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex,
- DontSpill, Options, TgtMod, TgtCtx).
diff --git a/lib/hipe/sparc/hipe_sparc_ra_naive.erl b/lib/hipe/sparc/hipe_sparc_ra_naive.erl
deleted file mode 100644
index 5ea9ead6bc..0000000000
--- a/lib/hipe/sparc/hipe_sparc_ra_naive.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_ra_naive).
--export([ra/4]).
-
--include("hipe_sparc.hrl").
-
-ra(CFG, Liveness, _Coloring_fp, _Options) -> % -> {CFG, Liveness, Coloring}
- {NewCFG,_DidSpill} =
- hipe_sparc_ra_postconditions:check_and_rewrite2(CFG, [], 'naive'),
- {NewCFG, Liveness, []}.
diff --git a/lib/hipe/sparc/hipe_sparc_ra_postconditions.erl b/lib/hipe/sparc/hipe_sparc_ra_postconditions.erl
deleted file mode 100644
index d3ecb43ec6..0000000000
--- a/lib/hipe/sparc/hipe_sparc_ra_postconditions.erl
+++ /dev/null
@@ -1,227 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_ra_postconditions).
-
--export([check_and_rewrite/3, check_and_rewrite2/3]).
-
--include("hipe_sparc.hrl").
-
-check_and_rewrite(CFG, Coloring, Allocator) ->
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_sparc_specific, no_context),
- check_and_rewrite2(CFG, TempMap, Allocator).
-
-check_and_rewrite2(CFG, TempMap, Allocator) ->
- Strategy = strategy(Allocator),
- do_bbs(hipe_sparc_cfg:labels(CFG), TempMap, Strategy, CFG, false).
-
-strategy(Allocator) ->
- case Allocator of
- 'normal' -> 'new';
- 'linearscan' -> 'fixed';
- 'naive' -> 'fixed'
- end.
-
-do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_sparc_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0),
- CFG = hipe_sparc_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
- do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
-do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap, Strategy) ->
- case I of
- #alu{} -> do_alu(I, TempMap, Strategy);
- #jmp{} -> do_jmp(I, TempMap, Strategy);
- %% #pseudo_br{} -> do_pseudo_br(I, TempMap, Strategy);
- #pseudo_call{} -> do_pseudo_call(I, TempMap, Strategy);
- #pseudo_move{} -> do_pseudo_move(I, TempMap, Strategy);
- #pseudo_set{} -> do_pseudo_set(I, TempMap, Strategy);
- #pseudo_spill_move{} -> do_pseudo_spill_move(I, TempMap, Strategy);
- #pseudo_tailcall{} -> do_pseudo_tailcall(I, TempMap, Strategy);
- #rdy{} -> do_rdy(I, TempMap, Strategy);
- #sethi{} -> do_sethi(I, TempMap, Strategy);
- #store{} -> do_store(I, TempMap, Strategy);
- #pseudo_fload{} -> do_pseudo_fload(I, TempMap, Strategy);
- #pseudo_fstore{} -> do_pseudo_fstore(I, TempMap, Strategy);
- _ -> {[I], false}
- end.
-
-%%% Fix relevant instruction types.
-
-do_alu(I=#alu{dst=Dst,src1=Src1,src2=Src2}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill1} = fix_dst(Dst, TempMap, Strategy),
- {FixSrc1,NewSrc1,DidSpill2} = fix_src1(Src1, TempMap, Strategy),
- {FixSrc2,NewSrc2,DidSpill3} = fix_src2_or_imm(Src2, TempMap, Strategy),
- NewI = I#alu{dst=NewDst,src1=NewSrc1,src2=NewSrc2},
- {FixSrc1 ++ FixSrc2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_jmp(I=#jmp{src1=Src1,src2=Src2}, TempMap, Strategy) ->
- {FixSrc1,NewSrc1,DidSpill1} = fix_src1(Src1, TempMap, Strategy),
- {FixSrc2,NewSrc2,DidSpill2} = fix_src2_or_imm(Src2, TempMap, Strategy),
- NewI = I#jmp{src1=NewSrc1,src2=NewSrc2},
- {FixSrc1 ++ FixSrc2 ++ [NewI], DidSpill1 or DidSpill2}.
-
--ifdef(notdef). % XXX: only for sparc64, alas
-do_pseudo_br(I=#pseudo_br{src=Src}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill} = fix_src1(Src, TempMap, Strategy),
- NewI = I#pseudo_br{src=NewSrc},
- {FixSrc ++ [NewI], DidSpill}.
--endif.
-
-do_pseudo_call(I=#pseudo_call{funv=FunV}, TempMap, Strategy) ->
- {FixFunV,NewFunV,DidSpill} = fix_funv(FunV, TempMap, Strategy),
- NewI = I#pseudo_call{funv=NewFunV},
- {FixFunV ++ [NewI], DidSpill}.
-
-do_pseudo_move(I=#pseudo_move{src=Src,dst=Dst}, TempMap, Strategy) ->
- %% Either Dst or Src (but not both) may be a pseudo temp.
- %% pseudo_move and pseudo_spill_move [XXX: not pseudo_tailcall]
- %% are special cases: in all other instructions, all temps must
- %% be non-pseudos after register allocation.
- case temp_is_spilled(Src, TempMap)
- andalso temp_is_spilled(Dst, TempMap)
- of
- true -> % Turn into pseudo_spill_move
- Temp = clone(Src, temp1(Strategy)),
- NewI = #pseudo_spill_move{src=Src,temp=Temp,dst=Dst},
- {[NewI], true};
- _ ->
- {[I], false}
- end.
-
-do_pseudo_set(I=#pseudo_set{dst=Dst}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
- NewI = I#pseudo_set{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_pseudo_spill_move(I=#pseudo_spill_move{temp=Temp}, TempMap, _Strategy) ->
- %% Temp is above the low water mark and must not have been spilled
- false = temp_is_spilled(Temp, TempMap),
- {[I], false}.
-
-do_pseudo_tailcall(I=#pseudo_tailcall{funv=FunV}, TempMap, Strategy) ->
- {FixFunV,NewFunV,DidSpill} = fix_funv(FunV, TempMap, Strategy),
- NewI = I#pseudo_tailcall{funv=NewFunV},
- {FixFunV ++ [NewI], DidSpill}.
-
-do_rdy(I=#rdy{dst=Dst}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
- NewI = I#rdy{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_sethi(I=#sethi{dst=Dst}, TempMap, Strategy) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap, Strategy),
- NewI = I#sethi{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_store(I=#store{src=Src,base=Base,disp=Disp}, TempMap, Strategy) ->
- {FixSrc,NewSrc,DidSpill1} = fix_src1(Src, TempMap, Strategy),
- {FixBase,NewBase,DidSpill2} = fix_src2(Base, TempMap, Strategy),
- {FixDisp,NewDisp,DidSpill3} = fix_src3_or_imm(Disp, TempMap, Strategy),
- NewI = I#store{src=NewSrc,base=NewBase,disp=NewDisp},
- {FixSrc ++ FixBase ++ FixDisp ++ [NewI], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_pseudo_fload(I=#pseudo_fload{base=Base}, TempMap, Strategy) ->
- {FixBase,NewBase,DidSpill} = fix_src1(Base, TempMap, Strategy),
- NewI = I#pseudo_fload{base=NewBase},
- {FixBase ++ [NewI], DidSpill}.
-
-do_pseudo_fstore(I=#pseudo_fstore{base=Base}, TempMap, Strategy) ->
- {FixBase,NewBase,DidSpill} = fix_src1(Base, TempMap, Strategy),
- NewI = I#pseudo_fstore{base=NewBase},
- {FixBase ++ [NewI], DidSpill}.
-
-%%% Fix Dst and Src operands.
-
-fix_funv(FunV, TempMap, Strategy) ->
- case FunV of
- #sparc_temp{} -> fix_src3(FunV, TempMap, Strategy);
- _ -> {[], FunV, false}
- end.
-
-fix_src2_or_imm(Src2, TempMap, Strategy) ->
- case Src2 of
- #sparc_temp{} -> fix_src2(Src2, TempMap, Strategy);
- _ -> {[], Src2, false}
- end.
-
-fix_src3_or_imm(Src3, TempMap, Strategy) ->
- case Src3 of
- #sparc_temp{} -> fix_src3(Src3, TempMap, Strategy);
- _ -> {[], Src3, false}
- end.
-
-fix_src1(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp1(Strategy)).
-
-temp1('new') -> [];
-temp1('fixed') -> hipe_sparc_registers:temp1().
-
-fix_src2(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp2(Strategy)).
-
-temp2('new') -> [];
-temp2('fixed') -> hipe_sparc_registers:temp2().
-
-fix_src3(Src, TempMap, Strategy) ->
- fix_src(Src, TempMap, temp3(Strategy)).
-
-temp3('new') -> [];
-temp3('fixed') -> hipe_sparc_registers:temp3().
-
-fix_src(Src, TempMap, RegOpt) ->
- case temp_is_spilled(Src, TempMap) of
- true ->
- NewSrc = clone(Src, RegOpt),
- {[hipe_sparc:mk_pseudo_move(Src, NewSrc)], NewSrc, true};
- _ ->
- {[], Src, false}
- end.
-
-fix_dst(Dst, TempMap, Strategy) ->
- case temp_is_spilled(Dst, TempMap) of
- true ->
- NewDst = clone(Dst, temp1(Strategy)),
- {[hipe_sparc:mk_pseudo_move(NewDst, Dst)], NewDst, true};
- _ ->
- {[], Dst, false}
- end.
-
-%%% Check if an operand is a pseudo-temp.
-
-temp_is_spilled(Temp, []) -> % special case for naive regalloc
- not(hipe_sparc:temp_is_precoloured(Temp));
-temp_is_spilled(Temp, TempMap) ->
- case hipe_sparc:temp_is_allocatable(Temp) of
- true ->
- Reg = hipe_sparc:temp_reg(Temp),
- tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
- false -> true
- end.
-
-%%% Make a certain reg into a clone of Temp.
-
-clone(Temp, RegOpt) ->
- Type = hipe_sparc:temp_type(Temp),
- case RegOpt of
- [] -> hipe_sparc:mk_new_temp(Type);
- Reg -> hipe_sparc:mk_temp(Reg, Type)
- end.
diff --git a/lib/hipe/sparc/hipe_sparc_ra_postconditions_fp.erl b/lib/hipe/sparc/hipe_sparc_ra_postconditions_fp.erl
deleted file mode 100644
index 5fa3a5fc59..0000000000
--- a/lib/hipe/sparc/hipe_sparc_ra_postconditions_fp.erl
+++ /dev/null
@@ -1,126 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_ra_postconditions_fp).
-
--export([check_and_rewrite/2]).
-
--include("hipe_sparc.hrl").
-
-check_and_rewrite(CFG, Coloring) ->
- TempMap = hipe_temp_map:cols2tuple(Coloring, hipe_sparc_specific_fp,
- no_context),
- do_bbs(hipe_sparc_cfg:labels(CFG), TempMap, CFG, false).
-
-do_bbs([], _TempMap, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_sparc_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, [], DidSpill0),
- CFG = hipe_sparc_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap),
- do_insns(Insns, TempMap, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
-do_insns([], _TempMap, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap) ->
- case I of
- #fp_binary{} -> do_fp_binary(I, TempMap);
- #fp_unary{} -> do_fp_unary(I, TempMap);
- #pseudo_fload{} -> do_pseudo_fload(I, TempMap);
- #pseudo_fmove{} -> do_pseudo_fmove(I, TempMap);
- #pseudo_fstore{} -> do_pseudo_fstore(I, TempMap);
- #pseudo_spill_fmove{} -> do_pseudo_spill_fmove(I, TempMap);
- _ -> {[I], false}
- end.
-
-%%% Fix relevant instruction types.
-
-do_fp_binary(I=#fp_binary{src1=Src1,src2=Src2,dst=Dst}, TempMap) ->
- {FixSrc1,NewSrc1,DidSpill1} = fix_src(Src1, TempMap),
- {FixSrc2,NewSrc2,DidSpill2} = fix_src(Src2, TempMap),
- {FixDst,NewDst,DidSpill3} = fix_dst(Dst, TempMap),
- NewI = I#fp_binary{src1=NewSrc1,src2=NewSrc2,dst=NewDst},
- {FixSrc1 ++ FixSrc2 ++ [NewI | FixDst], DidSpill1 or DidSpill2 or DidSpill3}.
-
-do_fp_unary(I=#fp_unary{src=Src,dst=Dst}, TempMap) ->
- {FixSrc,NewSrc,DidSpill1} = fix_src(Src, TempMap),
- {FixDst,NewDst,DidSpill2} = fix_dst(Dst, TempMap),
- NewI = I#fp_unary{src=NewSrc,dst=NewDst},
- {FixSrc ++ [NewI | FixDst], DidSpill1 or DidSpill2}.
-
-do_pseudo_fload(I=#pseudo_fload{dst=Dst}, TempMap) ->
- {FixDst,NewDst,DidSpill} = fix_dst(Dst, TempMap),
- NewI = I#pseudo_fload{dst=NewDst},
- {[NewI | FixDst], DidSpill}.
-
-do_pseudo_fmove(I=#pseudo_fmove{src=Src,dst=Dst}, TempMap) ->
- case temp_is_spilled(Src, TempMap)
- andalso temp_is_spilled(Dst, TempMap)
- of
- true -> % Turn into pseudo_spill_fmove
- Temp = clone(Src),
- NewI = #pseudo_spill_fmove{src=Src,temp=Temp,dst=Dst},
- {[NewI], true};
- _ ->
- {[I], false}
- end.
-
-do_pseudo_fstore(I=#pseudo_fstore{src=Src}, TempMap) ->
- {FixSrc,NewSrc,DidSpill} = fix_src(Src, TempMap),
- NewI = I#pseudo_fstore{src=NewSrc},
- {FixSrc ++ [NewI], DidSpill}.
-
-do_pseudo_spill_fmove(I=#pseudo_spill_fmove{temp=Temp}, TempMap) ->
- %% Temp is above the low water mark and must not have been spilled
- false = temp_is_spilled(Temp, TempMap),
- {[I], false}.
-
-%%% Fix Dst and Src operands.
-
-fix_src(Src, TempMap) ->
- case temp_is_spilled(Src, TempMap) of
- true ->
- NewSrc = clone(Src),
- {[hipe_sparc:mk_pseudo_fmove(Src, NewSrc)], NewSrc, true};
- _ ->
- {[], Src, false}
- end.
-
-fix_dst(Dst, TempMap) ->
- case temp_is_spilled(Dst, TempMap) of
- true ->
- NewDst = clone(Dst),
- {[hipe_sparc:mk_pseudo_fmove(NewDst, Dst)], NewDst, true};
- _ ->
- {[], Dst, false}
- end.
-
-%%% Check if an operand is a pseudo-temp.
-
-temp_is_spilled(Temp, TempMap) ->
- case hipe_sparc:temp_is_allocatable(Temp) of
- true ->
- Reg = hipe_sparc:temp_reg(Temp),
- tuple_size(TempMap) > Reg andalso hipe_temp_map:is_spilled(Reg, TempMap);
- false -> true
- end.
-
-%%% Create a new temp with the same type as an old one.
-
-clone(Temp) ->
- Type = hipe_sparc:temp_type(Temp), % XXX: always double?
- hipe_sparc:mk_new_temp(Type).
diff --git a/lib/hipe/sparc/hipe_sparc_registers.erl b/lib/hipe/sparc/hipe_sparc_registers.erl
deleted file mode 100644
index 47876e21d2..0000000000
--- a/lib/hipe/sparc/hipe_sparc_registers.erl
+++ /dev/null
@@ -1,291 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_registers).
-
--export([reg_name_gpr/1,
- reg_name_fpr/1,
- first_virtual/0,
- is_precoloured_gpr/1,
- is_precoloured_fpr/1,
- all_precoloured/0, % for coalescing ra
- return_value/0,
- temp1/0,
- temp2/0,
- temp3/0,
- heap_pointer/0,
- stack_pointer/0,
- proc_pointer/0,
- return_address/0,
- g0/0,
- %% heap_limit/0,
- %% fcalls/0,
- allocatable_gpr/0, % for coalescing ra
- allocatable_fpr/0,
- is_fixed/1, % for graph_coloring ra
- nr_args/0,
- arg/1,
- args/1,
- is_arg/1, % for linear_scan ra
- call_clobbered/0,
- tailcall_clobbered/0,
- live_at_return/0
- ]).
-
--include("../rtl/hipe_literals.hrl").
-
--define(G0, 0).
--define(G1, 1).
--define(G2, 2).
--define(G3, 3).
--define(G4, 4).
--define(G5, 5).
--define(G6, 6).
--define(G7, 7).
--define(O0, 8).
--define(O1, 9).
--define(O2, 10).
--define(O3, 11).
--define(O4, 12).
--define(O5, 13).
--define(O6, 14).
--define(O7, 15).
--define(L0, 16).
--define(L1, 17).
--define(L2, 18).
--define(L3, 19).
--define(L4, 20).
--define(L5, 21).
--define(L6, 22).
--define(L7, 23).
--define(I0, 24).
--define(I1, 25).
--define(I2, 26).
--define(I3, 27).
--define(I4, 28).
--define(I5, 29).
--define(I6, 30).
--define(I7, 31).
--define(LAST_PRECOLOURED,31). % must handle both GRP and FPR ranges
-
--define(RA, ?O7).
-
--define(ARG0, ?O1).
--define(ARG1, ?O2).
--define(ARG2, ?O3).
--define(ARG3, ?O4).
--define(ARG4, ?O5).
--define(ARG5, ?O0).
-
--define(TEMP1, ?I3). % stores RA around inc_stack calls, must be C calleE-save
--define(TEMP2, ?I4).
--define(TEMP3, ?I5).
-
--define(RETURN_VALUE, ?O0).
--define(HEAP_POINTER, ?I2).
--define(STACK_POINTER, ?I1).
--define(PROC_POINTER, ?I0).
-
-reg_name_gpr(R) ->
- case R of
- ?G0 -> "%g0";
- ?G1 -> "%g1";
- ?G2 -> "%g2";
- ?G3 -> "%g3";
- ?G4 -> "%g4";
- ?G5 -> "%g5";
- ?G6 -> "%g6";
- ?G7 -> "%g7";
- ?O0 -> "%o0";
- ?O1 -> "%o1";
- ?O2 -> "%o2";
- ?O3 -> "%o3";
- ?O4 -> "%o4";
- ?O5 -> "%o5";
- ?O6 -> "%sp";
- ?O7 -> "%o7";
- ?L0 -> "%l0";
- ?L1 -> "%l1";
- ?L2 -> "%l2";
- ?L3 -> "%l3";
- ?L4 -> "%l4";
- ?L5 -> "%l5";
- ?L6 -> "%l6";
- ?L7 -> "%l7";
- ?I0 -> "%i0";
- ?I1 -> "%i1";
- ?I2 -> "%i2";
- ?I3 -> "%i3";
- ?I4 -> "%i4";
- ?I5 -> "%i5";
- ?I6 -> "%fp";
- ?I7 -> "%i7";
- %% to handle code before regalloc:
- _ -> "%r" ++ integer_to_list(R)
- end.
-
-reg_name_fpr(R) -> [$f | integer_to_list(2*R)].
-
-%%% Must handle both GPR and FPR ranges.
-first_virtual() -> ?LAST_PRECOLOURED + 1.
-
-%%% These two tests have the same implementation, but that's
-%%% not something we should cast in stone in the interface.
-is_precoloured_gpr(R) -> R =< ?LAST_PRECOLOURED.
-is_precoloured_fpr(R) -> R =< ?LAST_PRECOLOURED.
-
-all_precoloured() ->
- %% <%g6, %g7, %o6, %i6> should be skipped as they are unused.
- %% Unfortunately, gaps in the list of precoloured registers
- %% cause the graph_color register allocator to create bogus
- %% assignments for those "registers", which in turn causes
- %% the "precoloured reg must map to itself" sanity check in
- %% the frame module to signal errors.
- [?G0, ?G1, ?G2, ?G3, ?G4, ?G5, ?G6, ?G7,
- ?O0, ?O1, ?O2, ?O3, ?O4, ?O5, ?O6, ?O7,
- ?L0, ?L1, ?L2, ?L3, ?L4, ?L5, ?L6, ?L7,
- ?I0, ?I1, ?I2, ?I3, ?I4, ?I5, ?I6, ?I7].
-
-return_value() -> ?RETURN_VALUE.
-
-temp1() -> ?TEMP1.
-temp2() -> ?TEMP2.
-temp3() -> ?TEMP3.
-
-heap_pointer() -> ?HEAP_POINTER.
-
-stack_pointer() -> ?STACK_POINTER.
-
-proc_pointer() -> ?PROC_POINTER.
-
-return_address() -> ?RA.
-
-g0() -> ?G0.
-
-allocatable_gpr() ->
- %% %g0 is not writable
- %% %g6, %g7, %o6, and %i6 are reserved for C
- %% %i0, %i1, and %i2 are fixed global registers
- %% %i4 may be used by the frame module for large load/store offsets
- [ ?G1, ?G2, ?G3, ?G4, ?G5,
- ?O0, ?O1, ?O2, ?O3, ?O4, ?O5, ?O7,
- ?L0, ?L1, ?L2, ?L3, ?L4, ?L5, ?L6, ?L7,
- ?I3, ?I5, ?I7].
-
-allocatable_fpr() ->
- %% We expose 16 virtual fp regs, 0-15, corresponding to the
- %% f0/f2/f4/.../f28/f30 double-precision hardware fp regs.
- %% The mapping is done by reg_name_fpr/1 and the assembler.
- %% We ignore f32/.../f60 since they cannot be used in loads
- %% or stores for non 8-byte aligned addresses.
- [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15].
-
-%% Needed for hipe_graph_coloring_regalloc.
-%% Presumably true for Reg in AllPrecoloured \ Allocatable.
-is_fixed(Reg) ->
- case Reg of
- ?HEAP_POINTER -> true;
- ?STACK_POINTER -> true;
- ?PROC_POINTER -> true;
- %% The following cases are required for linear scan:
- %% it gets confused if it sees a register which is
- %% neither allocatable nor global (fixed or one of
- %% the scratch registers set aside for linear scan).
- ?G0 -> true;
- ?G6 -> true;
- ?G7 -> true;
- ?O6 -> true;
- ?I6 -> true;
- _ -> false
- end.
-
-nr_args() -> ?SPARC_NR_ARG_REGS.
-
-args(Arity) when is_integer(Arity) ->
- N = erlang:min(Arity, ?SPARC_NR_ARG_REGS),
- args(N-1, []).
-
-args(I, Rest) when is_integer(I), I < 0 -> Rest;
-args(I, Rest) -> args(I-1, [arg(I) | Rest]).
-
-arg(N) ->
- if N < ?SPARC_NR_ARG_REGS ->
- case N of
- 0 -> ?ARG0;
- 1 -> ?ARG1;
- 2 -> ?ARG2;
- 3 -> ?ARG3;
- 4 -> ?ARG4;
- 5 -> ?ARG5
- end
- end.
-
-is_arg(R) ->
- case R of
- ?ARG0 -> ?SPARC_NR_ARG_REGS > 0;
- ?ARG1 -> ?SPARC_NR_ARG_REGS > 1;
- ?ARG2 -> ?SPARC_NR_ARG_REGS > 2;
- ?ARG3 -> ?SPARC_NR_ARG_REGS > 3;
- ?ARG4 -> ?SPARC_NR_ARG_REGS > 4;
- ?ARG5 -> ?SPARC_NR_ARG_REGS > 5;
- _ -> false
- end.
-
-%% Note: the fact that allocatable_gpr() is a subset of call_clobbered() is
-%% hard-coded in hipe_sparc_defuse:insn_defs_all_gpr/1
-call_clobbered() -> % does the RA strip the type or not?
- [%% ?G0 is the non-allocatable constant zero
- {?G1,tagged},{?G1,untagged},
- {?G2,tagged},{?G2,untagged},
- {?G3,tagged},{?G3,untagged},
- {?G4,tagged},{?G4,untagged},
- {?G5,tagged},{?G5,untagged},
- %% ?G6 is reserved for C
- %% ?G7 is reserved for C
- {?O0,tagged},{?O0,untagged},
- {?O1,tagged},{?O1,untagged},
- {?O2,tagged},{?O2,untagged},
- {?O3,tagged},{?O3,untagged},
- {?O4,tagged},{?O4,untagged},
- {?O5,tagged},{?O5,untagged},
- %% ?O6 is reserved for C
- {?O7,tagged},{?O7,untagged},
- {?L0,tagged},{?L0,untagged},
- {?L1,tagged},{?L1,untagged},
- {?L2,tagged},{?L2,untagged},
- {?L3,tagged},{?L3,untagged},
- {?L4,tagged},{?L4,untagged},
- {?L5,tagged},{?L5,untagged},
- {?L6,tagged},{?L6,untagged},
- {?L7,tagged},{?L7,untagged},
- %% ?I0 is fixed (P)
- %% ?I1 is fixed (NSP)
- %% ?I2 is fixed (HP)
- {?I3,tagged},{?I3,untagged},
- {?I4,tagged},{?I4,untagged},
- {?I5,tagged},{?I5,untagged},
- %% ?I6 is reserved for C
- {?I7,tagged},{?I7,untagged}
- ].
-
-tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}
- ,{?RA,tagged},{?RA,untagged}
- ].
-
-live_at_return() ->
- [{?HEAP_POINTER,untagged},
- {?STACK_POINTER,untagged},
- {?PROC_POINTER,untagged}
- ].
diff --git a/lib/hipe/sparc/hipe_sparc_subst.erl b/lib/hipe/sparc/hipe_sparc_subst.erl
deleted file mode 100644
index ce3bbb813a..0000000000
--- a/lib/hipe/sparc/hipe_sparc_subst.erl
+++ /dev/null
@@ -1,82 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_sparc_subst).
--export([insn_temps/2]).
--include("hipe_sparc.hrl").
-
-%% These should be moved to hipe_sparc and exported
--type temp() :: #sparc_temp{}.
--type src2() :: temp() | #sparc_simm13{}.
--type src2b() :: src2() | #sparc_uimm5{}.
--type funv() :: #sparc_mfa{} | #sparc_prim{} | temp().
--type arg() :: temp() | integer().
--type insn() :: tuple(). % for now
-
--type subst_fun() :: fun((temp()) -> temp()).
-
-%% @doc Maps over the temporaries in an instruction
--spec insn_temps(subst_fun(), insn()) -> insn().
-insn_temps(T, I) ->
- S2 = fun(O) -> src2_temps(T, O) end,
- S2B = fun(O) -> src2b_temps(T, O) end,
- Arg = fun(O) -> arg_temps(T, O) end,
- case I of
- #alu{src1=L,src2=R,dst=D} -> I#alu{src1=T(L),src2=S2B(R),dst=T(D)};
- #bp{} -> I;
- #comment{} -> I;
- #jmp{src1=L,src2=R} -> I#jmp{src1=T(L),src2=S2(R)};
- #label{} -> I;
- #pseudo_bp{} -> I;
- #pseudo_call{funv=F} -> I#pseudo_call{funv=funv_temps(T,F)};
- #pseudo_call_prepare{} -> I;
- #pseudo_move{src=S,dst=D} -> I#pseudo_move{src=T(S),dst=T(D)};
- #pseudo_ret{} -> I;
- #pseudo_set{dst=D}-> I#pseudo_set{dst=T(D)};
- #pseudo_spill_move{src=S,temp=U,dst=D} ->
- I#pseudo_spill_move{src=T(S),temp=T(U),dst=T(D)};
- #pseudo_tailcall{funv=F,stkargs=Stk} ->
- I#pseudo_tailcall{funv=funv_temps(T,F),stkargs=lists:map(Arg,Stk)};
- #pseudo_tailcall_prepare{} -> I;
- #rdy{dst=D} -> I#rdy{dst=T(D)};
- #sethi{dst=D} -> I#sethi{dst=T(D)};
- #store{src=S,base=B,disp=D} -> I#store{src=T(S),base=T(B),disp=S2(D)};
- #fp_binary{src1=L,src2=R,dst=D} ->
- I#fp_binary{src1=T(L),src2=T(R),dst=T(D)};
- #fp_unary{src=S,dst=D} -> I#fp_unary{src=T(S),dst=T(D)};
- #pseudo_fload{base=B,disp=Di,dst=Ds} ->
- I#pseudo_fload{base=T(B),disp=S2(Di),dst=T(Ds)};
- #pseudo_fmove{src=S,dst=D} -> I#pseudo_fmove{src=T(S),dst=T(D)};
- #pseudo_fstore{src=S,base=B,disp=D} ->
- I#pseudo_fstore{src=T(S),base=T(B),disp=S2(D)};
- #pseudo_spill_fmove{src=S,temp=U,dst=D} ->
- I#pseudo_spill_fmove{src=T(S),temp=T(U),dst=T(D)}
- end.
-
--spec src2_temps(subst_fun(), src2()) -> src2().
-src2_temps(_SubstTemp, I=#sparc_simm13{}) -> I;
-src2_temps(SubstTemp, T=#sparc_temp{}) -> SubstTemp(T).
-
--spec src2b_temps(subst_fun(), src2b()) -> src2b().
-src2b_temps(_SubstTemp, I=#sparc_uimm5{}) -> I;
-src2b_temps(SubstTemp, Op) -> src2_temps(SubstTemp, Op).
-
--spec funv_temps(subst_fun(), funv()) -> funv().
-funv_temps(_SubstTemp, M=#sparc_mfa{}) -> M;
-funv_temps(_SubstTemp, P=#sparc_prim{}) -> P;
-funv_temps(SubstTemp, T=#sparc_temp{}) -> SubstTemp(T).
-
--spec arg_temps(subst_fun(), arg()) -> arg().
-arg_temps(_SubstTemp, Imm) when is_integer(Imm) -> Imm;
-arg_temps(SubstTemp, T=#sparc_temp{}) -> SubstTemp(T).
diff --git a/lib/hipe/ssa/hipe_ssa.inc b/lib/hipe/ssa/hipe_ssa.inc
deleted file mode 100644
index 29e8b92266..0000000000
--- a/lib/hipe/ssa/hipe_ssa.inc
+++ /dev/null
@@ -1,973 +0,0 @@
-%% -*- mode: erlang; erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%----------------------------------------------------------------------
-%% File : hipe_ssa.inc
-%% Authors : Christoffer Vikström, Daniel Deogun, and Jesper Bengtsson
-%% Created : March 2002
-%% Purpose : Provides code which converts the code of a CFG into SSA
-%% (Static Single Assignment) form and back.
-%% A routine to check for SSA-ness is also provided.
-%%
-%% Major Modifications:
-%% * Feb 2003: Per Gustafsson - added SSA checker.
-%% * Aug 2003: Per Gustafsson - added removal of dead code.
-%% * Feb 2004: Kostis Sagonas - made it work on RTL level too.
-%% * Feb 2004: Tobias Lindahl - re-wrote the unconvert/1 function.
-%%----------------------------------------------------------------------
-
--export([convert/1, check/1, unconvert/1, remove_dead_code/1]).
-
--include("../main/hipe.hrl").
--include("../flow/cfg.hrl"). %% needed for the specs
--include("../ssa/hipe_ssa_liveness.inc"). %% needed for dead code removal
-
-%%----------------------------------------------------------------------
-%%
-%% NOTE! When the phi-instructions are placed, it is important that
-%% the internal order is preserved. Otherwise the (correct) order:
-%%
-%% v1 := phi({1, v2}, {2, v11})
-%% v2 := phi({1, v11}, {2, v12})
-%%
-%% can become (the incorrect)
-%%
-%% v2 := phi({1, v11}, {2, v12})
-%% v1 := phi({1, v2}, {2, v11})
-%%
-%% that will set v1 to the _new_ value of v2 instead of the old value.
-%%
-%%----------------------------------------------------------------------
-
--spec convert(#cfg{}) -> #cfg{}.
-
-convert(CFG) ->
- CFG1 = insertNewStartNode(CFG),
-
- ?opt_start_timer("Dominator Tree construction"),
- DomTree = hipe_dominators:domTree_create(CFG1),
- ?opt_stop_timer("Dominator Tree construction done"),
-
- ?opt_start_timer("Dominance Frontier"),
- DomFrontier = hipe_dominators:domFrontier_create(CFG1, DomTree),
- ?opt_stop_timer("Dominance Frontier done"),
-
- ?opt_start_timer("placement of Phi-nodes"),
- CFG2 = place_phi(CFG1, DomFrontier),
- ?opt_stop_timer("placement of Phi-nodes done"),
-
- ?opt_start_timer("Rename"),
- CFG3 = rename(CFG2, DomTree),
- ?opt_stop_timer("Rename done"),
-
- CFG3.
-
-%%----------------------------------------------------------------------
-
-insertNewStartNode(CFG) ->
- StartLabel = ?CFG:start_label(CFG),
- NewStartLabel = ?CODE:label_name(?CODE:mk_new_label()),
- BB = hipe_bb:mk_bb([?CODE:mk_goto(StartLabel)]),
- CFG2 = ?CFG:bb_add(CFG, NewStartLabel, BB),
- ?CFG:start_label_update(CFG2, NewStartLabel).
-
-
-%%======================================================================
-%% PlacePhi Algorithm
-%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Procedure : place_phi/2
-%% Purpose : Places phi nodes at appropriate places in the CFG.
-%% Arguments : CFG - Control Flow Graph.
-%% DF - Dominance Frontier.
-%% Returns : CFG with phi functions.
-%%----------------------------------------------------------------------
-
-place_phi(CFG, DF) ->
- AssMap = insertParams(CFG),
- AssMap2 = preProcess(CFG, AssMap),
- VarList = gb_trees:to_list(AssMap2),
- Liveness = ?LIVENESS:analyze(CFG),
- variableTraverse(CFG, DF, gb_trees:empty(), gb_trees:empty(),
- 0, AssMap2, Liveness, VarList).
-
-%%----------------------------------------------------------------------
-%% Procedure : insertParams/1
-%% Purpose : Inserts the parameters of the CFG into the AssMap.
-%% Arguments : CFG - Control Flow Graph
-%% Returns : AssMap - Assignment map.
-%%----------------------------------------------------------------------
-
-insertParams(CFG) ->
- StartLabel = ?CFG:start_label(CFG),
- Params = ?CFG:params(CFG),
- insertParams(Params, StartLabel, gb_trees:empty()).
-
-insertParams([Param|T], StartLabel, AssMap) ->
- insertParams(T, StartLabel, gb_trees:insert(Param, [StartLabel], AssMap));
-insertParams([], _, AssMap) -> AssMap.
-
-%%----------------------------------------------------------------------
-%% Procedure : preProcessg/2
-%% Purpose : Creates the assignment map.
-%% Arguments : CFG - Control Flow Graph
-%% AssMap - Assignment map
-%% Returns : AssMap.
-%%----------------------------------------------------------------------
-
-preProcess(CFG, AssMap) ->
- traverseLabels(CFG, ?CFG:labels(CFG), AssMap).
-
-%%----------------------------------------------------------------------
-%% Procedure : traverseLabels/3
-%% Purpose : Traverses all labels and adds all assignments in the basic
-%% block to the assignment map.
-%% Arguments : CFG - Control Flow Graph
-%% AssMap - Assignment Map
-%% Label - A label for a node
-%% Returns : AssMap.
-%%----------------------------------------------------------------------
-
-traverseLabels(CFG, [Label|T], AssMap) ->
- Code = get_code_from_label(CFG, Label),
- NewVarList = getAssignments(Code),
- traverseLabels(CFG, T, updateAssMap(NewVarList, Label, AssMap));
-traverseLabels(_, [], AssMap) -> AssMap.
-
-%%----------------------------------------------------------------------
-%% Procedure : getAssignments/1
-%% Purpose : Retrieves all assigned variables in a basic block.
-%% Arguments : InstrLst - A list of instructions from a basic block.
-%% VarList - A list of variables.
-%% Returns : VarList.
-%% Notes : This function may return a list containing duplicates.
-%%----------------------------------------------------------------------
-
-getAssignments(InstrList) -> getAssignments(InstrList, []).
-
-getAssignments([Instr|T], VarList) ->
- getAssignments(T, defs_to_rename(Instr) ++ VarList);
-getAssignments([], VarList) -> VarList.
-
-%%----------------------------------------------------------------------
-%% Procedure : updateAssMap/3
-%% Purpose : Updates the assignment map with. Each variable in the AssVar
-%% list is inserted with the value Label.
-%% Arguments : Label - a label of a node
-%% AssVar - a variable that is assigned at Label
-%% AssMap - Assignment map.
-%% Returns : AssMap.
-%%----------------------------------------------------------------------
-
-updateAssMap([AssVar|T], Label, AssMap) ->
- Lst = getAssMap(AssVar, AssMap),
- updateAssMap(T, Label, gb_trees:enter(AssVar, [Label|Lst], AssMap));
-updateAssMap([], _, AssMap) -> AssMap.
-
-getAssMap(AssVar, AssMap) ->
- case gb_trees:lookup(AssVar, AssMap) of
- {value, L} -> L;
- none -> []
- end.
-
-%%----------------------------------------------------------------------
-%% Procedure : variableTraverse/7
-%% Purpose : This function traverses all variables and adds phi functions
-%% at appropriate nodes.
-%% Arguments : CFG - Control Flow Graph
-%% DFMap - Dominance Frontier Map
-%% HasAlready - A map of nodes which already have phi functions
-%% Work -
-%% IterCount - Counter of how many iterations have been done
-%% AssMap - Assignment map
-%% VarLst - Variable list that is traversed
-%% Returns : CFG.
-%%----------------------------------------------------------------------
-
-variableTraverse(CFG, DFMap, HasAlready, Work,
- IterCount, AssMap, Liveness, [{Var,_}|VarLst]) ->
- IterCount2 = IterCount + 1,
- DefLst = getAssMap(Var, AssMap),
- {Work2, WorkLst2} = workListBuilder(DefLst, Work, [], IterCount2),
- {CFG2, HasAlready2, Work3} = doWork(CFG, DFMap, HasAlready,
- Work2, IterCount2, WorkLst2,
- Var, Liveness),
- variableTraverse(CFG2, DFMap, HasAlready2, Work3,
- IterCount2, AssMap, Liveness, VarLst);
-variableTraverse(CFG, _, _, _, _, _, _, []) -> CFG.
-
-%%----------------------------------------------------------------------
-%% Procedure : workListBuilder/4
-%% Purpose : Builds the worklist that the algorithm is working on.
-%% Arguments : Work -
-%% WorkLst - The worklist that is worked through
-%% IterCount - Counter of how many itterations that has been done
-%% Node - A node in the CFG
-%% Returns :
-%%----------------------------------------------------------------------
-
-workListBuilder([Node|T], Work, WorkLst, IterCount) ->
- case getCount(Node, Work) of
- 0 ->
- Work2 = gb_trees:enter(Node, IterCount, Work),
- workListBuilder(T, Work2, [Node|WorkLst], IterCount);
- _ ->
- Work2 = gb_trees:enter(Node, IterCount, Work),
- workListBuilder(T, Work2, [Node|WorkLst], IterCount)
- end;
-workListBuilder([], Work, WorkLst, _IterCount) ->
- {Work, WorkLst}.
-
-getCount(Key, Dict) ->
- case gb_trees:lookup(Key, Dict) of
- {value, V} -> V;
- none -> 0
- end.
-
-%%----------------------------------------------------------------------
-%% Procedure : doWork/7
-%% Purpose : This procedure works itself through the worklist and checks
-%% if a node needs any phi functions.
-%% Arguments : CFG - Control Flow Graph
-%% DFMap - Dominance Frontier Map
-%% HasAlready - A map of nodes that already have phi functions
-%% Work -
-%% IterCount - Counter of how many iterations have taken place
-%% WorkLst - The worklist that is worked through
-%% Var - Variable
-%% Returns : {CFG, HasAlready, Work}
-%%----------------------------------------------------------------------
-
-doWork(CFG, DFMap, HasAlready, Work, IterCount,
- [Node|WorkLst], Var, Liveness) ->
- DFofX = hipe_dominators:domFrontier_get(Node, DFMap),
- {CFG2, HasAlready2, Work2, WorkLst2} =
- checkPhiNeeds(CFG, DFofX, HasAlready, Work,
- IterCount, WorkLst, Var, Liveness),
- doWork(CFG2, DFMap, HasAlready2, Work2,
- IterCount, WorkLst2, Var, Liveness);
-doWork(CFG, _, HasAlready, Work, _, [], _, _) ->
- {CFG, HasAlready, Work}.
-
-%%----------------------------------------------------------------------
-%% Procedure : checkPhiNeeds/7
-%% Purpose : This function checks if a node needs a phi function and adds
-%% one if its needed.
-%% Arguments : CFG - Control Flow Graph
-%% DFofX - Dominance Frontier of a node
-%% HasAlready - A map of nodes that already have phi functions
-%% Work -
-%% IterCount - Counter of how many iterations have taken place
-%% WorkLst - The worklist that is worked through
-%% Var - Variable
-%% Returns : {CFG, HasAlready, Work, WorkLst}
-%%----------------------------------------------------------------------
-
-checkPhiNeeds(CFG, [Node|DFofX], HasAlready, Work,
- IterCount, WorkLst, Var, Liveness) ->
- case getCount(Node, HasAlready) < IterCount of
- true ->
- LiveIn = ?LIVENESS:livein(Liveness, Node),
- case lists:member(Var, LiveIn) of
- true ->
- CFG2 = insertPhiCode(CFG, Node, Var),
- HasAlready2 = gb_trees:enter(Node, IterCount, HasAlready),
- case getCount(Node, Work) < IterCount of
- true ->
- Work2 = gb_trees:enter(Node, IterCount, Work),
- WorkLst2 = [Node|WorkLst],
- checkPhiNeeds(CFG2, DFofX, HasAlready2, Work2,
- IterCount, WorkLst2, Var, Liveness);
- false ->
- checkPhiNeeds(CFG2, DFofX, HasAlready2, Work,
- IterCount, WorkLst, Var, Liveness)
- end;
- false ->
- checkPhiNeeds(CFG, DFofX, HasAlready, Work, IterCount,
- WorkLst, Var, Liveness)
- end;
- false ->
- checkPhiNeeds(CFG, DFofX, HasAlready, Work, IterCount,
- WorkLst, Var, Liveness)
- end;
-checkPhiNeeds(CFG, [], HasAlready, Work, _, WorkLst, _, _) ->
- {CFG, HasAlready, Work, WorkLst}.
-
-%%----------------------------------------------------------------------
-%% Procedure : insertPhiCode/3
-%% Purpose :
-%% Arguments : CFG - Control Flow Graph
-%% Node - A node
-%% Var - A variable
-%% Returns : CFG
-%%----------------------------------------------------------------------
-
-insertPhiCode(CFG, Node, Var) ->
- BB = ?CFG:bb(CFG, Node),
- Phi = ?CODE:mk_phi(Var),
- Code = [Phi | hipe_bb:code(BB)],
- ?CFG:bb_add(CFG, Node, hipe_bb:code_update(BB, Code)).
-
-
-%%======================================================================
-%% SSA Renaming pass
-%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Procedure : rename/2
-%% Purpose : Renames all the variables in the CFG according to the SSA
-%% conversion algorithm.
-%% Arguments : CFG - The CFG being translated.
-%% DomTree - The dominator tree of the CFG.
-%% Returns : A CFG where all variables are renamed.
-%%----------------------------------------------------------------------
-
-rename(CFG, DomTree) ->
- %% Reset the appropriate variable index so that we start from low
- %% variable numbers again
- reset_var_indx(),
- {CFG2,Current} = insertRenamedParams(CFG),
- rename(CFG2, ?CFG:start_label(CFG2), DomTree, Current).
-
-rename(CFG, Node, DomTree, Current) ->
- BB = ?CFG:bb(CFG, Node),
- Statements = hipe_bb:code(BB),
- {Statements2,Current2} = renameVars(Statements, Current),
- CFG1 = ?CFG:bb_add(CFG, Node, hipe_bb:code_update(BB, Statements2)),
- Succ = ?CFG:succ(CFG1, Node),
- CFG2 = updateSuccPhi(Succ, Node, CFG1, Current2),
- Children = hipe_dominators:domTree_getChildren(Node, DomTree),
- childrenRename(Children, CFG2, DomTree, Current2).
-
-%%----------------------------------------------------------------------
-%% Procedure : childrenRename/5
-%% Purpose : Renames all the nodes in a list according to the SSA
-%% conversion algorithm.
-%% Arguments : ChildList - the list of nodes being renamed
-%% CFG - the CFG that the children are a part of
-%% DomTree - The dominator tree for the CFG
-%% Current - the current index of all variables encountered
-%% Returns : CFG
-%%----------------------------------------------------------------------
-
-childrenRename([Child|Children], CFG, DomTree, Current) ->
- CFG2 = rename(CFG, Child, DomTree, Current),
- childrenRename(Children, CFG2, DomTree, Current);
-childrenRename([], CFG, _, _) ->
- CFG.
-
-%%----------------------------------------------------------------------
-%% Procedure : renameVars/3
-%% Purpose : Renames the variables in basic block
-%% Arguments : Statements - the basic block
-%% Current - the current index of all variables encountered
-%% Returns : {Statements,Current}
-%%----------------------------------------------------------------------
-
-renameVars(Statements, Current) ->
- renameVars(Statements, Current, []).
-
-renameVars([Statement|Statements], Current, Result) ->
- Statement2 = renameUses(Statement, Current),
- {Statement3,Current2} = renameDefs(Statement2, Current),
- renameVars(Statements, Current2, [Statement3|Result]);
-renameVars([], Current, Result) ->
- {lists:reverse(Result),Current}.
-
-%%----------------------------------------------------------------------
-%% Procedure : renameUses/2
-%% Purpose : Renames all the uses of a variable in a statement.
-%% Arguments : Statement - the statement being renamed.
-%% Current - the current index of all variables encountered.
-%% Returns : Statement
-%%----------------------------------------------------------------------
-
-renameUses(Statement, Current) ->
- case ?CODE:is_phi(Statement) of
- true -> Statement;
- false -> VarList = uses_to_rename(Statement),
- updateStatementUses(VarList, Statement, Current)
- end.
-
-%%----------------------------------------------------------------------
-%% Procedure : updateStatementUses/3
-%% Purpose : Traverses the variable list and renames all the instances
-%% of a variable in the Statement uses to its current value.
-%% Arguments : VarList - the list of variables being updated.
-%% Statement - the statement being updated.
-%% Current - the current index of all variables encountered.
-%% Returns : An updated statement.
-%%----------------------------------------------------------------------
-
-updateStatementUses(Vars, Statement, Current) ->
- Substs = [{Var,gb_trees:get(Var, Current)} || Var <- Vars],
- ?CODE:subst_uses(Substs, Statement).
-
-%%----------------------------------------------------------------------
-%% Procedure : renameDefs/3
-%% Purpose : Renames all the definitons in Statement.
-%% Arguments : Statement - the statement where the definitions are being
-%% renamed.
-%% Current - the current index of all variables encountered.
-%% Returns : Statement
-%%----------------------------------------------------------------------
-
-renameDefs(Statement, Current) ->
- VarList = defs_to_rename(Statement),
- updateStatementDefs(VarList, Statement, Current).
-
-%%----------------------------------------------------------------------
-%% Procedure : updateStatementDefs/4
-%% Purpose : traverses a variable list and exchanges all instances of
-%% the variable in the statements definitions by its current
-%% value.
-%% Arguments : VariableList - the list of varibles being renamed
-%% Statement - the statement whos definitions are being changed
-%% Current - the current index of all variables encountered
-%% Returns : {Statement, Current}
-%% Notes : Per Gustafsson:
-%% I changed this function to update the statement only when
-%% all substitutions are found.
-%%----------------------------------------------------------------------
-
-updateStatementDefs(Vars, Statement, Current) ->
- updateStatementDefs(Vars, Statement, Current, []).
-
-updateStatementDefs([Var|Vars], Statement, Current, Acc) ->
- {NewVar,Current2} = updateIndices(Current, Var),
- updateStatementDefs(Vars, Statement, Current2, [{Var,NewVar}|Acc]);
-updateStatementDefs([], Statement, Current, Acc) ->
- Statement2 = ?CODE:subst_defines(Acc, Statement),
- {Statement2,Current}.
-
-%%----------------------------------------------------------------------
-%% Procedure : updateIndices/3
-%% Purpose : This function is used for updating the Current hash table
-%% and for getting a new variable/fp variable/register.
-%% Arguments : Current - Hash table containg the current index for a
-%% particular variable.
-%% Variable - The variable that is used as key in the hash table.
-%% Returns : A two-tuple containing the new variable and Current.
-%%----------------------------------------------------------------------
-
-updateIndices(Current, Variable) ->
- New =
- case ?CODE:is_var(Variable) of
- true -> ?CODE:mk_new_var();
- false ->
- case is_fp_temp(Variable) of
- true -> mk_new_fp_temp();
- false ->
- case ?CODE:reg_is_gcsafe(Variable) of
- true -> ?CODE:mk_new_reg_gcsafe();
- false -> ?CODE:mk_new_reg()
- end
- end
- end,
- {New, gb_trees:enter(Variable, New, Current)}.
-
-%%----------------------------------------------------------------------
-%% Procedure : updateSuccPhi/4
-%% Purpose : This function is used for updating phi functions in a
-%% particular node's successors. That is, the function
-%% traverses the successor list of a node and updates the
-%% arguments in the phi function calls.
-%% Arguments : Succ - A successor to the node Parent.
-%% T - The remainder of the successor list
-%% Parent - The parent of the node Succ
-%% CFG - Control Flow Graph
-%% Current - Hash table containg the current index for a
-%% particular variable
-%% Returns : An updated version of the CFG
-%%----------------------------------------------------------------------
-
-updateSuccPhi([Succ|T], Parent, CFG, Current) ->
- CFG2 = updatePhi(Succ, Parent, CFG, Current),
- updateSuccPhi(T, Parent, CFG2, Current);
-updateSuccPhi([], _, CFG, _) ->
- CFG.
-
-%%----------------------------------------------------------------------
-%% Procedure : updatePhi/4
-%% Purpose : This function prepares for an update of a phi function call.
-%% That is, if a statement contains a phi function call
-%% then the number of predecessors are computed and the index
-%% of the parent in the predecessor list is used for computing
-%% which variable in the argument list of the phi function call
-%% that need to be updated.
-%% Arguments : Node - A node in the CFG
-%% Parent - The parent of the node Node in the dominator tree
-%% CFG - Control Flow Graph
-%% Current - Hash table containg the current index for a
-%% particular variable
-%% Returns : An updated version of the CFG
-%%----------------------------------------------------------------------
-
-updatePhi(Node, Parent, CFG, Current) ->
- BB = ?CFG:bb(CFG, Node),
- case hipe_bb:code(BB) of
- [Code|_] = Statements ->
- case ?CODE:is_phi(Code) of
- true ->
- Code2 = updateCode(Statements, Parent, Current),
- ?CFG:bb_add(CFG, Node, hipe_bb:code_update(BB, Code2));
- _ ->
- CFG
- end;
- _ ->
- CFG
- end.
-
-%%----------------------------------------------------------------------
-%% Procedure : updateCode/3
-%% Purpose : This function updates a statement that contains a phi
-%% function, i.e. it changes the arguments in the phi
-%% function to their correct names.
-%% Arguments : Code - A list of code
-%% Pred - A predecessor of the node containing the
-%% phi-function
-%% Current - Hash table containing the current index for a
-%% particular variable
-%% Returns : A list of Code
-%%----------------------------------------------------------------------
-
-updateCode(Code, Pred, Current) ->
- updateCode(Code, Pred, Current, []).
-
-updateCode([Stat|Stats] = Statements, Pred, Current, Result) ->
- case ?CODE:is_phi(Stat) of
- true ->
- Var = ?CODE:phi_id(Stat),
- Result2 = case gb_trees:lookup(Var, Current) of
- none ->
- [Stat|Result];
- {value,Var2} ->
- Stat2 = ?CODE:phi_enter_pred(Stat, Pred, Var2),
- [Stat2|Result]
- end,
- updateCode(Stats, Pred, Current, Result2);
- _ ->
- Result ++ Statements
- end.
-
-%%----------------------------------------------------------------------
-%% Procedure : insertRenamedParams/1
-%% Purpose : Inserts the parameters of the CFG into the working hashmaps.
-%% Arguments : CFG - the target control flow graph.
-%% Returns : {CFG,Current}
-%%----------------------------------------------------------------------
-
-insertRenamedParams(CFG) ->
- Params = ?CFG:params(CFG),
- %% Current - the current variable we are working on.
- {Current,Params2} = insertRenamedParams(Params, gb_trees:empty(), []),
- CFG2 = ?CFG:params_update(CFG, Params2),
- {CFG2,Current}.
-
-insertRenamedParams([Param|Params], Current, Result) ->
- {Var,Current2} = updateIndices(Current, Param),
- insertRenamedParams(Params, Current2, [Var|Result]);
-insertRenamedParams([], Current, Result) ->
- {Current,lists:reverse(Result)}.
-
-
-%%======================================================================
-%% SSA Checker
-%%======================================================================
-
-%%
-%% @doc Checks the control flow graph CFG of a function for SSA-ness.
-%% More specifically, it checks that all variables in the CFG are only
-%% defined once and that all uses of each variable in the function are
-%% dominated by a define. If a variable does not abide by these rules,
-%% a warning message will be printed on stdout.
-%%
--spec check(#cfg{}) -> 'ok'.
-
-check(CFG) ->
- Labels = ?CFG:labels(CFG),
- VarTree = traverse_labels(Labels, CFG),
- DomTree = hipe_dominators:domTree_create(CFG),
- test_uses(Labels, VarTree, DomTree, CFG).
-
-%%
-%% @doc Traverses all the labels in a CFG.
-%%
-traverse_labels(Labels, CFG) ->
- VarTree = add_args(?CFG:params(CFG)),
- traverse_labels(Labels, VarTree, CFG).
-
-traverse_labels([Label|Rest], VarTree, CFG) ->
- Code = get_code_from_label(CFG, Label),
- NewVarTree = traverse_code(Code, VarTree, Label),
- traverse_labels(Rest, NewVarTree, CFG);
-traverse_labels([], VarTree, _CFG) ->
- VarTree.
-
-%%
-%% @doc Traverses the code in a basic block.
-%%
-traverse_code([Instr|Rest], VarTree, Label) ->
- Defined = defs_to_rename(Instr),
- NewVarTree = add_to_var_tree(Defined, VarTree, Instr, Label),
- traverse_code(Rest, NewVarTree, Label);
-traverse_code([], VarTree, _) ->
- VarTree.
-
-%%
-%% @doc
-%% Adds a variable to the variable tree if the variable is defined.
-%% The entry in the variable tree will have the variable as key and a
-%% two tuple consisting of a list of Instructions and a list of labels
-%% where the variable is defined. If a variable is defined a second
-%% time a warning message to this effect is printed on stdout.
-%%
-add_to_var_tree([Var|Rest], VarTree, Instr, Label) ->
- NewVarTree =
- case gb_trees:lookup(Var, VarTree) of
- {value,{OldInstr,OldLabel}} ->
- ?WARNING_MSG("Variable: ~w defined a second time\n"++
- "in Instr: ~w\n"++
- "at Label: ~w\n"++
- "variable was first defined at Label(s) ~w\n"++
- "in Instr(s): ~w\n -> non SSA form\n",
- [Var,Instr,Label,OldLabel,OldInstr]),
- gb_trees:update(Var, {[Instr|OldInstr],[Label|OldLabel]}, VarTree);
- none ->
- gb_trees:insert(Var, {[Instr],[Label]}, VarTree)
- end,
- add_to_var_tree(Rest, NewVarTree, Instr, Label);
-add_to_var_tree([], VarTree, _, _) ->
- VarTree.
-
-%%
-%% @doc Adds the argument of a function to the VarTree.
-%% They are defined at Label 0.
-%%
-add_args(Args) ->
- add_args(Args, gb_trees:empty()).
-
-add_args([Arg|Rest], VarTree) ->
- add_args(Rest, gb_trees:insert(Arg, {[argument_variable],[0]}, VarTree));
-add_args([], VarTree) ->
- VarTree.
-
-%%
-%% The functions below test that a use is dominated by a corresponding def.
-%%
-
-%%
-%% This function is analogous to traverse_labels.
-%%
-test_uses([Label|Rest], VarTree, DomTree,CFG) ->
- Code = get_code_from_label(CFG, Label),
- test_code(Code, VarTree, Label, DomTree, CFG, []),
- test_uses(Rest, VarTree, DomTree, CFG);
-test_uses([], _VarTree, _DomTree, _CFG) ->
- ok.
-
-%%
-%% This function is analogous to traverse_code.
-%%
-test_code([Instr|Instrs], VarTree, Label, DomTree, CFG, Old) ->
- case ?CODE:is_phi(Instr) of
- true ->
- ArgList = ?CODE:phi_arglist(Instr),
- case ArgList of
- [_Arg] ->
- ?WARNING_MSG("Phi with only one source at BB with label ~w:\n",
- [Label]),
- %% case ?CODE of
- %% hipe_rtl -> ?CODE:pp_block(get_code_from_label(CFG, Label));
- %% _ -> ok
- %% end,
- ok;
- [_|_] -> ok
- end,
- lists:foreach(fun ({Pred,Var}) ->
- def_doms_use([Var], VarTree, Pred, DomTree,
- get_code_from_label(CFG,Pred))
- end, ArgList);
- false ->
- Uses = uses_to_rename(Instr),
- def_doms_use(Uses, VarTree, Label, DomTree, Old)
- end,
- test_code(Instrs, VarTree, Label, DomTree, CFG, [Instr|Old]);
-test_code([], _VarTree, _Label, _DomTree, _CFG, _Old) ->
- ok.
-
-get_code_from_label(CFG, Label) ->
- case ?CFG:bb(CFG,Label) of
- not_found ->
- ?error_msg("Basic block with label ~w was not found\n", [Label]);
- %% ?EXIT('Detected serious problem in SSA form');
- BB ->
- hipe_bb:code(BB)
- end.
-
-%%
-%% This function checks whether a use is dominated by a def.
-%% There are five different cases:
-%% 1. A use of an argument register. This use is dominated by the def.
-%% 2. Use and Def in same basic block if Use comes first this will
-%% lead to a warning message, otherwise it is ok.
-%% 3. The deinition is in a basic block that dominates the basic block
-%% of the use. This is ok.
-%% 4. The definition is in a basic block that does not dominate the use.
-%% This will result in a warning message being printed.
-%% 5. A use without any definition. This will result in a warning message
-%% being printed.
-%%
-def_doms_use([Var|Vars], VarTree, Label, DomTree, Old) ->
- case gb_trees:lookup(Var, VarTree) of
- {value,{_,[DefLabel|_]}} ->
- case DefLabel of
- 0 ->
- ok;
- Label ->
- Fun = fun(X) -> Defs = defs_to_rename(X),
- lists:any(fun(Y) -> Var == Y end, Defs)
- end,
- case lists:any(Fun, Old) of
- true ->
- ok;
- false ->
- ?WARNING_MSG("Variable : ~w used before definition in bb: ~w\n",
- [Var,Label])
- end;
- _ ->
- case hipe_dominators:domTree_dominates(DefLabel, Label, DomTree) of
- true ->
- ok;
- false ->
- ?WARNING_MSG("Definition does not dominate use for variable: ~w "++
- "at label: ~w (definition label: ~w)\n",
- [Var, Label, DefLabel])
- end
- end;
- none ->
- ?WARNING_MSG("Use with no definition of variable: ~w at label: ~w\n",
- [Var, Label])
- end,
- def_doms_use(Vars, VarTree, Label, DomTree, Old);
-def_doms_use([], _VarTree, _Label, _DomTree, _Old) ->
- ok.
-
-
-%%======================================================================
-%% SSA Un-Converter
-%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Procedure : unconvert/2
-%% Purpose : Removes all phi functions and propagates all
-%% assignments up to the appropriate predecessors.
-%% Arguments : CFG - Control Flow Graph
-%% Node - A node in the CFG
-%% Returns : CFG
-%% Note : The call to remove_trivial_bbs is needed so that moves,
-%% which are introduced in new basic blocks as part of the
-%% un-conversion, are merged with the basic blocks of their
-%% predecessors, if possible.
-%%----------------------------------------------------------------------
-
--spec unconvert(#cfg{}) -> #cfg{}.
-
-unconvert(CFG) ->
- ?CFG:remove_trivial_bbs(unconvert(?CFG:reverse_postorder(CFG), CFG)).
-
-unconvert([Node|Nodes], CFG) ->
- BB = ?CFG:bb(CFG, Node),
- Code = hipe_bb:code(BB),
- {Phis,Code2} = getPhiFuncts(Code, []),
- case Phis of
- [] ->
- unconvert(Nodes, CFG);
- _ ->
- BB2 = hipe_bb:code_update(BB, Code2),
- CFG2 = ?CFG:bb_add(CFG, Node, BB2),
- Pred = ?CFG:pred(CFG2, Node),
- PredMoveMap = get_moves(Pred, Phis),
- CFG3 = insert_move_bbs(PredMoveMap, Node, CFG2),
- unconvert(Nodes, CFG3)
- end;
-unconvert([], CFG) ->
- CFG.
-
-%%----------------------------------------------------------------------
-%% Procedure : get_moves/2 and /3
-%% Purpose : Find the moves that corresponds to phi-instructions of
-%% a block. Try to merge incoming edges to avoid duplicate
-%% blocks.
-%% Arguments : Preds - The predecessors to this block.
-%% Phis - The phi instructions that used to start this block.
-%% Returns : [{ListOfMoves, [Preds]}]
-%%----------------------------------------------------------------------
-
-get_moves(Preds, Phis) ->
- get_moves(Preds, Phis, gb_trees:empty()).
-
-get_moves([Pred|Left], Phis, Map)->
- Moves = get_moves_from_phis(Pred, Phis, []),
- NewMap =
- case gb_trees:lookup(Moves, Map) of
- none -> gb_trees:insert(Moves, [Pred], Map);
- {value,List} -> gb_trees:update(Moves, [Pred|List], Map)
- end,
- get_moves(Left, Phis, NewMap);
-get_moves([], _Phis, Map) ->
- gb_trees:to_list(Map).
-
-%%----------------------------------------------------------------------
-%% Procedure : get_moves_from_phis/3
-%% Purpose : Find all the moves that should be done in the edge
-%% coming in from Pred.
-%% Arguments : Pred - The predecessor
-%% Phis - Reverse list of phi instructions.
-%% Returns : [{Dst,Src}] representing the move instructions;
-%% ORDERING IS SIGNIFICANT!
-%%----------------------------------------------------------------------
-
-get_moves_from_phis(Pred, [Phi|Left], Acc) ->
- Dst = ?CODE:phi_dst(Phi),
- Src = ?CODE:phi_arg(Phi, Pred),
- NewAcc = [{Dst, Src}|Acc],
- get_moves_from_phis(Pred, Left, NewAcc);
-get_moves_from_phis(_Pred, [], Acc) ->
- Acc.
-
-%%----------------------------------------------------------------------
-%% Procedure : insert_move_bbs/3
-%% Purpose : Create the bbs that contains the moves.
-%% Arguments : Ordset - The move instruction tuples {Dst, Src}
-%% Preds - The predecessors that needs the moves in Ordset
-%% Label - The original label that contained the phis.
-%% Cfg - The current cfg
-%% Returns : The new Cfg.
-%%----------------------------------------------------------------------
-
-insert_move_bbs([{Ordset,Preds}|Left], Label, Cfg) ->
- Code = create_moves(Ordset, []) ++ [?CODE:mk_goto(Label)],
- BB = hipe_bb:mk_bb(Code),
- NewLabel = ?CODE:label_name(?CODE:mk_new_label()),
- NewCfg1 = ?CFG:bb_add(Cfg, NewLabel, BB),
- NewCfg2 = lists:foldl(fun(X, Acc) ->
- ?CFG:redirect(Acc, X, Label, NewLabel)
- end,
- NewCfg1, Preds),
- insert_move_bbs(Left, Label, NewCfg2);
-insert_move_bbs([], _Label, Cfg) ->
- Cfg.
-
-create_moves([{X,X}|Left], Acc) ->
- create_moves(Left, Acc);
-create_moves([{Dst,Src}|Left], Acc) ->
- create_moves(Left, [makePhiMove(Dst, Src)|Acc]);
-create_moves([], Acc) ->
- %% NOTE: ORDERING IS SIGNIFICANT!
- lists:reverse(Acc).
-
-%%----------------------------------------------------------------------
-%% Procedure : getPhiFuncts/2
-%% Purpose : This function returns the list of phi-functions from a
-%% list of intermediate code instructions.
-%% Arguments :
-%% List - A list of Code
-%% Result - Accumulative parameter to store the result
-%% Returns : Reverse list of the phi instructions. ORDERING IS SIGNIFICANT!
-%%----------------------------------------------------------------------
-
-getPhiFuncts([I|T] = List, Result) ->
- case ?CODE:is_phi(I) of
- true ->
- getPhiFuncts(T, [I|Result]);
- false ->
- {Result,List}
- end;
-getPhiFuncts([], Result) ->
- {Result,[]}.
-
-
-%%======================================================================
-%% Dead Code Elimination on SSA form
-%%======================================================================
-
--spec remove_dead_code(#cfg{}) -> #cfg{}.
-
-remove_dead_code(CFG) ->
- Lbls = ?CFG:reverse_postorder(CFG),
- Liveness = ssa_liveness__analyze(CFG),
- case do_lbls(Lbls, CFG, Liveness, false) of
- {CFG1,true} ->
- remove_dead_code(CFG1);
- {CFG1,false} ->
- CFG1
- end.
-
-do_lbls([Lbl|Rest], CFG, Liveness, Changed) ->
- LiveOut = gb_sets:from_list(ssa_liveness__liveout(Liveness, Lbl)),
- BB = ?CFG:bb(CFG, Lbl),
- Code = hipe_bb:code(BB),
- {NewCode,NewChanged} = do_code(lists:reverse(Code), LiveOut, Changed, []),
- NewBB = hipe_bb:code_update(BB, NewCode),
- NewCFG = ?CFG:bb_add(CFG, Lbl, NewBB),
- do_lbls(Rest, NewCFG, Liveness, NewChanged);
-do_lbls([], CFG, _Liveness, Changed) ->
- {CFG,Changed}.
-
-do_code([Instr|Instrs], LiveOut, Changed, Acc) ->
- Def = ?CODE:defines(Instr),
- Use = ?CODE:uses(Instr),
- DefSet = gb_sets:from_list(Def),
- UseSet = gb_sets:from_list(Use),
- LiveIn = gb_sets:union(gb_sets:difference(LiveOut, DefSet), UseSet),
- case gb_sets:is_empty(gb_sets:intersection(DefSet, LiveOut)) of
- false ->
- do_code(Instrs, LiveIn, Changed, [Instr|Acc]);
- true ->
- case ?CODE:is_call(Instr) of
- true ->
- case ?CODE:is_safe(Instr) of
- true ->
- case ?CODE:call_continuation(Instr) of
- [] ->
- do_code(Instrs, LiveOut, true, Acc);
- SuccLblName ->
- NewInstr = ?CODE:mk_goto(SuccLblName),
- do_code(Instrs, LiveOut, true, [NewInstr|Acc])
- end;
- false ->
- case ?CODE:call_dstlist(Instr) of
- [] -> %% result was not used anyway; no change
- do_code(Instrs, LiveIn, Changed, [Instr|Acc]);
- [_Dst] -> %% remove the unused assignment to call's destination
- NewInstr = ?CODE:call_dstlist_update(Instr, []),
- do_code(Instrs, LiveIn, true, [NewInstr|Acc]);
- [_|_] -> %% calls with multiple dests are left untouched
- do_code(Instrs, LiveIn, Changed, [Instr|Acc])
- end
- end;
- false ->
- case ?CODE:reduce_unused(Instr) of
- false -> % not a safe instruction - cannot be removed
- do_code(Instrs, LiveIn, Changed, [Instr|Acc]);
- Replacement ->
- do_code(lists:reverse(Replacement, Instrs), LiveOut, true, Acc)
- end
- end
- end;
-do_code([], _LiveOut, Changed, Acc) ->
- {Acc,Changed}.
-
diff --git a/lib/hipe/ssa/hipe_ssa_const_prop.inc b/lib/hipe/ssa/hipe_ssa_const_prop.inc
deleted file mode 100644
index 9c157e0833..0000000000
--- a/lib/hipe/ssa/hipe_ssa_const_prop.inc
+++ /dev/null
@@ -1,517 +0,0 @@
-%% -*- Erlang -*-
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-----------------------------------------------------------------------------
-%% File : hipe_ssa_const_prop.inc
-%% Author : Kostis Sagonas <kostis@it.uu.se>
-%% Description : Supporting routines for sparse conditional constant
-%% propagation on SSA form.
-%%
-%% Created : 21 June 2004 by Kostis Sagonas <kostis@it.uu.se>
-%%-----------------------------------------------------------------------------
-
-%%-----------------------------------------------------------------------------
-%% Procedure : propagate/1
-%% Purpose : Perform sparse conditional constant propagation on a
-%% control flow graph
-%% Arguments : CFG - The cfg to work on
-%% Returns : A new cfg.
-%%-----------------------------------------------------------------------------
-
--spec propagate(#cfg{}) -> #cfg{}.
-
-propagate(CFG) ->
- Environment = create_env(CFG),
- StartEdge = {?CFG:start_label(CFG), ?CFG:start_label(CFG)},
- NewEnvironment = scc([StartEdge], [], Environment),
- NewCFG = update_cfg(NewEnvironment),
- NewCFG.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_expressions/2 & visit_expressions/4
-%% Purpose : visit each instruction in a list of instructions.
-%% Arguments : Instructions - the list of instructions to visit
-%% Environment - have a guess.
-%% FlowWork - list of destination part of flowgraph edges
-%% from the visited instructions
-%% SSAWork - resulting ssa-edges from visited instrs.
-%% Returns : {FlowWorkList, SSAWorkList, Environment}
-%%-----------------------------------------------------------------------------
-
-visit_expressions(Instructions, Environment) ->
- visit_expressions(Instructions, Environment, [], []).
-
-visit_expressions([], Environment, FlowWork, SSAWork) ->
- {FlowWork, SSAWork, Environment};
-visit_expressions([Inst | Insts], Environment, FlowWork, SSAWork) ->
- {MoreFlowWork, MoreSSAWork, Environment1}
- = visit_expression(Inst, Environment),
- FlowWork1 = MoreFlowWork ++ FlowWork,
- SSAWork1 = MoreSSAWork ++ SSAWork,
- visit_expressions(Insts, Environment1, FlowWork1, SSAWork1).
-
-%%-----------------------------------------------------------------------------
-%% The environment record: Shared between incarnations of SCCP.
-%%-----------------------------------------------------------------------------
-
--record(env, {cfg :: #cfg{},
- executable_flags = gb_sets:empty() :: gb_sets:set(),
- handled_blocks = gb_sets:empty() :: gb_sets:set(),
- lattice_values = gb_trees:empty() :: gb_trees:tree(),
- ssa_edges = gb_trees:empty() :: gb_trees:tree()
- }).
-
-create_env(CFG) ->
- #env{cfg = CFG,
- executable_flags = gb_sets:empty(),
- handled_blocks = gb_sets:empty(),
- lattice_values = initialize_lattice(CFG),
- ssa_edges = initialize_ssa_edges(CFG)
- }.
-
-env__cfg(#env{cfg=CFG}) -> CFG.
-env__executable_flags(#env{executable_flags=Flags}) -> Flags.
-env__lattice_values(#env{lattice_values=Values}) -> Values.
-env__ssa_edges(#env{ssa_edges=Edges}) -> Edges.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : initialize_lattice/1
-%% Purpose : Compute the initial value-lattice for the CFG
-%% Arguments : CFG a control flow graph
-%% Returns : a value-latice (gb_tree)
-%%-----------------------------------------------------------------------------
-
-initialize_lattice(CFG) ->
- Lattice = gb_trees:empty(),
- Parameters = ?CFG:params(CFG),
- Inserter = fun(Parameter, Tree) ->
- gb_trees:insert(Parameter, bottom, Tree)
- end,
- lists:foldl(Inserter, Lattice, Parameters).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : initialize_ssa_edges/1
-%% Purpose : Compute the SSA edges in the CFG. SSA edges are used to map
-%% the definition of a value to its uses.
-%% Arguments : CFG - the cfg
-%% Returns : A gb_tree of values (variables & registers) to
-%% lists of {Node, Instruction} pairs.
-%%-----------------------------------------------------------------------------
-
-initialize_ssa_edges(CFG) ->
- IterateNodes =
- fun(Node, Tree1) ->
- IterateInstructions =
- fun(Instruction, Tree2) ->
- IterateArguments =
- fun(Argument, Tree3) ->
- Data = gb_trees:lookup(Argument, Tree3),
- NewEdge = {Node, Instruction},
- case Data of
- none ->
- %% insert assumes key is not present
- gb_trees:insert(Argument, [NewEdge], Tree3);
- {value, EdgeList} ->
- %% update assumes key is present
- gb_trees:update(Argument, [NewEdge|EdgeList], Tree3)
- end
- end,
- Arguments = ?CODE:uses(Instruction),
- lists:foldl(IterateArguments, Tree2, Arguments)
- end,
- Instructions = hipe_bb:code(?CFG:bb(CFG, Node)),
- lists:foldl(IterateInstructions, Tree1, Instructions)
- end,
- NodeList = ?CFG:labels(CFG),
- lists:foldl(IterateNodes, gb_trees:empty(), NodeList).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : scc/3
-%% Purpose : Do the symbolic execution of a cfg and compute the resulting
-%% value-lattice, and reachability information (Environment).
-%% This is the main loop that does a fixpoint computation of the
-%% lattice-values for each variable and register.
-%% Arguments : FlowWorkList - work list of control-flow edges
-%% SSAWorkList - work list of ssa-edges
-%% Environment - the environment that have been computed so far.
-%% Returns : The environment after execution
-%%-----------------------------------------------------------------------------
-
-scc([], [], Environment) ->
- Environment;
-%% Take an element from the FlowWorkList and process it
-scc([{Source,Destination} | FlowWorkList], SSAWorkList, Environment) ->
- case executable({Source, Destination}, Environment) of
- true ->
- scc(FlowWorkList, SSAWorkList, Environment);
- false ->
- Environment1 = mark_as_executable({Source,Destination}, Environment),
- Code = extract_code(Destination, Environment),
- {Environment2, Code1, ExtraSSA} =
- visit_phi_nodes(Code, Destination, Environment1, []),
- case handled(Destination, Environment2) of
- true ->
- scc(FlowWorkList, ExtraSSA ++ SSAWorkList, Environment2);
- false ->
- {MoreFlowDests, MoreSSAWork, Environment3} =
- visit_expressions(Code1, Environment2),
- MoreFlowWork = [{Destination, Node} || Node <- MoreFlowDests],
- FlowWorkList1 = MoreFlowWork ++ FlowWorkList,
- SSAWorkList1 = ExtraSSA ++ MoreSSAWork ++ SSAWorkList,
- Environment4 = mark_as_handled(Destination, Environment3),
- scc(FlowWorkList1, SSAWorkList1, Environment4)
- end
- end;
-%% Take an element from the SSAWorkList and process it
-scc([], [{Node, Instruction} | SSAWorkList], Environment) ->
- case reachable(Node, Environment) of
- true ->
- case ?CODE:is_phi(Instruction) of
- true ->
- {Environment1, MoreSSA} = visit_phi(Instruction, Node, Environment),
- scc([], MoreSSA ++ SSAWorkList, Environment1);
- false ->
- {MoreFlowDests, MoreSSAWork, Environment1} =
- visit_expression(Instruction, Environment),
- SSAWorkList1 = MoreSSAWork ++ SSAWorkList,
- MoreFlowWork = [{Node, Destination} || Destination<-MoreFlowDests],
- scc(MoreFlowWork, SSAWorkList1, Environment1)
- end;
- false ->
- scc([], SSAWorkList, Environment)
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_cfg/1
-%% Purpose : Transforms the cfg into something more pleasant.
-%% Here the mapping of variables & registers to lattice-values is
-%% used to actually change the code.
-%% Arguments : Environment - in which everything happens.
-%% Returns : A new CFG.
-%%-----------------------------------------------------------------------------
-
-update_cfg(Environment) ->
- NodeList = get_nodelist(Environment),
- CFG1 = update_nodes(NodeList, Environment),
- %% why not hipe_???_ssa:remove_dead_code ?
- CFG2 = ?CFG:remove_unreachable_code(CFG1),
- CFG2.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_nodes/2
-%% Purpose : loop over all nodes in a list of nodes, ignoring any
-%% non-reachable node.
-%% Arguments : NodeList - the list of nodes.
-%% Environment - in which everything happens.
-%% Returns : a new cfg.
-%%-----------------------------------------------------------------------------
-
-update_nodes([], Environment) ->
- env__cfg(Environment);
-update_nodes([Node | NodeList], Environment) ->
- NewEnvironment =
- case reachable(Node, Environment) of
- true ->
- Instructions = extract_code(Node, Environment),
- Updater = fun(Instruction) ->
- update_instruction(Instruction, Environment)
- end,
- NewInstructions = lists:flatmap(Updater, Instructions),
- update_code(Node, NewInstructions, Environment);
- false ->
- Environment
- end,
- update_nodes(NodeList, NewEnvironment).
-
-%%-----------------------------------------------------------------------------
-%% Procedure : update_code/3
-%% Purpose : Insert a list of new instructions into the cfg in the
-%% environment
-%% Arguments : Node - name of the bb whose instructions we replace.
-%% NewInstructions - The list of new instructions
-%% Env - The environment
-%% Returns : A new environment
-%%-----------------------------------------------------------------------------
-
-update_code(Node, NewInstructions, Environment) ->
- CFG = env__cfg(Environment),
- BB = ?CFG:bb(CFG, Node),
- OrderedInstructions = put_phi_nodes_first(NewInstructions),
- NewBB = hipe_bb:code_update(BB, OrderedInstructions),
- NewCFG = ?CFG:bb_add(CFG, Node, NewBB),
- Environment#env{cfg = NewCFG}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : put_phi_nodes_first/1
-%% Purpose : Move all phi-instructions to the beginning of the basic block.
-%% Arguments : Instructions - The list of instructions
-%% Returns : A list of instructions where the phi-nodes are first.
-%%-----------------------------------------------------------------------------
-
-put_phi_nodes_first(Instructions) ->
- {PhiInstructions, OtherInstructions} =
- partition(fun(X) -> ?CODE:is_phi(X) end, Instructions),
- PhiInstructions ++ OtherInstructions.
-
-%%-----------------------------------------------------------------------------
-
-partition(Function, List) ->
- partition(Function, List, [], []).
-
-partition(_Function, [], True, False) ->
- {lists:reverse(True), lists:reverse(False)};
-
-partition(Function, [Hd | Tail], True, False) ->
- case Function(Hd) of
- true ->
- partition(Function, Tail, [Hd | True], False);
- false ->
- partition(Function, Tail, True, [Hd | False])
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_phi_nodes/4
-%% Purpose : visit all the phi-nodes in a bb and return the list of
-%% remaining instructions, new ssa-edges and a new environment.
-%% Arguments : [Inst|Insts] - The list of instructions in the bb
-%% Node - Name of the current node.
-%% Environment - the environment
-%% SSAWork - the ssawork found so far.
-%% Returns : {Environment, Instruction list, SSAWorkList}
-%%-----------------------------------------------------------------------------
-
-visit_phi_nodes([], CurrentNode, _Environment, _SSAWork) ->
- ?EXIT({"~w: visit_phi_nodes/4 Basic block contains no code",
- ?MODULE, CurrentNode});
-visit_phi_nodes(Is = [Inst | Insts], Node, Environment, SSAWork) ->
- case ?CODE:is_phi(Inst) of
- true ->
- {Environment1, NewSSA} = visit_phi(Inst, Node, Environment),
- visit_phi_nodes(Insts, Node, Environment1, NewSSA ++ SSAWork);
- false ->
- {Environment, Is, SSAWork}
- end.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : visit_phi/3
-%% Purpose : visit a phi-node
-%% Arguments : PhiInstruction- The instruction
-%% CurrentNode - Name of the current node.
-%% Environment - the environment
-%% Returns : {NewEnvironment, SSAWork}
-%%-----------------------------------------------------------------------------
-
-visit_phi(PhiInstruction, CurrentNode, Environment) ->
- ArgumentList = ?CODE:phi_arglist(PhiInstruction),
- Value = get_phi_value(ArgumentList, CurrentNode, Environment, top),
- Name = ?CODE:phi_dst(PhiInstruction),
- {Environment1, SSAWork} = update_lattice_value({Name, Value}, Environment),
- {Environment1, SSAWork}.
-
-%%-----------------------------------------------------------------------------
-%% Procedure : get_phi_value/4
-%% Purpose : compute the result of a phi-function, taking care to ignore
-%% edges that are not yet executable.
-%% Arguments : ArgList - the list of arguments {Node, Value pair}
-%% CurrentNode - the current node
-%% Environment - well...
-%% CurrentValue - the meet of the relevant already processed values
-%% Returns : Integer, top or bottom
-%%-----------------------------------------------------------------------------
-
-%% the arglist contains {predecessor, variable} elements. Remember
-%% to be optimistic in this part, hopefully, topvalues will fall down
-%% to become constants. Hence topvalues are more or less ignored here.
-get_phi_value([], _CurrentNode, _Environment, CurrentValue) ->
- CurrentValue;
-get_phi_value([{PredecessorNode, Variable}| ArgList],
- CurrentNode,
- Environment,
- CurrentValue) ->
- case executable({PredecessorNode, CurrentNode}, Environment) of
- true ->
- NewValue = lookup_lattice_value(Variable, Environment),
- case NewValue of
- bottom ->
- bottom;
- top ->
- get_phi_value(ArgList, CurrentNode, Environment, CurrentValue);
- _ ->
- case CurrentValue of
- top ->
- get_phi_value(ArgList, CurrentNode, Environment, NewValue);
- _ ->
- case (NewValue =:= CurrentValue) of
- true ->
- get_phi_value(ArgList, CurrentNode, Environment, NewValue);
- false -> %% two different constants.
- bottom
- end
- end
- end;
- false -> %% non-executable transitions don't affect the value.
- get_phi_value(ArgList, CurrentNode, Environment, CurrentValue)
- end.
-
-%%------------------------------ environment ----------------------------------
-
-reachable(Node, Environment) ->
- Predecessors = predecessors(Node, Environment),
- Executable = fun(Pred) -> executable({Pred, Node}, Environment) end,
- lists:any(Executable, Predecessors).
-
-%%-----------------------------------------------------------------------------
-
-mark_as_executable(Edge, Environment) ->
- ExecutableFlags = env__executable_flags(Environment),
- ExecutableFlags1 = gb_sets:add(Edge, ExecutableFlags),
- Environment#env{executable_flags = ExecutableFlags1}.
-
-%%-----------------------------------------------------------------------------
-
-mark_as_handled(Node, Environment = #env{handled_blocks=Handled}) ->
- NewHandled = gb_sets:add_element(Node, Handled),
- Environment#env{handled_blocks=NewHandled}.
-
-handled(Node, #env{handled_blocks=Handled}) ->
- gb_sets:is_element(Node, Handled).
-
-%%-----------------------------------------------------------------------------
-
-extract_code(Node, Environment) ->
- CFG = env__cfg(Environment),
- case ?CFG:bb(CFG, Node) of
- not_found -> ?WARNING_MSG("Could not find label ~w.\n", [Node]),
- [];
- BB -> hipe_bb:code(BB)
- end.
-
-%%-----------------------------------------------------------------------------
-
-predecessors(Node, Environment) ->
- CFG = env__cfg(Environment),
- ?CFG:pred(CFG, Node).
-
-%%-----------------------------------------------------------------------------
-
-executable(Edge, Environment) ->
- ExecutableFlags = env__executable_flags(Environment),
- gb_sets:is_member(Edge, ExecutableFlags).
-
-%%-----------------------------------------------------------------------------
-
-update_lattice_value({[], _NewValue}, Environment) ->
- {Environment, []};
-update_lattice_value({Names, NewValue}, Environment) when is_list(Names) ->
- Update =
- fun(Dst, {Env, SSA}) ->
- {NewEnv, NewSSA} =
- update_lattice_value({Dst, NewValue}, Env),
- {NewEnv, SSA ++ NewSSA}
- end,
- lists:foldl(Update, {Environment, []}, Names);
-%% update_lattice_value({Name, {Res, N, Z, C, V} }, _) ->
-%% ?EXIT({"inserting dumt grejs", {Name, {Res, N, Z, C, V} } });
-update_lattice_value({Name, NewValue}, Environment) ->
- LatticeValues = env__lattice_values(Environment),
- {LatticeValues1, SSAWork} =
- case gb_trees:lookup(Name, LatticeValues) of
- none ->
- {gb_trees:insert(Name, NewValue, LatticeValues),
- lookup_ssa_edges(Name, Environment)};
- {value, NewValue} ->
- {LatticeValues, []};
- {value, _} ->
- {gb_trees:update(Name, NewValue, LatticeValues),
- lookup_ssa_edges(Name, Environment)}
- end,
- {Environment#env{lattice_values = LatticeValues1}, SSAWork}.
-
-%%-----------------------------------------------------------------------------
-
-lookup_ssa_edges(Variable, Environment) ->
- SSAEdges = env__ssa_edges(Environment),
- case gb_trees:lookup(Variable, SSAEdges) of
- {value, X} ->
- X;
- _ -> % Unused variable
- []
- end.
-
-%%-----------------------------------------------------------------------------
-
-get_nodelist(Environment) ->
- CFG = env__cfg(Environment),
- ?CFG:labels(CFG).
-
-%%-----------------------------------------------------------------------------
-
--ifdef(DEBUG).
-
-%%-----------------------------------------------------------------------------
-%%---------------------------------- DEBUG ------------------------------------
-
-error(Text) ->
- error(Text, []).
-
-error(Text, Data) ->
- io:format("Internal compiler error in ~w\n",[?MODULE]),
- io:format(Text, Data),
- io:format("\n\n"),
- halt().
-
-%%-----------------------------------------------------------------------------
-
-print_environment(Environment) ->
- io:format("============================================================\n"),
- io:format("Executable flags: "),
- print_executable_flags(env__executable_flags(Environment)),
- io:format("Lattice values --->\n"),
- print_lattice_values(env__lattice_values(Environment)),
- io:format("SSA edges --->\n"),
- print_ssa_edges(env__ssa_edges(Environment)),
- io:format("============================================================\n").
-
-%%-----------------------------------------------------------------------------
-
-print_executable_flags(ExecutableFlags) ->
- ListOfFlags = gb_sets:to_list(ExecutableFlags),
- Printer = fun ({Source, Destination}) ->
- io:format("(~w, ~w), ", [Source, Destination]) end,
- lists:foreach(Printer, ListOfFlags),
- io:format("()\n").
-
-%%-----------------------------------------------------------------------------
-
-print_lattice_values(LatticeValues) ->
- ListOfLatticeValues = gb_trees:to_list(LatticeValues),
- Printer = fun ({Key, Value}) ->
- io:format("~w = ~w\n", [Key, Value]) end,
- lists:foreach(Printer, ListOfLatticeValues).
-
-%%-----------------------------------------------------------------------------
-
-print_ssa_edges(SSAEdges) ->
- ListOfSSAEdges = gb_trees:to_list(SSAEdges),
- Printer = fun ({Key, Value}) ->
- io:format("~w: ~w\n", [Key, Value]) end,
- lists:foreach(Printer, ListOfSSAEdges).
-
-%%-----------------------------------------------------------------------------
-
--endif. %% DEBUG
-
-%%-----------------------------------------------------------------------------
-
diff --git a/lib/hipe/ssa/hipe_ssa_copy_prop.inc b/lib/hipe/ssa/hipe_ssa_copy_prop.inc
deleted file mode 100644
index 8677263213..0000000000
--- a/lib/hipe/ssa/hipe_ssa_copy_prop.inc
+++ /dev/null
@@ -1,193 +0,0 @@
-%%% -*- Erlang -*-
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%-------------------------------------------------------------------
-%%% File : hipe_ssa_copy_prop.inc
-%%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%%% Description : Copy propagation on SSA form.
-%%%
-%%% Created : 4 Apr 2003 by Tobias Lindahl <tobiasl@it.uu.se>
-%%%-------------------------------------------------------------------
-
--export([cfg/1]).
-
-%%--------------------------------------------------------------------
-%% Two passes through the code visiting the blocks in reverse
-%% postorder. The first pass binds all destinations of copying moves
-%% to the sources, and the second propagates the copies and removes
-%% the copying moves.
-%%
-%% Problem:
-%% Since phi-nodes are implemented as instructions they are not
-%% atomic. If we are not careful we can get the situation (after propagation):
-%%
-%% v0 = phi(v0, v2)
-%% v1 = phi(v0, v3)
-%% ^^
-%% where the underlined v0 really corresponds to the v0 before the first
-%% phi-instruction.
-%%
-%% Solution:
-%% * Find all dependencies between the uses of a phi-instruction to
-%% the destination of any earlier phi-instruction in the same phi-node;
-%% * Keep the copying move that defines the variable used in the
-%% latter phi-instruction; and
-%% * Do not propagate the copy into the phi-instruction
-%%
-%%--------------------------------------------------------------------
-
--spec cfg(#cfg{}) -> #cfg{}.
-
-cfg(Cfg) ->
- Labels = ?cfg:reverse_postorder(Cfg),
- {Info,PhiDep} = analyse(Labels, Cfg, gb_trees:empty(), gb_trees:empty()),
- rewrite(Labels, Cfg, Info, PhiDep).
-
-analyse([Label|Left], Cfg, Info, PhiDep) ->
- BB = ?cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- NewPhiDep = get_phi_dep(Code, gb_sets:empty(), PhiDep),
- NewInfo = analyse_code(Code, Info),
- analyse(Left, Cfg, NewInfo, NewPhiDep);
-analyse([], _Cfg, Info, PhiDep) ->
- {Info,PhiDep}.
-
-get_phi_dep([I|Left], Defined, Dep) ->
- case ?code:is_phi(I) of
- true ->
- Use = ?code:uses(I),
- [Def] = ?code:defines(I),
- NewDep = add_dep(Use, Defined, Dep),
- get_phi_dep(Left, gb_sets:insert(Def, Defined), NewDep);
- false ->
- Dep
- end;
-get_phi_dep([], _Defined, Dep) ->
- Dep.
-
-add_dep([Use|Left], Defined, Dep) ->
- case gb_trees:lookup(Use, Dep) of
- none ->
- add_dep(Left, Defined, gb_trees:insert(Use, Defined, Dep));
- {value, Set} ->
- NewSet = gb_sets:union(Defined, Set),
- add_dep(Left, Defined, gb_trees:enter(Use, NewSet, Dep))
- end;
-add_dep([], _Defined, Dep) ->
- Dep.
-
-has_dep(Use, Def, Dep) ->
- case gb_trees:lookup(Use, Dep) of
- none ->
- false;
- {value, Set} ->
- gb_sets:is_member(Def, Set)
- end.
-
-analyse_code([I|Left], Info) ->
- case ?code:is_move(I) of
- true ->
- NewInfo = get_info_move(I, Info),
- analyse_code(Left, NewInfo);
- false ->
- analyse_code(Left, Info)
- end;
-analyse_code([], Info) ->
- Info.
-
-get_info_move(I, Info) ->
- case ?code:uses(I) of
- [] -> %% Constant.
- Info;
- [Src] ->
- add_binding(?code:defines(I), Src, Info)
- end.
-
-rewrite([Label|Left], Cfg, Info, PhiDep) ->
- BB = ?cfg:bb(Cfg, Label),
- Code = hipe_bb:code(BB),
- NewCode = rewrite_code(Code, Info, PhiDep, []),
- NewBB = hipe_bb:code_update(BB, NewCode),
- rewrite(Left, ?cfg:bb_add(Cfg, Label, NewBB), Info, PhiDep);
-rewrite([], Cfg, _Info, _PhiDep) ->
- Cfg.
-
-rewrite_code([I|Left], Info, PhiDep, Acc) ->
- case ?code:is_move(I) of
- true ->
- Fun = fun(X, Y) -> ?code:mk_move(X, Y) end,
- NewI = rewrite_move(I, Fun, Info, PhiDep),
- rewrite_code(Left, Info, PhiDep, NewI++Acc);
- false ->
- NewI = rewrite_instr(I, Info, PhiDep),
- rewrite_code(Left, Info, PhiDep, [NewI|Acc])
- end;
-rewrite_code([], _Info, _PhiDep, Acc) ->
- lists:reverse(Acc).
-
-rewrite_move(I, Fun, Info, PhiDep) ->
- case ?code:uses(I) of
- [] ->%% Constant move. Keep it!
- [I];
- _ ->
- Dst = hd(?code:defines(I)),
- case gb_trees:lookup(Dst, Info) of
- {value, Root} ->
- case has_dep(Dst, Root, PhiDep) of
- true -> %% Must keep the copying move!
- [Fun(Dst, Root)];
- false ->
- []
- end;
- none ->
- []
- end
- end.
-
-rewrite_instr(I, Info, PhiDep) ->
- rewrite_instr0(I, ?code:uses(I), Info, PhiDep, []).
-
-rewrite_instr0(I, [Key|Left], Info, PhiDep, UpdateInfo) ->
- case gb_trees:lookup(Key, Info) of
- none ->
- rewrite_instr0(I, Left, Info, PhiDep, UpdateInfo);
- {value, Root} ->
- case gb_trees:lookup(Key, Info) of
- {value, Root} ->
- case has_dep(Key, Root, PhiDep) of
- true -> %% Must keep Key!
- rewrite_instr0(I, Left, Info, PhiDep, UpdateInfo);
- false ->
- rewrite_instr0(I, Left, Info, PhiDep, [{Key, Root}|UpdateInfo])
- end;
- _ ->
- rewrite_instr0(I, Left, Info, PhiDep, UpdateInfo)
- end
- end;
-rewrite_instr0(I, [], _Info, _PhiDep, UpdateInfo) ->
- ?code:subst(UpdateInfo, I).
-
-add_binding([Key|Left], Val, Info) ->
- %% Make sure the key is bound to the end of any copy-chains.
- NewInfo =
- case gb_trees:lookup(Val, Info) of
- {value, NewVal} ->
- gb_trees:insert(Key, NewVal, Info);
- none ->
- gb_trees:insert(Key, Val, Info)
- end,
- add_binding(Left, Val, NewInfo);
-add_binding([], _, Info) ->
- Info.
diff --git a/lib/hipe/ssa/hipe_ssa_liveness.inc b/lib/hipe/ssa/hipe_ssa_liveness.inc
deleted file mode 100644
index a1b49d5d35..0000000000
--- a/lib/hipe/ssa/hipe_ssa_liveness.inc
+++ /dev/null
@@ -1,326 +0,0 @@
-%% -*- Erlang -*-
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% GENERIC MODULE TO PERFORM LIVENESS ANALYSIS ON SSA FORM
-%%
-%% Exports:
-%% ~~~~~~~
-%% analyze(CFG) - returns a liveness analysis of CFG.
-%% liveout(Liveness, Label) - returns the list of variables that are
-%% live at exit from basic block named Label.
-%% livein(Liveness, Label) - returns the list of variables that are
-%% live on entry to the basic block named Label.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% Uncomment the following if this is ever needed as an independent module
-%%
--ifdef(LIVENESS_NEEDED).
--export([ssa_liveness__analyze/1,
- ssa_liveness__livein/2]).
-%% ssa_liveness__livein/3],
-%% ssa_liveness__liveout/2]).
--type set(E) :: gb_sets:set(E).
--type liveness(Label, Var) ::
- #{Label => {{Gen :: set(Var),
- Kill :: set(Var),
- {TotalDirGen :: set(Var),
- DirGen :: gb_trees:tree(Label, set(Var))}},
- LiveIn :: set(Var),
- LiveOut :: set(Var),
- Successors :: [Label]}}.
--endif.
-%% -ifdef(DEBUG_LIVENESS).
-%% -export([pp_liveness/1]).
-%% -endif.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Interface functions that MUST be implemented in the supporting files
-%%
-%% In the CFG file:
-%% ----------------
-%% - bb(CFG, L) -> BasicBlock, extract a basic block from a cfg.
-%% - postorder(CFG) -> [Labels], the labels of the cfg in postorder
-%% - succ(CFG, L) -> [Labels],
-%% - function(CFG) -> {M,F,A}
-%%
-%% In the CODE file:
-%% -----------------
-%% - uses(Instr) ->
-%% - defines(Instr) ->
-%% - is_phi(Instr) -> Boolean
-%% - phi_arglist(Instr) -> [{Pred, Var}]
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% The generic liveness analysis on SSA form
-%%
-ssa_liveness__analyze(CFG) ->
- PO = ?CFG:postorder(CFG),
- InitLiveness = liveness_init(init(PO, CFG)),
- merry_go_around(PO, InitLiveness).
-
-%%
-%% The fixpoint iteration
-%%
-
-merry_go_around(Labels, Liveness) ->
- case doit_once(Labels, Liveness) of
- {fixpoint, NewLiveness} ->
- NewLiveness;
- {value, NewLiveness} ->
- merry_go_around(Labels, NewLiveness)
- end.
-
-%%
-%% One iteration
-%%
-
-doit_once(Labels, Liveness) ->
- doit_once(Labels, Liveness, true).
-
-doit_once([], Liveness, FixPoint) ->
- if FixPoint -> {fixpoint, Liveness};
- true -> {value, Liveness}
- end;
-doit_once([L|Ls], Liveness, FixPoint) ->
- LiveOut = join_livein(Liveness, L),
- NewLiveness = update_liveout(L, LiveOut, Liveness),
- Kill = set_subtract(LiveOut, kill(L, NewLiveness)),
- LiveIn = set_union(Kill, gen(L, NewLiveness)),
- case update_livein(L, LiveIn, NewLiveness) of
- fixpoint -> doit_once(Ls, NewLiveness, FixPoint);
- {value, NewLiveness1} -> doit_once(Ls, NewLiveness1, false)
- end.
-
-%%
-%% updates liveness for a basic block
-%%
-
-update_livein(Label, NewLiveIn, Liveness) ->
- {GKD, LiveIn, LiveOut, Succ} = liveness_lookup(Label, Liveness),
- case LiveIn of
- NewLiveIn ->
- fixpoint;
- _ ->
- {value, liveness_update(Label, {GKD,NewLiveIn,LiveOut,Succ}, Liveness)}
- end.
-
-update_liveout(Label, NewLiveOut, Liveness) ->
- {GKD, LiveIn, _LiveOut, Succ} = liveness_lookup(Label, Liveness),
- liveness_update(Label, {GKD,LiveIn,NewLiveOut,Succ}, Liveness).
-
-%%
-%% Join live in to get the new live out.
-%%
-
-join_livein(Liveness, L) ->
- Succ = successors(L, Liveness),
- case Succ of
- [] -> % special case if no successors
- gb_sets:from_list(liveout_no_succ());
- _ ->
- join_livein1(L, Succ, Liveness)
- end.
-
-join_livein1(Pred, Labels, Liveness) ->
- join_livein1(Pred, Labels, Liveness, new_set()).
-
-join_livein1(_Pred, [], _Liveness, Live) ->
- Live;
-join_livein1(Pred, [L|Ls], Liveness, Live) ->
- OldLivein = livein_set(Liveness, L, Pred),
- NewLive = set_union(OldLivein, Live),
- join_livein1(Pred, Ls, Liveness, NewLive).
-
-
-ssa_liveness__liveout(Liveness, L) ->
- {_GKD, _LiveIn, LiveOut, Successors} = liveness_lookup(L, Liveness),
- case Successors of
- [] -> % special case if no successors
- liveout_no_succ();
- _ ->
- set_to_list(LiveOut)
- end.
-
--ifdef(LIVENESS_NEEDED).
-ssa_liveness__livein(Liveness, L) ->
- set_to_list(livein_set(Liveness, L)).
-
-%% ssa_liveness__livein(Liveness, L, Pred) ->
-%% set_to_list(livein_set(Liveness, L, Pred)).
-
-livein_set(Liveness, L) ->
- {{_Gen,_Kill,{TotalDirGen, _DirGen}}, LiveIn, _LiveOut, _Successors} =
- liveness_lookup(L, Liveness),
- set_union(TotalDirGen, LiveIn).
--endif.
-
-livein_set(Liveness, L, Pred) ->
- {{_Gen,_Kill,{_TotalDirGen, DirGen}}, LiveIn, _LiveOut, _Successors} =
- liveness_lookup(L, Liveness),
- case gb_trees:lookup(Pred, DirGen) of
- none ->
- LiveIn;
- {value, LiveInFromPred} ->
- set_union(LiveInFromPred, LiveIn)
- end.
-
-successors(L, Liveness) ->
- {_GKD, _LiveIn, _LiveOut, Successors} = liveness_lookup(L, Liveness),
- Successors.
-
-kill(L, Liveness) ->
- {{_Gen,Kill,_DirGen},_LiveIn,_LiveOut,_Successors} =
- liveness_lookup(L, Liveness),
- Kill.
-
-gen(L, Liveness) ->
- {{Gen,_Kill,_DirGen},_LiveIn,_LiveOut,_Successors} =
- liveness_lookup(L, Liveness),
- Gen.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% init returns a list of: {Label, {{Gen, Kill}, LiveIn, Successors}}
-%% - Label is the name of the basic block.
-%% - Gen is the set of varables that are used by this block.
-%% - Kill is the set of varables that are defined by this block.
-%% - LiveIn is the set of variables that are alive at entry to the
-%% block (initially empty).
-%% - Successors is a list of the successors to the block.
-
-init([], _) ->
- [];
-init([L|Ls], CFG) ->
- BB = ?CFG:bb(CFG, L),
- Code = hipe_bb:code(BB),
- Succ = ?CFG:succ(CFG, L),
- {Gen, Kill} = make_bb_transfer(Code, Succ),
- DirectedGen = get_directed_gen(Code),
- [{L, {{Gen, Kill, DirectedGen}, new_set(), new_set(), Succ}}
- | init(Ls, CFG)].
-
-make_bb_transfer([], _Succ) ->
- {new_set(), new_set()}; % {Gen, Kill}
-make_bb_transfer([I|Is], Succ) ->
- {Gen, Kill} = make_bb_transfer(Is, Succ),
- case ?CODE:is_phi(I) of
- true ->
- InstrKill = set_from_list(?CODE:defines(I)),
- Gen1 = set_subtract(Gen, InstrKill),
- Kill1 = set_union(Kill, InstrKill),
- {Gen1, Kill1};
- false ->
- InstrGen = set_from_list(?CODE:uses(I)),
- InstrKill = set_from_list(?CODE:defines(I)),
- Gen1 = set_subtract(Gen, InstrKill),
- Gen2 = set_union(Gen1, InstrGen),
- Kill1 = set_union(Kill, InstrKill),
- Kill2 = set_subtract(Kill1, InstrGen),
- {Gen2, Kill2}
- end.
-
-get_directed_gen(Code) ->
- Map = get_directed_gen_1(Code),
- TotalGen = lists:foldl(fun({_Pred, Gen}, Acc) ->
- set_union(Gen, Acc)
- end, new_set(), gb_trees:to_list(Map)),
- {TotalGen, Map}.
-
-get_directed_gen_1([I|Left])->
- case ?CODE:is_phi(I) of
- false ->
- gb_trees:empty();
- true ->
- Map = get_directed_gen_1(Left),
- ArgList = ?CODE:phi_arglist(I),
- lists:foldl(fun update_directed_gen/2, Map, ArgList)
- end.
-
-update_directed_gen({Pred, Var}, Map)->
- case gb_trees:lookup(Pred, Map) of
- none -> gb_trees:insert(Pred, set_from_list([Var]), Map);
- {value, Set} -> gb_trees:update(Pred, set_add(Var, Set), Map)
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% liveness
-%%
--compile({inline, [liveness_lookup/2, liveness_update/3]}).
-
-liveness_init(List) ->
- maps:from_list(List).
-
-liveness_lookup(Label, Liveness) ->
- maps:get(Label, Liveness).
-liveness_update(Label, Val, Liveness) ->
- maps:update(Label, Val, Liveness).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Sets
-%%
-
-new_set() ->
- gb_sets:empty().
-
-set_union(S1, S2) ->
- gb_sets:union(S1, S2).
-
-set_subtract(S1, S2) ->
- gb_sets:subtract(S1, S2).
-
-set_from_list(List) ->
- gb_sets:from_list(List).
-
-set_to_list(Set) ->
- gb_sets:to_list(Set).
-
-set_add(Var, Set) ->
- gb_sets:add(Var, Set).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Pretty printer
-%%
-
--ifdef(DEBUG_LIVENESS).
-
-pp_liveness(CFG) ->
- io:format("Liveness for ~p:\n", [?CFG:function(CGF)]),
- Liveness = analyze(CFG),
- RevPostorder = lists:reverse(?CFG:postorder(CFG)),
- Edges = [{X, Y} || X <- RevPostorder, Y <- ?CFG:succ(CFG, X)],
- pp_liveness_edges(Edges, Liveness).
-
-pp_liveness_edges([{From, To}|Left], Liveness)->
- LiveIn = livein(Liveness, To, From),
- io:format("Label ~w -> Label ~w: ~p\n", [From, To, LiveIn]),
- LiveOut = liveout(Liveness, From),
- io:format("Total live out from Label ~w: ~p\n", [From, LiveOut]),
- pp_liveness_edges(Left, Liveness);
-pp_liveness_edges([], _Liveness) ->
- ok.
-
--endif.
diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile
deleted file mode 100644
index 5085aabdf4..0000000000
--- a/lib/hipe/test/Makefile
+++ /dev/null
@@ -1,82 +0,0 @@
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES= \
- hipe_SUITE \
- opt_verify_SUITE
-
-# .erl files for these modules are automatically generated
-GEN_MODULES= \
- basic_SUITE \
- maps_SUITE \
- sanity_SUITE
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-INSTALL_PROGS= $(TARGET_FILES)
-
-# ----------------------------------------------------
-# Files
-# ----------------------------------------------------
-EMAKEFILE = Emakefile
-AUXILIARY_FILES = hipe.spec hipe_testsuite_driver.erl $(EMAKEFILE)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/hipe_test
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS +=
-
-EBIN = .
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-make_emakefile:
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
- > $(EMAKEFILE)
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(GEN_MODULES) \
- >> $(EMAKEFILE)
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \
- >> $(EMAKEFILE)
-
-tests debug opt: make_emakefile
- erl $(ERL_MAKE_FLAGS) -make
-
-clean:
- rm -f $(EMAKEFILE)
- rm -f $(TARGET_FILES) $(GEN_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
-
-release_docs_spec:
-
-release_tests_spec: make_emakefile
- $(INSTALL_DIR) "$(RELSYSDIR)"
- chmod -R u+w "$(RELSYSDIR)"
- $(INSTALL_DATA) $(AUXILIARY_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
- cd "$(RELSYSDIR)";\
- erlc hipe_testsuite_driver.erl;\
- erl -noshell -run hipe_testsuite_driver create_all_suites $(GEN_MODULES) -s erlang halt
diff --git a/lib/hipe/test/basic_SUITE_data/basic_arith.erl b/lib/hipe/test/basic_SUITE_data/basic_arith.erl
deleted file mode 100644
index 28e99be053..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_arith.erl
+++ /dev/null
@@ -1,72 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%---------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests cases for compilation of arithmetic.
-%%%---------------------------------------------------------------------
--module(basic_arith).
-
--export([test/0]).
-
-test() ->
- ok = test_rem(),
- ok = test_bit_ops(),
- ok = test_uplus(),
- ok = test_bsl_errors(),
- ok.
-
-%%----------------------------------------------------------------------
-%% Tests the remainder operator.
-
-test_rem() ->
- 2 = ret_rem(42, 20),
- -2 = ret_rem(-42, 20),
- -2 = ret_rem(-42, -20),
- {'EXIT', {badarith, _}} = ret_rem(3.14, 2),
- {'EXIT', {badarith, _}} = ret_rem(42, 3.14),
- ok.
-
-ret_rem(X, Y) ->
- catch X rem Y.
-
-%%----------------------------------------------------------------------
-%%
-
-test_bit_ops() ->
- 2 = bbb(11, 2, 16#3ff),
- ok.
-
-bbb(X, Y, Z) ->
- ((1 bsl X) bor Y) band Z.
-
-%%----------------------------------------------------------------------
-%% Tests unary plus: it used to be the identity function but not anymore
-
-test_uplus() ->
- badarith = try uplus(gazonk) catch error:Err -> Err end,
- 42 = uplus(42),
- ok.
-
-uplus(X) -> +(X).
-
-%%----------------------------------------------------------------------
-%% The first part of this test triggered a bug in the emulator as one
-%% of the arguments to bsl is not an integer.
-%%
-%% The second part triggered a compilation crash since an arithmetic
-%% expression resulting in a 'system_limit' exception was statically
-%% evaluated and an arithmetic result was expected.
-
-test_bsl_errors() ->
- {'EXIT', {'badarith', _}} = (catch (t1(0, pad, 0))),
- badarith = try t2(0, pad, 0) catch error:Err1 -> Err1 end,
- system_limit = try (id(1) bsl 100000000) catch error:Err2 -> Err2 end,
- ok.
-
-t1(_, X, _) ->
- (1 bsl X) + 1.
-
-t2(_, X, _) ->
- (X bsl 1) + 1.
-
-id(I) -> I.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl b/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl
deleted file mode 100644
index 6fafea3b09..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl
+++ /dev/null
@@ -1,102 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Tests for correct translation of various BEAM instructions.
-%%%-------------------------------------------------------------------
--module(basic_beam_instrs).
-
--export([test/0]).
-
-test() ->
- ok = test_make_fun(),
- ok = test_switch_val(),
- ok = test_put_literal(),
- ok = test_set_tuple_element(),
- ok = test_unguarded_unsafe_element(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests whether the translation of make_fun works.
-
-test_make_fun() ->
- {F, G} = double_the_fun(),
- ok = F(),
- {ok, 42} = G(42),
- FV1 = {ok, free_var1},
- FV2 = {also, {free, var2}},
- {FV1, {ok, [bv]}, FV2} = contains_fun(FV1, ignored, FV2),
- ok.
-
-double_the_fun() ->
- {fun () -> ok end, fun (V) -> {ok, V} end}.
-
-contains_fun(X, _IGNORED_ARG, Y) ->
- calls_fun(fun(Term) -> {X, Term, Y} end).
-
-calls_fun(F) ->
- F({ok, [bv]}).
-
-%%--------------------------------------------------------------------
-%% Tests whether the translation of switch_val works.
-
-test_switch_val() ->
- 'A' = sv(a),
- 'B' = sv(b),
- 'C' = sv(c),
- foo = sv(d),
- ok.
-
-sv(a) -> 'A';
-sv(b) -> 'B';
-sv(c) -> 'C';
-sv(_) -> foo.
-
-%%--------------------------------------------------------------------
-%% Tests correct handling of literals (statically constant terms)
-
--define(QUADRUPLE, {a,b,c,42}).
--define(DEEP_LIST, [42,[42,[42]]]).
-
-test_put_literal() ->
- ?QUADRUPLE = mk_literal_quadruple(),
- ?DEEP_LIST = mk_literal_deep_list(),
- ok.
-
-mk_literal_quadruple() ->
- ?QUADRUPLE.
-
-mk_literal_deep_list() ->
- ?DEEP_LIST.
-
-%%--------------------------------------------------------------------
-%% Tests whether the translation of set_tuple_element works.
-
--record(rec, {f1, f2, f3, f4, f5}).
-
-test_set_tuple_element() ->
- F2 = [a,b,c], F4 = {a,b},
- State0 = init_rec(F2, F4),
- State1 = simple_set(State0, 42),
- #rec{f1 = foo, f2 = F2, f3 = 42, f4 = F4, f5 = 42.0} = odd_set(State1, 21),
- ok.
-
-init_rec(F2, F4) ->
- #rec{f1 = bar, f2 = F2, f3 = 10, f4 = F4, f5 = 3.14}.
-
-simple_set(State, Val) -> %% f3 = Val is the one used in set_element;
- State#rec{f3 = Val, f5 = Val*2}. %% this checks the case of variable
-
-odd_set(State, Val) -> %% f3 = foo is the one used in set_element;
- State#rec{f1 = foo, f5 = Val*2.0}. %% this checks the case of constant
-
-%%--------------------------------------------------------------------
-%% Tests the handling of unguarded unsafe_element operations that BEAM
-%% can sometimes construct on records (when it has enough context).
-
-test_unguarded_unsafe_element() ->
- {badrecord, rec} = try unguarded_unsafe_element(42) catch error:E -> E end,
- ok.
-
-unguarded_unsafe_element(X) ->
- X#rec{f1 = X#rec.f3}.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bifs.erl b/lib/hipe/test/basic_SUITE_data/basic_bifs.erl
deleted file mode 100644
index e7ee2f3678..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_bifs.erl
+++ /dev/null
@@ -1,257 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests for handling of BIFs in guards and body calls.
-%%%-------------------------------------------------------------------
--module(basic_bifs).
-
--export([test/0]).
-
--define(BIG, 1398479237498374913984792374983749).
-
-test() ->
- ok = test_abs(),
- ok = test_binary_part(),
- ok = test_element(),
- ok = test_float(),
- ok = test_float_to_list(),
- ok = test_integer_to_list(),
- ok = test_list_to_float(),
- ok = test_list_to_integer(),
- ok = test_round(),
- ok = test_trunc(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_abs() ->
- t_abs(5.5, 0.0, -100.0, 5, 0, -100, ?BIG).
-
-t_abs(F1, F2, F3, I1, I2, I3, BigNum) ->
- %% Floats.
- 5.5 = abs(F1),
- 0.0 = abs(F2),
- 100.0 = abs(F3),
- %% Integers.
- 5 = abs(I1),
- 0 = abs(I2),
- 100 = abs(I3),
- %% Bignums.
- BigNum = abs(BigNum),
- BigNum = abs(-BigNum),
- ok.
-
-%%--------------------------------------------------------------------
-%% Checks that 2-ary and 3-ary BIFs can be compiled to native code.
-
-test_binary_part() ->
- Bin = <<1,2,3,4,5,6,7,8,9,10>>,
- BinPart = bp3(Bin),
- <<7,8>> = bp2(BinPart),
- ok.
-
-bp2(Bin) ->
- binary_part(Bin, {1, 2}).
-
-bp3(Bin) ->
- binary_part(Bin, byte_size(Bin), -5).
-
-%%--------------------------------------------------------------------
-
-test_element() ->
- true = elem({a, b}),
- false = elem({a, c}),
- other = elem(gazonk),
- ok.
-
-elem(T) when element(1, T) == a -> element(2, T) == b;
-elem(_) -> other.
-
-%%--------------------------------------------------------------------
-
-test_float() ->
- t_float(0, 42, -100, 2.5, 0.0, -100.42, ?BIG, -?BIG).
-
-t_float(I1, I2, I3, F1, F2, F3, B1, B2) ->
- 0.0 = float(I1),
- 2.5 = float(F1),
- 0.0 = float(F2),
- -100.42 = float(F3),
- 42.0 = float(I2),
- -100.0 = float(I3),
- %% Bignums.
- 1398479237498374913984792374983749.0 = float(B1),
- -1398479237498374913984792374983749.0 = float(B2),
- %% Extremly big bignums.
- Big = list_to_integer(duplicate(2000, $1)),
- {'EXIT', _} = (catch float(Big)),
- %% Invalid types and lists.
- {'EXIT', _} = (catch my_list_to_integer(atom)),
- {'EXIT', _} = (catch my_list_to_integer(123)),
- {'EXIT', _} = (catch my_list_to_integer([$1, [$2]])),
- {'EXIT', _} = (catch my_list_to_integer("1.2")),
- {'EXIT', _} = (catch my_list_to_integer("a")),
- {'EXIT', _} = (catch my_list_to_integer("")),
- ok.
-
-my_list_to_integer(X) ->
- list_to_integer(X).
-
-%%--------------------------------------------------------------------
-
-test_float_to_list() ->
- test_ftl("0.0e+0", 0.0),
- test_ftl("2.5e+1", 25.0),
- test_ftl("2.5e+0", 2.5),
- test_ftl("2.5e-1", 0.25),
- test_ftl("-3.5e+17", -350.0e15),
- ok.
-
-test_ftl(Expect, Float) ->
- %% No \n on the next line -- we want the line number from t_float_to_list.
- Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
-
-%% Removes any non-significant zeros in a floating point number.
-%% Example: 2.500000e+01 -> 2.5e+1
-
-remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$+, $e|Rest], [X|Result]);
-remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$-, $e|Rest], [X|Result]);
-remove_zeros([$0, $.|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$., $0, $e|Result]);
-remove_zeros([$0|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$e|Result]);
-remove_zeros([Char|Rest], Result) ->
- remove_zeros(Rest, [Char|Result]);
-remove_zeros([], Result) ->
- Result.
-
-%%--------------------------------------------------------------------
-
-test_integer_to_list() ->
- t_integer_to_list(0, 42, 32768, 268435455, 123456932798748738738).
-
-t_integer_to_list(I1, I2, I3, I4, BIG) ->
- "0" = integer_to_list(I1),
- "42" = integer_to_list(I2),
- "-42" = integer_to_list(-I2),
- "-42" = integer_to_list(-I2),
- "32768" = integer_to_list(I3),
- "268435455" = integer_to_list(I4),
- "-268435455" = integer_to_list(-I4),
- "123456932798748738738" = integer_to_list(BIG),
- BigList = duplicate(2000, $1),
- Big = list_to_integer(BigList),
- BigList = integer_to_list(Big),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_list_to_float() ->
- ok = t_list_to_float_safe(),
- ok = t_list_to_float_risky().
-
-t_list_to_float_safe() ->
- 0.0 = my_list_to_float("0.0"),
- 0.0 = my_list_to_float("-0.0"),
- 0.5 = my_list_to_float("0.5"),
- -0.5 = my_list_to_float("-0.5"),
- 100.0 = my_list_to_float("1.0e2"),
- 127.5 = my_list_to_float("127.5"),
- -199.5 = my_list_to_float("-199.5"),
- {'EXIT', _} = (catch my_list_to_float("0")),
- {'EXIT', _} = (catch my_list_to_float("0..0")),
- {'EXIT', _} = (catch my_list_to_float("0e12")),
- {'EXIT', _} = (catch my_list_to_float("--0.0")),
- ok.
-
-my_list_to_float(X) ->
- list_to_float(X).
-
-%% This might crash the emulator. (Used to crash Erlang 4.4.1 on Unix.)
-
-t_list_to_float_risky() ->
- Many_Ones = duplicate(25000, $1),
- ok = case list_to_float("2." ++ Many_Ones) of
- F when is_float(F), 0.0 < F, F =< 3.14 -> ok
- end,
- {'EXIT', _} = (catch list_to_float("2" ++ Many_Ones)),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_list_to_integer() ->
- ok = t_list_to_integer_small("0", "00", "-0", "1", "-1", "42", "-12",
- "32768", "268435455", "-268435455"),
- ok = t_list_to_integer_bignum("123456932798748738738666"),
- ok.
-
-t_list_to_integer_small(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10) ->
- 0 = list_to_integer(S1),
- 0 = list_to_integer(S2),
- 0 = list_to_integer(S3),
- 1 = list_to_integer(S4),
- -1 = list_to_integer(S5),
- 42 = list_to_integer(S6),
- -12 = list_to_integer(S7),
- 32768 = list_to_integer(S8),
- 268435455 = list_to_integer(S9),
- -268435455 = list_to_integer(S10),
- ok.
-
-t_list_to_integer_bignum(S) ->
- 123456932798748738738666 = list_to_integer(S),
- case list_to_integer(duplicate(2000, $1)) of
- I when is_integer(I), I > 123456932798748738738666 -> ok
- end.
-
-%%--------------------------------------------------------------------
-
-test_round() ->
- ok = t_round_small(0.0, 0.4, 0.5, -0.4, -0.5, 255.3, 255.6, -1033.3, -1033.6),
- ok = t_round_big(4294967296.1, 4294967296.9),
- ok.
-
-t_round_small(F1, F2, F3, F4, F5, F6, F7, F8, F9) ->
- 0 = round(F1),
- 0 = round(F2),
- 1 = round(F3),
- 0 = round(F4),
- -1 = round(F5),
- 255 = round(F6),
- 256 = round(F7),
- -1033 = round(F8),
- -1034 = round(F9),
- ok.
-
-t_round_big(B1, B2) ->
- 4294967296 = round(B1),
- 4294967297 = round(B2),
- -4294967296 = round(-B1),
- -4294967297 = round(-B2),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_trunc() ->
- t_trunc(0.0, 5.3333, -10.978987, 4294967305.7).
-
-t_trunc(F1, F2, F3, B) ->
- 0 = trunc(F1),
- 5 = trunc(F2),
- -10 = trunc(F3),
- %% Bignums.
- 4294967305 = trunc(B),
- -4294967305 = trunc(-B),
- ok.
-
-%%--------------------------------------------------------------------
-%% Auxiliary functions below
-
-duplicate(N, X) when is_integer(N), N >= 0 ->
- duplicate(N, X, []).
-
-duplicate(0, _, L) -> L;
-duplicate(N, X, L) -> duplicate(N-1, X, [X|L]).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bignums.erl b/lib/hipe/test/basic_SUITE_data/basic_bignums.erl
deleted file mode 100644
index e3b523b3f5..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_bignums.erl
+++ /dev/null
@@ -1,143 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples that test bignum arithmetic and matching.
-%%%-------------------------------------------------------------------
--module(basic_bignums).
-
--export([test/0, test_bsl/0]).
-
-test() ->
- ok = test_ops(),
- ok = test_big_fac(),
- ok = test_int_overfl_32(),
- ok = test_int_overfl_64(),
- ok = test_int_overfl_32_guard(),
- ok = test_int_overfl_64_guard(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Define some constants for the tests of arithmetic operators
-
--define(X, 68719476736).
--define(Y, 98765432101234).
--define(Z, 4722366482869645213696).
--define(W, 339254531512339254531512).
-
--define(B1, 4398046511104).
--define(B5, 1645504557321206042154969182557350504982735865633579863348609024).
--define(B17, 86182066610968551542636378241108028056376767329454880514019834315878107616003372189510312530372009184902888961739623919010110377987011442493486117202360415845666384627768436296772219009176743399772868636439042064384).
-
-%%--------------------------------------------------------------------
-
-test_ops() ->
- ok = test_mult(),
- ok = test_div(),
- ok = test_round(),
- ok = test_trunc(),
- ok = test_bsl(),
- ok.
-
-test_mult() ->
- ?Z = mult(?X, ?X),
- ok.
-
-mult(X, Y) -> X * Y.
-
-test_div() ->
- 4 = div_f(339254531512, ?X),
- 0 = div_f(?Y, ?Y+1),
- 64 = div_f(?B1, ?X),
- ?X = div_f(?Z, ?X),
- 1073741824 = div_f(?Z, ?B1),
- ok.
-
-div_f(X, Y) -> X div Y.
-
-test_round() ->
- 0 = round_f(?Z, ?W),
- 1 = round_f(?Y, ?Y),
- 71 = round_f(?W, ?Z),
- 1437 = round_f(?Y, ?X),
- 47813960 = round_f(?Z, ?Y),
- 4936803183406 = round_f(?W, ?X),
- ok.
-
-trunc_f(X, Y) -> round(X/Y).
-
-test_trunc() ->
- 0 = trunc_f(?Z, ?W),
- 1 = trunc_f(?Y, ?Y),
- 72 = trunc_f(?W, ?Z),
- 1437 = trunc_f(?Y, ?X),
- 47813961 = trunc_f(?Z, ?Y),
- 4936803183407 = trunc_f(?W, ?X),
- ok.
-
-round_f(X, Y) -> trunc(X/Y).
-
-test_bsl() ->
- ?B1 = bsl_f(1, 42),
- ?B5 = n(5, fun erlang:'bsl'/2, 1, 42), % use the operator
- ?B17 = n(17, fun bsl_f/2, 1, 42), % use the local function
- ok.
-
-bsl_f(X, Y) -> X bsl Y.
-
-%% applies a binary function N times
-n(1, F, X, Y) -> F(X, Y);
-n(N, F, X, Y) when N > 1 -> n(N-1, F, F(X, Y), Y).
-
-%%--------------------------------------------------------------------
-
--define(FAC42, 1405006117752879898543142606244511569936384000000000).
-
-test_big_fac() ->
- ?FAC42 = fac(42),
- ok.
-
-fac(0) -> 1;
-fac(N) -> N * fac(N-1).
-
-%%--------------------------------------------------------------------
-%% Tests for correct handling of integer overflow
-
-test_int_overfl_32() ->
- 16#7FFFFFF = add(16#7FFFFFF, 0),
- 16#8000000 = add(16#8000000, 0),
- 16#8000001 = add(16#8000000, 1),
- case add(16#7FFFFFF, 1) of
- 16#8000000 -> ok;
- -16#7FFFFFF -> error
- end.
-
-test_int_overfl_64() ->
- 16#7FFFFFFFFFFFFFF = add(16#7FFFFFFFFFFFFFF, 0),
- 16#800000000000000 = add(16#800000000000000, 0),
- 16#800000000000001 = add(16#800000000000000, 1),
- case add(16#7FFFFFFFFFFFFFF, 1) of
- 16#800000000000000 -> ok;
- -16#7FFFFFFFFFFFFFF -> error
- end.
-
-add(X, Y) -> X + Y.
-
-%%--------------------------------------------------------------------
-%% Tests for correct handling of integer overflow in guards
-
-test_int_overfl_32_guard() ->
- ok = overfl_in_guard(16#7ffffff, 0),
- ok = overfl_in_guard(16#7ffffff, 16#7ffffff),
- ok.
-
-test_int_overfl_64_guard() ->
- ok = overfl_in_guard(16#7ffffffffffffff, 0),
- ok = overfl_in_guard(16#7ffffffffffffff, 16#7ffffffffffffff),
- ok.
-
-overfl_in_guard(X, Y) ->
- case ok of
- V when X+Y > 12 -> V;
- _ -> bad
- end.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_boolean.erl b/lib/hipe/test/basic_SUITE_data/basic_boolean.erl
deleted file mode 100644
index e4a91ef5af..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_boolean.erl
+++ /dev/null
@@ -1,47 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Tests for correct translation of booleans and their primitives.
-%%%-------------------------------------------------------------------
--module(basic_boolean).
-
--export([test/0]).
-
-test() ->
- ok = test_boolean_ops(false, true),
- ok = test_orelse_redundant(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_boolean_ops(F, T) ->
- true = T and T,
- false = T and F,
- false = F and T,
- false = F and F,
- true = T or T,
- true = T or F,
- true = F or T,
- false = F or F,
- true = T andalso T,
- false = T andalso F,
- false = F andalso T,
- false = F andalso F,
- true = T orelse T,
- true = T orelse F,
- true = F orelse T,
- false = F orelse F,
- ok.
-
-%%--------------------------------------------------------------------
-%% Redundant test in BEAM code will generate type warning.
-
-test_orelse_redundant() ->
- true = test_orelse(true, true, true),
- ok.
-
-test_orelse(A, B, C) ->
- A andalso B orelse C.
-
-%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl b/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl
deleted file mode 100644
index 964b0f423a..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl
+++ /dev/null
@@ -1,138 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples that exhibited bugs in the BEAM compiler.
-%%%-------------------------------------------------------------------
--module(basic_bugs_beam).
-
--export([test/0]).
-
-%% the following is needed for the test_weird_message
--export([loop/1]).
-%% the following are needed for the test_catch_bug
--behaviour(gen_server).
--export([start_link/1]).
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
-
-test() ->
- ok = test_fp_basic_blocks(),
- ok = test_weird_message(),
- ok = test_catch_bug(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Test which shows that BEAM's splitting of basic blocks should take
-%% into account that arithmetic operations implemented as BIFs can
-%% also cause exceptions and thus calls to BIFs should end basic blocks.
-%%
-%% Investigated and fixed in the beginning of April 2004.
-%%--------------------------------------------------------------------
-
-test_fp_basic_blocks() ->
- ok = t1(),
- ok = t2().
-
-t1() ->
- X = (catch bad_arith1(2.0, 1.7)),
- case X of
- {'EXIT', {badarith, _}} ->
- ok;
- _ ->
- error
- end.
-
-bad_arith1(X, Y) when is_float(X) ->
- X1 = X * 1.7e+308,
- X2 = X1 + 1.0,
- Y1 = Y * 2,
- {X2, Y1}.
-
-%% Similarly, it is not kosher to have anything that can fail inside
-%% the fp block since it will throw the exception before the fp
-%% exception and we will get the same problems.
-
-t2() ->
- case catch bad_arith2(2.0, []) of
- {'EXIT', {badarith, _}} ->
- ok;
- _ ->
- error
- end.
-
-bad_arith2(X, Y) when is_float(X) ->
- X1 = X * 1.7e+308,
- Y1 = element(1, Y),
- {X1 + 1.0, Y1}.
-
-%%--------------------------------------------------------------------
-%% Sending 'test' to this process should return 'ok'. But:
-%%
-%% 1> MOD:test().
-%% Weird: received true
-%% timeout
-%%
-%% Surprisingly, the message has been bound to the value of 'ena'
-%% in the record! The problem was visible in the .S file.
-%%--------------------------------------------------------------------
-
--record(state, {ena = true}).
-
-test_weird_message() ->
- P = spawn_link(?MODULE, loop, [#state{}]),
- P ! {msg, self()},
- receive
- What -> What
- after 42 -> timeout
- end.
-
-loop(S) ->
- receive
- _ when S#state.ena == false ->
- io:format("Weird: ena is false\n");
- % loop(S);
- {msg, Pid} ->
- Pid ! ok;
- % loop(S);
- Other ->
- io:format("Weird: received ~p\n", [Other])
- % loop(S)
- end.
-
-%%--------------------------------------------------------------------
-%% This was posted on the Erlang mailing list as a question:
-%%
-%% Given the module below and the function call
-%% "catch_bug:start_link(foo)."
-%% from the Erlang shell, why does Erlang crash with "Catch not found"?
-%%
-%% The BEAM compiler was generating wrong code for this case;
-%% this was fixed in R9C-0. Native code generation was OK.
-%%--------------------------------------------------------------------
-
-test_catch_bug() ->
- ignore = start_link(foo),
- ok.
-
-start_link(Param) ->
- gen_server:start_link(?MODULE, Param, []).
-
-init(Param) ->
- process_flag(trap_exit, true),
- (catch begin
- dummy(Param),
- (catch exit(bar))
- end
- ),
- ignore.
-
-dummy(_) -> ok.
-
-%% gen_server callbacks below
-handle_call(_Call, _From, State) -> {noreply, State}.
-handle_cast(_Msg, State) -> {noreply, State}.
-handle_info(_Msg, State) -> {noreply, State}.
-terminate(_Reason, _State) -> ok.
-code_change(_OldVsn, State, _Extra) -> {ok, State}.
-
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl
deleted file mode 100644
index c6bec39632..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl
+++ /dev/null
@@ -1,531 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%----------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples that exhibited bugs in the HiPE compiler.
-%%%----------------------------------------------------------------------
--module(basic_bugs_hipe).
-
--export([test/0]).
-
-% Ensure type optimization is turned off for id/1
--export([id/1]).
-
-test() ->
- ok = test_ets_bifs(),
- ok = test_szar_bug(),
- ok = test_bit_shift(),
- ok = test_match_big_list(),
- ok = test_unsafe_bsl(),
- ok = test_unsafe_bsr(),
- ok = test_R12B5_seg_fault(),
- ok = test_switch_neg_int(),
- ok = test_icode_range_anal(),
- ok = test_icode_range_call(),
- ok = test_icode_type_miscompile(),
- ok.
-
-%%-----------------------------------------------------------------------
-%% From: Bjorn Gustavsson
-%%
-%% This code, if HiPE compiled, crashed like this (on SPARC)
-%%
-%% (gdb) where
-%% #0 fullsweep_heap (p=0x2c60dc, new_sz=610, objv=0xffbee8b4, nobj=3)
-%% at beam/ggc.c:1060
-%% #1 0x7ff24 in erts_garbage_collect (p=0x2c60dc, need=2, objv=0x1128fc, ...)
-%% at beam/ggc.c:1648
-%% #2 0xab6fc in hipe_mode_switch (p=0x2c60dc, cmd=704512, reg=0x1128fc)
-%% at hipe/hipe_mode_switch.c:180
-%% #3 0x8e27c in process_main () at beam/beam_emu.c:3314
-%% #4 0x31338 in erl_start (argc=9, argv=0xffbeed5c) at beam/erl_init.c:936
-%% #5 0x2d9f4 in main (argc=9, argv=0xffbeed5c) at sys/unix/erl_main.c:28
-%%
-%% A guess at what could be the problem: From R8, many ets BIFs trap
-%% to other ets BIFs with a *different* arity (i.e. they have more or
-%% less arguments). I have probably forgotten to mention that subtle
-%% change.
-%%-----------------------------------------------------------------------
-
-test_ets_bifs() ->
- Seed = {1032, 15890, 22716},
- put(random_seed, Seed),
- do_random_test().
-
-do_random_test() ->
- OrdSet = ets:new(xxx, [ordered_set]),
- Set = ets:new(xxx, []),
- do_n_times(fun() ->
- Key = create_random_string(25),
- Value = create_random_tuple(25),
- ets:insert(OrdSet, {Key, Value}),
- ets:insert(Set, {Key, Value})
- end, 5000),
- %% io:format("~nData inserted~n"),
- do_n_times(fun() ->
- I = random:uniform(25),
- Key = create_random_string(I) ++ '_',
- L1 = ets_match_object(OrdSet, {Key, '_'}),
- L2 = lists:sort(ets_match_object(Set, {Key, '_'})),
- case L1 == L2 of
- false ->
- %% io:format("~p != ~p~n", [L1, L2]),
- exit({not_eq, L1, L2});
- true ->
- ok
- end
- end, 2000),
- %% io:format("~nData matched~n"),
- ets:match_delete(OrdSet, '_'),
- ets:match_delete(Set, '_'),
- ok.
-
-create_random_string(0) ->
- [];
-create_random_string(OfLength) ->
- C = case random:uniform(2) of
- 1 -> (random:uniform($Z - $A + 1) - 1) + $A;
- _ -> (random:uniform($z - $a + 1) - 1) + $a
- end,
- [C | create_random_string(OfLength - 1)].
-
-create_random_tuple(OfLength) ->
- list_to_tuple([list_to_atom([X]) || X <- create_random_string(OfLength)]).
-
-ets_match_object(Tab,Expr) ->
- case random:uniform(2) of
- 1 -> ets:match_object(Tab,Expr);
- _ -> match_object_chunked(Tab,Expr)
- end.
-
-match_object_chunked(Tab,Expr) ->
- match_object_chunked_collect(ets:match_object(Tab, Expr,
- random:uniform(1999) + 1)).
-
-match_object_chunked_collect('$end_of_table') ->
- [];
-match_object_chunked_collect({Results, Continuation}) ->
- Results ++ match_object_chunked_collect(ets:match_object(Continuation)).
-
-do_n_times(_, 0) ->
- ok;
-do_n_times(Fun, N) ->
- Fun(),
- case N rem 1000 of
- 0 -> ok; %% WAS: io:format(".");
- _ -> ok
- end,
- do_n_times(Fun, N - 1).
-
-%%-----------------------------------------------------------------------
-%% From: Jozsef Berces (PR/ECZ)
-%% Date: Feb 19, 2004
-%%
-%% Program which was added to the testsuite as a result of another bug
-%% report involving tuples as funs. Thanks God, these are no longer
-%% supported, but the following is a good test for testing calling
-%% native code funs from BEAM code (lists:map, lists:filter, ...).
-%%-----------------------------------------------------------------------
-
-test_szar_bug() ->
- ["A","B","C"] = smartconcat([], "H'A, H'B, H'C"),
- ok.
-
-smartconcat(B, L) ->
- LL = tokenize(L, $,),
- NewlineDel = fun (X) -> killcontrol(X) end,
- StripFun = fun (X) -> string:strip(X) end,
- LL2 = lists:map(NewlineDel, lists:map(StripFun, LL)),
- EmptyDel = fun(X) ->
- case string:len(X) of
- 0 -> false;
- _ -> true
- end
- end,
- LL3 = lists:filter(EmptyDel, LL2),
- HexFormat = fun(X, Acc) ->
- case string:str(X, "H'") of
- 1 ->
- case checkhex(string:substr(X, 3)) of
- {ok, Y} ->
- {Y, Acc};
- _ ->
- {X, Acc + 1}
- end;
- _ ->
- {X, Acc + 1}
- end
- end,
- {LL4,_Ret} = lists:mapfoldl(HexFormat, 0, LL3),
- lists:append(B, lists:sublist(LL4, lists:max([0, 25 - length(B)]))).
-
-checkhex(L) ->
- checkhex(L, "").
-
-checkhex([H | T], N) when H >= $0, H =< $9 ->
- checkhex(T, [H | N]);
-checkhex([H | T], N) when H >= $A, H =< $F ->
- checkhex(T, [H | N]);
-checkhex([H | T], N) when H =< 32 ->
- checkhex(T, N);
-checkhex([_ | _], _) ->
- {error, ""};
-checkhex([], N) ->
- {ok, lists:reverse(N)}.
-
-killcontrol([C | S]) when C < 32 ->
- killcontrol(S);
-killcontrol([C | S]) ->
- [C | killcontrol(S)];
-killcontrol([]) ->
- [].
-
-tokenize(L, C) ->
- tokenize(L, C, [], []).
-
-tokenize([C | T], C, A, B) ->
- case A of
- [] ->
- tokenize(T, C, [], B);
- _ ->
- tokenize(T, C, [], [lists:reverse(A) | B])
- end;
-tokenize([H | T], C, A, B) ->
- tokenize(T, C, [H | A], B);
-tokenize(_, _, [], B) ->
- lists:reverse(B);
-tokenize(_, _, A, B) ->
- lists:reverse([lists:reverse(A) | B]).
-
-%%-----------------------------------------------------------------------
-%% From: Niclas Pehrsson
-%% Date: Apr 20, 2006
-%%
-%% We found something weird with the bit shifting in HiPE. It seems
-%% that bsr in some cases shifts the bits in the wrong way...
-%%
-%% Fixed about 10 mins afterwards; was a bug in constant propagation.
-%%-----------------------------------------------------------------------
-
-test_bit_shift() ->
- 1 = plain_shift(), % 1
- 6 = length_list_plus(), % 6
- 0 = shift_length_list(), % 0
- 1 = shift_length_list_plus(), % 1
- 1 = shift_length_list_plus2(), % 1
- 24 = shift_length_list_plus_bsl(), % 24
- 1 = shift_fun(), % 1
- %% {1, 6, 0, 1, 1, 24, 1} = {A, B, C, D, E, F, G},
- ok.
-
-plain_shift() ->
- 6 bsr 2.
-
-length_list() ->
- length([0,0]).
-
-length_list_plus() ->
- length([0,0]) + 4.
-
-shift_length_list() ->
- length([0,0]) bsr 2.
-
-shift_length_list_plus() ->
- (length([0,0]) + 4) bsr 2.
-
-shift_length_list_plus_bsl() ->
- (length([0,0]) + 4) bsl 2.
-
-shift_length_list_plus2() ->
- N = length([0,0]) + 4,
- N bsr 2.
-
-shift_fun() ->
- (length_list() + 4) bsr 2.
-
-%%-----------------------------------------------------------------------
-%% From: Igor Goryachev
-%% Date: June 15, 2006
-%%
-%% I have experienced a different behaviour and possibly a weird result
-%% while playing with matching a big list on x86 and x86_64 machines.
-%%-----------------------------------------------------------------------
-
--define(BIG_LIST,
- ["uid", "nickname", "n_family", "n_given", "email_pref",
- "tel_home_number", "tel_cellular_number", "adr_home_country",
- "adr_home_locality", "adr_home_region", "url", "gender", "bday",
- "constitution", "height", "weight", "hair", "routine", "smoke",
- "maritalstatus", "children", "independence", "school_number",
- "school_locality", "school_title", "school_period", "org_orgname",
- "title", "adr_work_locality", "photo_type", "photo_binval"]).
-
-test_match_big_list() ->
- case create_tuple_with_big_const_list() of
- {selected, ?BIG_LIST, _} -> ok;
- _ -> weird
- end.
-
-create_tuple_with_big_const_list() ->
- {selected, ?BIG_LIST, [{"test"}]}.
-
-%%-----------------------------------------------------------------------
-%% In October 2006 the HiPE compiler acquired more type-driven
-%% optimisations of arithmetic operations. One of these, the
-%% transformation of bsl to a pure fixnum bsl fixnum -> fixnum version
-%% (unsafe_bsl), was incorrectly performed even when the result
-%% wouldn't be a fixnum. The error occurred for all backends, but the
-%% only place known to break was hipe_arm:imm_to_am1/2. Some
-%% immediates got broken on ARM, causing segmentation faults in
-%% compiler_tests when HiPE recompiled itself.
-%%-----------------------------------------------------------------------
-
-test_unsafe_bsl() ->
- ok = bsl_check(bsl_test_cases()).
-
-bsl_test_cases() ->
- [{16#FF, {16#FF, 0}},
- {16#F000000F, {16#FF, 2}}].
-
-bsl_check([]) -> ok;
-bsl_check([{X, Y}|Rest]) ->
- case imm_to_am1(X) of
- Y -> bsl_check(Rest);
- _ -> 'hipe_broke_bsl'
- end.
-
-imm_to_am1(Imm) ->
- imm_to_am1(Imm band 16#FFFFFFFF, 16).
-imm_to_am1(Imm, RotCnt) ->
- if Imm >= 0, Imm =< 255 -> {Imm, RotCnt band 15};
- true ->
- NewRotCnt = RotCnt - 1,
- if NewRotCnt =:= 0 -> []; % full circle, no joy
- true ->
- NewImm = (Imm bsr 2) bor ((Imm band 3) bsl 30),
- imm_to_am1(NewImm, NewRotCnt)
- end
- end.
-
-%%-----------------------------------------------------------------------
-%% Another transformation, namely that of bsr to a pure fixnum bsr
-%% fixnum -> fixnum version (unsafe_bsr), failed to check for shifts
-%% larger than the number of bits in fixnums. Such shifts should
-%% return zero, but instead they became plain machine-level shift
-%% instructions. Machines often only consider the low-order bits of
-%% the shift count, so machine-level shifts larger than the word size
-%% do not match the Erlang semantics.
-%%-----------------------------------------------------------------------
-
-test_unsafe_bsr() ->
- ok = bsr_check(bsr_test_cases()).
-
-bsr_test_cases() ->
- [{16#FF, 4, 16#0F},
- {16#FF, 64, 0}].
-
-bsr_check([]) -> ok;
-bsr_check([{X, Y, Z}|Rest]) ->
- case do_bsr(X, Y) of
- Z -> bsr_check(Rest);
- _ -> 'hipe_broke_bsr'
- end.
-
-do_bsr(X, Y) ->
- (X band 16#FFFF) bsr (Y band 16#FFFF).
-
-%%-----------------------------------------------------------------------
-%% From: Sergey S, mid January 2009.
-%%
-%% While I was playing with +native option, I run into a bug in HiPE
-%% which leads to segmentation fault using +native and Erlang R12B-5.
-%%
-%% Eshell V5.6.5
-%% 1> crash:test().
-%% # Some message to be printed here each loop iteration
-%% Segmentation fault
-%%
-%% Diagnosed and fixed by Mikael Pettersson (22 Jan 2009):
-%%
-%% I've analysed the recently posted HiPE bug report on erlang-bugs
-%% <http://www.erlang.org/pipermail/erlang-bugs/2009-January/001162.html>.
-%% The segfault is caused by memory corruption, which in turn is caused
-%% by RTL removing an update of the HP (heap pointer) register due to
-%% what looks like broken liveness information.
-%%-----------------------------------------------------------------------
-
-test_R12B5_seg_fault() ->
- _ = spawn(fun() -> init() end),
- ok.
-
-init() ->
- repeat(5, fun() -> void end),
- receive after infinity -> ok end.
-
-repeat(0, _) ->
- ok;
-repeat(N, Fun) ->
- %% io:format("# Some message to be printed here each loop iteration\n"),
- Fun(),
- repeat(N - 1, Fun).
-
-%%-----------------------------------------------------------------------
-%% From: Jon Meredith
-%% Date: July 9, 2009
-%%
-%% Binary search key tables are sorted by the loader based on the
-%% runtime representations of the keys as unsigned words. However,
-%% the code generated for the binary search used signed comparisons.
-%% That worked for atoms and non-negative fixnums, but not for
-%% negative fixnums. Fixed by Mikael Pettersson July 10, 2009.
-%%-----------------------------------------------------------------------
-
-test_switch_neg_int() ->
- ok = f(-80, 8).
-
-f(10, -1) -> ok;
-f(X, Y) ->
- Y = g(X),
- f(X + 10, Y - 1).
-
-g(X) -> % g(0) should be 0 but became -1
- case X of
- 0 -> 0;
- -10 -> 1;
- -20 -> 2;
- -30 -> 3;
- -40 -> 4;
- -50 -> 5;
- -60 -> 6;
- -70 -> 7;
- -80 -> 8;
- _ -> -1
- end.
-
-%%-----------------------------------------------------------------------
-%% From: Paul Guyot
-%% Date: Jan 31, 2011
-%%
-%% There is a bug in HiPE compilation with the comparison of floats
-%% with integers. This bug happens in functions f/1 and g/2 below.
-%% BEAM will evaluate f_eq(42) and f_eq(42.0) to true, while HiPE
-%% will evaluate them to false.
-%%
-%% The culprit was the Icode range analysis which was buggy. (On the
-%% other hand, HiPE properly evaluated these calls to true if passed
-%% the option 'no_icode_range'.) Fixed by Kostis Sagonas.
-%% --------------------------------------------------------------------
-
-test_icode_range_anal() ->
- true = f_eq(42),
- true = f_eq(42.0),
- false = f_ne(42),
- false = f_ne(42.0),
- false = f_eq_ex(42),
- false = f_eq_ex(42.0),
- true = f_ne_ex(42),
- true = f_ne_ex(42.0),
- false = f_gt(42),
- false = f_gt(42.0),
- true = f_le(42),
- true = f_le(42.0),
- zero_test = g(0, test),
- zero_test = g(0.0, test),
- non_zero_test = g(42, test),
- other = g(42, other),
- ok.
-
-f_eq(X) ->
- Y = X / 2,
- Y == 21.
-
-f_ne(X) ->
- Y = X / 2,
- Y /= 21.
-
-f_eq_ex(X) ->
- Y = X / 2,
- Y =:= 21.
-
-f_ne_ex(X) ->
- Y = X / 2,
- Y =/= 21.
-
-f_gt(X) ->
- Y = X / 2,
- Y > 21.
-
-f_le(X) ->
- Y = X / 2,
- Y =< 21.
-
-g(X, Z) ->
- Y = X / 2,
- case Z of
- test when Y == 0 -> zero_test;
- test -> non_zero_test;
- other -> other
- end.
-
-%%-----------------------------------------------------------------------
-%% From: Rich Neswold
-%% Date: Oct 5, 2016
-%%
-%% The following was a bug in the HiPE compiler's range analysis. The
-%% function range_client/2 below would would not stop when N reached 0,
-%% but keep recursing into the second clause forever.
-%%
-%% The problem turned out to be in hipe_icode_range:analyse_call/2,
-%% which would note update the argument ranges of the callee if the
-%% result of the call was ignored.
-%% -----------------------------------------------------------------------
--define(TIMEOUT, 42).
-
-test_icode_range_call() ->
- Self = self(),
- Client = spawn_link(fun() -> range_client(Self, 4) end),
- range_server(4, Client).
-
-range_server(0, _Client) ->
- receive
- stopping -> ok;
- {called_with, 0} -> error(failure)
- after ?TIMEOUT -> error(timeout)
- end;
-range_server(N, Client) ->
- receive
- {called_with, N} ->
- Client ! proceed
- after ?TIMEOUT -> error(timeout)
- end,
- range_server(N-1, Client). % tailcall (so the bug does not affect it)
-
-range_client(Server, 0) ->
- Server ! stopping;
-range_client(Server, N) ->
- Server ! {called_with, N},
- receive proceed -> ok end,
- range_client(Server, N - 1), % non-tailrecursive call with ignored result
- ok.
-
-test_icode_type_miscompile() ->
- List0 = id([{1,1},{1,1}]),
-
- %% The expressions below produce a list that the SSA type pass knows is
- %% a list of two-tuples, but hipe_icode_type does not.
- %%
- %% Changing the `F(X)` call to just `X` helps the icode type pass figure
- %% things out, making the bug disappear.
- F = fun({_, _}=X) -> X end,
- List = [F(X) || {_,_}=X <- List0],
-
- type_miscompile(List, List, []).
-
-type_miscompile([{Same, Same} | As], [{Same, Same} | Bs], Acc) ->
- type_miscompile(As, Bs, [gaffel | Acc]);
-type_miscompile([], [], Acc) ->
- %% Acc is non-empty when everything works as expected.
- true = Acc =/= [],
- ok.
-
-id(I) -> I.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl b/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl
deleted file mode 100644
index 8dab2cab1f..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl
+++ /dev/null
@@ -1,157 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests for correct execution of comparison operators.
-%%%-------------------------------------------------------------------
--module(basic_comparisons).
-
--export([test/0]).
-
-test() ->
- Ns = [0, 0.0, 42, 42.0, gazonk],
- T1F4 = [true, false, false, false, false],
- T2F3 = [true, true, false, false, false],
- F1T4 = [false, true, true, true, true],
- F2T3 = [false, false, true, true, true],
- %% tests for calls
- T1F4 = [eq_exact_call(0, N) || N <- Ns],
- F1T4 = [ne_exact_call(0, N) || N <- Ns],
- T2F3 = [eq_call(0, N) || N <- Ns],
- F2T3 = [ne_call(0, N) || N <- Ns],
- %% tests for guards
- T1F4 = [eq_exact_guard(0, N) || N <- Ns],
- F1T4 = [ne_exact_guard(0, N) || N <- Ns],
- T2F3 = [eq_guard(0, N) || N <- Ns],
- F2T3 = [ne_guard(0, N) || N <- Ns],
- %% some more tests
- ok = test_against_zero(),
- ok = test_against_other_terms(),
- ok = test_sofs_func(),
- ok.
-
-test_against_zero() ->
- Xs = [0, 1, 0.0],
- [true, false, false] = [is_zero_int(X) || X <- Xs],
- [true, false, true] = [is_zero_num(X) || X <- Xs],
- [false, true, true] = [is_nonzero_int(X) || X <- Xs],
- [false, true, false] = [is_nonzero_num(X) || X <- Xs],
- ok.
-
-test_against_other_terms() ->
- TTT = {true, true, true},
- FFF = {false, false, false},
- TTT = {is_foo_exact(foo), is_foo_term1(foo), is_foo_term2(foo)},
- FFF = {is_foo_exact(bar), is_foo_term1(bar), is_foo_term2(bar)},
- FFF = {is_nonfoo_exact(foo), is_nonfoo_term1(foo), is_nonfoo_term2(foo)},
- TTT = {is_nonfoo_exact(bar), is_nonfoo_term1(bar), is_nonfoo_term2(bar)},
- Tup = {a, {42}, [c]},
- TTT = {is_tuple_skel(Tup), is_tuple_exact(Tup), is_tuple_term(Tup)},
- BNi = <<42>>,
- TTT = {is_bin_exact(BNi), is_bin_term1(BNi), is_bin_term2(BNi)},
- BNf = <<42/float>>,
- FFF = {is_bin_exact(BNf), is_bin_term1(BNf), is_bin_term2(BNf)},
- ok.
-
-test_sofs_func() ->
- L = [0, 0.0],
- ok = sofs_func(L, L, L).
-
-%%--------------------------------------------------------------------
-%% Test for comparison operators used in body calls
-
-eq_exact_call(X, Y) -> X =:= Y.
-
-ne_exact_call(X, Y) -> X =/= Y.
-
-eq_call(X, Y) -> X == Y.
-
-ne_call(X, Y) -> X /= Y.
-
-%%--------------------------------------------------------------------
-%% Tests for comparison operators used as guards
-
-eq_exact_guard(X, Y) when X =:= Y -> true;
-eq_exact_guard(_, _) -> false.
-
-ne_exact_guard(X, Y) when X =/= Y -> true;
-ne_exact_guard(_, _) -> false.
-
-eq_guard(X, Y) when X == Y -> true;
-eq_guard(_, _) -> false.
-
-ne_guard(X, Y) when X /= Y -> true;
-ne_guard(_, _) -> false.
-
-%%--------------------------------------------------------------------
-
-is_zero_int(N) when N =:= 0 -> true;
-is_zero_int(_) -> false.
-
-is_nonzero_int(N) when N =/= 0 -> true;
-is_nonzero_int(_) -> false.
-
-is_zero_num(N) when N == 0 -> true;
-is_zero_num(_) -> false.
-
-is_nonzero_num(N) when N /= 0 -> true;
-is_nonzero_num(_) -> false.
-
-%%--------------------------------------------------------------------
-%% There should not really be any difference in the generated code
-%% for the following three functions.
-
-is_foo_exact(A) when A =:= foo -> true;
-is_foo_exact(_) -> false.
-
-is_foo_term1(A) when A == foo -> true;
-is_foo_term1(_) -> false.
-
-is_foo_term2(A) when foo == A -> true;
-is_foo_term2(_) -> false.
-
-%%--------------------------------------------------------------------
-%% Same for these cases
-
-is_nonfoo_exact(A) when A =/= foo -> true;
-is_nonfoo_exact(_) -> false.
-
-is_nonfoo_term1(A) when A /= foo -> true;
-is_nonfoo_term1(_) -> false.
-
-is_nonfoo_term2(A) when foo /= A -> true;
-is_nonfoo_term2(_) -> false.
-
-%%--------------------------------------------------------------------
-
-is_tuple_skel({A,{B},[C]}) when is_atom(A), is_integer(B), is_atom(C) -> true;
-is_tuple_skel(T) when is_tuple(T) -> false.
-
-is_tuple_exact(T) when T =:= {a,{42},[c]} -> true;
-is_tuple_exact(T) when is_tuple(T) -> false.
-
-is_tuple_term(T) when T == {a,{42.0},[c]} -> true;
-is_tuple_term(T) when is_tuple(T) -> false.
-
-%%--------------------------------------------------------------------
-%% But for binaries the treatment has to be different, due to the need
-%% for construction of the binary in the guard.
-
-is_bin_exact(B) when B =:= <<42>> -> true;
-is_bin_exact(_) -> false.
-
-is_bin_term1(B) when B == <<42>> -> true;
-is_bin_term1(_) -> false.
-
-is_bin_term2(B) when <<42>> == B -> true;
-is_bin_term2(_) -> false.
-
-%%--------------------------------------------------------------------
-%% a test from sofs.erl which failed at some point
-
-sofs_func([X | Ts], X0, L) when X /= X0 ->
- sofs_func(Ts, X, L);
-sofs_func([X | _Ts], X0, _L) when X == X0 ->
- ok;
-sofs_func([], _X0, L) ->
- L.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_edge_cases.erl b/lib/hipe/test/basic_SUITE_data/basic_edge_cases.erl
deleted file mode 100644
index 9bf5cf52cd..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_edge_cases.erl
+++ /dev/null
@@ -1,142 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%----------------------------------------------------------------------
-%%% Contains
-%%%----------------------------------------------------------------------
--module(basic_edge_cases).
-
--export([test/0]).
-
-test() ->
- ok = test_float_spills(),
- ok = test_infinite_loops(),
- ok.
-
-%% Contains more float temps live at a single point than there are float
-%% registers in any backend
-
-test_float_spills() ->
- {{{2942.0,4670.0,3198.0,4926.0,2206.0,4734.0},
- {3118.0,2062.0,5174.0,3038.0,3618.0,3014.0},
- {2542.0,2062.0,4934.0,2590.0,3098.0,3062.0},
- {2950.0,3666.0,2574.0,5038.0,1866.0,2946.0},
- {3126.0,3050.0,3054.0,5070.0,2258.0,2714.0},
- {4734.0,2206.0,4926.0,3198.0,4670.0,2942.0}},
- 58937.0} =
- mat66_flip_sum(35.0,86.0,32.0,88.0,33.0,57.0,
- 22.0,77.0,91.0,80.0,14.0,33.0,
- 51.0,28.0,87.0,20.0,91.0,11.0,
- 68.0,83.0,64.0,82.0,10.0,86.0,
- 74.0,18.0,08.0,52.0,10.0,14.0,
- 89.0,34.0,64.0,66.0,58.0,55.0,
- 0.0, 5),
- ok.
-
-mat66_flip_sum(M11, M12, M13, M14, M15, M16,
- M21, M22, M23, M24, M25, M26,
- M31, M32, M33, M34, M35, M36,
- M41, M42, M43, M44, M45, M46,
- M51, M52, M53, M54, M55, M56,
- M61, M62, M63, M64, M65, M66,
- Acc, Ctr)
- when is_float(M11), is_float(M12), is_float(M13),
- is_float(M14), is_float(M15), is_float(M16),
- is_float(M21), is_float(M22), is_float(M23),
- is_float(M24), is_float(M25), is_float(M26),
- is_float(M31), is_float(M32), is_float(M33),
- is_float(M34), is_float(M35), is_float(M36),
- is_float(M41), is_float(M42), is_float(M43),
- is_float(M44), is_float(M45), is_float(M46),
- is_float(M51), is_float(M52), is_float(M53),
- is_float(M54), is_float(M55), is_float(M56),
- is_float(M61), is_float(M62), is_float(M63),
- is_float(M64), is_float(M65), is_float(M66),
- is_float(Acc) ->
- R11 = M66+M11, R12 = M65+M12, R13 = M64+M13,
- R14 = M63+M14, R15 = M62+M15, R16 = M61+M16,
- R21 = M56+M21, R22 = M55+M22, R23 = M54+M23,
- R24 = M53+M24, R25 = M52+M25, R26 = M51+M26,
- R31 = M46+M31, R32 = M45+M32, R33 = M44+M33,
- R34 = M43+M34, R35 = M42+M35, R36 = M41+M36,
- R41 = M26+M41, R42 = M25+M42, R43 = M24+M43,
- R44 = M23+M44, R45 = M22+M45, R46 = M21+M46,
- R51 = M36+M51, R52 = M35+M52, R53 = M34+M53,
- R54 = M33+M54, R55 = M32+M55, R56 = M31+M56,
- R61 = M16+M61, R62 = M15+M62, R63 = M14+M63,
- R64 = M13+M64, R65 = M12+M65, R66 = M11+M66,
- case Ctr of
- 0 ->
- {{{R11, R12, R13, R14, R15, R16},
- {R21, R22, R23, R24, R25, R26},
- {R31, R32, R33, R34, R35, R36},
- {R41, R42, R43, R44, R45, R46},
- {R51, R52, R53, R54, R55, R56},
- {R61, R62, R63, R64, R65, R66}},
- Acc};
- _ ->
- NewAcc = 0.0 + M11 + M12 + M13 + M14 + M15 + M16 +
- + M21 + M22 + M23 + M24 + M25 + M26
- + M31 + M32 + M33 + M34 + M35 + M36
- + M41 + M42 + M43 + M44 + M45 + M46
- + M51 + M52 + M53 + M54 + M55 + M56
- + M61 + M62 + M63 + M64 + M65 + M66
- + Acc,
- mat66_flip_sum(R11+1.0, R12+1.0, R13+1.0, R14+1.0, R15+1.0, R16+1.0,
- R21+1.0, R22+1.0, R23+1.0, R24+1.0, R25+1.0, R26+1.0,
- R31+1.0, R32+1.0, R33+1.0, R34+1.0, R35+1.0, R36+1.0,
- R41+1.0, R42+1.0, R43+1.0, R44+1.0, R45+1.0, R46+1.0,
- R51+1.0, R52+1.0, R53+1.0, R54+1.0, R55+1.0, R56+1.0,
- R61+1.0, R62+1.0, R63+1.0, R64+1.0, R65+1.0, R66+1.0,
- NewAcc, Ctr-1)
- end.
-
-%% Infinite loops must receive reduction tests, and might trip up basic block
-%% weighting, leading to infinite weights and/or divisions by zero.
-
-test_infinite_loops() ->
- OldTrapExit = process_flag(trap_exit, true),
- ok = test_infinite_loop(fun infinite_recursion/0),
- ok = test_infinite_loop(fun infinite_corecursion/0),
- RecursiveFun = fun RecursiveFun() -> RecursiveFun() end,
- ok = test_infinite_loop(RecursiveFun),
- CorecursiveFunA = fun CorecursiveFunA() ->
- CorecursiveFunA1 = fun () -> CorecursiveFunA() end,
- CorecursiveFunA1()
- end,
- ok = test_infinite_loop(CorecursiveFunA),
- CorecursiveFunB1 = fun(CorecursiveFunB) -> CorecursiveFunB() end,
- CorecursiveFunB = fun CorecursiveFunB() ->
- CorecursiveFunB1(CorecursiveFunB)
- end,
- ok = test_infinite_loop(CorecursiveFunB),
- CorecursiveFunC1 = fun CorecursiveFunC1(Other) ->
- Other(CorecursiveFunC1)
- end,
- CorecursiveFunC = fun CorecursiveFunC(Other) ->
- Other(CorecursiveFunC)
- end,
- ok = test_infinite_loop(fun() -> CorecursiveFunC(CorecursiveFunC1) end),
- ok = test_infinite_loop(fun() -> CorecursiveFunC(CorecursiveFunC) end),
- true = process_flag(trap_exit, OldTrapExit),
- ok.
-
--define(INFINITE_LOOP_TIMEOUT, 100).
-test_infinite_loop(Fun) ->
- Tester = spawn_link(Fun),
- kill_soon(Tester),
- receive {'EXIT', Tester, awake} ->
- undefined = process_info(Tester),
- ok
- after ?INFINITE_LOOP_TIMEOUT -> error(timeout)
- end.
-
-infinite_recursion() -> infinite_recursion().
-
-infinite_corecursion() -> infinite_corecursion_1().
-infinite_corecursion_1() -> infinite_corecursion().
-
-kill_soon(Pid) ->
- _ = spawn_link(fun() ->
- timer:sleep(1),
- erlang:exit(Pid, awake)
- end),
- ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
deleted file mode 100644
index 9f79231e5a..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
+++ /dev/null
@@ -1,693 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that raise exceptions and catch them.
-%%%-------------------------------------------------------------------
--module(basic_exceptions).
-
--export([test/0]).
-
-%% functions used as arguments to spawn/3
--export([bad_guy/2]).
-
-test() ->
- ok = test_catches(),
- ok = test_catch_exit(42),
- ok = test_catch_throw(42),
- ok = test_catch_element(),
- ok = test_catch_crash(),
- ok = test_catch_empty(),
- ok = test_catch_merge(),
- ok = test_catches_merged(),
- ok = test_pending_errors(),
- ok = test_bad_fun_call(),
- ok = test_guard_bif(),
- ok = test_eclectic(),
- ok = test_raise(),
- ok = test_effect(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Written in 2001 by Erik Johansson.
-
-test_catches() ->
- ExitBar = {'EXIT', bar},
- L1 = [ExitBar, ok, ExitBar, {ok, ExitBar}],
- L1 = [t1(), t2(), t3(), t4()],
- badarith = (catch element(1, element(2, t5(a, b)))),
- L2 = [42, ExitBar, ExitBar, {no_exception, ok}],
- L2 = [t5(21, 21), t6(), t7(), t8()],
- ok.
-
-t1() ->
- catch foo().
-
-t2() ->
- V = (catch ok()),
- s(),
- V.
-
-t3() ->
- V = (catch foo()),
- V.
-
-t4() ->
- V1 = ok(),
- V2 = (catch foo()),
- {V1, V2}.
-
-t5(A, B) ->
- catch A + B.
-
-t6() ->
- catch {no_exception, ok(), foo()}.
-
-t7() ->
- catch {no_exception, foo(), ok()}.
-
-t8() ->
- catch {no_exception, ok()}.
-
-foo() ->
- s(),
- exit(bar).
-
-ok() -> s(), ok.
-
-s() -> nada.
-
-%%--------------------------------------------------------------------
-
-test_catch_exit(N) ->
- {'EXIT', N} = (catch exit(N)),
- {'EXIT', 42} = (catch exit(42)),
- 42 = try exit(N) catch exit:R1 -> R1 end,
- 42 = try exit(42) catch exit:R2 -> R2 end,
- ok.
-
-%%--------------------------------------------------------------------
-
-test_catch_throw(N) ->
- N = (catch throw(N)),
- 42 = (catch throw(42)),
- 42 = try throw(N) catch throw:R1 -> R1 end,
- 42 = try throw(42) catch throw:R2 -> R2 end,
- ok.
-
-%%--------------------------------------------------------------------
-
-test_catch_element() ->
- 'EXIT' = test_catch_element([]),
- 'EXIT' = test_catch_element(42),
- ok.
-
-test_catch_element(N) ->
- element(1, catch element(N, {1,2,3,4,5,6,7,8,9,10,11})).
-
-%%--------------------------------------------------------------------
-
--define(try_match(E),
- catch ?MODULE:non_existing(),
- {'EXIT', {{badmatch, nomatch}, _}} = (catch E = no_match())).
-
-test_catch_crash() ->
- ?try_match(a),
- ?try_match(42),
- ?try_match({a, b, c}),
- ?try_match([]),
- ?try_match(1.0),
- ok.
-
-no_match() -> nomatch.
-
-%% small_test() ->
-%% catch ?MODULE:non_existing(),
-%% io:format("Before\n",[]),
-%% hipe_bifs:show_nstack(self()),
-%% io:format("After\n",[]),
-%% garbage_collect().
-
-%%--------------------------------------------------------------------
-%% Tests whether the HiPE compiler optimizes catches in a way that
-%% does not result in an infinite loop.
-%%--------------------------------------------------------------------
-
-test_catch_empty() ->
- badmatch().
-
-badmatch() ->
- Big = ret_big(),
- Float = ret_float(),
- catch a = Big,
- catch b = Float,
- ok = case Big of Big -> ok end,
- ok = case Float of Float -> ok end,
- ok.
-
-ret_big() ->
- 329847987298478924982978248748729829487298292982972978239874.
-
-ret_float() ->
- 3.1415927.
-
-%%--------------------------------------------------------------------
-%% Test that shows how BEAM can merge catch-end blocks that belong to
-%% different catch-start instructions. Written by Richard Carlsson.
-%%--------------------------------------------------------------------
-
-test_catch_merge() ->
- merge(get(whatever)).
-
-merge(foo=X) ->
- catch f(X),
- catch g(X);
-merge(X) ->
- catch f(X),
- catch g(X).
-
-f(_) -> ok.
-
-g(_) -> ok.
-
-%%--------------------------------------------------------------------
-%% Written by Tobias Lindahl.
-
-test_catches_merged() ->
- {'EXIT', _} = merged_catches(foo),
- {'EXIT', {badarith, _}} = merged_catches(bar),
- {'EXIT', _} = merged_catches(baz),
- ok.
-
-merged_catches(X) ->
- case X of
- foo -> catch fail1(0);
- bar -> catch {catch(1 = X), fail2(0)};
- baz -> catch fail3(0)
- end.
-
-fail1(X) -> 1/X.
-
-fail2(X) -> 1/X.
-
-fail3(X) -> 1/X.
-
-%%--------------------------------------------------------------------
-%% Taken from exception_SUITE.erl
-%%--------------------------------------------------------------------
-
-test_pending_errors() ->
- error_logger:tty(false), % disable printouts of error reports
- pending_errors().
-
-%% Test various exceptions, in the presence of a previous error
-%% suppressed in a guard.
-pending_errors() ->
- pending(e_badmatch, {badmatch, b}),
- pending(x, function_clause),
- pending(e_case, {case_clause, xxx}),
- pending(e_if, if_clause),
- %% pending(e_badarith, badarith),
- %% pending(e_undef, undef),
- pending(e_timeoutval, timeout_value),
- %% pending(e_badarg, badarg),
- %% pending(e_badarg_spawn, badarg),
- ok.
-
-bad_guy(pe_badarith, Other) when Other+1 =:= 0 -> % badarith (suppressed)
- ok;
-bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed)
- ok;
-bad_guy(_, e_case) ->
- case xxx() of
- ok -> ok
- end; % case_clause
-bad_guy(_, e_if) ->
- B = b(),
- if
- a == B -> ok
- end; % if_clause
-%% bad_guy(_, e_badarith) ->
-%% 1+b; % badarith
-bad_guy(_, e_undef) ->
- non_existing_module:foo(); % undef
-bad_guy(_, e_timeoutval) ->
- receive
- after gazonk -> ok % timeout_value
- end;
-bad_guy(_, e_badarg) ->
- node(xxx); % badarg
-bad_guy(_, e_badarg_spawn) ->
- spawn({}, {}, {}); % badarg
-bad_guy(_, e_badmatch) ->
- a = b(). % badmatch
-
-xxx() -> xxx.
-
-b() -> b.
-
-pending(Arg, Expected) ->
- pending(pe_badarith, Arg, Expected),
- pending(pe_badarg, Arg, Expected).
-
-pending(First, Second, Expected) ->
- pending_catched(First, Second, Expected),
- pending_exit_message([First, Second], Expected).
-
-pending_catched(First, Second, Expected) ->
- %% ok = io:format("Catching bad_guy(~p, ~p)\n", [First, Second]),
- case catch bad_guy(First, Second) of
- {'EXIT', Reason} ->
- pending(Reason, bad_guy, [First, Second], Expected);
- Other ->
- exit({not_exit, Other})
- end.
-
-pending_exit_message(Args, Expected) ->
- %% ok = io:format("Trapping exits from spawn_link(~p, ~p, ~p)\n",
- %% [?MODULE, bad_guy, Args]),
- process_flag(trap_exit, true),
- Pid = spawn_link(?MODULE, bad_guy, Args),
- receive
- {'EXIT', Pid, Reason} ->
- pending(Reason, bad_guy, Args, Expected);
- Other ->
- exit({unexpected_message, Other})
- after 10000 ->
- exit(timeout)
- end,
- process_flag(trap_exit, false).
-
-%% pending({badarg, [{erlang,Bif,BifArgs},{?MODULE,Func,Arity}|_]},
-%% Func, Args, _Code)
-%% when atom(Bif), list(BifArgs), length(Args) =:= Arity ->
-%% ok;
-pending({badarg,Trace}, _, _, _) when is_list(Trace) ->
- ok;
-%% pending({undef,[{non_existing_module,foo,[]}|_]}, _, _, _) ->
-%% ok;
-pending({undef,Trace}, _, _, _) when is_list(Trace) ->
- ok;
-%% pending({function_clause,[{?MODULE,Func,Args}|_]}, Func, Args, _Code) ->
-%% ok;
-pending({function_clause,Trace}, _, _, _) when is_list(Trace) ->
- ok;
-%% pending({Code,[{?MODULE,Func,Arity}|_]}, Func, Args, Code)
-%% when length(Args) =:= Arity ->
-%% ok;
-pending({Code,Trace}, _, _, Code) when is_list(Trace) ->
- ok;
-pending(Reason, _Function, _Args, _Code) ->
- exit({bad_exit_reason, Reason}).
-
-%%--------------------------------------------------------------------
-%% Taken from fun_SUITE.erl
-%%
-%% Checks correct exception throwing when calling a bad fun.
-%%--------------------------------------------------------------------
-
-test_bad_fun_call() ->
- ok = bad_call_fc(42),
- ok = bad_call_fc(xx),
- ok = bad_call_fc({}),
- ok = bad_call_fc({1}),
- ok = bad_call_fc({1,2,3}),
- ok = bad_call_fc({1,2,3}),
- ok = bad_call_fc({1,2,3,4}),
- ok = bad_call_fc({1,2,3,4,5,6}),
- ok = bad_call_fc({1,2,3,4,5}),
- ok = bad_call_fc({1,2}),
- ok.
-
-bad_call_fc(Fun) ->
- Args = [some, stupid, args],
- Res = (catch Fun(Fun(Args))),
- case Res of
- {'EXIT', {{badfun, Fun} ,_Where}} ->
- ok; %% = io:format("~p(~p) -> ~p\n", [Fun, Args, Res]);
- Other ->
- io:format("~p(~p) -> ~p\n", [Fun, Args, Res]),
- exit({bad_result, Other})
- end.
-
-%%--------------------------------------------------------------------
-%% Taken from guard_SUITE.erl
-%%
-%% Tests correct handling of exceptions by calling guard BIFs with
-%% nasty (but legal arguments).
-%%--------------------------------------------------------------------
-
-test_guard_bif() ->
- Big = -237849247829874297658726487367328971246284736473821617265433,
- Float = 387924.874,
-
- %% Succeding use of guard bifs.
-
- try_gbif('abs/1', Big, -Big),
- try_gbif('float/1', Big, float(Big)),
- try_gbif('trunc/1', Float, 387924.0),
- try_gbif('round/1', Float, 387925.0),
- try_gbif('length/1', [], 0),
-
- try_gbif('length/1', [a], 1),
- try_gbif('length/1', [a, b], 2),
- try_gbif('length/1', lists:seq(0, 31), 32),
-
- try_gbif('hd/1', [a], a),
- try_gbif('hd/1', [a, b], a),
-
- try_gbif('tl/1', [a], []),
- try_gbif('tl/1', [a, b], [b]),
- try_gbif('tl/1', [a, b, c], [b, c]),
-
- try_gbif('size/1', {}, 0),
- try_gbif('size/1', {a}, 1),
- try_gbif('size/1', {a, b}, 2),
- try_gbif('size/1', {a, b, c}, 3),
- try_gbif('size/1', list_to_binary([]), 0),
- try_gbif('size/1', list_to_binary([1]), 1),
- try_gbif('size/1', list_to_binary([1, 2]), 2),
- try_gbif('size/1', list_to_binary([1, 2, 3]), 3),
-
- try_gbif('element/2', {x}, {1, x}),
- try_gbif('element/2', {x, y}, {1, x}),
- try_gbif('element/2', {x, y}, {2, y}),
-
- try_gbif('self/0', 0, self()),
- try_gbif('node/0', 0, node()),
- try_gbif('node/1', self(), node()),
-
- %% Failing use of guard bifs.
-
- try_fail_gbif('abs/1', Big, 1),
- try_fail_gbif('abs/1', [], 1),
-
- try_fail_gbif('float/1', Big, 42),
- try_fail_gbif('float/1', [], 42),
-
- try_fail_gbif('trunc/1', Float, 0.0),
- try_fail_gbif('trunc/1', [], 0.0),
-
- try_fail_gbif('round/1', Float, 1.0),
- try_fail_gbif('round/1', [], a),
-
- try_fail_gbif('length/1', [], 1),
- try_fail_gbif('length/1', [a], 0),
- try_fail_gbif('length/1', a, 0),
- try_fail_gbif('length/1', {a}, 0),
-
- try_fail_gbif('hd/1', [], 0),
- try_fail_gbif('hd/1', [a], x),
- try_fail_gbif('hd/1', x, x),
-
- try_fail_gbif('tl/1', [], 0),
- try_fail_gbif('tl/1', [a], x),
- try_fail_gbif('tl/1', x, x),
-
- try_fail_gbif('size/1', {}, 1),
- try_fail_gbif('size/1', [], 0),
- try_fail_gbif('size/1', [a], 1),
- try_fail_gbif('size/1', fun() -> 1 end, 0),
- try_fail_gbif('size/1', fun() -> 1 end, 1),
-
- try_fail_gbif('element/2', {}, {1, x}),
- try_fail_gbif('element/2', {x}, {1, y}),
- try_fail_gbif('element/2', [], {1, z}),
-
- try_fail_gbif('self/0', 0, list_to_pid("<0.0.0>")),
- try_fail_gbif('node/0', 0, xxxx),
- try_fail_gbif('node/1', self(), xxx),
- try_fail_gbif('node/1', yyy, xxx),
- ok.
-
-try_gbif(Id, X, Y) ->
- case guard_bif(Id, X, Y) of
- {Id, X, Y} ->
- %% io:format("guard_bif(~p, ~p, ~p) -- ok\n", [Id, X, Y]);
- ok;
- Other ->
- ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n",
- [Id, X, Y, Other]),
- exit({bad_result,try_gbif})
- end.
-
-try_fail_gbif(Id, X, Y) ->
- case catch guard_bif(Id, X, Y) of
- %% {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y]}|_]}} ->
- {'EXIT', {function_clause,_}} -> % in HiPE, a trace is not generated
- %% io:format("guard_bif(~p, ~p, ~p) -- ok\n", [Id,X,Y]);
- ok;
- Other ->
- ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n",
- [Id, X, Y, Other]),
- exit({bad_result,try_fail_gbif})
- end.
-
-guard_bif('abs/1', X, Y) when abs(X) == Y ->
- {'abs/1', X, Y};
-guard_bif('float/1', X, Y) when float(X) == Y ->
- {'float/1', X, Y};
-guard_bif('trunc/1', X, Y) when trunc(X) == Y ->
- {'trunc/1', X, Y};
-guard_bif('round/1', X, Y) when round(X) == Y ->
- {'round/1', X, Y};
-guard_bif('length/1', X, Y) when length(X) == Y ->
- {'length/1', X, Y};
-guard_bif('hd/1', X, Y) when hd(X) == Y ->
- {'hd/1', X, Y};
-guard_bif('tl/1', X, Y) when tl(X) == Y ->
- {'tl/1', X, Y};
-guard_bif('size/1', X, Y) when size(X) == Y ->
- {'size/1', X, Y};
-guard_bif('element/2', X, {Pos, Expected}) when element(Pos, X) == Expected ->
- {'element/2', X, {Pos, Expected}};
-guard_bif('self/0', X, Y) when self() == Y ->
- {'self/0', X, Y};
-guard_bif('node/0', X, Y) when node() == Y ->
- {'node/0', X, Y};
-guard_bif('node/1', X, Y) when node(X) == Y ->
- {'node/1', X, Y}.
-
-%%--------------------------------------------------------------------
-%% Taken from trycatch_SUITE.erl (compiler test suite).
-%%
-%% Cases that are commented out contain exception information that was
-%% added to Erlang/OTP in commit e8d45ae14c6c3bdfcbbc7964228b004ef4f11ea6
-%% (May 2017) only in the BEAM emulator. Thus, part of this test fails
-%% when compiled in native code.
-%% The remaining cases are uncommented so that they are properly tested
-%% in native code too.
-%%--------------------------------------------------------------------
-
-test_eclectic() ->
- V = {make_ref(),3.1415926535,[[]|{}]},
- {{value,{value,V},V},V} =
- eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
- {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
- eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
- {{error,{exit,V},{'EXIT',V}},V} =
- eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
- %% {{value,{value,V},V},
- %% {'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}} =
- %% eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
- {{'EXIT',V},V} =
- eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
- %% {{error,{'div',{1,0}},{'EXIT',{badarith,[{erlang,'div',[1,0],_},{?MODULE,my_div,2,_}|_]}}},
- %% {'EXIT',V}} =
- %% eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
- {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
- {'EXIT',V}} =
- eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
- %%
- {{value,{value,{value,V},V}},V} =
- eclectic_2({value,{value,V}}, undefined, {value,V}),
- {{value,{throw,{value,V},V}},V} =
- eclectic_2({throw,{value,V}}, throw, {value,V}),
- {{caught,{'EXIT',V}},undefined} =
- eclectic_2({value,{value,V}}, undefined, {exit,V}),
- {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
- eclectic_2({error,{value,V}}, throw, {error,V}),
- %% The following fails in native code
- %% %% {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
- %% %% eclectic_2({value,{'abs',V}}, undefined, {value,V}),
- %% {{caught,{'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}},V} =
- %% eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
- {{caught,{'EXIT',V}},undefined} =
- eclectic_2({value,{error,V}}, undefined, {exit,V}),
- {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
- eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
- ok.
-
-eclectic_1(X, C, Y) ->
- erase(eclectic),
- Done = make_ref(),
- Try =
- try case X of
- {catch_foo,V} -> catch {Done,foo(V)};
- {foo,V} -> {Done,foo(V)}
- end of
- {Done,D} -> {value,D,catch foo(D)};
- {'EXIT',_}=Exit -> Exit;
- D -> {D,catch foo(D)}
- catch
- C:D -> {C,D,catch foo(D)}
- after
- put(eclectic, catch foo(Y))
- end,
- {Try,erase(eclectic)}.
-
-eclectic_2(X, C, Y) ->
- Done = make_ref(),
- erase(eclectic),
- Catch =
- case
- catch
- {Done,
- try foo(X) of
- V -> {value,V,foo(V)}
- catch
- C:D -> {C,D,foo(D)}
- after
- put(eclectic, foo(Y))
- end} of
- {Done,Z} -> {value,Z};
- Z -> {caught,Z}
- end,
- {Catch,erase(eclectic)}.
-
-foo({value,Value}) -> Value;
-foo({'div',{A,B}}) ->
- my_div(A, B);
-foo({'add',{A,B}}) ->
- my_add(A, B);
-foo({'abs',X}) ->
- my_abs(X);
-foo({error,Error}) ->
- erlang:error(Error);
-foo({throw,Throw}) ->
- erlang:throw(Throw);
-foo({exit,Exit}) ->
- erlang:exit(Exit);
-foo({raise,{Class,Reason}}) ->
- erlang:raise(Class, Reason);
-foo(Term) when not is_atom(Term) -> Term.
-%%foo(Atom) when is_atom(Atom) -> % must not be defined!
-
-my_div(A, B) ->
- A div B.
-
-my_add(A, B) ->
- A + B.
-
-my_abs(X) ->
- abs(X).
-
-test_raise() ->
- test_raise(fun() -> exit({exit,tuple}) end),
- test_raise(fun() -> abs(id(x)) end),
- test_raise(fun() -> throw({was,thrown}) end),
-
- badarg = bad_raise(fun() -> abs(id(x)) end),
-
- ok.
-
-bad_raise(Expr) ->
- try
- Expr()
- catch
- _:E:Stk ->
- erlang:raise(bad_class, E, Stk)
- end.
-
-test_raise(Expr) ->
- test_raise_1(Expr),
- test_raise_2(Expr),
- test_raise_3(Expr).
-
-test_raise_1(Expr) ->
- erase(exception),
- try
- do_test_raise_1(Expr)
- catch
- C:E:Stk ->
- {C,E,Stk} = erase(exception)
- end.
-
-do_test_raise_1(Expr) ->
- try
- Expr()
- catch
- C:E:Stk ->
- %% Here the stacktrace must be built.
- put(exception, {C,E,Stk}),
- erlang:raise(C, E, Stk)
- end.
-
-test_raise_2(Expr) ->
- erase(exception),
- try
- do_test_raise_2(Expr)
- catch
- C:E:Stk ->
- {C,E} = erase(exception),
- try
- Expr()
- catch
- _:_:S ->
- [StkTop|_] = S,
- [StkTop|_] = Stk
- end
- end.
-
-do_test_raise_2(Expr) ->
- try
- Expr()
- catch
- C:E:Stk ->
- %% Here it is possible to replace erlang:raise/3 with
- %% the raw_raise/3 instruction since the stacktrace is
- %% not actually used.
- put(exception, {C,E}),
- erlang:raise(C, E, Stk)
- end.
-
-test_raise_3(Expr) ->
- try
- do_test_raise_3(Expr)
- catch
- exit:{exception,C,E}:Stk ->
- try
- Expr()
- catch
- C:E:S ->
- [StkTop|_] = S,
- [StkTop|_] = Stk
- end
- end.
-
-do_test_raise_3(Expr) ->
- try
- Expr()
- catch
- C:E:Stk ->
- %% Here it is possible to replace erlang:raise/3 with
- %% the raw_raise/3 instruction since the stacktrace is
- %% not actually used.
- erlang:raise(exit, {exception,C,E}, Stk)
- end.
-
-test_effect() ->
- ok = effect_try(2),
- {'EXIT',{badarith,_}} = (catch effect_try(bad)),
- ok.
-
-effect_try(X) ->
- try
- X + 1
- catch
- C:E:Stk ->
- erlang:raise(C, E, Stk)
- end,
- ok.
-
-id(I) -> I.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_floats.erl b/lib/hipe/test/basic_SUITE_data/basic_floats.erl
deleted file mode 100644
index ce28f6e156..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_floats.erl
+++ /dev/null
@@ -1,250 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that manipulate floating point numbers.
-%%%-------------------------------------------------------------------
--module(basic_floats).
-
--export([test/0]).
--export([test_fmt_double_fpe_leak/0]). % suppress the unused warning
-
-test() ->
- ok = test_arith_ops(),
- ok = test_fp_ebb(),
- ok = test_fp_phi(),
- ok = test_big_bad_float(),
- ok = test_catch_bad_fp_arith(),
- ok = test_catch_fp_conv(),
- ok = test_fp_with_fp_exceptions(),
- %% ok = test_fmt_double_fpe_leak(), % this requires printing
- ok = test_icode_type_crash(),
- ok = test_icode_type_crash_2(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_arith_ops() ->
- E = 2.5617,
- 5.703200000000001 = add(E),
- 0.5798000000000001 = sub(E),
- 8.047580550000001 = mult(E),
- -6.023e23 = negate(6.023e23),
- ok.
-
-add(X) ->
- 3.1415 + X.
-
-sub(X) ->
- 3.1415 - X.
-
-mult(X) ->
- 3.1415 * X.
-
-%% tests the translation of the fnegate BEAM instruction.
-negate(X) ->
- - (X + 0.0).
-
-%%--------------------------------------------------------------------
-%% Test the construction of overlapping extended basic blocks where
-%% BEAM has constructed one and hipe_icode_fp constructs the other.
-%%--------------------------------------------------------------------
-
-test_fp_ebb() ->
- 1.0 = foo(2 * math:pi()),
- 1.0 = bar(2 * math:pi()),
- ok.
-
-foo(X) ->
- X / (2 * math:pi()).
-
-bar(X) ->
- F = float_two(),
- case F < 3.0 of
- true -> (X * F) / ((2 * F) * math:pi());
- false -> weird
- end.
-
-float_two() ->
- 2.0.
-
-%%--------------------------------------------------------------------
-
-test_fp_phi() ->
- 10 = fp_phi(10, 100),
- undefined = fp_phi(1.1e302, 0.000000001),
- ok.
-
-fp_phi(A, B) ->
- case catch A / B of
- {'EXIT', _Reason} -> undefined;
- _ -> round(100 * (A / B))
- end.
-
-%%--------------------------------------------------------------------
-
--define(BS, "93904329458954829589425849258998492384932849328493284932849328493284932389248329432932483294832949245827588578423578435783475834758375837580745807304258924584295924588459834958349589348589345934859384958349583945893458934859438593485995348594385943859438593458934589345938594385934859483958348934589435894859485943859438594594385938459438595034950439504395043950495043593485943758.0").
-
-test_big_bad_float() ->
- ok = try f2l(?BS) catch error:badarg -> ok end,
- ok = case catch f2l(?BS) of {'EXIT', {badarg, _}} -> ok end,
- ok.
-
-f2l(F) ->
- float_to_list(list_to_float(F)).
-
-%%--------------------------------------------------------------------
-%% Tests catching of floating point bad arithmetic.
-
-test_catch_bad_fp_arith() ->
- 5.7 = f(2.56),
- {'EXIT', {badarith, _}} = bad_arith(9.9),
- ok.
-
-f(F) when is_float(F) -> F + 3.14.
-
-bad_arith(F) when is_float(F) ->
- catch F * 1.70000e+308.
-
-%%--------------------------------------------------------------------
-%% Tests proper catching of exceptions due to illegal convertion of
-%% bignums to floating point numbers.
-
-test_catch_fp_conv() ->
- F = 1.7e308, %% F is a number very close to a maximum float.
- ok = big_arith(F),
- ok = big_const_float(F),
- ok.
-
-big_arith(F) ->
- I = trunc(F),
- {'EXIT', {badarith, _}} = big_int_arith(I),
- ok.
-
-big_int_arith(I) when is_integer(I) ->
- catch(3.0 + 2*I).
-
-big_const_float(F) ->
- I = trunc(F),
- badarith = try (1/(2*I)) catch error:Err -> Err end,
- _ = 2/I,
- {'EXIT', _} = (catch 4/(2*I)),
- ok.
-
-%%--------------------------------------------------------------------
-%% Forces floating point exceptions and tests that subsequent, legal,
-%% operations are calculated correctly.
-
-test_fp_with_fp_exceptions() ->
- 0.0 = math:log(1.0),
- badarith = try math:log(float_minus_one()) catch error:E1 -> E1 end,
- 0.0 = math:log(1.0),
- badarith = try math:log(float_zero()) catch error:E2 -> E2 end,
- 0.0 = math:log(1.0),
- %% An old-fashioned exception here just so as to test this case also
- {'EXIT', _} = (catch fp_mult(3.23e133, 3.57e257)),
- 0.0 = math:log(1.0),
- badarith = try fp_div(5.0, 0.0) catch error:E3 -> E3 end,
- 0.0 = math:log(1.0),
- ok.
-
-fp_mult(X, Y) -> X * Y.
-
-fp_div(X, Y) -> X / Y.
-
-%% The following two function definitions appear here just to shut
-%% off 'expression will fail with a badarg' warnings from the compiler
-
-float_zero() -> 0.0.
-
-float_minus_one() -> -1.0.
-
-%%--------------------------------------------------------------------
-%% Test that erl_printf_format.c:fmt_double() does not leak pending FP
-%% exceptions to subsequent code. This used to break x87 FP code on
-%% 32-bit x86. Based on a problem report from Richard Carlsson.
-
-test_fmt_double_fpe_leak() ->
- test_fmt_double_fpe_leak(float_zero(), int_two()),
- ok.
-
-%% We need the specific sequence of erlang:display/1 on a float that
-%% triggers faulting ops in fmt_double() followed by a simple FP BIF.
-%% We also need to repeat this at least three times.
-test_fmt_double_fpe_leak(X, Y) ->
- erlang:display(X), _ = math:log10(Y),
- erlang:display(X), _ = math:log10(Y),
- erlang:display(X), _ = math:log10(Y),
- erlang:display(X), _ = math:log10(Y),
- erlang:display(X),
- math:log10(Y).
-
-int_two() -> 2.
-
-%%--------------------------------------------------------------------
-%% Contains code which confuses the icode_type analysis and results
-%% in a compiler crash. Stipped down from code sent by Paul Guyot.
-%% Compiles alright with the option 'no_icode_type' but that defeats
-%% the purpose of the test.
-
-test_icode_type_crash() ->
- Fun = f(1, 2, 3),
- 42.0 = Fun(),
- ok.
-
-f(A, B, C) ->
- fun () ->
- X = case A of
- 0 -> 1 / B;
- _ -> A / C
- end,
- Y = case B of
- a -> 1.0;
- b -> 2.0;
- _ -> 6.0
- end,
- Z = case C of
- c -> 0.1 * X;
- _ -> 7.0
- end,
- Y * Z
- end.
-
-%%--------------------------------------------------------------------
-%% Contains another case that crashed hipe_icode_fp. This sample was
-%% sent by Mattias Jansson (25 Nov 2015). It compiled alright with the
-%% option 'no_icode_type' but that defeats the purpose of the test.
-%% Unfortunately, the execution of this code goes into an infinite
-%% loop, even if the map in the second argument of eat_what/2 gets the
-%% appropriate key-value pairs. Still, it is retained as a test
-%% because it exposed a different crash than test_icode_type_crash/0.
-
-test_icode_type_crash_2() ->
- {'EXIT', {function_clause, _}} = (catch eat()),
- ok.
-
-eat() ->
- eat_what(1.0, #{}).
-
-eat_what(Factor, #{rat_type := LT} = Rat) ->
- #{cheese := Cheese} = Rat,
- UnitCheese = Cheese / 2,
- RetA = case eat() of
- {full, RetA1} ->
- CheeseB2 = min(RetA1, UnitCheese) * Factor,
- case eat() of
- full -> {win, RetA1};
- hungry -> {partial, RetA1 - CheeseB2}
- end;
- AOther -> AOther
- end,
- RetB = case eat() of
- {full, RetB1} ->
- CheeseA2 = min(RetB1, UnitCheese) * Factor,
- rat:init(single, LT, CheeseA2),
- case eat() of
- full -> {full, RetB1};
- hungry -> {hungry, RetB1 - CheeseA2}
- end
- end,
- {RetA, RetB}.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_fun.erl b/lib/hipe/test/basic_SUITE_data/basic_fun.erl
deleted file mode 100644
index 18ba7fdb3f..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_fun.erl
+++ /dev/null
@@ -1,124 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Tests for correct handling of funs.
-%%%-------------------------------------------------------------------
--module(basic_fun).
-
--export([test/0]).
-
--export([dummy_foo/4, add1/1, test_fun03/0]).
-
-test() ->
- ok = test_calls(),
- ok = test_is_function(),
- ok = test_is_function2(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests function and fun calls.
-
-test_calls() ->
- ok = test_apply_call(?MODULE, dummy_foo),
- ok = test_fun_call(fun dummy_foo/4),
- ok = test_fun_call(fun ?MODULE:dummy_foo/4),
- ok.
-
-test_apply_call(M, F) ->
- M:F(bar, 42, foo, 17).
-
-test_fun_call(Fun) ->
- Fun(bar, 42, foo, 17).
-
-dummy_foo(_, _, foo, _) -> ok.
-
-%%--------------------------------------------------------------------
-%% Tests handling of funs out of exported functions and 2-tuple funs.
-
-test_fun03() ->
- MFPair = add1_as_2tuple(),
- 4712 = do_call(add1_as_export(), 4711),
- {badfun, MFPair} = try do_call(MFPair, 88) catch error:Err -> Err end,
- true = do_guard(add1_as_export()),
- false = do_guard(MFPair), % 2-tuples do not satisfy is_function/1
- ok.
-
-do_call(F, X) -> F(X).
-
-do_guard(F) when is_function(F) -> true;
-do_guard(_) -> false.
-
-add1_as_export() -> fun ?MODULE:add1/1.
-
-add1_as_2tuple() -> {?MODULE, add1}.
-
-add1(X) -> X+1.
-
-%%--------------------------------------------------------------------
-%% Tests the is_function guard and BIF.
-
-test_is_function() ->
- Fun = fun (X, foo) -> dummy_foo(X, mnesia_lib, foo, [X]) end,
- ok = test_when_guard(Fun),
- ok = test_if_guard(Fun),
- ok.
-
-test_when_guard(X) when is_function(X) -> ok.
-
-test_if_guard(X) ->
- if is_function(X) -> ok;
- true -> weird
- end.
-
-%%--------------------------------------------------------------------
-%% Tests the is_function2 guard and BIF.
-
-test_is_function2() ->
- ok = test_guard(),
- ok = test_guard2(),
- ok = test_call(),
- ok.
-
-test_guard() ->
- zero_fun = test_f2(fun () -> ok end),
- unary_fun = test_f2(fun(X) -> X end),
- binary_fun = test_f2(fun (X, Y) -> {X, Y} end),
- no_fun = test_f2(gazonk),
- ok.
-
-test_f2(Fun) when is_function(Fun, 0) ->
- zero_fun;
-test_f2(Fun) when is_function(Fun, 1) ->
- unary_fun;
-test_f2(Fun) when is_function(Fun, 2) ->
- binary_fun;
-test_f2(_) ->
- no_fun.
-
-test_guard2() ->
- zero_fun = test_f2_n(fun () -> ok end, 0),
- unary_fun = test_f2_n(fun (X) -> X end, 1),
- binary_fun = test_f2_n(fun (X, Y) -> {X, Y} end, 2),
- no_fun = test_f2_n(gazonk, 0),
- ok.
-
-test_f2_n(F, N) when is_function(F, N) ->
- case N of
- 0 -> zero_fun;
- 1 -> unary_fun;
- 2 -> binary_fun
- end;
-test_f2_n(_, _) ->
- no_fun.
-
-test_call() ->
- true = test_fn2(fun (X, Y) -> {X,Y} end, 2),
- false = test_fn2(fun (X, Y) -> {X,Y} end, 3),
- false = test_fn2(gazonk, 2),
- {'EXIT', {badarg, _TR1}} = (catch test_fn2(gazonk, gazonk)),
- {'EXIT', {badarg, _TR2}} = (catch test_fn2(fun (X, Y) -> {X, Y} end, gazonk)),
- ok.
-
-test_fn2(F, N) ->
- is_function(F, N).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_guards.erl b/lib/hipe/test/basic_SUITE_data/basic_guards.erl
deleted file mode 100644
index 81eeed7c3b..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_guards.erl
+++ /dev/null
@@ -1,164 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests for correct handling of guards and guard BIFs.
-%%%-------------------------------------------------------------------
--module(basic_guards).
-
--export([test/0]).
-%% Prevent the inlining of the following functions
--export([bad_arith/0, bad_tuple/0, is_strange_guard/0]).
-
-test() ->
- ok = guard0(4.2),
- ok = guard1([foo]),
- ok = test_guard2(),
- ok = test_guard3(),
- ok = test_guard4(),
- ok = test_is_boolean(),
- ok = test_bad_guards(),
- ok.
-
-%%--------------------------------------------------------------------
-
-guard0(X) when X /= 0, is_float(X) ->
- ok.
-
-guard1(X) when is_atom(X) orelse is_float(X) ->
- error1;
-guard1(X) when is_reference(hd(X)) ->
- error2;
-guard1(X) when is_integer(hd(X)) ->
- error3;
-guard1(X) when hd(X) == foo ->
- ok.
-
-%%--------------------------------------------------------------------
-
-test_guard2() ->
- ok1 = guard2(true),
- not_boolean = guard2(42),
- ok2 = guard2(false),
- ok.
-
-guard2(X) when X -> % gets transformed to: is_boolean(X), X =:= true
- ok1;
-guard2(X) when X =:= false ->
- ok2;
-guard2(_) ->
- not_boolean.
-
-%%--------------------------------------------------------------------
-
--define(is_foo(X), (is_atom(X) or (is_tuple(X) and (element(1, X) =:= 'foo')))).
-
-test_guard3() ->
- no = f('foo'),
- yes = f({'foo', 42}),
- no = f(42),
- ok.
-
-f(X) when ?is_foo(X) -> yes;
-f(_) -> no.
-
-%%--------------------------------------------------------------------
-
--define(EXT_REF, <<131,114,0,3,100,0,19,114,101,102,95,116,101,115,116,95,98,117,103,64,103,111,114,98,97,103,2,0,0,0,125,0,0,0,0,0,0,0,0>>).
-
-test_guard4() ->
- yes = is_ref(make_ref()),
- no = is_ref(gazonk),
- yes = is_ref(an_external_ref(?EXT_REF)),
- ok.
-
-is_ref(Ref) when is_reference(Ref) -> yes;
-is_ref(_Ref) -> no.
-
-an_external_ref(Bin) ->
- binary_to_term(Bin).
-
-%%--------------------------------------------------------------------
-
-test_is_boolean() ->
- ok = is_boolean_in_if(),
- ok = is_boolean_in_guard().
-
-is_boolean_in_if() ->
- ok1 = tif(true),
- ok2 = tif(false),
- not_bool = tif(other),
- ok.
-
-is_boolean_in_guard() ->
- ok = tg(true),
- ok = tg(false),
- not_bool = tg(other),
- ok.
-
-tif(V) ->
- Yes = yes(), %% just to prevent the optimizer removing this
- if
- %% the following line generates an is_boolean instruction
- V, Yes == yes ->
- %% while the following one does not (?!)
- %% Yes == yes, V ->
- ok1;
- not(not(not(V))) ->
- ok2;
- V ->
- ok3;
- true ->
- not_bool
- end.
-
-tg(V) when is_boolean(V) ->
- ok;
-tg(_) ->
- not_bool.
-
-yes() -> yes.
-
-%%--------------------------------------------------------------------
-%% original test by Bjorn G
-
-test_bad_guards() ->
- ok = bad_arith(),
- ok = bad_tuple(),
- ok = is_strange_guard(),
- ok.
-
-bad_arith() ->
- 13 = bad_arith1(1, 12),
- 42 = bad_arith1(1, infinity),
- 42 = bad_arith1(infinity, 1),
- 42 = bad_arith2(infinity, 1),
- 42 = bad_arith3(inf),
- 42 = bad_arith4(infinity, 1),
- ok.
-
-bad_arith1(T1, T2) when (T1 + T2) < 17 -> T1 + T2;
-bad_arith1(_, _) -> 42.
-
-bad_arith2(T1, T2) when (T1 * T2) < 17 -> T1 * T2;
-bad_arith2(_, _) -> 42.
-
-bad_arith3(T) when (bnot T) < 17 -> T;
-bad_arith3(_) -> 42.
-
-bad_arith4(T1, T2) when (T1 bsr T2) < 10 -> T1 bsr T2;
-bad_arith4(_, _) -> 42.
-
-bad_tuple() ->
- error = bad_tuple1(a),
- error = bad_tuple1({a, b}),
- x = bad_tuple1({x, b}),
- y = bad_tuple1({a, b, y}),
- ok.
-
-bad_tuple1(T) when element(1, T) =:= x -> x;
-bad_tuple1(T) when element(3, T) =:= y -> y;
-bad_tuple1(_) -> error.
-
-is_strange_guard() when is_tuple({1, bar, length([1, 2, 3, 4]), self()}) -> ok;
-is_strange_guard() -> error.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl
deleted file mode 100644
index 306c6a39ce..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl
+++ /dev/null
@@ -1,31 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that depend on the compiler inliner being turned on.
-%%%-------------------------------------------------------------------
--module(basic_inline_module).
-
--export([test/0]).
-
--compile([inline]). %% necessary for these tests
-
-test() ->
- ok = test_case_end_atom(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests whether the translation of a case_end instruction works even
-%% when an exception (no matching case pattern) is to be raised.
-
-test_case_end_atom() ->
- {'EXIT',{{case_clause,some_atom},_Trace}} = (catch test_case_stm_inlining()),
- ok.
-
-test_case_stm_inlining() ->
- case some_atom() of
- another_atom -> strange_result
- end.
-
-some_atom() ->
- some_atom.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl
deleted file mode 100644
index 73367c5c45..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl
+++ /dev/null
@@ -1,326 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples, mostly taken from the mailing list, that
-%%% crashed the BEAM compiler or gave an internal error at some point.
-%%%-------------------------------------------------------------------
--module(basic_issues_beam).
-
--export([test/0]).
-
-test() ->
- ok = test_crash_R10_hinde(),
- ok = test_error_R10_mander(),
- ok = test_error_R11_bjorklund(),
- ok = test_error_R11_rath(),
- ok = test_error_R12_empty_bin_rec(),
- ok = test_bug_R12_cornish(),
- ok = test_crash_R12_morris(),
- ok = test_error_R13_almeida(),
- ok = test_error_R13B01_fisher(),
- ok = test_error_R13B01_sawatari(),
- ok = test_error_R13B01_whongo(),
- ok = test_error_R16B03_norell(),
- ok = test_error_try_wings(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Fisher R10 compiler crash
-%%--------------------------------------------------------------------
-
--record(r, {a, b, c}).
-
-test_crash_R10_hinde() ->
- rec_R10_hinde(#r{}).
-
-rec_R10_hinde(As) ->
- case As of
- A when A#r.b == ""; A#r.b == undefined -> ok;
- _ -> error
- end.
-
-%%--------------------------------------------------------------------
-%% From: Peter-Henry Mander
-%% Date: 27 Jan, 2005
-%%
-%% I managed to isolate a non-critical BEAM compilation error
-%% (internal error in v3_codegen) when compiling the following code:
-%%--------------------------------------------------------------------
-
-test_error_R10_mander() ->
- try just_compile_me_R10() catch _:_ -> ok end.
-
-just_compile_me_R10() ->
- URI_Before =
- {absoluteURI,
- {scheme, fun() -> nil end},
- {hier_part,
- {net_path,
- {srvr,
- {userinfo, nil},
- fun() -> nil end},
- nil},
- {port, nil}}},
- {absoluteURI,
- {scheme, _},
- {hier_part,
- {net_path,
- {srvr,
- {userinfo, nil},
- _HostportBefore},
- nil},
- {port, nil}}} = URI_Before,
- %% ... some funky code ommitted, not relevant ...
- {absoluteURI,
- {scheme, _},
- {hier_part,
- {net_path,
- {srvr,
- {userinfo, nil},
- HostportAfter},
- nil},
- {port, nil}}} = URI_Before,
- %% NOTE: I intended to write URI_After instead of URI_Before
- %% but the accident revealed that when you add the line below,
- %% it causes internal error in v3_codegen on compilation
- {hostport, {hostname, "HostName"}, {port, nil}} = HostportAfter,
- ok.
-
-%%--------------------------------------------------------------------
-%% From: Martin Bjorklund
-%% Date: Aug 16, 2006
-%%
-%% I found this compiler bug in R10B-10 and R11B-0.
-%%
-%% Function -just_compile_me/0-fun-2-/1 refers to undefined label 18
-%% ./bjorklund_R11compiler_bug.erl:none: internal error in beam_clean;
-%% crash reason: {{case_clause,{'EXIT',{undefined_label,18}}},
-%% [{compile,'-select_passes/2-anonymous-2-',2},
-%% {compile,'-internal_comp/4-anonymous-1-',2},
-%% {compile,fold_comp,3},
-%% {compile,internal_comp,4},
-%% {compile,internal,3}]}
-%%--------------------------------------------------------------------
-
-test_error_R11_bjorklund() ->
- just_compile_me_R11_bjorklund().
-
-just_compile_me_R11_bjorklund() ->
- G = fun() -> ok end,
- try
- G() %% fun() -> ok end
- after
- fun({A, B}) -> A + B end
- end.
-
-%%--------------------------------------------------------------------
-%% From: Tim Rath
-%% Date: Sep 13, 2006
-%% Subject: Compiler bug not quite fixed
-%%
-%%
-%% I saw a compiler bug posted to the list by Martin Bjorklund that
-%% appeared to be exactly the problem I'm seeing, and then noticed
-%% that this was fixed in R11B-1. Unfortunately, though R11B-1 appears
-%% to fix the code submitted by Martin, it does not fix my case.
-%%
-%% Function -just_compile_me/0-fun-2-/1 refers to undefined label 13
-%% ./rath_R11compiler_bug.erl:none: internal error in beam_clean;
-%% crash reason: {{case_clause,{'EXIT',{undefined_label,13}}},
-%% [{compile,'-select_passes/2-anonymous-2-',2},
-%% {compile,'-internal_comp/4-anonymous-1-',2},
-%% {compile,fold_comp,3},
-%% {compile,internal_comp,4},
-%% {compile,internal,3}]}
-%%--------------------------------------------------------------------
-
-test_error_R11_rath() ->
- just_compile_me_R11_rath().
-
-just_compile_me_R11_rath() ->
- A = {6},
- try
- io:fwrite("")
- after
- fun () ->
- fun () -> {_} = A end
- end
- end.
-
-%%----------------------------------------------------------------------
-%% Program that crashed the R12B-0 compiler: internal error in v3_codegen
-%%----------------------------------------------------------------------
-
--record(rec, {a = <<>> :: binary(), b = 42 :: integer()}).
-
-test_error_R12_empty_bin_rec() ->
- 42 = test_empty_bin_rec(#rec{}),
- ok.
-
-test_empty_bin_rec(R) ->
- #rec{a = <<>>} = R,
- R#rec.b.
-
-%%----------------------------------------------------------------------
-%% From: Simon Cornish
-%% Date: Jan 13, 2008
-%%
-%% The attached Erlang code demonstrates an R12B-0 bug with funs.
-%% Compile and evaluate the two die/1 calls for two different failure modes.
-%% It seems to me that the live register check for call_fun is off by one.
-%%----------------------------------------------------------------------
-
--record(b, {c}).
-
-test_bug_R12_cornish() ->
- {a2, a} = die(a),
- {a2, {b, c}} = die({b, c}),
- ok.
-
-die(A) ->
- F = fun() -> {ok, A} end,
- if A#b.c =:= [] -> one;
- true ->
- case F() of
- {ok, A2} -> {a2, A2};
- _ -> three
- end
- end.
-
-%%----------------------------------------------------------------------
-%% From: Hunter Morris
-%% Date: Nov 20, 2008
-%%
-%% The following code (tested with R12B-4 or R12B-5, vanilla compiler
-%% options) produces a compiler crash. It's nonsensical, and I realise
-%% that andalso can be quite evil, but it's a crash nonetheless.
-%%----------------------------------------------------------------------
-
-test_crash_R12_morris() ->
- foo(42).
-
-foo(Bar) when (is_integer(Bar) andalso Bar =:= 0) ; Bar =:= 42 ->
- ok.
-
-%%--------------------------------------------------------------------
-%% From: Paulo Sergio Almeida
-%% Date: May 20, 2009
-%%
-%% The following code when compiled under R13B gives a compiler error.
-%% Function loop/1 refers to undefined label 6
-%% ./almeida_R13compiler_bug.erl:none: internal error in beam_peep;
-%% crash reason: {{case_clause,{'EXIT',{undefined_label,6}}},
-%% [{compile,'-select_passes/2-anonymous-2-',2},
-%% {compile,'-internal_comp/4-anonymous-1-',2},
-%%--------------------------------------------------------------------
-
-test_error_R13_almeida() ->
- self() ! {backup, 42, false},
- loop([]).
-
-loop(Tids) ->
- receive
- {backup, Tid, Dumping} ->
- case Dumping of
- false -> ok;
- _ -> receive {logged, Tab, Tid} -> put({log, Tab}, Tid) end
- end,
- collect(Tid, Tids, [])
- end.
-
-collect(_, _, _) -> ok.
-
-%%--------------------------------------------------------------------
-%% Fisher R13B01 compiler error
-%%--------------------------------------------------------------------
-
-test_error_R13B01_fisher() ->
- perform_select({foo, "42"}).
-
-perform_select({Type, Keyval}) ->
- try
- if is_atom(Type) andalso length(Keyval) > 0 -> ok;
- true -> ok
- end
- catch
- _:_ -> fail
- end.
-
-%%--------------------------------------------------------------------
-%% From: Mikage Sawatari
-%% Date: Jun 12, 2009
-%%
-%% I have the following compilation problem on Erlang R13B01.
-%% Compiler reports "Internal consistency check failed".
-%%--------------------------------------------------------------------
-
-test_error_R13B01_sawatari() ->
- test_sawatari([1, null, 3], <<1, 2, 3>>).
-
-test_sawatari([], _Bin) -> ok;
-test_sawatari([H|T], Bin) ->
- _ = case H of
- null -> <<Bin/binary>>;
- _ -> ok
- end,
- test_sawatari(T, Bin).
-
-%%--------------------------------------------------------------------
-
-test_error_R13B01_whongo() ->
- S = "gazonk",
- S = orgno_alphanum(S),
- ok.
-
-orgno_alphanum(Cs) ->
- [C || C <- Cs, ((C >= $0) andalso (C =< $9))
- orelse ((C >= $a) andalso (C =< $z))
- orelse ((C >= $A) andalso (C =< $Z))].
-
-%%--------------------------------------------------------------------
-%% I'm getting an Internal Consistency Check error when attempting to
-%% build Wings3D on Mac OS X 10.4.2 (Erlang OTP R10B-6):
-%%
-%% erlc -pa /ebin +warn_unused_vars -I/include -I ../e3d -W +debug_info
-%% '-Dwings_version="0.98.31"' -pa ../ebin -o../ebin wings_color.erl
-%% wings_color: function internal_rgb_to_hsv/3+97:
-%% Internal consistency check failed - please report this bug.
-%% Instruction: {test,is_eq_exact,{f,80},[{x,0},{atom,error}]}
-%% Error: {unsafe_instruction,{float_error_state,cleared}}:
-%%
-%% The problem is the interaction of the 'try' construct with the
-%% handling of FP exceptions.
-%%--------------------------------------------------------------------
-
-test_error_try_wings() ->
- %% a call with a possible FP exception
- {199.99999999999997, 0.045454545454545456, 44} = rgb_to_hsv(42, 43, 44),
- ok.
-
-rgb_to_hsv(R, G, B) ->
- Max = lists:max([R, G, B]),
- Min = lists:min([R, G, B]),
- V = Max,
- {Hue, Sat} = try
- {if Min == B -> (G-Min)/(R+G-2.0*Min);
- Min == R -> (1.0+(B-Min)/(B+G-2.0*Min));
- Min == G -> (2.0+(R-Min)/(B+R-2.0*Min))
- end * 120, (Max-Min)/Max}
- catch
- error:badarith -> {undefined, 0.0}
- end,
- {Hue, Sat, V}.
-
-%%--------------------------------------------------------------------
-%% From: Ulf Norell
-%% Date: Feb 28, 2014
-%%
-%% This caused an internal error in v3_codegen
-%%--------------------------------------------------------------------
-
-test_error_R16B03_norell() ->
- test_error_R16B03_norell(#r{}, gazonk).
-
-test_error_R16B03_norell(Rec, Tag) ->
- is_record(Rec, Tag, 3) orelse ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
deleted file mode 100644
index fc87abb54e..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
+++ /dev/null
@@ -1,177 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples that exhibited crashes in the HiPE compiler.
-%%%-------------------------------------------------------------------
--module(basic_issues_hipe).
-
--export([test/0]).
-
-%% functions that need to be exported so that they are retained and/or
-%% not specialized away by the compiler.
--export([auth/4, wxSizer_replace/2, parent_class/1]).
-
-test() ->
- ok = test_dominance_trees(),
- ok = test_merged_const(),
- ok = test_var_pair(),
- ok = test_bif_fails(),
- ok = test_find_catches(),
- ok = test_heap_allocate_trim(),
- ok = wxSizer_replace(),
- ok.
-
-%%--------------------------------------------------------------------
-%% This is taken from a file sent to us by Martin Bjorklund @ Nortel
-%% on 14th November 2004. The problem was in the SSA unconvert pass.
-%%
-%% No tests here; we simply check that the HiPE compiler does not go
-%% into an infinite loop when compiling strange functions like this.
-%%--------------------------------------------------------------------
-
-auth(_, A, B, C) ->
- auth(A, B, C, []).
-
-%%--------------------------------------------------------------------
-%% Exposed a crash in the generation of dominance trees used in SSA.
-%%--------------------------------------------------------------------
-
--record(state, {f}).
-
-test_dominance_trees() ->
- {ok, true} = doit(true, #state{f = true}),
- ok.
-
-doit(Foo, S) ->
- Fee = case Foo of
- Bar when Bar == S#state.f; Bar == [] -> true;
- _ -> false
- end,
- {ok, Fee}.
-
-%%--------------------------------------------------------------------
-%% Checks that the merging of constants in the constant table uses the
-%% appropriate comparison function for this.
-%%--------------------------------------------------------------------
-
-test_merged_const() ->
- Const1 = {'', 1.0000},
- Const2 = {'', 1},
- match(Const1, Const2).
-
-match(A, A) ->
- error;
-match(_A, _B) ->
- ok.
-
-%%--------------------------------------------------------------------
-%% Checks that the HiPE compiler does not get confused by constant
-%% data structures similar to the internal compiler data structures.
-%%--------------------------------------------------------------------
-
-test_var_pair() ->
- ok = var_pair([gazonk]).
-
-var_pair([_|_]) ->
- var_pair({var, some_atom});
-var_pair(_) ->
- ok.
-
-%%--------------------------------------------------------------------
-%% This module was causing the HiPE compiler to crash in January 2007.
-%% The culprit was an "optimization" of the BEAM compiler: postponing
-%% the save of x variables when BIFs cannot fail. This was fixed on
-%% February 1st, by making the HiPE compiler use the same functions
-%% as the BEAM compiler for deciding whether a BIF fails.
-%%--------------------------------------------------------------------
-
-test_bif_fails() ->
- [42] = bif_fails_in_catch([42]),
- true = bif_fails_in_try([42]),
- ok.
-
-bif_fails_in_catch(X) ->
- case catch get(gazonk) of
- _ -> X
- end.
-
-bif_fails_in_try(X) ->
- try
- true = X =/= []
- catch
- _ -> nil(X)
- end.
-
-nil(_) -> [].
-
-%%--------------------------------------------------------------------
-%% Test that resulted in a native code compiler crash in the code of
-%% hipe_icode_exceptions:find_catches/1 when compiling find_catches/2.
-%%--------------------------------------------------------------------
-
-test_find_catches() ->
- 42 = find_catches(a, false),
- ok.
-
-find_catches(X, Y) ->
- case X of
- a when Y =:= true ->
- catch id(X),
- X;
- b when Y =:= true ->
- catch id(X),
- X;
- a ->
- catch id(X),
- 42;
- b ->
- catch id(X),
- 42
- end.
-
-id(X) -> X.
-
-%%--------------------------------------------------------------------
-%% Date: Dec 28, 2007
-%%
-%% This is a test adapted from the file sent to the Erlang mailing
-%% list by Eranga Udesh. The file did not compile because of problems
-%% with the heap_allocate instruction and stack trimming.
-%%--------------------------------------------------------------------
-
-test_heap_allocate_trim() ->
- {abandon, 42} = get_next_retry(a, 42),
- ok.
-
-get_next_retry(Error, Count) ->
- case catch pair(retry_scheme, {Error, Count}) of
- _ ->
- case pair(Error, Count) of
- _ -> {abandon, Count}
- end
- end.
-
-pair(A, B) -> {A, B}.
-
-%%--------------------------------------------------------------------
-%% Date: June 11, 2018
-%%
-%% Stripped down test case (from `wxSizer') that crashed the lazy code
-%% motion pass of the HiPE compiler in a pre-release of Erlang/OTP 21.
-%% A similar crash existed in `ssl_correction'.
-%%--------------------------------------------------------------------
-
-wxSizer_replace() ->
- wxSizer_replace(?MODULE, ?MODULE).
-
--define(CLASS(Type, Class), ((Type) =:= Class) orelse (Type):parent_class(Class)).
-
-wxSizer_replace(OldwinT, NewwinT) -> % this function was the culprit
- ?CLASS(OldwinT, ?MODULE),
- ?CLASS(NewwinT, ?MODULE),
- ok.
-
-parent_class(wxWindow) -> true;
-parent_class(wxEvtHandler) -> true;
-parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_lists.erl b/lib/hipe/test/basic_SUITE_data/basic_lists.erl
deleted file mode 100644
index 264a7f86f6..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_lists.erl
+++ /dev/null
@@ -1,61 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that manipulate and pattern match against lists
-%%% (perhaps by calling functions from the 'lists' module).
-%%%-------------------------------------------------------------------
--module(basic_lists).
-
--export([test/0]).
-
-test() ->
- ok = test_length(),
- ok = test_lists_key(),
- ok = test_lists_and_strings(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_length() ->
- Len = 42,
- Lst = mklist(Len, []),
- Len = iterate(100, Lst),
- ok.
-
-mklist(0, L) -> L;
-mklist(X, L) -> mklist(X-1, [X|L]).
-
-iterate(0, L) -> len(L, 0);
-iterate(X, L) -> len(L, 0), iterate(X-1, L).
-
-len([_|X], L) -> len(X, L+1);
-len([], L) -> L.
-
-%%--------------------------------------------------------------------
-
-test_lists_key() ->
- First = {x, 42.0},
- Second = {y, -77},
- Third = {z, [a, b, c], {5.0}},
- List = [First, Second, Third],
- {value, First} = key_search_find(42, 2, List),
- ok.
-
-key_search_find(Key, Pos, List) ->
- case lists:keyfind(Key, Pos, List) of
- false ->
- false = lists:keysearch(Key, Pos, List);
- Tuple when is_tuple(Tuple) ->
- {value, Tuple} = lists:keysearch(Key, Pos, List)
- end.
-
-%%--------------------------------------------------------------------
-
-test_lists_and_strings() ->
- LL = ["H'A", " H'B", " H'C"],
- LL2 = lists:map(fun string:strip/1, LL),
- HexFormat = fun(X, Acc) -> {string:substr(X, 3), Acc} end,
- {LL3,_Ret} = lists:mapfoldl(HexFormat, 0, LL2),
- ["A", "B", "C"] = lists:sublist(LL3, 42),
- ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_module_info.erl b/lib/hipe/test/basic_SUITE_data/basic_module_info.erl
deleted file mode 100644
index cab48b10ba..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_module_info.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%% Date: Oct 25, 2003
-%%%
-%%% Tests whether calling module_info from the same module works.
-%%% This seems trivial, but the problem is that the module_info/[0,1]
-%%% functions that the BEAM file contains used to be dummy functions
-%%% containing crap. So, these functions could not be used for
-%%% compilation to native code and the functions that the BEAM loader
-%%% generates should have been used instead. This was a HiPE bug
-%%% reported by Dan Wallin.
-%%%-------------------------------------------------------------------
--module(basic_module_info).
-
--export([test/0]).
-
-test() ->
- L = test_local_mi0_call(),
- E = test_remote_mi1_call(),
- {3, 3} = {L, E},
- ok.
-
-test_local_mi0_call() ->
- ModInfo = module_info(),
- %% io:format("ok, ModInfo=~w\n", [ModInfo]),
- {exports, FunList} = lists:keyfind(exports, 1, ModInfo),
- length(FunList).
-
-test_remote_mi1_call() ->
- FunList = ?MODULE:module_info(exports),
- length(FunList).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
deleted file mode 100644
index 807c4b0d0d..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
+++ /dev/null
@@ -1,217 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : basic_num_bif.erl
-%%% Description : Taken from the compiler test suite
-%%%-------------------------------------------------------------------
--module(basic_num_bif).
-
--export([test/0]).
-
-%% Tests optimization of the BIFs:
-%% abs/1
-%% float/1
-%% float_to_list/1
-%% integer_to_list/1
-%% list_to_float/1
-%% list_to_integer/1
-%% round/1
-%% trunc/1
-
-test() ->
- Funs = [fun t_abs/0, fun t_float/0,
- fun t_float_to_list/0, fun t_integer_to_list/0,
- fun t_list_to_float_safe/0, fun t_list_to_float_risky/0,
- fun t_list_to_integer/0, fun t_round/0, fun t_trunc/0],
- lists:foreach(fun (F) -> ok = F() end, Funs).
-
-t_abs() ->
- %% Floats.
- 5.5 = abs(5.5),
- 0.0 = abs(0.0),
- 100.0 = abs(-100.0),
- %% Integers.
- 5 = abs(5),
- 0 = abs(0),
- 100 = abs(-100),
- %% The largest smallnum. OTP-3190.
- X = (1 bsl 27) - 1,
- X = abs(X),
- X = abs(X-1)+1,
- X = abs(X+1)-1,
- X = abs(-X),
- X = abs(-X-1)-1,
- X = abs(-X+1)+1,
- %% Bignums.
- BigNum = 13984792374983749,
- BigNum = abs(BigNum),
- BigNum = abs(-BigNum),
- ok.
-
-t_float() ->
- 0.0 = float(0),
- 2.5 = float(2.5),
- 0.0 = float(0.0),
- -100.55 = float(-100.55),
- 42.0 = float(42),
- -100.0 = float(-100),
- %% Bignums.
- 4294967305.0 = float(4294967305),
- -4294967305.0 = float(-4294967305),
- %% Extremely big bignums.
- Big = list_to_integer(lists:duplicate(2000, $1)),
- {'EXIT', {badarg, _}} = (catch float(Big)),
- ok.
-
-%% Tests float_to_list/1.
-
-t_float_to_list() ->
- test_ftl("0.0e+0", 0.0),
- test_ftl("2.5e+1", 25.0),
- test_ftl("2.5e+0", 2.5),
- test_ftl("2.5e-1", 0.25),
- test_ftl("-3.5e+17", -350.0e15),
- ok.
-
-test_ftl(Expect, Float) ->
- %% No on the next line -- we want the line number from t_float_to_list.
- Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
-
-%% Removes any non-significant zeros in a floating point number.
-%% Example: 2.500000e+01 -> 2.5e+1
-
-remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$+, $e|Rest], [X|Result]);
-remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$-, $e|Rest], [X|Result]);
-remove_zeros([$0, $.|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$., $0, $e|Result]);
-remove_zeros([$0|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$e|Result]);
-remove_zeros([Char|Rest], Result) ->
- remove_zeros(Rest, [Char|Result]);
-remove_zeros([], Result) ->
- Result.
-
-%% Tests integer_to_list/1.
-
-t_integer_to_list() ->
- "0" = integer_to_list(0),
- "42" = integer_to_list(42),
- "-42" = integer_to_list(-42),
- "-42" = integer_to_list(-42),
- "32768" = integer_to_list(32768),
- "268435455" = integer_to_list(268435455),
- "-268435455" = integer_to_list(-268435455),
- "123456932798748738738" = integer_to_list(123456932798748738738),
- Big_List = lists:duplicate(2000, $1),
- Big = list_to_integer(Big_List),
- Big_List = integer_to_list(Big),
- ok.
-
-%% Tests list_to_float/1.
-
-t_list_to_float_safe() ->
- 0.0 = list_to_float("0.0"),
- 0.0 = list_to_float("-0.0"),
- 0.5 = list_to_float("0.5"),
- -0.5 = list_to_float("-0.5"),
- 100.0 = list_to_float("1.0e2"),
- 127.5 = list_to_float("127.5"),
- -199.5 = list_to_float("-199.5"),
- ok.
-
-%% This might crash the emulator...
-%% (Known to crash the Unix version of Erlang 4.4.1)
-
-t_list_to_float_risky() ->
- Many_Ones = lists:duplicate(25000, $1),
- _ = list_to_float("2."++Many_Ones),
- {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
- ok.
-
-%% Tests list_to_integer/1.
-
-t_list_to_integer() ->
- 0 = list_to_integer("0"),
- 0 = list_to_integer("00"),
- 0 = list_to_integer("-0"),
- 1 = list_to_integer("1"),
- -1 = list_to_integer("-1"),
- 42 = list_to_integer("42"),
- -12 = list_to_integer("-12"),
- 32768 = list_to_integer("32768"),
- 268435455 = list_to_integer("268435455"),
- -268435455 = list_to_integer("-268435455"),
- %% Bignums.
- 123456932798748738738 = list_to_integer("123456932798748738738"),
- _ = list_to_integer(lists:duplicate(2000, $1)),
- ok.
-
-%% Tests round/1.
-
-t_round() ->
- 0 = round(0.0),
- 0 = round(0.4),
- 1 = round(0.5),
- 0 = round(-0.4),
- -1 = round(-0.5),
- 255 = round(255.3),
- 256 = round(255.6),
- -1033 = round(-1033.3),
- -1034 = round(-1033.6),
- %% OTP-3722:
- X = (1 bsl 27) - 1,
- MX = -X,
- MXm1 = -X-1,
- MXp1 = -X+1,
- F = X + 0.0,
- X = round(F),
- X = round(F+1)-1,
- X = round(F-1)+1,
- MX = round(-F),
- MXm1 = round(-F-1),
- MXp1 = round(-F+1),
- X = round(F+0.1),
- X = round(F+1+0.1)-1,
- X = round(F-1+0.1)+1,
- MX = round(-F+0.1),
- MXm1 = round(-F-1+0.1),
- MXp1 = round(-F+1+0.1),
- X = round(F-0.1),
- X = round(F+1-0.1)-1,
- X = round(F-1-0.1)+1,
- MX = round(-F-0.1),
- MXm1 = round(-F-1-0.1),
- MXp1 = round(-F+1-0.1),
- 0.5 = abs(round(F+0.5)-(F+0.5)),
- 0.5 = abs(round(F-0.5)-(F-0.5)),
- 0.5 = abs(round(-F-0.5)-(-F-0.5)),
- 0.5 = abs(round(-F+0.5)-(-F+0.5)),
- %% Bignums.
- 4294967296 = round(4294967296.1),
- 4294967297 = round(4294967296.9),
- -4294967296 = -round(4294967296.1),
- -4294967297 = -round(4294967296.9),
- ok.
-
-t_trunc() ->
- 0 = trunc(0.0),
- 5 = trunc(5.3333),
- -10 = trunc(-10.978987),
- %% The largest smallnum, converted to float (OTP-3722):
- X = (1 bsl 27) - 1,
- F = X + 0.0,
- %% io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
- %% [X, X, binary_to_list(term_to_binary(X)),
- %% F, F, binary_to_list(term_to_binary(F)),
- %% trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
- X = trunc(F),
- X = trunc(F+1)-1,
- X = trunc(F-1)+1,
- X = -trunc(-F),
- X = -trunc(-F-1)-1,
- X = -trunc(-F+1)+1,
- %% Bignums.
- 4294967305 = trunc(4294967305.7),
- -4294967305 = trunc(-4294967305.7),
- ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl b/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl
deleted file mode 100644
index 93240354a7..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples that test pattern matching against terms of
-%%% various types.
-%%%-------------------------------------------------------------------
--module(basic_pattern_match).
-
--export([test/0]).
-
-test() ->
- ok = test_hello_world(),
- ok = test_list_plus_plus_match(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Trivial test to test pattern matching compilation with atoms, the
-%% correct handling of all sorts of alphanumeric types in Erlang, and
-%% conversions between them.
-
-test_hello_world() ->
- String = gimme(string),
- String = atom_to_list(gimme(atom)),
- String = binary_to_list(gimme(binary)),
- true = (list_to_atom(String) =:= gimme(atom)),
- true = (list_to_binary(String) =:= gimme(binary)),
- ok.
-
-gimme(string) ->
- "hello world";
-gimme(atom) ->
- 'hello world';
-gimme(binary) ->
- <<"hello world">>.
-
-%%--------------------------------------------------------------------
-%% Makes sure that pattern matching expressions involving ++ work OK.
-%% The third expression caused a problem in the Erlang shell of R11B-5.
-%% It worked OK in both interpreted and compiled code.
-
-test_list_plus_plus_match() ->
- ok = (fun("X" ++ _) -> ok end)("X"),
- ok = (fun([$X | _]) -> ok end)("X"),
- ok = (fun([$X] ++ _) -> ok end)("X"),
- ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_random.erl b/lib/hipe/test/basic_SUITE_data/basic_random.erl
deleted file mode 100644
index 783947bd31..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_random.erl
+++ /dev/null
@@ -1,238 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% A test for list handling created using the 'random' module.
-%%%-------------------------------------------------------------------
--module(basic_random).
-
--export([test/0]).
-
-%% It can be used as a benchmark by playing with the following defines
--define(N, 1000).
--define(Iter, 500).
-
-test() ->
- ok = random(?N).
-
-random(N) ->
- random(N, ?Iter).
-
-random(N, Iter) ->
- random:seed(1, 2, 3),
- t(ranlist(N, [], N*100), Iter).
-
-ranlist(0, L, _N) -> L;
-ranlist(N, L, N0) -> ranlist(N-1, [random:uniform(N0)+300 | L], N0).
-
-t(_, 0) -> ok;
-t(L, Iter) ->
- %% io:format("Sort starting~n"),
- sort(L),
- t(L, Iter-1).
-
-sort([X, Y | L]) when X =< Y ->
- split_1(X, Y, L, [], []);
-sort([X, Y | L]) ->
- split_2(X, Y, L, [], []);
-sort(L) ->
- L.
-
-%% Ascending.
-split_1(X, Y, [Z | L], R, Rs) when Z >= Y ->
- split_1(Y, Z, L, [X | R], Rs);
-split_1(X, Y, [Z | L], R, Rs) when Z >= X ->
- split_1(Z, Y, L, [X | R], Rs);
-split_1(X, Y, [Z | L], [], Rs) ->
- split_1(X, Y, L, [Z], Rs);
-split_1(X, Y, [Z | L], R, Rs) ->
- split_1_1(X, Y, L, R, Rs, Z);
-split_1(X, Y, [], R, Rs) ->
- rmergel([[Y, X | R] | Rs], []).
-
-%% One out-of-order element, S.
-split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y ->
- split_1_1(Y, Z, L, [X | R], Rs, S);
-split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X ->
- split_1_1(Z, Y, L, [X | R], Rs, S);
-split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z ->
- split_1(S, Z, L, [], [[Y, X | R] | Rs]);
-split_1_1(X, Y, [Z | L], R, Rs, S) ->
- split_1(Z, S, L, [], [[Y, X | R] | Rs]);
-split_1_1(X, Y, [], R, Rs, S) ->
- rmergel([[S], [Y, X | R] | Rs], []).
-
-%% Descending.
-split_2(X, Y, [Z | L], R, Rs) when Z =< Y ->
- split_2(Y, Z, L, [X | R], Rs);
-split_2(X, Y, [Z | L], R, Rs) when Z =< X ->
- split_2(Z, Y, L, [X | R], Rs);
-split_2(X, Y, [Z | L], [], Rs) ->
- split_2(X, Y, L, [Z], Rs);
-split_2(X, Y, [Z | L], R, Rs) ->
- split_2_1(X, Y, L, R, Rs, Z);
-split_2(X, Y, [], R, Rs) ->
- mergel([[Y, X | R] | Rs], []).
-
-split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< Y ->
- split_2_1(Y, Z, L, [X | R], Rs, S);
-split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< X ->
- split_2_1(Z, Y, L, [X | R], Rs, S);
-split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z ->
- split_2(S, Z, L, [], [[Y, X | R] | Rs]);
-split_2_1(X, Y, [Z | L], R, Rs, S) ->
- split_2(Z, S, L, [], [[Y, X | R] | Rs]);
-split_2_1(X, Y, [], R, Rs, S) ->
- mergel([[S], [Y, X | R] | Rs], []).
-
-mergel([[] | L], Acc) ->
- mergel(L, Acc);
-mergel([A, [H2 | T2], [H3 | T3] | L], Acc) ->
- mergel(L, [merge3_1(A, [], H2, T2, H3, T3) | Acc]);
-mergel([A, [H | T]], Acc) ->
- rmergel([merge2_1(A, H, T, []) | Acc], []);
-mergel([L], []) ->
- L;
-mergel([L], Acc) ->
- rmergel([lists:reverse(L, []) | Acc], []);
-mergel([], []) ->
- [];
-mergel([], Acc) ->
- rmergel(Acc, []);
-mergel([A, [] | L], Acc) ->
- mergel([A | L], Acc);
-mergel([A, B, [] | L], Acc) ->
- mergel([A, B | L], Acc).
-
-rmergel([A, [H2 | T2], [H3 | T3] | L], Acc) ->
- rmergel(L, [rmerge3_1(A, [], H2, T2, H3, T3) | Acc]);
-rmergel([A, [H | T]], Acc) ->
- mergel([rmerge2_1(A, H, T, []) | Acc], []);
-rmergel([L], Acc) ->
- mergel([lists:reverse(L, []) | Acc], []);
-rmergel([], Acc) ->
- mergel(Acc, []).
-
-%% Take L1 apart.
-merge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 =< H2 ->
- merge3_12(T1, H1, H2, T2, H3, T3, M);
-merge3_1([H1 | T1], M, H2, T2, H3, T3) ->
- merge3_21(T1, H1, H2, T2, H3, T3, M);
-merge3_1(_nil, M, H2, T2, H3, T3) when H2 =< H3 ->
- merge2_1(T2, H3, T3, [H2 | M]);
-merge3_1(_nil, M, H2, T2, H3, T3) ->
- merge2_1(T3, H2, T2, [H3 | M]).
-
-%% Take L2 apart.
-merge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 =< H2 ->
- merge3_12(T1, H1, H2, T2, H3, T3, M);
-merge3_2(T1, H1, M, [H2 | T2], H3, T3) ->
- merge3_21(T1, H1, H2, T2, H3, T3, M);
-merge3_2(T1, H1, M, _nil, H3, T3) when H1 =< H3 ->
- merge2_1(T1, H3, T3, [H1 | M]);
-merge3_2(T1, H1, M, _nil, H3, T3) ->
- merge2_1(T3, H1, T1, [H3 | M]).
-
-%% H1 <= H2. Inlined.
-merge3_12(T1, H1, H2, T2, H3, T3, M) when H3 < H1 ->
- merge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
-merge3_12(T1, H1, H2, T2, H3, T3, M) ->
- merge3_1(T1, [H1 | M], H2, T2, H3, T3).
-
-%% H1 <= H2, take L3 apart.
-merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H1 ->
- merge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
-merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) ->
- merge3_1(T1, [H1 | M], H2, T2, H3, T3);
-merge3_12_3(T1, H1, H2, T2, M, _nil) ->
- merge2_1(T1, H2, T2, [H1 | M]).
-
-%% H1 > H2. Inlined.
-merge3_21(T1, H1, H2, T2, H3, T3, M) when H3 < H2 ->
- merge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
-merge3_21(T1, H1, H2, T2, H3, T3, M) ->
- merge3_2(T1, H1, [H2 | M], T2, H3, T3).
-
-%% H1 > H2, take L3 apart.
-merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H2 ->
- merge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
-merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) ->
- merge3_2(T1, H1, [H2 | M], T2, H3, T3);
-merge3_21_3(T1, H1, H2, T2, M, _nil) ->
- merge2_1(T2, H1, T1, [H2 | M]).
-
-%% Take L1 apart.
-rmerge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 > H2 ->
- rmerge3_12(T1, H1, H2, T2, H3, T3, M);
-rmerge3_1([H1 | T1], M, H2, T2, H3, T3) ->
- rmerge3_21(T1, H1, H2, T2, H3, T3, M);
-rmerge3_1(_nil, M, H2, T2, H3, T3) when H2 > H3 ->
- rmerge2_1(T2, H3, T3, [H2 | M]);
-rmerge3_1(_nil, M, H2, T2, H3, T3) ->
- rmerge2_1(T3, H2, T2, [H3 | M]).
-
-%% Take L2 apart.
-rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 > H2 ->
- rmerge3_12(T1, H1, H2, T2, H3, T3, M);
-rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) ->
- rmerge3_21(T1, H1, H2, T2, H3, T3, M);
-rmerge3_2(T1, H1, M, _nil, H3, T3) when H1 > H3 ->
- rmerge2_1(T1, H3, T3, [H1 | M]);
-rmerge3_2(T1, H1, M, _nil, H3, T3) ->
- rmerge2_1(T3, H1, T1, [H3 | M]).
-
-%% H1 > H2. Inlined.
-rmerge3_12(T1, H1, H2, T2, H3, T3, M) when H3 >= H1 ->
- rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
-rmerge3_12(T1, H1, H2, T2, H3, T3, M) ->
- rmerge3_1(T1, [H1 | M], H2, T2, H3, T3).
-
-%% H1 > H2, take L3 apart.
-rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H1 ->
- rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
-rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) ->
- rmerge3_1(T1, [H1 | M], H2, T2, H3, T3);
-rmerge3_12_3(T1, H1, H2, T2, M, _nil) ->
- rmerge2_1(T1, H2, T2, [H1 | M]).
-
-%% H1 =< H2. Inlined.
-rmerge3_21(T1, H1, H2, T2, H3, T3, M) when H3 >= H2 ->
- rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
-rmerge3_21(T1, H1, H2, T2, H3, T3, M) ->
- rmerge3_2(T1, H1, [H2 | M], T2, H3, T3).
-
-%% H1 =< H2, take L3 apart.
-rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H2 ->
- rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
-rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) ->
- rmerge3_2(T1, H1, [H2 | M], T2, H3, T3);
-rmerge3_21_3(T1, H1, H2, T2, M, _nil) ->
- rmerge2_1(T2, H1, T1, [H2 | M]).
-
-merge2_1([H1 | T1], H2, T2, M) when H2 < H1 ->
- merge2_2(T1, H1, T2, [H2 | M]);
-merge2_1([H1 | T1], H2, T2, M) ->
- merge2_1(T1, H2, T2, [H1 | M]);
-merge2_1(_nil, H2, T2, M) ->
- lists:reverse(T2, [H2 | M]).
-
-merge2_2(T1, H1, [H2 | T2], M) when H1 < H2 ->
- merge2_1(T1, H2, T2, [H1 | M]);
-merge2_2(T1, H1, [H2 | T2], M) ->
- merge2_2(T1, H1, T2, [H2 | M]);
-merge2_2(T1, H1, _nil, M) ->
- lists:reverse(T1, [H1 | M]).
-
-rmerge2_1([H1 | T1], H2, T2, M) when H2 >= H1 ->
- rmerge2_2(T1, H1, T2, [H2 | M]);
-rmerge2_1([H1 | T1], H2, T2, M) ->
- rmerge2_1(T1, H2, T2, [H1 | M]);
-rmerge2_1(_nil, H2, T2, M) ->
- lists:reverse(T2, [H2 | M]).
-
-rmerge2_2(T1, H1, [H2 | T2], M) when H1 >= H2 ->
- rmerge2_1(T1, H2, T2, [H1 | M]);
-rmerge2_2(T1, H1, [H2 | T2], M) ->
- rmerge2_2(T1, H1, T2, [H2 | M]);
-rmerge2_2(T1, H1, _nil, M) ->
- lists:reverse(T1, [H1 | M]).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_receive.erl b/lib/hipe/test/basic_SUITE_data/basic_receive.erl
deleted file mode 100644
index 20e3f350e8..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_receive.erl
+++ /dev/null
@@ -1,145 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains code examples that test correct handling of receives.
-%%%-------------------------------------------------------------------
--module(basic_receive).
-
--export([test/0]).
-
-test() ->
- ok = test_wait_timeout(),
- ok = test_double_timeout(),
- ok = test_reschedule(),
- ok = test_recv_mark(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_wait_timeout() ->
- receive after 42 -> ok end.
-
-%%--------------------------------------------------------------------
-
-test_double_timeout() ->
- self() ! foo,
- self() ! another_foo,
- receive
- non_existent -> weird
- after 0 -> timeout
- end,
- receive
- foo -> ok
- after 1000 -> timeout
- end.
-
-%%--------------------------------------------------------------------
-%% Check that RESCHEDULE returns from BIFs work.
-
-test_reschedule() ->
- erts_debug:set_internal_state(available_internal_state, true),
- First = self(),
- Second = spawn(fun() -> doit(First) end),
- receive
- Second -> ok
- end,
- receive
- after 42 -> ok
- end,
- erts_debug:set_internal_state(hipe_test_reschedule_resume, Second),
- ok.
-
-doit(First) ->
- First ! self(),
- erts_debug:set_internal_state(hipe_test_reschedule_suspend, 1).
-
-%%--------------------------------------------------------------------
-%% Check that we cannot cause a recv_mark,recv_set pair to misbehave and
-%% deadlock the process.
-
-test_recv_mark() ->
- ok = test_recv_mark(fun disturber_nop/0),
- ok = test_recv_mark(fun disturber_receive/0),
- ok = test_recv_mark(fun disturber_other/0),
- ok = test_recv_mark(fun disturber_recurse/0),
- ok = test_recv_mark_after(self(), fun disturber_after_recurse/0, false),
- ok = test_recv_mark(fun disturber_other_recurse/0),
- ok = test_recv_mark(fun disturber_other_after/0),
- ok = test_recv_mark_nested().
-
-test_recv_mark(Disturber) ->
- Ref = make_ref(),
- self() ! Ref,
- Disturber(),
- receive Ref -> ok
- after 0 -> error(failure)
- end.
-
-disturber_nop() -> ok.
-
-disturber_receive() ->
- self() ! message,
- receive message -> ok end.
-
-disturber_other() ->
- Ref = make_ref(),
- self() ! Ref,
- receive Ref -> ok end.
-
-disturber_recurse() ->
- aborted = (catch test_recv_mark(fun() -> throw(aborted) end)),
- ok.
-
-test_recv_mark_after(Recipient, Disturber, IsInner) ->
- Ref = make_ref(),
- Recipient ! Ref,
- Disturber(),
- receive
- Ref -> ok
- after 0 ->
- case IsInner of
- true -> expected;
- false -> error(failure)
- end
- end.
-
-disturber_after_recurse() ->
- NoOp = fun() -> ok end,
- BlackHole = spawn(NoOp),
- expected = test_recv_mark_after(BlackHole, NoOp, true),
- ok.
-
-disturber_other_recurse() ->
- aborted = (catch disturber_other_recurse(fun() -> throw(aborted) end)),
- ok.
-
-disturber_other_recurse(InnerD) ->
- Ref = make_ref(),
- self() ! Ref,
- InnerD(),
- receive Ref -> ok
- after 0 -> error(failure)
- end.
-
-disturber_other_after() ->
- BlackHole = spawn(fun() -> ok end),
- Ref = make_ref(),
- BlackHole ! Ref,
- receive Ref -> error(imposible)
- after 0 -> ok
- end.
-
-test_recv_mark_nested() ->
- Ref1 = make_ref(),
- self() ! Ref1,
- begin
- Ref2 = make_ref(),
- self() ! Ref2,
- receive Ref2 -> ok end
- end,
- receive Ref1 -> ok
- after 0 -> error(failure)
- end.
-
-%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_records.erl b/lib/hipe/test/basic_SUITE_data/basic_records.erl
deleted file mode 100644
index cbb451196c..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_records.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that manipulate and pattern match against records.
-%%%-------------------------------------------------------------------
--module(basic_records).
-
--export([test/0]).
-
-test() ->
- ok = test_rec1(),
- ok.
-
-%%--------------------------------------------------------------------
-
--record(r, {ra}).
--record(s, {sa, sb, sc, sd}).
-
-test_rec1() ->
- R = #r{},
- S = #s{},
- S1 = S#s{sc=R, sd=1},
- R1 = S1#s.sc,
- undefined = R1#r.ra,
- ok.
-
-%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl b/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl
deleted file mode 100644
index 0f94320a33..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl
+++ /dev/null
@@ -1,65 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Tests the strength reduction component of the HiPE compiler.
-%%%-------------------------------------------------------------------
--module(basic_strength_reduce).
-
--export([test/0]).
-%% These functions are exported so as to not remove them by inlining
--export([crash_0/1, crash_1/1, crash_2/1, crash_3/1, bug_div_2N/1]).
-
-test() ->
- ok = test_strength_reduce1(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_strength_reduce1() ->
- ok = crash_0(0),
- ok = crash_1(42),
- ok = crash_2(42),
- ok = crash_3(42),
- 5 = 42 bsr 3 = bug_div_2N(42),
- -6 = -42 bsr 3 = bug_div_2N(-42) - 1,
- ok.
-
-%% This is a crash report by Peter Wang (10 July 2007) triggering an
-%% R11B-5 crash: strength reduction could not handle calls with no
-%% destination
-crash_0(A) ->
- case A of
- 0 ->
- A div 8,
- ok
- end.
-
-%% The above was simplified to the following which showed another
-%% crash, this time on RTL
-crash_1(A) when is_integer(A), A >= 0 ->
- A div 8,
- ok.
-
-%% A similar crash like the first one, but in a different place in the
-%% code, was triggered by the following code
-crash_2(A) when is_integer(A), A >= 0 ->
- A div 1,
- ok.
-
-%% A crash similar to the first one happened in the following code
-crash_3(A) ->
- case A of
- 42 ->
- A * 0,
- ok
- end.
-
-%% Strength reduction for div/2 and rem/2 with a power of 2
-%% should be performed only for non-negative integers
-bug_div_2N(X) when is_integer(X), X >= 0 ->
- X div 8;
-bug_div_2N(X) when is_integer(X), X < 0 ->
- X div 8.
-
-%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_switches.erl b/lib/hipe/test/basic_SUITE_data/basic_switches.erl
deleted file mode 100644
index 0a7ae5b8b7..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_switches.erl
+++ /dev/null
@@ -1,52 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests for pattern matching switches.
-%%%-------------------------------------------------------------------
--module(basic_switches).
-
--export([test/0]).
-
-test() ->
- ok = test_switch_mix(),
- ok.
-
-%%---------------------------------------------------------------------
-
--define(BIG1, 21323233222132323322).
--define(BIG2, 4242424242424242424242424242424242).
-
-test_switch_mix() ->
- small1 = t(42),
- small2 = t(17),
- big1 = t(?BIG1),
- big2 = t(?BIG2),
- atom = t(foo),
- pid = t(self()),
- float = t(4.2),
- ok.
-
-t(V) ->
- S = self(),
- case V of
- 42 -> small1;
- 17 -> small2;
- ?BIG1 -> big1;
- ?BIG2 -> big2;
- 1 -> no;
- 2 -> no;
- 3 -> no;
- 4 -> no;
- 5 -> no;
- 6 -> no;
- 7 -> no;
- 8 -> no;
- foo -> atom;
- 9 -> no;
- 4.2 -> float;
- S -> pid;
- _ -> no
- end.
-
-%%---------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl b/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl
deleted file mode 100644
index 0124f13df6..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl
+++ /dev/null
@@ -1,39 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that check that tail recursion optimization occurs.
-%%%-------------------------------------------------------------------
--module(basic_tail_rec).
-
--export([test/0]).
--export([app0/2]). %% used in an apply/3 call
-
-test() ->
- ok = test_app_tail(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Written by Mikael Pettersson: check that apply is tail recursive.
-
-%% Increased the following quantity from 20 to 30 so that the test
-%% remains valid even with the naive register allocator. - Kostis
--define(SIZE_INCREASE, 30).
-
-test_app_tail() ->
- Inc = start(400),
- %% io:format("Inc ~w\n", [Inc]),
- case Inc > ?SIZE_INCREASE of
- true ->
- {error, "apply/3 is not tail recursive in native code"};
- false ->
- ok
- end.
-
-start(N) ->
- app0(N, hipe_bifs:nstack_used_size()).
-
-app0(0, Size0) ->
- hipe_bifs:nstack_used_size() - Size0;
-app0(N, Size) ->
- apply(?MODULE, app0, [N-1, Size]).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_tuples.erl b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
deleted file mode 100644
index 96e39d565a..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
+++ /dev/null
@@ -1,191 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that manipulate and pattern match against tuples.
-%%%-------------------------------------------------------------------
--module(basic_tuples).
-
--export([test/0]).
-
-test() ->
- Num = 4711,
- ok = test_match({}, {1}, {1,2}, {1,2,3}, {1,2,3,4}, {1,2,3,4,5},
- {1,2,3,4,5,6}, {1,2,3,4,5,6,7}, {1,2,3,4,5,6,7,8}),
- ok = test_size({}, {a}, {{a},{b}}, {a,{b},c}),
- ok = test_element({}, {a}, {a,b}, Num),
- ok = test_setelement({}, {1}, {1,2}, 3, [1,2]),
- ok = test_tuple_to_list({}, {a}, {a,b}, {a,b,c}, {a,b,c,d}, Num),
- ok = test_list_to_tuple([], [a], [a,b], [a,b,c], [a,b,c,d], Num),
- ok = test_tuple_with_case(),
- ok = test_tuple_in_guard({a, b}, {a, b, c}),
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests matching of tuples
-
-test_match(T0, T1, T2, T3, T4, T5, T6, T7, T8) ->
- {} = T0,
- {1} = T1,
- {1, 2} = T2,
- {1, 2, 3} = T3,
- {1, 2, 3, 4} = T4,
- {1, 2, 3, 4, 5} = T5,
- {1, 2, 3, 4, 5, 6} = T6,
- T6 = {1, 2, 3, 4, 5, 6},
- T7 = {1, 2, 3, 4, 5, 6, 7},
- {1, 2, 3, 4, 5, 6, 7, 8} = T8,
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests the size/1 and tuple_size/1 BIFs.
-
-test_size(T0, T1, T2, T3) ->
- [0, 1, 2, 3] = [size(T) || T <- [T0, T1, T2, T3]],
- [0, 1, 2, 3] = [tuple_size(T) || T <- [T0, T1, T2, T3]],
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests element/2.
-
-test_element(T0, T1, T2, N) ->
- a = element(1, T1),
- a = element(1, T2),
- %% indirect calls to element/2
- List = lists:seq(1, N),
- Tuple = list_to_tuple(List),
- ok = get_elements(List, Tuple, 1),
- %% element/2 of larger tuple with omitted bounds test
- true = lists:all(fun(I) -> I * I =:= square(I) end, lists:seq(1, 20)),
- %% some cases that throw exceptions
- {'EXIT', _} = (catch my_element(0, T2)),
- {'EXIT', _} = (catch my_element(3, T2)),
- {'EXIT', _} = (catch my_element(1, T0)),
- {'EXIT', _} = (catch my_element(1, List)),
- {'EXIT', _} = (catch my_element(1, N)),
- {'EXIT', _} = (catch my_element(1.5, T2)),
- ok.
-
-my_element(Pos, Term) ->
- element(Pos, Term).
-
-get_elements([Element|Rest], Tuple, Pos) ->
- Element = element(Pos, Tuple),
- get_elements(Rest, Tuple, Pos + 1);
-get_elements([], _Tuple, _Pos) ->
- ok.
-
-squares() ->
- {1*1, 2*2, 3*3, 4*4, 5*5, 6*6, 7*7, 8*8, 9*9, 10*10,
- 11*11, 12*12, 13*13, 14*14, 15*15, 16*16, 17*17, 18*18, 19*19, 20*20}.
-
-square(N) when is_integer(N), N >= 1, N =< 20 ->
- %% The guard tests lets the range analysis conclude N to be an integer in the
- %% 1..20 range. 20-1=19 is bigger than ?SET_LIMIT in erl_types.erl, and will
- %% thus be represented by an ?int_range() rather than an ?int_set().
- %% Because of the range analysis, the bounds test of this element/2 call
- %% should be omitted.
- element(N, squares()).
-
-%%--------------------------------------------------------------------
-%% Tests set_element/3.
-
-test_setelement(T0, T1, Pair, Three, L) ->
- {x} = setelement(1, T1, x),
- {x, 2} = setelement(1, Pair, x),
- {1, x} = setelement(2, Pair, x),
- %% indirect calls to setelement/3
- Tuple = list_to_tuple(lists:duplicate(2048, x)),
- NewTuple = set_all_elements(Tuple, 1),
- NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)),
- %% the following cases were rewritten to use the Three
- %% variable in this weird way so as to silence the compiler
- {'EXIT', _} = (catch setelement(Three - Three, Pair, x)),
- {'EXIT', _} = (catch setelement(Three, Pair, x)),
- {'EXIT', _} = (catch setelement(Three div Three, T0, x)),
- {'EXIT', _} = (catch setelement(Three div Three, L, x)),
- {'EXIT', _} = (catch setelement(Three / 2, Pair, x)),
- ok.
-
-set_all_elements(Tuple, Pos) when Pos =< tuple_size(Tuple) ->
- set_all_elements(setelement(Pos, Tuple, Pos+7), Pos+1);
-set_all_elements(Tuple, Pos) when Pos > tuple_size(Tuple) ->
- Tuple.
-
-%%--------------------------------------------------------------------
-%% Tests tuple_to_list/1.
-
-test_tuple_to_list(T0, T1, T2, T3, T4, Size) ->
- [] = tuple_to_list(T0),
- [a] = tuple_to_list(T1),
- [a, b] = tuple_to_list(T2),
- [a, b, c] = tuple_to_list(T3),
- [a, b, c, d] = tuple_to_list(T4),
- [a, b, c, d] = tuple_to_list(T4),
- %% test a big tuple
- List = lists:seq(1, Size),
- Tuple = list_to_tuple(List),
- Size = tuple_size(Tuple),
- List = tuple_to_list(Tuple),
- %% some cases that should result in errors
- {'EXIT', _} = (catch my_tuple_to_list(element(2, T3))),
- {'EXIT', _} = (catch my_tuple_to_list(Size)),
- ok.
-
-my_tuple_to_list(X) ->
- tuple_to_list(X).
-
-%%--------------------------------------------------------------------
-%% Tests list_to_tuple/1.
-
-test_list_to_tuple(L0, L1, L2, L3, L4, Size) ->
- {} = list_to_tuple(L0),
- {a} = list_to_tuple(L1),
- {a, b} = list_to_tuple(L2),
- {a, b, c} = list_to_tuple(L3),
- {a, b, c, d} = list_to_tuple(L4),
- {a, b, c, d, e} = list_to_tuple(L4++[e]),
- %% test list_to_tuple with a big list
- Tuple = list_to_tuple(lists:seq(1, Size)),
- Size = tuple_size(Tuple),
- %% some cases that should result in errors
- {'EXIT', _} = (catch my_list_to_tuple({a,b})),
- {'EXIT', _} = (catch my_list_to_tuple([hd(L1)|hd(L2)])),
- ok.
-
-my_list_to_tuple(X) ->
- list_to_tuple(X).
-
-%%--------------------------------------------------------------------
-%% Tests that a case nested inside a tuple is ok.
-%% (This was known to crash earlier versions of BEAM.)
-
-test_tuple_with_case() ->
- {reply, true} = tuple_with_case(),
- ok.
-
-tuple_with_case() ->
- %% The following comments apply to the BEAM compiler.
- void(), % Reset var count.
- {reply, % Compiler will choose {x,1} for tuple.
- case void() of % Call will reset var count.
- {'EXIT', Reason} -> % Case will return in {x,1} (first free),
- {error, Reason}; % but the tuple will be build in {x,1},
- _ -> % so case value is lost and a circular
- true % data element is built.
- end}.
-
-void() -> ok.
-
-%%--------------------------------------------------------------------
-%% Test to build a tuple in a guard.
-
-test_tuple_in_guard(T2, T3) ->
- %% T2 = {a, b}; T3 = {a, b, c}
- ok = if T2 == {element(1, T3), element(2, T3)} -> ok;
- true -> other
- end,
- ok = if T3 == {element(1, T3), element(2, T3), element(3, T3)} -> ok;
- true -> other
- end,
- ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_add.erl b/lib/hipe/test/bs_SUITE_data/bs_add.erl
deleted file mode 100644
index 4b92e6b413..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_add.erl
+++ /dev/null
@@ -1,26 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------------
-%% The guard in f/3 revealed a problem in the translation of the 'bs_add'
-%% BEAM instruction to Icode. The fail label was not properly translated.
-%% Fixed 3/2/2011. Then in 2015 we found another issue: g/2. Also fixed.
-%%-------------------------------------------------------------------------
--module(bs_add).
-
--export([test/0]).
-
-test() ->
- 42 = f(<<12345:16>>, 4711, <<42>>),
- true = g(<<1:13>>, 3), %% was handled OK, but
- false = g(<<>>, gurka), %% this one leaked badarith
- ok.
-
-f(Bin, A, B) when <<A:9, B:7/binary>> == Bin ->
- gazonk;
-f(Bin, _, _) when is_binary(Bin) ->
- 42.
-
-%% Complex way of testing (bit_size(Bin) + Len) rem 8 =:= 0
-g(Bin, Len) when is_binary(<<Bin/binary-unit:1, 123:Len>>) ->
- true;
-g(_, _) ->
- false.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_bincomp.erl b/lib/hipe/test/bs_SUITE_data/bs_bincomp.erl
deleted file mode 100644
index 082b83bab9..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_bincomp.erl
+++ /dev/null
@@ -1,79 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_bincomp.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : Test bit comprehensions
-%%% Created : 13 Sep 2006
-%%%-------------------------------------------------------------------
--module(bs_bincomp).
-
--export([test/0]).
-
-test() ->
- ok = byte_aligned(),
- ok = bit_aligned(),
- ok = extended_byte_aligned(),
- ok = extended_bit_aligned(),
- ok = mixed(),
- ok.
-
-byte_aligned() ->
- <<"abcdefg">> = << <<(X+32)>> || <<X>> <= <<"ABCDEFG">> >>,
- <<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || <<X:32>> <= <<1:32,2:32,3:32,4:32>> >>,
- <<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || <<X:16>> <= <<1:16,2:16,3:16,4:16>> >>,
- ok.
-
-bit_aligned() ->
- <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
- << <<(X+32):7>> || <<X>> <= <<"ABCDEFG">> >>,
- <<"ABCDEFG">> =
- << <<(X-32)>> || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> >>,
- <<1:31/little,2:31/little,3:31/little,4:31/little>> =
- << <<X:31/little>> || <<X:31>> <= <<1:31,2:31,3:31,4:31>> >>,
- <<1:31/little,2:31/little,3:31/little,4:31/little>> =
- << <<X:31/little>> || <<X:15>> <= <<1:15,2:15,3:15,4:15>> >>,
- ok.
-
-extended_byte_aligned() ->
- <<"abcdefg">> = << <<(X+32)>> || X <- "ABCDEFG" >>,
- "abcdefg" = [(X+32) || <<X>> <= <<"ABCDEFG">>],
- <<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || X <- [1,2,3,4] >>,
- [256,512,768,1024] =
- [X || <<X:16/little>> <= <<1:16,2:16,3:16,4:16>>],
- ok.
-
-extended_bit_aligned() ->
- <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
- << <<(X+32):7>> || X <- "ABCDEFG" >>,
- "ABCDEFG" = [(X-32) || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>],
- <<1:31/little,2:31/little,3:31/little,4:31/little>> =
- << <<X:31/little>> || X <- [1,2,3,4] >>,
- [256,512,768,1024] =
- [X || <<X:15/little>> <= <<1:15,2:15,3:15,4:15>>],
- ok.
-
-mixed() ->
- <<2,3,3,4,4,5,5,6>> =
- << <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>> >>,
- <<2,3,3,4,4,5,5,6>> =
- << <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, Y <- [1,2] >>,
- <<2,3,3,4,4,5,5,6>> =
- << <<(X+Y)>> || X <- [1,2,3,4], Y <- [1,2] >>,
- [2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>>],
- [2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X>> <= <<1,2,3,4>>, Y <- [1,2]],
- <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- << <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>> >>,
- <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- << <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2] >>,
- <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- << <<(X+Y):3>> || X <- [1,2,3,4], Y <- [1,2] >>,
- [2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>],
- [2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2]],
- ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_bits.erl b/lib/hipe/test/bs_SUITE_data/bs_bits.erl
deleted file mode 100644
index ef9a6bb137..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_bits.erl
+++ /dev/null
@@ -1,150 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_bits.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : Tests for bit stream operations including matching,
-%%% construction, binary_to_list and list_to_binary
-%%% Created : 6 Sep 2006
-%%%-------------------------------------------------------------------
--module(bs_bits).
-
--export([test/0]).
-
-test() ->
- <<1:100>> = <<1:100>>,
- ok = match(7),
- ok = match(9),
- ok = match1(15),
- ok = match1(31),
- ok = horrid_match(),
- ok = test_bitstr(),
- ok = test_is_bitstr(<<1:1>>,<<8>>),
- ok = test_is_binary(<<1:1>>,<<8>>),
- ok = test_bitsize(),
- ok = asymmetric_tests(),
- ok = big_asymmetric_tests(),
- ok = bitstr_to_and_from_list(),
- ok = big_bitstr_to_and_from_list(),
- ok = send_and_receive(),
- ok = send_and_receive_alot(),
- ok.
-
-match(N) ->
- <<0:N>> = <<0:N>>,
- ok.
-
-match1(N) ->
- <<42:N/little>> = <<42:N/little>>,
- ok.
-
-test_is_bitstr(Bitstr, Binary) ->
- true = is_bitstring(Bitstr),
- true = is_bitstring(Binary),
- ok = if is_bitstring(Bitstr) -> ok end,
- ok = if is_bitstring(Binary) -> ok end.
-
-test_is_binary(Bitstr, Binary) ->
- false = is_binary(Bitstr),
- true = is_binary(Binary),
- ok = if is_binary(Bitstr) -> not_ok; true -> ok end,
- ok = if is_binary(Binary) -> ok end.
-
-test_bitsize() ->
- 101 = erlang:bit_size(<<1:101>>),
- 1001 = erlang:bit_size(<<1:1001>>),
- 80 = erlang:bit_size(<<1:80>>),
- 800 = erlang:bit_size(<<1:800>>),
- Bin = <<0:16#1000000>>,
- BigBin = list_to_bitstring([Bin||_ <- lists:seq(1,16#10)]++[<<1:1>>]),
- 16#10000001 = bit_size(BigBin),
- %% Only run these on computers with lots of memory
- %% HugeBin = list_to_bitstring([BigBin||_ <- lists:seq(1,16#10)]++[<<1:1>>]),
- %% 16#100000011 = bit_size(HugeBin),
- 0 = erlang:bit_size(<<>>),
- ok.
-
-horrid_match() ->
- <<1:4,B:24/bitstring>> = <<1:4,42:24/little>>,
- <<42:24/little>> = B,
- ok.
-
-test_bitstr() ->
- <<1:7,B/bitstring>> = <<1:7,<<1:1,6>>/bitstring>>,
- <<1:1,6>> = B,
- B = <<1:1,6>>,
- ok.
-
-asymmetric_tests() ->
- <<1:12>> = <<0,1:4>>,
- <<0,1:4>> = <<1:12>>,
- <<1:1,X/bitstring>> = <<128,255,0,0:2>>,
- <<1,254,0,0:1>> = X,
- X = <<1,254,0,0:1>>,
- <<1:1,X1:25/bitstring>> = <<128,255,0,0:2>>,
- <<1,254,0,0:1>> = X1,
- X1 = <<1,254,0,0:1>>,
- ok.
-
-big_asymmetric_tests() ->
- <<1:875,1:12>> = <<1:875,0,1:4>>,
- <<1:875,0,1:4>> = <<1:875,1:12>>,
- <<1:1,X/bitstring>> = <<128,255,0,0:2,1:875>>,
- <<1,254,0,0:1,1:875>> = X,
- X = <<1,254,0,0:1,1:875>>,
- <<1:1,X1:900/bitstring>> = <<128,255,0,0:2,1:875>>,
- <<1,254,0,0:1,1:875>> = X1,
- X1 = <<1,254,0,0:1,1:875>>,
- ok.
-
-bitstr_to_and_from_list() ->
- <<1:7>> = list_to_bitstring(bitstring_to_list(<<1:7>>)),
- <<1,2,3,4,1:1>> = list_to_bitstring(bitstring_to_list(<<1,2,3,4,1:1>>)),
- [1,2,3,4,<<1:1>>] = bitstring_to_list(<<1,2,3,4,1:1>>),
- <<1:1,1,2,3,4>> = list_to_bitstring([<<1:1>>,1,2,3,4]),
- [128,129,1,130,<<0:1>>] = bitstring_to_list(<<1:1,1,2,3,4>>),
- ok.
-
-big_bitstr_to_and_from_list() ->
- <<1:800,2,3,4,1:1>> = list_to_bitstring(bitstring_to_list(<<1:800,2,3,4,1:1>>)),
- [1,2,3,4|_Rest1] = bitstring_to_list(<<1,2,3,4,1:800,1:1>>),
- <<1:801,1,2,3,4>> = list_to_bitstring([<<1:801>>,1,2,3,4]),
- ok.
-
-send_and_receive() ->
- Bin = <<1,2:7>>,
- Pid = spawn(fun() -> receiver(Bin) end),
- Pid ! {self(),<<1:7,8:5,Bin/bitstring>>},
- receive
- ok ->
- ok
- end.
-
-receiver(Bin) ->
- receive
- {Pid,<<1:7,8:5,Bin/bitstring>>} ->
- Pid ! ok
- end.
-
-send_and_receive_alot() ->
- Bin = <<1:1000001>>,
- Pid = spawn(fun() -> receiver_alot(Bin) end),
- send_alot(100,Bin,Pid).
-
-send_alot(N,Bin,Pid) when N > 0 ->
- Pid ! {self(),<<1:7,8:5,Bin/bitstring>>},
- receive
- ok ->
- ok
- end,
- send_alot(N-1,Bin,Pid);
-send_alot(0,_Bin,Pid) ->
- Pid ! no_more,
- ok.
-
-receiver_alot(Bin) ->
- receive
- {Pid,<<1:7,8:5,Bin/bitstring>>} ->
- Pid ! ok;
- no_more -> ok
- end,
- receiver_alot(Bin).
diff --git a/lib/hipe/test/bs_SUITE_data/bs_bitsize.erl b/lib/hipe/test/bs_SUITE_data/bs_bitsize.erl
deleted file mode 100644
index c0774e7279..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_bitsize.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------
--module(bs_bitsize).
-
--export([test/0]).
-
-test() ->
- true = bitsize_in_body(<<1:42>>),
- true = bitsize_in_guard(<<1:7>>),
- 8 = constant_binary(42),
- ok.
-
-bitsize_in_body(Bin) ->
- 42 =:= erlang:bit_size(Bin).
-
-bitsize_in_guard(Bin) when erlang:bit_size(Bin) rem 7 =:= 0 ->
- true;
-bitsize_in_guard(Bin) when is_bitstring(Bin) ->
- false.
-
-%% Tests that binary constants can properly be treated in Icode
-constant_binary(N) when N > 0 ->
- bit_size(<<42>>).
diff --git a/lib/hipe/test/bs_SUITE_data/bs_bugs_R08.erl b/lib/hipe/test/bs_SUITE_data/bs_bugs_R08.erl
deleted file mode 100644
index 7b62a17cfb..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_bugs_R08.erl
+++ /dev/null
@@ -1,32 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------
-%% When executing this in R8 (and compiled with R8) the result was
-%% {ok,[148,129,0,0]} but should be {ok,[145,148,113,129,0,0,0,0]}
-%% Thanks to Kenneth Lundin for sending this to us.
-%%-------------------------------------------------------------------
-
--module(bs_bugs_R08).
-
--export([test/0]).
-
-test() ->
- List = [145,148,113,129,0,0,0,0],
- {ok, List} = msisdn_internal_storage(<<145,148,113,129,0,0,0,0>>, []),
- ok.
-
-%% msisdn_internal_storage/3
-%% Convert MSISDN binary to internal datatype (TBCD-octet list)
-
-msisdn_internal_storage(<<>>, MSISDN) ->
- {ok, lists:reverse(MSISDN)};
-msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>, MSISDN) ->
- {ok, lists:reverse(MSISDN)};
-msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>, MSISDN) when
- DigitN < 10 ->
- {ok, lists:reverse([(DigitN bor 2#11110000)|MSISDN])};
-msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>, MSISDN) when
- DigitNplus1 < 10, DigitN < 10 ->
- NewMSISDN = [((DigitNplus1 bsl 4) bor DigitN)|MSISDN],
- msisdn_internal_storage(Rest, NewMSISDN);
-msisdn_internal_storage(_Rest, _MSISDN) ->
- {fault}. %% Mandatory IE incorrect
diff --git a/lib/hipe/test/bs_SUITE_data/bs_bugs_R09.erl b/lib/hipe/test/bs_SUITE_data/bs_bugs_R09.erl
deleted file mode 100644
index 670f2a08bb..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_bugs_R09.erl
+++ /dev/null
@@ -1,35 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Date: Mon, 7 Jun 2004 13:07:39 +0300
-%% From: Einar Karttunen
-%% To: Erlang ML <erlang-questions@erlang.org>
-%% Subject: Apparent binary matching bug with native compilation
-%%
-%% It seems that there is a problem with binary matching when
-%% compiling native code. A length prefixed field matches one
-%% byte too short in the native case.
-%%
-%% The test module works when compiled with no options, but
-%% crashes with case_clause when compiled with [native].
-%% This has been confirmed with R9C-0 and hipe snapshot 5/4/2004.
-%%--------------------------------------------------------------------
-
--module(bs_bugs_R09).
-
--export([test/0]).
-
-test() ->
- ["rei",".",[]] = pp(<<3,$r,$e,$i,0>>),
- ok.
-
-pp(Bin) ->
- %% io:format("PP with ~p~n", [Bin]),
- case Bin of
- <<>> ->
- ["."];
- <<_:2, Len:6, Part:Len/binary>> ->
- [binary_to_list(Part)];
- <<_:2, Len:6, Part:Len/binary, Rest/binary>> ->
- %% io:format("Len ~p Part ~p Rest ~p~n", [Len,Part,Rest]),
- [binary_to_list(Part), "." | pp(Rest)]
- end.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_bugs_R12.erl b/lib/hipe/test/bs_SUITE_data/bs_bugs_R12.erl
deleted file mode 100644
index 43ee9eb85b..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_bugs_R12.erl
+++ /dev/null
@@ -1,133 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Contains three cases of bugs that were reported for R12B
-%%--------------------------------------------------------------------
--module(bs_bugs_R12).
-
--export([test/0]).
-
-test() ->
- ok = test_beam_bug(),
- ok = test_v3_codegen(),
- ok = test_hipe_bug(),
- ok.
-
-%%--------------------------------
-%% First test case: a bug in BEAM
-%%--------------------------------
-test_beam_bug() ->
- lists:foreach(fun (_) -> ok = run(100) end, [1,2,3,4]).
-
-%% For testing - runs scanner N number of times with same input
-run(N) ->
- lists:foreach(fun(_) -> scan(<<"region:whatever">>, []) end, lists:seq(1, N)).
-
-scan(<<>>, TokAcc) ->
- lists:reverse(['$thats_all_folks$' | TokAcc]);
-scan(<<D, Z, Rest/binary>>, TokAcc)
- when (D =:= $D orelse D =:= $d) and
- ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
- scan(<<Z, Rest/binary>>, ['AND' | TokAcc]);
-scan(<<D>>, TokAcc) when (D =:= $D) or (D =:= $d) ->
- scan(<<>>, ['AND' | TokAcc]);
-scan(<<N, Z, Rest/binary>>, TokAcc)
- when (N =:= $N orelse N =:= $n) and
- ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
- scan(<<Z, Rest/binary>>, ['NOT' | TokAcc]);
-scan(<<C, Rest/binary>>, TokAcc) when (C >= $A) and (C =< $Z);
- (C >= $a) and (C =< $z);
- (C >= $0) and (C =< $9) ->
- case Rest of
- <<$:, R/binary>> ->
- scan(R, [{'FIELD', C} | TokAcc]);
- _ ->
- scan(Rest, [{'KEYWORD', C} | TokAcc])
- end.
-
-%%---------------------------------------------------
-%% Second test case: an internal error in v3_codegen
-%% Reported by Mateusz Berezecki on 19/1/2008
-%%---------------------------------------------------
--define(S, {42, 4242, 4711}).
--define(R, <<90,164,116>>).
-
-test_v3_codegen() ->
- _ = random:seed(?S),
- B0 = gen_bit(120, <<>>),
- B1 = set_bit(B0, 5),
- B2 = clr_bit(B1, 5),
- ?R = set_bit(B2, 5),
- ok.
-
-gen_bit(0, Acc) -> Acc;
-gen_bit(N, Acc) when is_integer(N), N > 0 ->
- gen_bit(N-1, <<Acc/bits, (random:uniform(2)-1):1>>).
-
-%% sets bit K in the Bitmap
-set_bit(<<_Start:32/unsigned-little-integer, Bitmap/bits>>, K)
- when is_integer(K), 0 < K, K =< bit_size(Bitmap) ->
- Before = K-1,
- After = bit_size(Bitmap) - K,
- <<BeforeBits:Before/bits, _:1, AfterBits:After/bits>> = Bitmap,
- <<BeforeBits/bits, 1:1, AfterBits/bits>>.
-
-%% clears bit K in the Bitmap
-clr_bit(<<_Start:32/unsigned-little-integer, Bitmap/bits>>, K)
- when is_integer(K), 0 < K, K =< bit_size(Bitmap) ->
- Before = K-1,
- After = bit_size(Bitmap) - K,
- <<BeforeBits:Before/bits, _:1, AfterBits:After/bits>> = Bitmap,
- <<BeforeBits/bits, 0:1, AfterBits/bits>>.
-
-%%--------------------------------------------------------------------
-%% Third test case: a bug in HiPE
-%% Reported by Steve Vinoski on 1/3/2008
-%%
-%% Below find the results of compiling and running the example code at
-%% the bottom of this message. Using "c" to compile gives the right
-%% answer; using "hipe:c" gives the wrong answer. This is with R12B-1.
-%%
-%% Within the code, on the second instance of function check/2 you'll
-%% find a commented-out guard. If you uncomment the guard, then the
-%% code works correctly with both "c" and "hipe:c".
-%%---------------------------------------------------------------------
-
-test_hipe_bug() ->
- String = "2006/10/02/Linux-Journal",
- Binary = list_to_binary(String),
- StringToMatch = "200x/" ++ String ++ " ",
- BinaryToMatch = list_to_binary(StringToMatch),
- {ok, Binary} = match(BinaryToMatch),
- ok.
-
-match(<<>>) ->
- nomatch;
-match(Bin) ->
- <<Front:16/binary, Tail/binary>> = Bin,
- case Front of
- <<_:3/binary,"x/",Y:4/binary,$/,M:2/binary,$/,D:2/binary,$/>> ->
- case check(Tail) of
- {ok, Match} ->
- {ok, <<Y/binary,$/,M/binary,$/,D/binary,$/,Match/binary>>};
- {nomatch, Skip} ->
- {skip, Skip+size(Front)};
- _ ->
- wrong_answer
- end;
- _ ->
- nomatch
- end.
-
-check(Bin) ->
- check(Bin, 0).
-check(<<$ , _/binary>>, 0) ->
- {nomatch, 0};
-check(Bin, Len) -> %when Len < size(Bin) ->
- case Bin of
- <<Front:Len/binary, $ , _/binary>> ->
- {ok, Front};
- <<_:Len/binary, $., _/binary>> ->
- {nomatch, Len};
- _ ->
- check(Bin, Len+1)
- end.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_build.erl b/lib/hipe/test/bs_SUITE_data/bs_build.erl
deleted file mode 100644
index 256cea9403..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_build.erl
+++ /dev/null
@@ -1,41 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_build.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose :
-%%%
-%%% Created : 12 Sep 2007
-%%%-------------------------------------------------------------------
--module(bs_build).
-
--export([test/0]).
-
-test() ->
- <<0,1,2,3,4,5,6>> = Bin = << <<X>> || X <- lists:seq(0, 6)>>,
- test(Bin).
-
-test(Bin) ->
- <<0,1,2,3,4,5,6,0,1,2,3,4,5,6>> = RealBin = multiply(Bin, 2),
- <<6,5,4,3,2,1,0,6,5,4,3,2,1,0>> = reverse(RealBin),
- RealBin = copy(RealBin),
- RealBin = bc(RealBin),
- ok.
-
-multiply(Bin, 1) ->
- Bin;
-multiply(Bin, N) when N > 0 ->
- <<(multiply(Bin, N-1))/binary, Bin/binary>>.
-
-bc(Bin) ->
- << <<X>> || <<X>> <= Bin >>.
-
-reverse(<<X, Rest/binary>>) ->
- <<(reverse(Rest))/binary, X>>;
-reverse(<<>>) -> <<>>.
-
-copy(Bin) ->
- copy(Bin, <<>>).
-
-copy(<<X, Rest/binary>>, Bin) ->
- copy(Rest, <<Bin/binary, X>>);
-copy(<<>>, Bin) -> Bin.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_catch_bug.erl b/lib/hipe/test/bs_SUITE_data/bs_catch_bug.erl
deleted file mode 100644
index 6125f8f87f..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_catch_bug.erl
+++ /dev/null
@@ -1,25 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_catch_bug.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : Tests a catch-related bug which might destroy properties
-%%% of ICode CFGs which are assumed by the subsequent ICode
-%%% binary pass.
-%%% Created : 22 Jan 2004
-%%% -------------------------------------------------------------------
--module(bs_catch_bug).
-
--export([test/0]).
-
-test() ->
- test(foo, <<>>).
-
-%% Introduced auxiliary test/2 function so that constant propagation
-%% does not destroy the properties of the test. - Kostis 26/1/2004
-test(X, Bin) ->
- catch (<<_/binary>> = X),
- X = case Bin of
- <<42,_/binary>> -> weird_bs_match;
- _ -> X
- end,
- ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_checksum.erl b/lib/hipe/test/bs_SUITE_data/bs_checksum.erl
deleted file mode 100644
index ca4f254f12..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_checksum.erl
+++ /dev/null
@@ -1,35 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Code from Zoltan Toth that crashed the HiPE compiler (in R11B-3).
-%% The problem was that the binary matching produces a pretty large
-%% integer and we tried to find the range for this integer in a bad way.
-%% Fixed on the same day -- 6th March 2007.
-%%--------------------------------------------------------------------
-
--module(bs_checksum).
-
--export([test/0]).
-
-test() ->
- "3389DAE361AF79B04C9C8E7057F60CC6" = checksum(<<42>>),
- ok.
-
-checksum(Bin) ->
- Context = erlang:md5_init(),
- checksum(Context, Bin).
-
-checksum(Context, <<>>) ->
- bin_to_hex(erlang:md5_final(Context));
-checksum(Context, <<Bin:20480/binary,Rest/binary>>) ->
- checksum(erlang:md5_update(Context, Bin), Rest);
-checksum(Context,Bin) ->
- checksum(erlang:md5_update(Context, Bin), <<>>).
-
-bin_to_hex(Bin) ->
- lists:flatten([byte_to_hex(X) || X <- binary_to_list(Bin)]).
-
-byte_to_hex(Byte) ->
- [int_to_hex(Byte div 16), int_to_hex(Byte rem 16)].
-
-int_to_hex(Int) when Int < 10 -> $0 + Int;
-int_to_hex(Int) when Int > 9 -> $A + Int - 10.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_construct.erl b/lib/hipe/test/bs_SUITE_data/bs_construct.erl
deleted file mode 100644
index aa85626857..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_construct.erl
+++ /dev/null
@@ -1,314 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Tests that basic cases of binary construction work
-%%--------------------------------------------------------------------
--module(bs_construct).
-
--export([test/0]).
-
-test() ->
- <<42>> = sz(8),
- <<42:8/little>> = sz_little(8),
- <<55>> = take_five(1, 3, 1, 7, 4),
- ok = bs5(),
- 16#10000008 = bit_size(large_bin(1, 2, 3, 4)),
- ok = bad_ones(),
- ok = zero_width(),
- ok = not_used(),
- ok = bad_append(),
- ok = system_limit(),
- ok = bad_floats(),
- ok = huge_binaries(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Taken from a bug report submitted by Dan Wallin (24 Oct 2003), the
-%% following cases test construction of binaries whose segments have
-%% sizes that are statically unknown.
-
-sz(S) ->
- <<42:S>>.
-
-sz_little(S) ->
- <<42:S/little>>.
-
-take_five(A, Head, FB, C, Tail) ->
- <<A:Head, FB:1, C:Tail>>.
-
-%%--------------------------------------------------------------------
-
-bs5() ->
- Const = mk_constant(),
- Pairs = mk_pairs(),
- true = are_same(Const, Pairs),
- true = lists:all(fun ({B, L}) -> binary_to_list(B) =:= L end, Pairs),
- ok.
-
-are_same(C, L) ->
- C =:= L.
-
-mk_constant() ->
- [{<<213>>,[213]},
- {<<56>>,[56]},
- {<<1,2>>,[1,2]},
- {<<71>>,[71]},
- {<<8,1>>,[8,1]},
- {<<3,9>>,[3,9]},
- {<<9,3>>,[9,3]},
- {<<0,0,0,0>>,[0,0,0,0]},
- {<<62,0,0,0>>,[62,0,0,0]},
- {<<0,0,0,62>>,[0,0,0,62]},
- {<<138,99,0,147>>,[138,99,0,147]},
- {<<138,99,0,148>>,[138,99,0,148]},
- {<<147,0,99,138>>,[147,0,99,138]},
- {<<255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255>>,
- [255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]},
- {<<13>>,[13]},
- {<<0,4,0,5>>,[0,4,0,5]},
- {<<129>>,[129]},
- {<<129>>,[129]},
- {<<1,2>>,[1,2]},
- {<<1>>,[1]},
- {<<4,3,1>>,[4,3,1]},
- {<<47>>,[47]},
- {<<>>,[]},
- {<<97,112,97>>,[97,112,97]},
- {<<46,110,142,77,45,204,233>>,[46,110,142,77,45,204,233]},
- {<<>>,[]}].
-
-mk_pairs() ->
- L4 = [138,99,0,147],
- [{<<-43>>,[256-43]},
- {<<56>>,[56]},
- {<<1,2>>,[1,2]},
- {<<4:4,7:4>>,[4*16+7]},
- {<<1:5,1:11>>,[1*8,1]},
- {<<777:16/big>>,[3,9]},
- {<<777:16/little>>,[9,3]},
- {<<0.0:32/float>>,[0,0,0,0]},
- {<<0.125:32/float>>,[62,0,0,0]},
- {<<0.125:32/little-float>>,[0,0,0,62]},
- {<<57285702734876389752897683:32>>,L4},
- {<<57285702734876389752897684:32>>,[138,99,0,148]},
- {<<57285702734876389752897683:32/little>>,lists:reverse(L4)},
- {<<-1:17/unit:8>>,lists:duplicate(17,255)},
- {<<13>>,[13]},
- {<<4:8/unit:2,5:2/unit:8>>,[0,4,0,5]},
- {<<1:1,0:6,1:1>>,[129]},
- {<<1:1/little,0:6/little,1:1/little>>,[129]},
- {<<<<1,2>>/binary>>,[1,2]},
- {<<<<1,2>>:1/binary>>,[1]},
- {<<4,3,<<1,2>>:1/binary>>,[4,3,1]},
- {<<(256*45+47)>>,[47]},
- {<<57:0>>,[]},
- {<<"apa">>,"apa"},
- {<<1:3,"string",9:5>>,[46,110,142,77,45,204,233]},
- {<<>>,[]}].
-
-%%--------------------------------------------------------------------
-%% Constructs a big enough binary to have a bit size that needs a
-%% bignum on 32-bit architectures
-
-large_bin(X1, X2, X3, X4) ->
- Sz = 16#4000000,
- <<1, <<X1:Sz, X2:Sz, X3:Sz, X4:Sz>>/bits>>.
-
-%%--------------------------------------------------------------------
-%% Test construction of "bad" binaries
-
--define(FAIL(Expr), {'EXIT', {badarg, _}} = (catch Expr)).
-
-bad_ones() ->
- PI = math:pi(),
- ?FAIL(<<PI>>),
- Bin12 = <<1,2>>,
- ?FAIL(<<Bin12>>),
- E = 2.71,
- ?FAIL(<<E/binary>>),
- Int = 24334,
- ?FAIL(<<Int/binary>>),
- BigInt = 24334344294788947129487129487219847,
- ?FAIL(<<BigInt/binary>>),
- Bin123 = <<1,2,3>>,
- ?FAIL(<<Bin123/float>>),
- ok.
-
-%%--------------------------------------------------------------------
-%% Taken from the emulator bs_construct_SUITE - seg faulted till 18.1
-
-zero_width() ->
- Z = id(0),
- Small = id(42),
- Big = id(1 bsl 128), % puts stuff on the heap
- <<>> = <<Small:Z>>,
- <<>> = <<Small:0>>,
- <<>> = <<Big:Z>>,
- <<>> = <<Big:0>>,
- ok.
-
-id(X) -> X.
-
-%%--------------------------------------------------------------------
-%% Taken from bs_construct_SUITE. The test checks that constructed
-%% binaries that are not used would still give a `badarg' exception.
-%% Problem was that in native code one of them gave `badarith'.
-
-not_used() ->
- ok = not_used1(3, <<"dum">>),
- {'EXIT',{badarg,_}} = (catch not_used1(42, "dum_string")),
- {'EXIT',{badarg,_}} = (catch not_used2(666, -2)),
- {'EXIT',{badarg,_}} = (catch not_used2(666, "bad_size")), % this one
- {'EXIT',{badarg,_}} = (catch not_used3(666)),
- ok.
-
-not_used1(I, BinString) ->
- <<I:32,BinString/binary>>,
- ok.
-
-not_used2(I, Sz) ->
- <<I:Sz>>,
- ok.
-
-not_used3(I) ->
- <<I:(-8)>>,
- ok.
-
-%%--------------------------------------------------------------------
-%% Taken from bs_construct_SUITE.
-
-bad_append() ->
- do_bad_append(<<127:1>>, fun append_unit_3/1),
- do_bad_append(<<127:2>>, fun append_unit_3/1),
- do_bad_append(<<127:17>>, fun append_unit_3/1),
-
- do_bad_append(<<127:3>>, fun append_unit_4/1),
- do_bad_append(<<127:5>>, fun append_unit_4/1),
- do_bad_append(<<127:7>>, fun append_unit_4/1),
- do_bad_append(<<127:199>>, fun append_unit_4/1),
-
- do_bad_append(<<127:7>>, fun append_unit_8/1),
- do_bad_append(<<127:9>>, fun append_unit_8/1),
-
- do_bad_append(<<0:8>>, fun append_unit_16/1),
- do_bad_append(<<0:15>>, fun append_unit_16/1),
- do_bad_append(<<0:17>>, fun append_unit_16/1),
- ok.
-
-do_bad_append(Bin0, Appender) ->
- {'EXIT',{badarg,_}} = (catch Appender(Bin0)),
-
- Bin1 = id(<<0:3,Bin0/bitstring>>),
- <<_:3,Bin2/bitstring>> = Bin1,
- {'EXIT',{badarg,_}} = (catch Appender(Bin2)),
-
- %% Create a writable binary.
- Empty = id(<<>>),
- Bin3 = <<Empty/bitstring,Bin0/bitstring>>,
- {'EXIT',{badarg,_}} = (catch Appender(Bin3)),
- ok.
-
-append_unit_3(Bin) ->
- <<Bin/binary-unit:3,0:1>>.
-
-append_unit_4(Bin) ->
- <<Bin/binary-unit:4,0:1>>.
-
-append_unit_8(Bin) ->
- <<Bin/binary,0:1>>.
-
-append_unit_16(Bin) ->
- <<Bin/binary-unit:16,0:1>>.
-
-%%--------------------------------------------------------------------
-%% Taken from bs_construct_SUITE.
-
-system_limit() ->
- WordSize = erlang:system_info(wordsize),
- BitsPerWord = WordSize * 8,
- {'EXIT',{system_limit,_}} =
- (catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>),
- {'EXIT',{system_limit,_}} =
- (catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>),
- {'EXIT',{system_limit,_}} =
- (catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>),
-
- %% Would fail to load.
- {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 67)>>),
- {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 64)+1)>>),
- case WordSize of
- 4 ->
- system_limit_32();
- 8 ->
- ok
- end.
-
-system_limit_32() ->
- {'EXIT',{badarg,_}} = (catch <<42:(-1)>>),
- {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>),
- {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>),
- {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>),
- {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>),
- {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>),
- {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
-
- %% The size would be silently truncated, resulting in a crash.
- {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 35)>>),
- {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 32)+1)>>),
-
- %% Would fail to load.
- {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 43)>>),
- {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 40)+1)>>),
- ok.
-
-%%--------------------------------------------------------------------
-
-bad_floats() ->
- WordSize = erlang:system_info(wordsize),
- BitsPerWord = WordSize * 8,
- {'EXIT',{badarg,_}} = (catch <<3.14:(id(33))/float>>),
- {'EXIT',{badarg,_}} = (catch <<3.14:(id(64 bor 32))/float>>),
- {'EXIT',{badarg,_}} = (catch <<3.14:(id((1 bsl 28) bor 32))/float>>),
- {'EXIT',{system_limit,_}} = (catch <<3.14:(id(1 bsl BitsPerWord))/float>>),
- ok.
-
-%%--------------------------------------------------------------------
-%% A bug in the implementation of binaries compared sizes in bits with sizes in
-%% bytes, causing <<0:(id((1 bsl 31)-1))>> to fail to construct with
-%% 'system_limit'.
-%% <<0:(id((1 bsl 32)-1))>> was succeeding because the comparison was
-%% (incorrectly) signed.
-
-huge_binaries() ->
- case erlang:system_info(wordsize) of
- 4 ->
- Old = erts_debug:set_internal_state(available_internal_state, true),
- case erts_debug:set_internal_state(binary, (1 bsl 29)-1) of
- false ->
- io:format("\nNot enough memory to create 512Mb binary\n",[]);
- Bin->
- huge_binaries_32(Bin)
- end,
- erts_debug:set_internal_state(available_internal_state, Old);
-
- 8 -> ok
- end,
- garbage_collect(),
- id(<<0:(id((1 bsl 31)-1))>>),
- garbage_collect(),
- id(<<0:(id((1 bsl 30)-1))>>),
- garbage_collect(),
- ok.
-
-huge_binaries_32(AlmostIllegal) ->
- %% Attempt construction of too large binary using bs_init/1 (which takes the
- %% number of bytes as an argument, which should be compared to the maximum
- %% size in bytes).
- {'EXIT',{system_limit,_}} = (catch <<0:32,AlmostIllegal/binary>>),
- %% Attempt construction of too large binary using bs_init/1 with a size in
- %% bytes that has the msb set (and would be negative if it was signed).
- {'EXIT',{system_limit,_}} =
- (catch <<0:8, AlmostIllegal/binary, AlmostIllegal/binary,
- AlmostIllegal/binary, AlmostIllegal/binary,
- AlmostIllegal/binary, AlmostIllegal/binary,
- AlmostIllegal/binary, AlmostIllegal/binary>>),
- ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_decode.erl b/lib/hipe/test/bs_SUITE_data/bs_decode.erl
deleted file mode 100644
index d12654a1e3..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_decode.erl
+++ /dev/null
@@ -1,980 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-
--module(bs_decode).
-
--export([test/0]).
-
--include("bs_decode_extract.hrl").
-
--define(PDU, <<30,16,0,90,0,1,0,0,255,255,255,255,81,67,101,7,0,0,0,96,
- 6,12,146,18,14,0,15,252,16,0,0,17,0,0,128,0,2,241,33,131,
- 0,20,7,97,112,110,48,49,51,97,8,101,114,105,99,115,115,
- 111,110,2,115,101,132,0,20,128,192,35,16,1,5,0,16,5,117,
- 115,101,114,53,5,112,97,115,115,53,133,0,4,172,28,12,1,
- 133,0,4,172,28,12,3,134,0,8,145,148,113,129,0,0,0,0>>).
-
--define(RES, {ok,{sesT_createReqV0,
- {mvsgT_tid,{mvsgT_imsi,<<81,67,101,7,0,0,0,240>>},6},
- [81,67,101,7,0,0,0,96],
- {sesT_qualityOfServiceV0,1,4,9,2,18},
- 0,subscribed,0,0,
- {mvsgT_pdpAddressType,ietf_ipv4,[]},
- [<<"apn013a">>,<<"ericsson">>,<<"se">>],
- {masT_protocolConfigOptions,[],
- {masT_pap,true,1,5,"user5","pass5"},
- []},
- {mvsgT_ipAddress,ipv4,172,28,12,1,0,0,0,0},
- {mvsgT_ipAddress,ipv4,172,28,12,3,0,0,0,0},
- {mvsT_msisdn,<<145,148,113,129,0,0,0,0>>}},
- 1}).
-
-test() ->
- ?RES = decode_v0_opt(42, ?PDU),
- ok.
-
-decode_v0_opt(0, Pdu) ->
- decode_gtpc_msg(Pdu);
-decode_v0_opt(N, Pdu) ->
- decode_gtpc_msg(Pdu),
- decode_v0_opt(N-1, Pdu).
-
-%%% --------------------------------------------------------------
-%%% #3.1.2 DECODE GTP-C MESSAGE
-%%% --------------------------------------------------------------
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% Function : decode_gtpc_msg(GTP_C_Message)->
-%%% {ok,Request,ControlDataUs} |
-%%% {fault,Cause,Request,ControlDataUs}
-%%%
-%%% Types : GTP_C_Message = binary(), GTP-C message from SGSN
-%%% Request = record(), Containing decoded request
-%%% ControlDataUS = record(), Containing header info
-%%% Cause = integer(), Error code
-%%%
-%%% Description: This function decodes a binary GTP-C message and
-%%% stores it in a record. Different records are used
-%%% for different message types.
-%%%
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-%%% Create PDP Context Request
-%%% GTP97, SNN=0
-%%% (No SNDCP N-PDU number)
-decode_gtpc_msg(<<0:3,_:4,0:1,16:8,_Length:16,SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,InformationElements/binary>>) ->
- Errors = #protocolErrors{},
- {ok,TID2} = tid_internal_storage(TID,[]),
- EmptyCreateReq = #sesT_createReqV0{tid = TID2,
- tidRaw = binary_to_list(TID)},
- case catch decode_ie_create(InformationElements,0,Errors,EmptyCreateReq) of
- {ok,CreateReq} ->
- {ok,CreateReq,SequenceNumber};
- {fault,Cause,CreateReq} ->
- {fault,Cause,CreateReq,SequenceNumber};
- {'EXIT',_Reason} ->
- {fault,193,EmptyCreateReq,SequenceNumber}
- end;
-
-%%% Update PDP Context Request
-%%% GTP97, SNN=0
-%%% (No SNDCP N-PDU number)
-decode_gtpc_msg(<<0:3,_:4,0:1,18:8,_Length:16,SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,InformationElements/binary>>) ->
- io:format("hej", []),
- Errors = #protocolErrors{},
- {ok,TID2}=tid_internal_storage(TID,[]),
- EmptyUpdateReq=#sesT_updateReqV0{tid=TID2,
- tidRaw=binary_to_list(TID)},
- case catch decode_ie_update(InformationElements,0,Errors,
- EmptyUpdateReq) of
- {ok,UpdateReq} ->
- {ok,UpdateReq,SequenceNumber};
- {fault,Cause,UpdateReq} ->
- {fault,Cause,UpdateReq,SequenceNumber};
- {'EXIT',Reason} ->
- io:format("hej", []),
- {fault,193,EmptyUpdateReq,SequenceNumber, Reason}
- end;
-
-%%% Delete PDP Context Request
-%%% GTP97, SNN=0
-%%% (No SNDCP N-PDU number)
-decode_gtpc_msg(<<0:3,_:4,0:1,20:8,_Length:16,SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,_InformationElements/binary>>) ->
- {ok,TID2} = tid_internal_storage(TID,[]),
- DeleteReq = #sesT_deleteReqV0{tid=TID2},
- {ok,DeleteReq,SequenceNumber};
-
-%%% Delete PDP Context Response
-%%% GTP97, SNN=0
-%%% (No SNDCP N-PDU number)
-decode_gtpc_msg(<<0:3,_:4,0:1,21:8,_Length:16,SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,InformationElements/binary>>) ->
- {ok,TID2} = tid_internal_storage(TID,[]),
- EmptyDeleteRes = #sesT_deleteResV0{tid=TID2},
- case catch decode_ie_delete_res(InformationElements,0,EmptyDeleteRes) of
- {ok, DeleteRes} ->
- {ok,DeleteRes,SequenceNumber};
- {fault,Cause,DeleteRes} ->
- {fault,Cause,DeleteRes,SequenceNumber};
- {'EXIT',_Reason} ->
- {fault,193,EmptyDeleteRes,SequenceNumber}
- end;
-
-%%% Error handling
-decode_gtpc_msg(_GTP_C_Message) ->
- {fault}.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% decode_ie_create/4
-%%% Decode information elements for Create PDP Context Request
-
-%%% All elements decoded
-decode_ie_create(<<>>,PresentIEs,Errors,CreateReq) ->
- %% Check mandatory IE's
- if
- (PresentIEs band 16#77D) =/= 16#77D ->
- {fault,202,CreateReq}; %Mandatory IE missing
- true -> %OK
- %% Check errors during decoding
- case Errors of
- #protocolErrors{invalidManIE=true} -> %Invalid mandatory IE
- {fault,201,CreateReq}; %Mandatory IE incorrect
- #protocolErrors{outOfSequence=true} -> %Out of sequence
- {fault,193,CreateReq}; %Invalid message format
- #protocolErrors{incorrectOptIE=true} -> %Incorrect optional IE
- {fault,203,CreateReq}; %Optional IE incorrect
- _ -> %OK
- {ok,CreateReq}
- end
- end;
-
-%%% Quality of Service Profile, Mandatory
-decode_ie_create(<<6:8,QoSElement:3/binary-unit:8,Rest/binary>>,PresentIEs,
- Errors,CreateReq) ->
- if
- (PresentIEs band 16#00000001) =:= 16#00000001 -> %Repeated IE's, ignore
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000001 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- <<_:2,DelayClass:3,ReliabilityClass:3,
- PeakThroughput:4,_:1,PrecedenceClass:3,
- _:3,MeanThroughput:5>> = QoSElement,
- QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass,
- reliabilityClass=ReliabilityClass,
- peakThroughput=PeakThroughput,
- precedenceClass=PrecedenceClass,
- meanThroughput=MeanThroughput},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{qos=QoS},
- decode_ie_create(Rest,(PresentIEs bor 16#00000001),
- UpdatedErrors,UpdatedCreateReq);
- true -> %OK
- <<_:2,DelayClass:3,ReliabilityClass:3,
- PeakThroughput:4,_:1,PrecedenceClass:3,
- _:3,MeanThroughput:5>> = QoSElement,
- QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass,
- reliabilityClass=ReliabilityClass,
- peakThroughput=PeakThroughput,
- precedenceClass=PrecedenceClass,
- meanThroughput=MeanThroughput},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{qos=QoS},
- decode_ie_create(Rest,(PresentIEs bor 16#00000001),
- Errors,UpdatedCreateReq)
- end;
-
-%%% Recovery, Optional
-decode_ie_create(<<14:8,Recovery:8,Rest/binary>>,
- PresentIEs,Errors,CreateReq) ->
- if
- (PresentIEs band 16#00000002) =:= 16#00000002 -> %Repeated IE, ignored
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000002 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{recovery=Recovery},
- decode_ie_create(Rest,(PresentIEs bor 16#00000002),
- UpdatedErrors,UpdatedCreateReq);
- true -> %OK
- UpdatedCreateReq=CreateReq#sesT_createReqV0{recovery=Recovery},
- decode_ie_create(Rest,(PresentIEs bor 16#00000002),Errors,
- UpdatedCreateReq)
- end;
-
-%%% Selection mode, Mandatory
-decode_ie_create(<<15:8,_:6,SelectionMode:2,Rest/binary>>,PresentIEs,
- Errors,CreateReq) ->
- if
- (PresentIEs band 16#00000004) =:= 16#00000004 -> %Repeated IE, ignored
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000004 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{
- selMode=selection_mode_internal_storage(SelectionMode)},
- decode_ie_create(Rest,(PresentIEs bor 16#00000004),
- UpdatedErrors,UpdatedCreateReq);
- true -> %OK
- UpdatedCreateReq=CreateReq#sesT_createReqV0{
- selMode=selection_mode_internal_storage(SelectionMode)},
- decode_ie_create(Rest,(PresentIEs bor 16#00000004),Errors,
- UpdatedCreateReq)
- end;
-
-%%% Flow Label Data I, Mandatory
-decode_ie_create(<<16:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,CreateReq) ->
- if
- (PresentIEs band 16#00000008) =:= 16#00000008 -> %Repeated IE, ignored
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000008 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblData=FlowLabel},
- decode_ie_create(Rest,(PresentIEs bor 16#00000008),
- UpdatedErrors,UpdatedCreateReq);
- true -> %OK
- UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblData=FlowLabel},
- decode_ie_create(Rest,(PresentIEs bor 16#00000008),Errors,
- UpdatedCreateReq)
- end;
-
-%%% Flow Label Signalling, Mandatory
-decode_ie_create(<<17:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,CreateReq) ->
- if
- (PresentIEs band 16#00000010) =:= 16#00000010 -> %Repeated IE, ignored
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000010 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblSig=FlowLabel},
- decode_ie_create(Rest,(PresentIEs bor 16#00000010),
- UpdatedErrors,UpdatedCreateReq);
- true -> %OK
- UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblSig=FlowLabel},
- decode_ie_create(Rest,(PresentIEs bor 16#00000010),Errors,
- UpdatedCreateReq)
- end;
-
-%%% End User Address, Mandatory
-decode_ie_create(<<128:8,Length:16,More/binary>>,PresentIEs,
- Errors,CreateReq) ->
- <<PDPElement:Length/binary-unit:8,Rest/binary>> = More,
- if
- (PresentIEs band 16#00000020) =:= 16#00000020 -> %Repeated IE, ignore
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000020 -> %Out of sequence
- case pdp_addr_internal_storage(PDPElement) of
- {ok,PDPAddress} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{endUserAdd=PDPAddress},
- decode_ie_create(Rest,(PresentIEs bor 16#00000020),
- UpdatedErrors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true,
- outOfSequence=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000020),
- UpdatedErrors,CreateReq)
- end;
- true -> %OK
- case pdp_addr_internal_storage(PDPElement) of
- {ok,PDPAddress} ->
- UpdatedCreateReq=CreateReq#sesT_createReqV0{endUserAdd=PDPAddress},
- decode_ie_create(Rest,(PresentIEs bor 16#00000020),
- Errors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000020),
- UpdatedErrors,CreateReq)
- end
- end;
-
-%%% Access Point Name, Mandatory
-decode_ie_create(<<131:8,Length:16,More/binary>>,PresentIEs,
- Errors,CreateReq) ->
- <<APNElement:Length/binary-unit:8,Rest/binary>> = More,
- if
- (PresentIEs band 16#00000040) =:= 16#00000040 -> %Repeated IE, ignore
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000040 -> %Out of sequence
- case catch apn_internal_storage(APNElement,[]) of
- {ok,APN} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{accPointName=APN},
- decode_ie_create(Rest,(PresentIEs bor 16#00000040),
- UpdatedErrors,UpdatedCreateReq);
- _ ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true,
- invalidManIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000040),
- UpdatedErrors,CreateReq)
- end;
- true -> %OK
- case catch apn_internal_storage(APNElement,[]) of
- {ok,APN} ->
- UpdatedCreateReq=CreateReq#sesT_createReqV0{accPointName=APN},
- decode_ie_create(Rest,(PresentIEs bor 16#00000040),
- Errors,UpdatedCreateReq);
- _ ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000040),
- UpdatedErrors,CreateReq)
- end
- end;
-
-%%% Protocol Configuration Options, Optional
-decode_ie_create(<<132:8,Length:16,More/binary>>,PresentIEs,Errors,CreateReq) ->
- <<ConfigurationElement:Length/binary-unit:8,Rest/binary>> = More,
- if
- (PresentIEs band 16#00000080) =:= 16#00000080 -> %Repeated IE, ignore
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000080 -> %Out of sequence
- case catch pco_internal_storage(ConfigurationElement) of
- {ok,PCO} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{protConOpt=PCO},
- decode_ie_create(Rest,(PresentIEs bor 16#00000080),
- UpdatedErrors,UpdatedCreateReq);
- _ ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true,
- incorrectOptIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000080),
- UpdatedErrors,CreateReq)
- end;
- true -> %OK
- case catch pco_internal_storage(ConfigurationElement) of
- {ok,PCO} ->
- UpdatedCreateReq=CreateReq#sesT_createReqV0{protConOpt=PCO},
- decode_ie_create(Rest,(PresentIEs bor 16#00000080),
- Errors,UpdatedCreateReq);
- _ ->
- UpdatedErrors=Errors#protocolErrors{incorrectOptIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000080),
- UpdatedErrors,CreateReq)
- end
- end;
-
-%%% SGSN Address for signalling, Mandatory OR SGSN Address for user traffic, Mandatory
-decode_ie_create(<<133:8,Length:16,More/binary>>,PresentIEs,
- Errors,CreateReq) ->
- <<AddressElement:Length/binary-unit:8,Rest/binary>> = More,
- if
- (PresentIEs band 16#00000300) =:= 16#00000300 -> %Repeated IE, ignore
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000200 -> %Out of sequence
- if
- (PresentIEs band 16#00000100) =:= 16#00000000 -> %Signalling
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddSig=GSNAddr},
- decode_ie_create(Rest,(PresentIEs bor 16#00000100),
- UpdatedErrors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true,
- outOfSequence=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000100),
- UpdatedErrors,CreateReq)
- end;
- true -> % User traffic
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddUser=GSNAddr},
- decode_ie_create(Rest,(PresentIEs bor 16#00000200),
- UpdatedErrors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true,
- outOfSequence=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000200),
- UpdatedErrors,CreateReq)
- end
- end;
- PresentIEs < 16#00000100 -> %OK, SGSN Address for signalling
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddSig=GSNAddr},
- decode_ie_create(Rest,(PresentIEs bor 16#00000100),
- Errors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000100),
- UpdatedErrors,CreateReq)
- end;
- true -> %OK, SGSN Address for user traffic
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddUser=GSNAddr},
- decode_ie_create(Rest,(PresentIEs bor 16#00000200),
- Errors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000200),
- UpdatedErrors,CreateReq)
- end
- end;
-
-%%% MSISDN, Mandatory
-decode_ie_create(<<134:8,Length:16,More/binary>>,PresentIEs,
- Errors,CreateReq) ->
- <<MSISDNElement:Length/binary-unit:8,Rest/binary>> = More,
- if
- (PresentIEs band 16#00000400) =:= 16#00000400 -> %Repeated IE, ignore
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- PresentIEs > 16#00000400 -> %Out of sequence
- case msisdn_internal_storage(MSISDNElement,[]) of
- {ok,MSISDN} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedCreateReq=CreateReq#sesT_createReqV0{msisdn=MSISDN},
- decode_ie_create(Rest,(PresentIEs bor 16#00000400),
- UpdatedErrors,UpdatedCreateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true,invalidManIE=true},
- decode_ie_create(Rest,(PresentIEs bor 16#00000400),
- UpdatedErrors,CreateReq)
- end;
- true -> %OK
- UpdatedCreateReq=CreateReq#sesT_createReqV0{msisdn=#mvsT_msisdn{value=MSISDNElement}},
- decode_ie_create(Rest,(PresentIEs bor 16#00000400),
- Errors,UpdatedCreateReq)
-
- end;
-
-%%% Private Extension, Optional
-%%% Not implemented
-
-%%% Error handling, Unexpected or unknown IE
-decode_ie_create(UnexpectedIE,PresentIEs,Errors,CreateReq) ->
- case check_ie(UnexpectedIE) of
- {defined_ie,Rest} -> %OK, ignored
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- {handled_ie,Rest} -> %OK, ignored
- decode_ie_create(Rest,PresentIEs,Errors,CreateReq);
- {unhandled_ie} -> %Error, abort decoding
- {fault,193,CreateReq} %Invalid message format
- end.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% decode_ie_update/4
-%%% Decode information elements for Update PDP Context Request
-
-%%% All elements decoded
-decode_ie_update(<<>>,PresentIEs,Errors,UpdateReq) ->
- %% Check mandatory IE's
- if
- (PresentIEs band 16#3D) =/= 16#3D ->
- {fault,202,UpdateReq}; %Mandatory IE missing
- true -> %OK
- %% Check errors during decoding
- case Errors of
- #protocolErrors{invalidManIE=true} -> %Invalid mandatory IE
- {fault,201,UpdateReq}; %Mandatory IE incorrect
- #protocolErrors{outOfSequence=true} -> %Out of sequence
- {fault,193,UpdateReq}; %Invalid message format
- _ -> %OK
- {ok,UpdateReq}
- end
- end;
-
-%%% Quality of Service Profile, Mandatory
-decode_ie_update(<<6:8,QoSElement:3/binary-unit:8,Rest/binary>>,PresentIEs,
- Errors,UpdateReq) ->
- if
- (PresentIEs band 16#00000001) =:= 16#00000001 -> %Repeated IE's, ignore
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- PresentIEs > 16#00000001 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- <<_:2,DelayClass:3,ReliabilityClass:3,
- PeakThroughput:4,_:1,PrecedenceClass:3,
- _:3,MeanThroughput:5>> = QoSElement,
- QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass,
- reliabilityClass=ReliabilityClass,
- peakThroughput=PeakThroughput,
- precedenceClass=PrecedenceClass,
- meanThroughput=MeanThroughput},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{qos=QoS},
- decode_ie_update(Rest,(PresentIEs bor 16#00000001),
- UpdatedErrors,UpdatedUpdateReq);
- true -> %OK
- <<_:2,DelayClass:3,ReliabilityClass:3,
- PeakThroughput:4,_:1,PrecedenceClass:3,
- _:3,MeanThroughput:5>> = QoSElement,
- QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass,
- reliabilityClass=ReliabilityClass,
- peakThroughput=PeakThroughput,
- precedenceClass=PrecedenceClass,
- meanThroughput=MeanThroughput},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{qos=QoS},
- decode_ie_update(Rest,(PresentIEs bor 16#00000001),
- Errors,UpdatedUpdateReq)
- end;
-
-%%% Recovery, Optional
-decode_ie_update(<<14:8,Recovery:8,Rest/binary>>,PresentIEs,Errors,UpdateReq) ->
- if
- (PresentIEs band 16#00000002) =:= 16#00000002 -> %Repeated IE, ignored
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- PresentIEs > 16#00000002 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{recovery=Recovery},
- decode_ie_update(Rest,(PresentIEs bor 16#00000002),
- UpdatedErrors,UpdatedUpdateReq);
- true -> %OK
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{recovery=Recovery},
- decode_ie_update(Rest,(PresentIEs bor 16#00000002),Errors,
- UpdatedUpdateReq)
- end;
-
-%%% Flow Label Data I, Mandatory
-decode_ie_update(<<16:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,UpdateReq) ->
- if
- (PresentIEs band 16#00000004) =:= 16#00000004 -> %Repeated IE, ignored
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- PresentIEs > 16#00000004 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblData=FlowLabel},
- decode_ie_update(Rest,(PresentIEs bor 16#00000004),
- UpdatedErrors,UpdatedUpdateReq);
- true -> %OK
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblData=FlowLabel},
- decode_ie_update(Rest,(PresentIEs bor 16#00000004),Errors,
- UpdatedUpdateReq)
- end;
-
-%%% Flow Label Signalling, Mandatory
-decode_ie_update(<<17:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,UpdateReq) ->
- if
- (PresentIEs band 16#00000008) =:= 16#00000008 -> %Repeated IE, ignored
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- PresentIEs > 16#00000008 -> %Out of sequence
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblSig=FlowLabel},
- decode_ie_update(Rest,(PresentIEs bor 16#00000008),
- UpdatedErrors,UpdatedUpdateReq);
- true -> %OK
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblSig=FlowLabel},
- decode_ie_update(Rest,(PresentIEs bor 16#00000008),Errors,
- UpdatedUpdateReq)
- end;
-
-%%% SGSN Address for signalling, Mandatory OR SGSN Address for user traffic, Mandatory
-decode_ie_update(<<133:8,Length:16,More/binary>>,PresentIEs,
- Errors,UpdateReq) ->
- <<AddressElement:Length/binary-unit:8,Rest/binary>> = More,
- if
- (PresentIEs band 16#00000030) =:= 16#00000030 -> %Repeated IE, ignore
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- PresentIEs > 16#00000020 -> %Out of sequence
- if
- (PresentIEs band 16#00000010) =:= 16#00000000 -> %Signalling
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddSig=GSNAddr},
- decode_ie_update(Rest,(PresentIEs bor 16#00000010),
- UpdatedErrors,UpdatedUpdateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true,
- outOfSequence=true},
- decode_ie_update(Rest,(PresentIEs bor 16#00000010),
- UpdatedErrors,UpdateReq)
- end;
- true -> % User traffic
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedErrors=Errors#protocolErrors{outOfSequence=true},
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddUser=GSNAddr},
- decode_ie_update(Rest,(PresentIEs bor 16#00000020),
- UpdatedErrors,UpdatedUpdateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true,
- outOfSequence=true},
- decode_ie_update(Rest,(PresentIEs bor 16#00000020),
- UpdatedErrors,UpdateReq)
- end
- end;
- PresentIEs < 16#00000010 -> %OK, SGSN Address for signalling
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddSig=GSNAddr},
- decode_ie_update(Rest,(PresentIEs bor 16#00000010),
- Errors,UpdatedUpdateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true},
- decode_ie_update(Rest,(PresentIEs bor 16#00000010),
- UpdatedErrors,UpdateReq)
- end;
- true -> %OK, SGSN Address for user traffic
- case gsn_addr_internal_storage(AddressElement) of
- {ok,GSNAddr} ->
- UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddUser=GSNAddr},
- decode_ie_update(Rest,(PresentIEs bor 16#00000020),
- Errors,UpdatedUpdateReq);
- {fault} ->
- UpdatedErrors=Errors#protocolErrors{invalidManIE=true},
- decode_ie_update(Rest,(PresentIEs bor 16#00000020),
- UpdatedErrors,UpdateReq)
- end
- end;
-
-%%% Private Extension, Optional
-%%% Not implemented
-
-%%% Error handling, Unexpected or unknown IE
-decode_ie_update(UnexpectedIE,PresentIEs,Errors,UpdateReq) ->
- case check_ie(UnexpectedIE) of
- {defined_ie,Rest} -> %OK, ignored
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- {handled_ie,Rest} -> %OK, ignored
- decode_ie_update(Rest,PresentIEs,Errors,UpdateReq);
- {unhandled_ie} -> %Error, abort decoding
- {fault,193,UpdateReq} %Invalid message format
- end.
-
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% decode_ie_delete_req/4
-%%% Decode information elements for Delete PDP Context Request
-
-%%% Private Extension, Optional
-%%% Not implemented
-
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% decode_ie_delete_res/4
-%%% Decode information elements for Delete PDP Context Response
-
-%%% All elements decoded
-decode_ie_delete_res(<<>>,PresentIEs,DeleteRes) ->
- %% Check mandatory IE's
- if
- (PresentIEs band 16#0001) =/= 16#0001 ->
- {fault,202,DeleteRes}; %Mandatory IE missing
- true -> %OK
- {ok,DeleteRes}
- end;
-
-%%% Cause, Mandatory
-decode_ie_delete_res(<<1:8,Cause:8,Rest/binary>>,PresentIEs,DeleteRes) ->
- if
- (PresentIEs band 16#00000001) =:= 16#00000001 -> %Repeated IE, ignored
- decode_ie_delete_res(Rest,PresentIEs,DeleteRes);
- true -> %OK
- UpdatedDeleteRes=DeleteRes#sesT_deleteResV0{cause=Cause},
- decode_ie_delete_res(Rest,(PresentIEs bor 16#00000001),
- UpdatedDeleteRes)
- end;
-
-%%% Private Extension, Optional
-%%% Not implemented
-
-%%% Error handling, Unexpected or unknown IE
-decode_ie_delete_res(UnexpectedIE,PresentIEs,DeleteRes) ->
- case check_ie(UnexpectedIE) of
- {defined_ie,Rest} -> %OK, ignored
- decode_ie_delete_res(Rest,PresentIEs,DeleteRes);
- {handled_ie,Rest} -> %OK, ignored
- decode_ie_delete_res(Rest,PresentIEs,DeleteRes);
- {unhandled_ie} -> %Error, abort decoding
- {fault,193,DeleteRes} %Invalid message format
- end.
-
-%%% --------------------------------------------------------------
-%%% #3.2 COMMON INTERNAL FUNCTIONS
-%%% --------------------------------------------------------------
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% check_ie/1
-%%% Check Information Element, Unexpected or Unknown
-check_ie(<<1:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% IMSI
-check_ie(<<2:8,_:8/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% RAI
-check_ie(<<3:8,_:6/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% TTLI
-check_ie(<<4:8,_:4/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% P-TMSI
-check_ie(<<5:8,_:4/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Quality of Service Profile
-check_ie(<<6:8,_:3/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Reordering Required
-check_ie(<<8:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Authentication Triplet
-check_ie(<<9:8,_:28/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% MAP Cause
-check_ie(<<11:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% P-TMSI Signature
-check_ie(<<12:8,_:3/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% MS Validated
-check_ie(<<13:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Recovery
-check_ie(<<14:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Selection Mode
-check_ie(<<15:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Flow Label Data I
-check_ie(<<16:8,_:16,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Flow Label Signalling
-check_ie(<<17:8,_:16,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Flow Label Data II
-check_ie(<<18:8,_:32,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% MS Not Reachable Reason
-check_ie(<<19:8,_:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% Charging ID
-check_ie(<<127:8,_:4/binary-unit:8,Rest/binary>>) ->
- {defined_ie,Rest};
-%%% TLV element, skipped using Length
-check_ie(<<1:1,_:7,Length:16,More/binary>>) ->
- if
- Length > byte_size(More) ->
- {unhandled_ie};
- true ->
- <<_:Length/binary-unit:8,Rest/binary>> = More,
- {handled_ie,Rest}
- end;
-%%% TV element, unknown size. Can not be handled.
-check_ie(_UnhandledIE) ->
- {unhandled_ie}.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% tid_internal_storage/3
-%%% Convert TID binary to internal datatype
-tid_internal_storage(Bin,_) ->
- Size = byte_size(Bin) - 1,
- <<Front:Size/binary,NSAPI:4,DigitN:4>> = Bin,
- Result =
- case DigitN of
- 2#1111 ->
- #mvsgT_tid{imsi = #mvsgT_imsi{value = Front}, nsapi = NSAPI};
- _ ->
- Value = <<Front/binary,2#1111:4,DigitN:4>>,
- #mvsgT_tid{imsi = #mvsgT_imsi{value = Value}, nsapi = NSAPI}
- end,
- {ok,Result}.
-%% tid_internal_storage(<<NSAPI:4,2#1111:4>>,IMSI) ->
-%% {ok,#mvsgT_tid{imsi=#mvsgT_imsi{value=lists:reverse(IMSI)},
-%% nsapi=NSAPI}};
-%% tid_internal_storage(<<NSAPI:4,DigitN:4>>,IMSI) when
-%% DigitN < 10 ->
-%% {ok,#mvsgT_tid{imsi=#mvsgT_imsi{value=lists:reverse([(DigitN bor 2#11110000)|IMSI])},
-%% nsapi=NSAPI}};
-%% tid_internal_storage(<<2#11111111:8,Rest/binary>>,IMSI) ->
-%% tid_internal_storage(Rest,IMSI);
-%% tid_internal_storage(<<2#1111:4,DigitN:4,Rest/binary>>,IMSI) when
-%% DigitN < 10 ->
-%% tid_internal_storage(Rest,[(DigitN bor 2#11110000)|IMSI]);
-%% tid_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,IMSI) when
-%% DigitNplus1 < 10,
-%% DigitN < 10 ->
-%% tid_internal_storage(Rest,[((DigitNplus1 bsl 4) bor DigitN)|IMSI]);
-%% tid_internal_storage(_Rest,_IMSI) ->
-%% {fault}. %% Mandatory IE incorrect
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% selection_mode_internal_storage/1
-%%% Convert Selection Mode integer to internal datatype (enum)
-selection_mode_internal_storage(0) ->
- subscribed;
-selection_mode_internal_storage(1) ->
- msRequested;
-selection_mode_internal_storage(2) ->
- sgsnSelected;
-selection_mode_internal_storage(3) ->
- sgsnSelected.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% pdp_addr_internal_storage/1
-%%% Convert PDP address to internal datatype (record containing
-%%% addresstype and value)
-pdp_addr_internal_storage(<<_:4,0:4,1:8>>) ->
- {ok,#mvsgT_pdpAddressType{pdpTypeNbr=etsi_ppp,address=[]}};
-pdp_addr_internal_storage(<<_:4,0:4,2:8>>) ->
- {ok,#mvsgT_pdpAddressType{pdpTypeNbr=etsi_osp_ihoss,address=[]}};
-pdp_addr_internal_storage(<<_:4,1:4,16#21:8>>) ->
- {ok,#mvsgT_pdpAddressType{pdpTypeNbr=ietf_ipv4,address=[]}};
-pdp_addr_internal_storage(<<_:4,1:4,16#21:8,IP_A:8,IP_B:8,IP_C:8,IP_D:8>>) ->
- {ok,#mvsgT_pdpAddressType{pdpTypeNbr=ietf_ipv4,
- address=[IP_A,IP_B,IP_C,IP_D]}};
-pdp_addr_internal_storage(<<_:4,1:4,16#57:8,IP_A:16,IP_B:16,IP_C:16,IP_D:16,
- IP_E:16,IP_F:16,IP_G:16,IP_H:16>>) ->
- {ok,#mvsgT_pdpAddressType{pdpTypeNbr=ietf_ipv6,
- address=[IP_A,IP_B,IP_C,IP_D,IP_E,IP_F,IP_G,IP_H]}};
-pdp_addr_internal_storage(_PDP_ADDR) ->
- {fault}.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% apn_internal_storage/2
-%%% Convert APN to internal datatype (List containing APN labels)
-apn_internal_storage(<<>>,APN) ->
- {ok,lists:reverse(APN)};
-apn_internal_storage(<<Length:8,Rest/binary>>,APN) ->
- <<Label:Length/binary-unit:8,MoreAPNLabels/binary>> = Rest,
- apn_internal_storage(MoreAPNLabels,[Label|APN]).
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% pco_internal_storage/1
-%%% Convert Protocol Configuration Options to internal datatype.
-%%% Implemented configuration options:
-%%% For PPP:
-%%% LCP - Not implemented
-%%% PAP - Authenticate request
-%%% CHAP - Challenge
-%%% - Response
-%%% IPCP - IP-Address
-%%% For OSP:IHOSS
-%%% Nothing implemented
-pco_internal_storage(<<1:1,_:4,0:3,PPPConfigurationOptions/binary>>) ->
- case ppp_configuration_options(PPPConfigurationOptions,
- #masT_pap{exists=false},[],[]) of
- {ok,PAP,CHAP,IPCP} ->
- {ok,#masT_protocolConfigOptions{pap=PAP,chap=CHAP,ipcp=IPCP}};
- {fault} ->
- {fault}
- end;
-pco_internal_storage(<<1:1,_:4,1:3,_OSP_IHOSSConfigurationOptions/binary>>) ->
- {ok,osp_ihoss};
-pco_internal_storage(_UnknownConfigurationOptions) ->
- {fault}. %% Optional IE incorrect
-
-ppp_configuration_options(<<>>,PAP,CHAP,IPCP) ->
- {ok,PAP,CHAP,IPCP};
-ppp_configuration_options(<<16#C021:16,Length:8,More/binary>>,PAP,CHAP,IPCP) ->
- %% LCP - Not implemented
- <<_LCP:Length/binary-unit:8,Rest/binary>> = More,
- ppp_configuration_options(Rest,PAP,CHAP,IPCP);
-ppp_configuration_options(<<16#C023:16,_Length:8,1:8,Identifier:8,DataLength:16,
- More/binary>>,_PAP,CHAP,IPCP) ->
- %% PAP - Authenticate request
- ActualDataLength=DataLength-4, %% DataLength includes Code, Identifier and itself
- <<Data:ActualDataLength/binary-unit:8,Rest/binary>> = More,
- <<PeerIDLength:8,PeerData/binary>> = Data,
- <<PeerID:PeerIDLength/binary-unit:8,PasswdLength:8,PasswordData/binary>> = PeerData,
- <<Password:PasswdLength/binary,_Padding/binary>> = PasswordData,
- ppp_configuration_options(Rest,#masT_pap{exists=true,code=1,id=Identifier,
- username=binary_to_list(PeerID),
- password=binary_to_list(Password)},CHAP,IPCP);
-
-ppp_configuration_options(<<16#C023:16,Length:8,More/binary>>,PAP,CHAP,IPCP) ->
- %% PAP - Other, not implemented
- <<_PAP:Length/binary-unit:8,Rest/binary>> = More,
- ppp_configuration_options(Rest,PAP,CHAP,IPCP);
-ppp_configuration_options(<<16#C223:16,_Length:8,1:8,Identifier:8,DataLength:16,
- More/binary>>,PAP,CHAP,IPCP) ->
- %% CHAP - Challenge
- ActualDataLength=DataLength-4, %% DataLength includes Code, Identifier and itself
- <<Data:ActualDataLength/binary-unit:8,Rest/binary>> = More,
- <<ValueSize:8,ValueAndName/binary>> = Data,
- <<Value:ValueSize/binary-unit:8,Name/binary>> = ValueAndName,
- ppp_configuration_options(Rest,PAP,[#masT_chap{code=1,id=Identifier,
- value=binary_to_list(Value),
- name=binary_to_list(Name)}|CHAP],
- IPCP);
-ppp_configuration_options(<<16#C223:16,_Length:8,2:8,Identifier:8,DataLength:16,
- More/binary>>,PAP,CHAP,IPCP) ->
- %% CHAP - Response
- ActualDataLength=DataLength-4, %% DataLength includes Code, Identifier and itself
- <<Data:ActualDataLength/binary-unit:8,Rest/binary>> = More,
- <<ValueSize:8,ValueAndName/binary>> = Data,
- <<Value:ValueSize/binary-unit:8,Name/binary>> = ValueAndName,
- ppp_configuration_options(Rest,PAP,[#masT_chap{code=2,id=Identifier,
- value=binary_to_list(Value),
- name=binary_to_list(Name)}|CHAP],
- IPCP);
-ppp_configuration_options(<<16#C223:16,Length:8,More/binary>>,PAP,CHAP,IPCP) ->
- %% CHAP - Other, not implemented
- <<_CHAP:Length/binary-unit:8,Rest/binary>> = More,
- ppp_configuration_options(Rest,PAP,CHAP,IPCP);
-ppp_configuration_options(<<16#8021:16,_Length:8,1:8,Identifier:8,OptionsLength:16,
- More/binary>>,PAP,CHAP,IPCP) ->
- %% IPCP - Configure request
- ActualOptionsLength=OptionsLength-4, %% OptionsLength includes Code, Identifier and itself
- <<Options:ActualOptionsLength/binary-unit:8,Rest/binary>> = More,
- case Options of
- <<3:8,6:8,A1:8,A2:8,A3:8,A4:8>> ->
- %% IP Address, version 4
- ppp_configuration_options(Rest,PAP,CHAP,
- [#masT_ipcp{exists=true,code=1,
- id=Identifier,
- ipcpList=[#masT_ipcpData{type=3,ipAddress=
- #mvsgT_ipAddress{version=ipv4,
- a1=A1,a2=A2,
- a3=A3,a4=A4,
- a5=0,a6=0,
- a7=0,a8=0},
- rawMessage=binary_to_list(Options)}]}|IPCP]);
- <<129:8,6:8,B1:8,B2:8,B3:8,B4:8>> ->
- %% IP Address, version 4
- ppp_configuration_options(Rest,PAP,CHAP,
- [#masT_ipcp{exists=true,code=1,
- id=Identifier,
- ipcpList=[#masT_ipcpData{type=129,ipAddress=
- #mvsgT_ipAddress{version=ipv4,
- a1=B1,a2=B2,
- a3=B3,a4=B4},
- rawMessage=binary_to_list(Options)}]}|IPCP]);
-
- <<131:8,6:8,C1:8,C2:8,C3:8,C4:8>> ->
- %% IP Address, version 4
- ppp_configuration_options(Rest,PAP,CHAP,
- [#masT_ipcp{exists=true,code=1,
- id=Identifier,
- ipcpList=[#masT_ipcpData{type=131,ipAddress=
- #mvsgT_ipAddress{version=ipv4,
- a1=C1,a2=C2,
- a3=C3,a4=C4},
- rawMessage=binary_to_list(Options)}]}|IPCP]);
- _ ->
- ppp_configuration_options(Rest,PAP,CHAP,IPCP)
- end;
-ppp_configuration_options(<<_UnknownProtocolID:16,Length:8,More/binary>>,
- PAP,CHAP,IPCP) ->
- <<_Skipped:Length/binary-unit:8,Rest/binary>> = More,
- ppp_configuration_options(Rest,PAP,CHAP,IPCP);
-ppp_configuration_options(_Unhandled,_PAP,_CHAP,_IPCP) ->
- {fault}.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% gsn_addr_internal_storage/1
-%%% Convert GSN Address to internal datatype
-gsn_addr_internal_storage(<<IP_A:8,IP_B:8,IP_C:8,IP_D:8>>) ->
- {ok,#mvsgT_ipAddress{version=ipv4,a1=IP_A,a2=IP_B,a3=IP_C,a4=IP_D,a5=0,a6=0,a7=0,a8=0}};
-gsn_addr_internal_storage(<<IP_A:16,IP_B:16,IP_C:16,IP_D:16,
- IP_E:16,IP_F:16,IP_G:16,IP_H:16>>) ->
- {ok,#mvsgT_ipAddress{version=ipv6,a1=IP_A,a2=IP_B,a3=IP_C,a4=IP_D,
- a5=IP_E,a6=IP_F,a7=IP_G,a8=IP_H}};
-gsn_addr_internal_storage(_GSN_ADDR) ->
- {fault}.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% msisdn_internal_storage/3
-%%% Convert MSISDN binary to internal datatype (TBCD-octet list)
-
-msisdn_internal_storage(<<>>,MSISDN) ->
- {ok,#mvsT_msisdn{value=lists:reverse(MSISDN)}};
-msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) ->
- {ok,#mvsT_msisdn{value=lists:reverse(MSISDN)}};
-msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when
- DigitN < 10 ->
- {ok,#mvsT_msisdn{value=lists:reverse([(DigitN bor 2#11110000)|MSISDN])}};
-msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,MSISDN) when
- DigitNplus1 < 10,
- DigitN < 10 ->
- NewMSISDN=[((DigitNplus1 bsl 4) bor DigitN)|MSISDN],
- msisdn_internal_storage(Rest,NewMSISDN);
-msisdn_internal_storage(_Rest,_MSISDN) ->
- {fault}. %% Mandatory IE incorrect
diff --git a/lib/hipe/test/bs_SUITE_data/bs_decode_extract.hrl b/lib/hipe/test/bs_SUITE_data/bs_decode_extract.hrl
deleted file mode 100644
index 80add514a0..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_decode_extract.hrl
+++ /dev/null
@@ -1,91 +0,0 @@
--ifndef(EXTDEC_HRL).
--define(EXTDEC_HRL, true).
-
--record(protocolErrors,{
- invalidManIE=false,
- outOfSequence=false,
- incorrectOptIE=false}).
--record(mvsT_msisdn, {value}).
--record(mvsT_isdnAddress, {value}).
--record(mvsT_hlrAddress, {value}).
--record(mvsT_authenticationTriplet, {rand, sres, kc}).
--record(mvsT_authenticationQuintuplet, {rand, xres, ck, ik, autn}).
--record(mvsT_resynchInfo, {rand, auts}).
--record(mvsT_resynch, {label, value}).
--record(mvsT_storeImsiFault, {label, value}).
--record(mvsT_additionalImsisResults, {roamingStatus, defaultApnOperatorId, misc1, misc2, misc3}).
--record(mvsT_pdpActiveRecord, {contextId, nsapi, pdpTypeReq, pdpAddrReq, apnReq, qosReq, pdpTypeInUse, pdpAddressNature, pdpAddressInUse, apnInUse, ggsnAddrInUse, qosNegotiated}).
--record(mvsgT_rai, {mcc, mnc, lac, rac}).
--record(mvsgT_lai, {mcc, mnc, lac}).
--record(mvsgT_errorInd, {dummyElement}).
--record(mvsgT_deleteRes, {cause}).
--record(mvsgT_deleteReq, {dummyElement}).
--record(mvsgT_ptmsi, {value}).
--record(mvsgT_ddRef, {cid, extId, validity}).
--record(mvsgT_dpRef, {cid, devId}).
--record(mvsgT_qualityOfService, {delayClass, relClass, peakThrput, precClass, meanThrput}).
--record(mvsgT_pdpAddressType, {pdpTypeNbr, address}).
--record(mvsgT_msNetworkCapability, {gea1, smCapDediccatedChannel, smCapGprsChannel, ucs2Support, ssScreenInd}).
--record(mvsgT_cellId, {mcc, mnc, lac, rac, ci}).
--record(mvsgT_ipAddress, {version, a1, a2, a3, a4, a5, a6, a7, a8}).
--record(mvsgT_restartContextData, {gsn_address, restart_counter}).
--record(mvsgT_updateRes, {cause, qos, ggsnAddSig, ggsnAddUser, recovery, flowLabDataI, flowLabSig, chargId, optFlags}).
--record(mvsgT_updateReq, {qos, sgsnAddSig, sgsnAddUser, recovery, flowLabDataI, flowLabSig, otpFlags}).
--record(mvsgT_imsi, {value}).
--record(mvsgT_tid, {imsi, nsapi}).
--record(mvsgT_extQualityOfService, {allocRetention, trfClass, delOrder, delOfErrSDU, maxSDUSize, maxBRUp, maxBRDown, residualBER, sduErrorRatio, transferDelay, traffHandlPrio, guarBRUp, guarBRDown}).
--record(mvsgT_qualServ, {label, value}).
--record(sesT_gnDevContextData, {numberOfContext, recoveryInfoArray}).
--record(sesT_tid, {imsi, nsapi}).
--record(sesT_gnDevContextDataInfo, {dummy}).
--record(sesT_teid, {value}).
--record(sesT_qualityOfServiceV1, {allocRetPriority, delayClass, reliabilityClass, peakThroughput, precedenceClass, meanThroughput, trafficClass, deliveryOrder, delivOfErrSDU, maxSDUsize, maxBrUp, maxBrDown, residualBER, sduErrorRatio, transferDelay, trafficHandlPrio, guaranteedBrUp, guaranteedBrDown}).
--record(sesT_flowLbl, {value}).
--record(sesT_qualityOfServiceV0, {delayClass, reliabilityClass, peakThroughput, precedenceClass, meanThroughput}).
--record(sesT_createReq, {dummy}).
--record(sesT_createRes, {dummy}).
--record(sesT_deleteReq, {dummy}).
--record(sesT_deleteRes, {dummy}).
--record(sesT_gtid, {imsi, nsapi}).
--record(sesT_updateReq, {dummy}).
--record(sesT_updateRes, {dummy}).
--record(sesT_gcontrolDataUs, {gtpSeqNr, gsnAddress, gtunnelId, gsnPort}).
--record(sesT_gcontrolDataDs, {gtpSeqNr, gsnAddress, protocol, gtunnelId, flowLabSig, gsnPort}).
--record(sesT_createResV1, {cause, teidSignalling, teidData, ggsnAddSig, ggsnAddUser, reorderingReq, recovery, chargId, endUserAdd, optFlags, protConOpt, qos}).
--record(sesT_createReqV1, {qos, sgsnAddSig, sgsnAddUser, selMode, recovery, msisdn, endUserAdd, accPointName, optFlags, protConOpt, imsi, teidData, teidSignalling, nsapi}).
--record(sesT_deleteReqV1, {teardownInd, nsapi}).
--record(sesT_deleteResV1, {cause}).
--record(sesT_updateReqV1, {imsi, recovery, teidData, teidSignalling, nsapi, sgsnAddSig, sgsnAddUser, qos}).
--record(sesT_updateResV1, {cause, recovery, teidData, teidSignalling, chargId, ggsnAddSig, ggsnAddUser, qos}).
--record(sesT_deleteReqV0, {tid}).
--record(sesT_deleteResV0, {tid, cause}).
--record(sesT_createReqV0, {tid, tidRaw, qos, recovery, selMode, flowLblData, flowLblSig, endUserAdd, accPointName, protConOpt, sgsnAddSig, sgsnAddUser, msisdn}).
--record(sesT_createResV0, {tid, cause, qos, reorderingReq, recovery, flowLblData, flowLblSig, chargId, endUserAdd, protConOpt, ggsnAddSig, ggsnAddUser}).
--record(sesT_updateReqV0, {tid, tidRaw, qos, recovery, flowLblData, flowLblSig, sgsnAddSig, sgsnAddUser}).
--record(sesT_updateResV0, {tid, cause, qos, recovery, flowLblData, flowLblSig, chargId, ggsnAddSig, ggsnAddUser}).
--record(sesT_echoReq, {dummy}).
--record(sesT_echoRes, {dummy}).
--record(sesT_echoReqV1, {dummy}).
--record(sesT_echoResV1, {recovery}).
--record(sesT_echoReqV0, {dummy}).
--record(sesT_echoResV0, {recovery}).
--record(masT_apnSecurity, {sgsnSel, subscribedSel, userSel, ipSpoofing}).
--record(masT_radiusServer, {radiusApn, radiusAddress, radiusMepAddress, timer, tries, secret}).
--record(masT_ipSegment, {startSegAddress, stopSegAddress, netmask}).
--record(masT_llf, {name, metric, id}).
--record(masT_apnLink, {ggsnAddress, ipSegList, ipAddressOrigin, llfConnName, mepAddress}).
--record(masT_ispSubObj, {label, value}).
--record(masT_ipcpData, {type, ipAddress, rawMessage}).
--record(masT_ipcp, {exists, code, id, ipcpList}).
--record(masT_pap, {exists, code, id, username, password}).
--record(masT_chap, {code, id, value, name}).
--record(masT_ispDevContextData, {nsapi, ipAddress, apnhandle}).
--record(masT_protocolConfigOptions, {chap, pap, ipcp}).
--record(masT_apnRadius, {radiusAddress, timer, tries, secret}).
--record(masT_outbandRadius, {gwAddress, llfConnName, primRadius, secRadius}).
--record(masT_radiusPair, {primRadius, secRadius}).
--record(masT_radiusOpt, {dummyMsisdnAuth, dummyMsisdnAcct, msisdnInAuth, msisdnInAcct, sendFullImsi, sendMccMnc, sendSelMode, sendChargingId, asynchAcct}).
--record(masT_radiusConfig, {hostApn, authPair, acctList, radiusOptions}).
--record(masT_apnConfig, {link, security, radiusConfig, primDns, secDns, dhcpAddress, indAcct, indAuth, userNameBasedSelection}).
-
--endif.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_des.erl b/lib/hipe/test/bs_SUITE_data/bs_des.erl
deleted file mode 100644
index 9c495d37ad..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_des.erl
+++ /dev/null
@@ -1,734 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_des.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : An implementation of the DES Encryption/Descryption
-%%% algorithm using Erlang binaries.
-%%%
-%%% Created : 14 Apr 2004
-%%%-------------------------------------------------------------------
--module(bs_des).
-
--export([encode/2, decode/2, test/0]).
-
--define(ITERATIONS, 42). %% for benchmarking use a higher number
-
-test() ->
- Bin = <<1:64>>,
- Size= byte_size(Bin),
- Key = <<4704650607608769871263876:64>>,
- Jumbled = run_encode(?ITERATIONS, Bin, Key),
- Unjumbled = run_decode(?ITERATIONS, Jumbled, Key),
- <<Bin:Size/binary,_/binary>> = Unjumbled,
- ok.
-
-run_encode(1, Bin, Key) ->
- encode(Bin, Key);
-run_encode(N, Bin, Key) ->
- encode(Bin, Key),
- run_encode(N-1, Bin, Key).
-
-run_decode(1, Bin, Key) ->
- decode(Bin, Key);
-run_decode(N, Bin, Key) ->
- decode(Bin, Key),
- run_decode(N-1, Bin, Key).
-
-encode(Data, Key) ->
- Keys = schedule(Key),
- list_to_binary(encode_data(Data, Keys)).
-
-decode(Data, Key) ->
- Keys = lists:reverse(schedule(Key)),
- list_to_binary(decode_data(Data, Keys)).
-
-encode_data(<<Data:8/binary, Rest/binary>>, Keys) ->
- [ipinv(des_core(ip(Data), Keys))|encode_data(Rest, Keys)];
-encode_data(<<Rest/binary>>, Keys) ->
- case byte_size(Rest) of
- 0 -> [];
- X ->
- Y = 8 - X,
- Data = <<Rest/binary, 0:Y/integer-unit:8>>,
- [ipinv(des_core(ip(Data), Keys))]
- end.
-
-decode_data(<<Data:8/binary, Rest/binary>>, Keys) ->
- [ipinv(dechiper(ip(Data), Keys))|decode_data(Rest, Keys)];
-decode_data(_, _Keys) ->
- [].
-
-schedule(Key) ->
- NewKey = pc1(Key),
- subkeys(NewKey, 1).
-
-subkeys(_Key, 17) ->
- [];
-subkeys(Key, N) ->
- TmpKey =
- case rotate(N) of
- 1 ->
- <<X1:1, L:27, X2:1, R:27>> = Key,
- <<L:27, X1:1, R:27, X2:1>>;
- 2 ->
- <<X1:2, L:26, X2:2, R:26>> = Key,
- <<L:26, X1:2, R:26, X2:2>>
- end,
- [pc2(TmpKey)|subkeys(TmpKey, N+1)].
-
-pc2(<<I1:1, I2:1, I3:1, I4:1, I5:1, I6:1, I7:1, I8:1,
- _I9:1, I10:1, I11:1, I12:1, I13:1, I14:1, I15:1, I16:1,
- I17:1, _I18:1, I19:1, I20:1, I21:1, _I22:1, I23:1, I24:1,
- _I25:1, I26:1, I27:1, I28:1, I29:1, I30:1, I31:1, I32:1,
- I33:1, I34:1, _I35:1, I36:1, I37:1, _I38:1, I39:1, I40:1,
- I41:1, I42:1, _I43:1, I44:1, I45:1, I46:1, I47:1, I48:1,
- I49:1, I50:1, I51:1, I52:1, I53:1, _I54:1, I55:1, I56:1>>) ->
- <<I14:1, I17:1, I11:1, I24:1, I1:1, I5:1, I3:1, I28:1,
- I15:1, I6:1, I21:1, I10:1, I23:1, I19:1, I12:1, I4:1,
- I26:1, I8:1, I16:1, I7:1, I27:1, I20:1, I13:1, I2:1,
- I41:1, I52:1, I31:1, I37:1, I47:1, I55:1, I30:1, I40:1,
- I51:1, I45:1, I33:1, I48:1, I44:1, I49:1, I39:1, I56:1,
- I34:1, I53:1, I46:1, I42:1, I50:1, I36:1, I29:1, I32:1>>.
-
-pc1(<<I1:1, I2:1, I3:1, I4:1, I5:1, I6:1, I7:1, _:1,
- I9:1, I10:1, I11:1, I12:1, I13:1, I14:1, I15:1, _:1,
- I17:1, I18:1, I19:1, I20:1, I21:1, I22:1, I23:1, _:1,
- I25:1, I26:1, I27:1, I28:1, I29:1, I30:1, I31:1, _:1,
- I33:1, I34:1, I35:1, I36:1, I37:1, I38:1, I39:1, _:1,
- I41:1, I42:1, I43:1, I44:1, I45:1, I46:1, I47:1, _:1,
- I49:1, I50:1, I51:1, I52:1, I53:1, I54:1, I55:1, _:1,
- I57:1, I58:1, I59:1, I60:1, I61:1, I62:1, I63:1, _:1>>) ->
- <<I57:1, I49:1, I41:1, I33:1, I25:1, I17:1, I9:1, I1:1,
- I58:1, I50:1, I42:1, I34:1, I26:1, I18:1, I10:1, I2:1,
- I59:1, I51:1, I43:1, I35:1, I27:1, I19:1, I11:1, I3:1,
- I60:1, I52:1, I44:1, I36:1, I63:1, I55:1, I47:1, I39:1,
- I31:1, I23:1, I15:1, I7:1, I62:1, I54:1, I46:1, I38:1,
- I30:1, I22:1, I14:1, I6:1, I61:1, I53:1, I45:1, I37:1,
- I29:1, I21:1, I13:1, I5:1, I28:1, I20:1, I12:1, I4:1>>.
-
-ip(<<I1:1, I2:1, I3:1, I4:1, I5:1, I6:1, I7:1, I8:1,
- I9:1, I10:1, I11:1, I12:1, I13:1, I14:1, I15:1, I16:1,
- I17:1, I18:1, I19:1, I20:1, I21:1, I22:1, I23:1, I24:1,
- I25:1, I26:1, I27:1, I28:1, I29:1, I30:1, I31:1, I32:1,
- I33:1, I34:1, I35:1, I36:1, I37:1, I38:1, I39:1, I40:1,
- I41:1, I42:1, I43:1, I44:1, I45:1, I46:1, I47:1, I48:1,
- I49:1, I50:1, I51:1, I52:1, I53:1, I54:1, I55:1, I56:1,
- I57:1, I58:1, I59:1, I60:1, I61:1, I62:1, I63:1, I64:1>>) ->
- <<I58:1, I50:1, I42:1, I34:1, I26:1, I18:1, I10:1, I2:1,
- I60:1, I52:1, I44:1, I36:1, I28:1, I20:1, I12:1, I4:1,
- I62:1, I54:1, I46:1, I38:1, I30:1, I22:1, I14:1, I6:1,
- I64:1, I56:1, I48:1, I40:1, I32:1, I24:1, I16:1, I8:1,
- I57:1, I49:1, I41:1, I33:1, I25:1, I17:1, I9:1, I1:1,
- I59:1, I51:1, I43:1, I35:1, I27:1, I19:1, I11:1, I3:1,
- I61:1, I53:1, I45:1, I37:1, I29:1, I21:1, I13:1, I5:1,
- I63:1, I55:1, I47:1, I39:1, I31:1, I23:1, I15:1, I7:1>>.
-
-ipinv(<<I58:1, I50:1, I42:1, I34:1, I26:1, I18:1, I10:1, I2:1,
- I60:1, I52:1, I44:1, I36:1, I28:1, I20:1, I12:1, I4:1,
- I62:1, I54:1, I46:1, I38:1, I30:1, I22:1, I14:1, I6:1,
- I64:1, I56:1, I48:1, I40:1, I32:1, I24:1, I16:1, I8:1,
- I57:1, I49:1, I41:1, I33:1, I25:1, I17:1, I9:1, I1:1,
- I59:1, I51:1, I43:1, I35:1, I27:1, I19:1, I11:1, I3:1,
- I61:1, I53:1, I45:1, I37:1, I29:1, I21:1, I13:1, I5:1,
- I63:1, I55:1, I47:1, I39:1, I31:1, I23:1, I15:1, I7:1>>) ->
- <<I1:1, I2:1, I3:1, I4:1, I5:1, I6:1, I7:1, I8:1,
- I9:1, I10:1, I11:1, I12:1, I13:1, I14:1, I15:1, I16:1,
- I17:1, I18:1, I19:1, I20:1, I21:1, I22:1, I23:1, I24:1,
- I25:1, I26:1, I27:1, I28:1, I29:1, I30:1, I31:1, I32:1,
- I33:1, I34:1, I35:1, I36:1, I37:1, I38:1, I39:1, I40:1,
- I41:1, I42:1, I43:1, I44:1, I45:1, I46:1, I47:1, I48:1,
- I49:1, I50:1, I51:1, I52:1, I53:1, I54:1, I55:1, I56:1,
- I57:1, I58:1, I59:1, I60:1, I61:1, I62:1, I63:1, I64:1>>.
-
-dechiper(<<L:4/binary, R:4/binary>>, Keys) ->
- dechiper(L, R, Keys, 16).
-
-dechiper(L, R, [], 0) ->
- <<L:4/binary, R:4/binary>>;
-dechiper(L, R, [Key|Rest], I) ->
- NewL = ebit(L),
- XorL = xor48(NewL, Key),
- Sboxed = sboxing(XorL),
- Ped = p(Sboxed),
- EndL = xor32(Ped, R),
- dechiper(EndL, L, Rest, I-1).
-
-des_core(<<L:4/binary, R:4/binary>>, Keys) ->
- des_core(L, R, Keys, 0).
-
-des_core(L, R, [], 16) ->
- <<L:4/binary, R:4/binary>>;
-des_core(L, R, [Key|Rest], I) when I<16 ->
- NewR = ebit(R),
- XorR = xor48(NewR, Key),
- Sboxed = sboxing(XorR),
- Ped = p(Sboxed),
- EndR = xor32(Ped, L),
- des_core(R, EndR, Rest, I+1).
-
-ebit(<<I1:1, I2:2, I3:2,I4:2,I5:2,I6:2,
- I7:2,I8:2,I9:2,I10:2,I11:2,I12:2,
- I13:2,I14:2,I15:2,I16:2,I17:1>>) ->
- <<I17:1, I1:1, I2:2, I3:2, I3:2,
- I4:2, I5:2, I5:2, I6:2,
- I7:2, I7:2, I8:2, I9:2,
- I9:2, I10:2, I11:2, I11:2,
- I12:2, I13:2, I13:2, I14:2,
- I15:2, I15:2, I16:2, I17:1, I1:1>>.
-
-p(<<I1:1, I2:1, I3:1, I4:1, I5:1, I6:1, I7:1, I8:1,
- I9:1, I10:1, I11:1, I12:1, I13:1, I14:1, I15:1, I16:1,
- I17:1, I18:1, I19:1, I20:1, I21:1, I22:1, I23:1, I24:1,
- I25:1, I26:1, I27:1, I28:1, I29:1, I30:1, I31:1, I32:1>>) ->
- <<I16:1, I7:1, I20:1, I21:1, I29:1, I12:1, I28:1, I17:1,
- I1:1, I15:1, I23:1, I26:1, I5:1, I18:1, I31:1, I10:1,
- I2:1, I8:1, I24:1, I14:1, I32:1, I27:1, I3:1, I9:1,
- I19:1, I13:1, I30:1, I6:1, I22:1, I11:1, I4:1, I25:1>>.
-
-rotate(1) -> 1;
-rotate(2) -> 1;
-rotate(9) -> 1;
-rotate(16) -> 1;
-rotate(N) when N>0, N<17 -> 2.
-
-%% xor64(<<I1:16, I2:16, I3:16, I4:16>>,<<J1:16, J2:16, J3:16, J4:16>>) ->
-%% K1 = I1 bxor J1,
-%% K2 = I2 bxor J2,
-%% K3 = I3 bxor J3,
-%% K4 = I4 bxor J4,
-%% <<K1:16, K2:16, K3:16, K4:16>>.
-
-xor48(<<I1:16, I2:16, I3:16>>,<<J1:16, J2:16, J3:16>>) ->
- K1 = I1 bxor J1,
- K2 = I2 bxor J2,
- K3 = I3 bxor J3,
- <<K1:16, K2:16, K3:16>>.
-
-xor32(<<I1:16, I2:16>>,<<J1:16, J2:16>>) ->
- K1 = I1 bxor J1,
- K2 = I2 bxor J2,
- <<K1:16, K2:16>>.
-
-sboxing(<<A1:6, A2:6, A3:6, A4:6, A5:6, A6:6, A7:6, A8:6>>) ->
- S1 = sbox(A1, 1),
- S2 = sbox(A2, 2),
- S3 = sbox(A3, 3),
- S4 = sbox(A4, 4),
- S5 = sbox(A5, 5),
- S6 = sbox(A6, 6),
- S7 = sbox(A7, 7),
- S8 = sbox(A8, 8),
- <<S1:4,S2:4,S3:4,S4:4,S5:4,S6:4,S7:4,S8:4>>.
-
-sbox(0,1) -> 14;
-sbox(1,1) -> 0;
-sbox(2,1) -> 4;
-sbox(3,1) -> 15;
-sbox(4,1) -> 13;
-sbox(5,1) -> 7;
-sbox(6,1) -> 1;
-sbox(7,1) -> 4;
-sbox(8,1) -> 2;
-sbox(9,1) -> 14;
-sbox(10,1) -> 15;
-sbox(11,1) -> 2;
-sbox(12,1) -> 11;
-sbox(13,1) -> 13;
-sbox(14,1) -> 8;
-sbox(15,1) -> 1;
-sbox(16,1) -> 3;
-sbox(17,1) -> 10;
-sbox(18,1) -> 10;
-sbox(19,1) -> 6;
-sbox(20,1) -> 6;
-sbox(21,1) -> 12;
-sbox(22,1) -> 12;
-sbox(23,1) -> 11;
-sbox(24,1) -> 5;
-sbox(25,1) -> 9;
-sbox(26,1) -> 9;
-sbox(27,1) -> 5;
-sbox(28,1) -> 0;
-sbox(29,1) -> 3;
-sbox(30,1) -> 7;
-sbox(31,1) -> 8;
-sbox(32,1) -> 4;
-sbox(33,1) -> 15;
-sbox(34,1) -> 1;
-sbox(35,1) -> 12;
-sbox(36,1) -> 14;
-sbox(37,1) -> 8;
-sbox(38,1) -> 8;
-sbox(39,1) -> 2;
-sbox(40,1) -> 13;
-sbox(41,1) -> 4;
-sbox(42,1) -> 6;
-sbox(43,1) -> 9;
-sbox(44,1) -> 2;
-sbox(45,1) -> 1;
-sbox(46,1) -> 11;
-sbox(47,1) -> 7;
-sbox(48,1) -> 15;
-sbox(49,1) -> 5;
-sbox(50,1) -> 12;
-sbox(51,1) -> 11;
-sbox(52,1) -> 9;
-sbox(53,1) -> 3;
-sbox(54,1) -> 7;
-sbox(55,1) -> 14;
-sbox(56,1) -> 3;
-sbox(57,1) -> 10;
-sbox(58,1) -> 10;
-sbox(59,1) -> 0;
-sbox(60,1) -> 5;
-sbox(61,1) -> 6;
-sbox(62,1) -> 0;
-sbox(63,1) -> 13;
-sbox(0,2) -> 15;
-sbox(1,2) -> 3;
-sbox(2,2) -> 1;
-sbox(3,2) -> 13;
-sbox(4,2) -> 8;
-sbox(5,2) -> 4;
-sbox(6,2) -> 14;
-sbox(7,2) -> 7;
-sbox(8,2) -> 6;
-sbox(9,2) -> 15;
-sbox(10,2) -> 11;
-sbox(11,2) -> 2;
-sbox(12,2) -> 3;
-sbox(13,2) -> 8;
-sbox(14,2) -> 4;
-sbox(15,2) -> 14;
-sbox(16,2) -> 9;
-sbox(17,2) -> 12;
-sbox(18,2) -> 7;
-sbox(19,2) -> 0;
-sbox(20,2) -> 2;
-sbox(21,2) -> 1;
-sbox(22,2) -> 13;
-sbox(23,2) -> 10;
-sbox(24,2) -> 12;
-sbox(25,2) -> 6;
-sbox(26,2) -> 0;
-sbox(27,2) -> 9;
-sbox(28,2) -> 5;
-sbox(29,2) -> 11;
-sbox(30,2) -> 10;
-sbox(31,2) -> 5;
-sbox(32,2) -> 0;
-sbox(33,2) -> 13;
-sbox(34,2) -> 14;
-sbox(35,2) -> 8;
-sbox(36,2) -> 7;
-sbox(37,2) -> 10;
-sbox(38,2) -> 11;
-sbox(39,2) -> 1;
-sbox(40,2) -> 10;
-sbox(41,2) -> 3;
-sbox(42,2) -> 4;
-sbox(43,2) -> 15;
-sbox(44,2) -> 13;
-sbox(45,2) -> 4;
-sbox(46,2) -> 1;
-sbox(47,2) -> 2;
-sbox(48,2) -> 5;
-sbox(49,2) -> 11;
-sbox(50,2) -> 8;
-sbox(51,2) -> 6;
-sbox(52,2) -> 12;
-sbox(53,2) -> 7;
-sbox(54,2) -> 6;
-sbox(55,2) -> 12;
-sbox(56,2) -> 9;
-sbox(57,2) -> 0;
-sbox(58,2) -> 3;
-sbox(59,2) -> 5;
-sbox(60,2) -> 2;
-sbox(61,2) -> 14;
-sbox(62,2) -> 15;
-sbox(63,2) -> 9;
-sbox(0,3) -> 10;
-sbox(1,3) -> 13;
-sbox(2,3) -> 0;
-sbox(3,3) -> 7;
-sbox(4,3) -> 9;
-sbox(5,3) -> 0;
-sbox(6,3) -> 14;
-sbox(7,3) -> 9;
-sbox(8,3) -> 6;
-sbox(9,3) -> 3;
-sbox(10,3) -> 3;
-sbox(11,3) -> 4;
-sbox(12,3) -> 15;
-sbox(13,3) -> 6;
-sbox(14,3) -> 5;
-sbox(15,3) -> 10;
-sbox(16,3) -> 1;
-sbox(17,3) -> 2;
-sbox(18,3) -> 13;
-sbox(19,3) -> 8;
-sbox(20,3) -> 12;
-sbox(21,3) -> 5;
-sbox(22,3) -> 7;
-sbox(23,3) -> 14;
-sbox(24,3) -> 11;
-sbox(25,3) -> 12;
-sbox(26,3) -> 4;
-sbox(27,3) -> 11;
-sbox(28,3) -> 2;
-sbox(29,3) -> 15;
-sbox(30,3) -> 8;
-sbox(31,3) -> 1;
-sbox(32,3) -> 13;
-sbox(33,3) -> 1;
-sbox(34,3) -> 6;
-sbox(35,3) -> 10;
-sbox(36,3) -> 4;
-sbox(37,3) -> 13;
-sbox(38,3) -> 9;
-sbox(39,3) -> 0;
-sbox(40,3) -> 8;
-sbox(41,3) -> 6;
-sbox(42,3) -> 15;
-sbox(43,3) -> 9;
-sbox(44,3) -> 3;
-sbox(45,3) -> 8;
-sbox(46,3) -> 0;
-sbox(47,3) -> 7;
-sbox(48,3) -> 11;
-sbox(49,3) -> 4;
-sbox(50,3) -> 1;
-sbox(51,3) -> 15;
-sbox(52,3) -> 2;
-sbox(53,3) -> 14;
-sbox(54,3) -> 12;
-sbox(55,3) -> 3;
-sbox(56,3) -> 5;
-sbox(57,3) -> 11;
-sbox(58,3) -> 10;
-sbox(59,3) -> 5;
-sbox(60,3) -> 14;
-sbox(61,3) -> 2;
-sbox(62,3) -> 7;
-sbox(63,3) -> 12;
-sbox(0,4) -> 7;
-sbox(1,4) -> 13;
-sbox(2,4) -> 13;
-sbox(3,4) -> 8;
-sbox(4,4) -> 14;
-sbox(5,4) -> 11;
-sbox(6,4) -> 3;
-sbox(7,4) -> 5;
-sbox(8,4) -> 0;
-sbox(9,4) -> 6;
-sbox(10,4) -> 6;
-sbox(11,4) -> 15;
-sbox(12,4) -> 9;
-sbox(13,4) -> 0;
-sbox(14,4) -> 10;
-sbox(15,4) -> 3;
-sbox(16,4) -> 1;
-sbox(17,4) -> 4;
-sbox(18,4) -> 2;
-sbox(19,4) -> 7;
-sbox(20,4) -> 8;
-sbox(21,4) -> 2;
-sbox(22,4) -> 5;
-sbox(23,4) -> 12;
-sbox(24,4) -> 11;
-sbox(25,4) -> 1;
-sbox(26,4) -> 12;
-sbox(27,4) -> 10;
-sbox(28,4) -> 4;
-sbox(29,4) -> 14;
-sbox(30,4) -> 15;
-sbox(31,4) -> 9;
-sbox(32,4) -> 10;
-sbox(33,4) -> 3;
-sbox(34,4) -> 6;
-sbox(35,4) -> 15;
-sbox(36,4) -> 9;
-sbox(37,4) -> 0;
-sbox(38,4) -> 0;
-sbox(39,4) -> 6;
-sbox(40,4) -> 12;
-sbox(41,4) -> 10;
-sbox(42,4) -> 11;
-sbox(43,4) -> 1;
-sbox(44,4) -> 7;
-sbox(45,4) -> 13;
-sbox(46,4) -> 13;
-sbox(47,4) -> 8;
-sbox(48,4) -> 15;
-sbox(49,4) -> 9;
-sbox(50,4) -> 1;
-sbox(51,4) -> 4;
-sbox(52,4) -> 3;
-sbox(53,4) -> 5;
-sbox(54,4) -> 14;
-sbox(55,4) -> 11;
-sbox(56,4) -> 5;
-sbox(57,4) -> 12;
-sbox(58,4) -> 2;
-sbox(59,4) -> 7;
-sbox(60,4) -> 8;
-sbox(61,4) -> 2;
-sbox(62,4) -> 4;
-sbox(63,4) -> 14;
-sbox(0,5) -> 2;
-sbox(1,5) -> 14;
-sbox(2,5) -> 12;
-sbox(3,5) -> 11;
-sbox(4,5) -> 4;
-sbox(5,5) -> 2;
-sbox(6,5) -> 1;
-sbox(7,5) -> 12;
-sbox(8,5) -> 7;
-sbox(9,5) -> 4;
-sbox(10,5) -> 10;
-sbox(11,5) -> 7;
-sbox(12,5) -> 11;
-sbox(13,5) -> 13;
-sbox(14,5) -> 6;
-sbox(15,5) -> 1;
-sbox(16,5) -> 8;
-sbox(17,5) -> 5;
-sbox(18,5) -> 5;
-sbox(19,5) -> 0;
-sbox(20,5) -> 3;
-sbox(21,5) -> 15;
-sbox(22,5) -> 15;
-sbox(23,5) -> 10;
-sbox(24,5) -> 13;
-sbox(25,5) -> 3;
-sbox(26,5) -> 0;
-sbox(27,5) -> 9;
-sbox(28,5) -> 14;
-sbox(29,5) -> 8;
-sbox(30,5) -> 9;
-sbox(31,5) -> 6;
-sbox(32,5) -> 4;
-sbox(33,5) -> 11;
-sbox(34,5) -> 2;
-sbox(35,5) -> 8;
-sbox(36,5) -> 1;
-sbox(37,5) -> 12;
-sbox(38,5) -> 11;
-sbox(39,5) -> 7;
-sbox(40,5) -> 10;
-sbox(41,5) -> 1;
-sbox(42,5) -> 13;
-sbox(43,5) -> 14;
-sbox(44,5) -> 7;
-sbox(45,5) -> 2;
-sbox(46,5) -> 8;
-sbox(47,5) -> 13;
-sbox(48,5) -> 15;
-sbox(49,5) -> 6;
-sbox(50,5) -> 9;
-sbox(51,5) -> 15;
-sbox(52,5) -> 12;
-sbox(53,5) -> 0;
-sbox(54,5) -> 5;
-sbox(55,5) -> 9;
-sbox(56,5) -> 6;
-sbox(57,5) -> 10;
-sbox(58,5) -> 3;
-sbox(59,5) -> 4;
-sbox(60,5) -> 0;
-sbox(61,5) -> 5;
-sbox(62,5) -> 14;
-sbox(63,5) -> 3;
-sbox(0,6) -> 12;
-sbox(1,6) -> 10;
-sbox(2,6) -> 1;
-sbox(3,6) -> 15;
-sbox(4,6) -> 10;
-sbox(5,6) -> 4;
-sbox(6,6) -> 15;
-sbox(7,6) -> 2;
-sbox(8,6) -> 9;
-sbox(9,6) -> 7;
-sbox(10,6) -> 2;
-sbox(11,6) -> 12;
-sbox(12,6) -> 6;
-sbox(13,6) -> 9;
-sbox(14,6) -> 8;
-sbox(15,6) -> 5;
-sbox(16,6) -> 0;
-sbox(17,6) -> 6;
-sbox(18,6) -> 13;
-sbox(19,6) -> 1;
-sbox(20,6) -> 3;
-sbox(21,6) -> 13;
-sbox(22,6) -> 4;
-sbox(23,6) -> 14;
-sbox(24,6) -> 14;
-sbox(25,6) -> 0;
-sbox(26,6) -> 7;
-sbox(27,6) -> 11;
-sbox(28,6) -> 5;
-sbox(29,6) -> 3;
-sbox(30,6) -> 11;
-sbox(31,6) -> 8;
-sbox(32,6) -> 9;
-sbox(33,6) -> 4;
-sbox(34,6) -> 14;
-sbox(35,6) -> 3;
-sbox(36,6) -> 15;
-sbox(37,6) -> 2;
-sbox(38,6) -> 5;
-sbox(39,6) -> 12;
-sbox(40,6) -> 2;
-sbox(41,6) -> 9;
-sbox(42,6) -> 8;
-sbox(43,6) -> 5;
-sbox(44,6) -> 12;
-sbox(45,6) -> 15;
-sbox(46,6) -> 3;
-sbox(47,6) -> 10;
-sbox(48,6) -> 7;
-sbox(49,6) -> 11;
-sbox(50,6) -> 0;
-sbox(51,6) -> 14;
-sbox(52,6) -> 4;
-sbox(53,6) -> 1;
-sbox(54,6) -> 10;
-sbox(55,6) -> 7;
-sbox(56,6) -> 1;
-sbox(57,6) -> 6;
-sbox(58,6) -> 13;
-sbox(59,6) -> 0;
-sbox(60,6) -> 11;
-sbox(61,6) -> 8;
-sbox(62,6) -> 6;
-sbox(63,6) -> 13;
-sbox(0,7) -> 4;
-sbox(1,7) -> 13;
-sbox(2,7) -> 11;
-sbox(3,7) -> 0;
-sbox(4,7) -> 2;
-sbox(5,7) -> 11;
-sbox(6,7) -> 14;
-sbox(7,7) -> 7;
-sbox(8,7) -> 15;
-sbox(9,7) -> 4;
-sbox(10,7) -> 0;
-sbox(11,7) -> 9;
-sbox(12,7) -> 8;
-sbox(13,7) -> 1;
-sbox(14,7) -> 13;
-sbox(15,7) -> 10;
-sbox(16,7) -> 3;
-sbox(17,7) -> 14;
-sbox(18,7) -> 12;
-sbox(19,7) -> 3;
-sbox(20,7) -> 9;
-sbox(21,7) -> 5;
-sbox(22,7) -> 7;
-sbox(23,7) -> 12;
-sbox(24,7) -> 5;
-sbox(25,7) -> 2;
-sbox(26,7) -> 10;
-sbox(27,7) -> 15;
-sbox(28,7) -> 6;
-sbox(29,7) -> 8;
-sbox(30,7) -> 1;
-sbox(31,7) -> 6;
-sbox(32,7) -> 1;
-sbox(33,7) -> 6;
-sbox(34,7) -> 4;
-sbox(35,7) -> 11;
-sbox(36,7) -> 11;
-sbox(37,7) -> 13;
-sbox(38,7) -> 13;
-sbox(39,7) -> 8;
-sbox(40,7) -> 12;
-sbox(41,7) -> 1;
-sbox(42,7) -> 3;
-sbox(43,7) -> 4;
-sbox(44,7) -> 7;
-sbox(45,7) -> 10;
-sbox(46,7) -> 14;
-sbox(47,7) -> 7;
-sbox(48,7) -> 10;
-sbox(49,7) -> 9;
-sbox(50,7) -> 15;
-sbox(51,7) -> 5;
-sbox(52,7) -> 6;
-sbox(53,7) -> 0;
-sbox(54,7) -> 8;
-sbox(55,7) -> 15;
-sbox(56,7) -> 0;
-sbox(57,7) -> 14;
-sbox(58,7) -> 5;
-sbox(59,7) -> 2;
-sbox(60,7) -> 9;
-sbox(61,7) -> 3;
-sbox(62,7) -> 2;
-sbox(63,7) -> 12;
-sbox(0,8) -> 13;
-sbox(1,8) -> 1;
-sbox(2,8) -> 2;
-sbox(3,8) -> 15;
-sbox(4,8) -> 8;
-sbox(5,8) -> 13;
-sbox(6,8) -> 4;
-sbox(7,8) -> 8;
-sbox(8,8) -> 6;
-sbox(9,8) -> 10;
-sbox(10,8) -> 15;
-sbox(11,8) -> 3;
-sbox(12,8) -> 11;
-sbox(13,8) -> 7;
-sbox(14,8) -> 1;
-sbox(15,8) -> 4;
-sbox(16,8) -> 10;
-sbox(17,8) -> 12;
-sbox(18,8) -> 9;
-sbox(19,8) -> 5;
-sbox(20,8) -> 3;
-sbox(21,8) -> 6;
-sbox(22,8) -> 14;
-sbox(23,8) -> 11;
-sbox(24,8) -> 5;
-sbox(25,8) -> 0;
-sbox(26,8) -> 0;
-sbox(27,8) -> 14;
-sbox(28,8) -> 12;
-sbox(29,8) -> 9;
-sbox(30,8) -> 7;
-sbox(31,8) -> 2;
-sbox(32,8) -> 7;
-sbox(33,8) -> 2;
-sbox(34,8) -> 11;
-sbox(35,8) -> 1;
-sbox(36,8) -> 4;
-sbox(37,8) -> 14;
-sbox(38,8) -> 1;
-sbox(39,8) -> 7;
-sbox(40,8) -> 9;
-sbox(41,8) -> 4;
-sbox(42,8) -> 12;
-sbox(43,8) -> 10;
-sbox(44,8) -> 14;
-sbox(45,8) -> 8;
-sbox(46,8) -> 2;
-sbox(47,8) -> 13;
-sbox(48,8) -> 0;
-sbox(49,8) -> 15;
-sbox(50,8) -> 6;
-sbox(51,8) -> 12;
-sbox(52,8) -> 10;
-sbox(53,8) -> 9;
-sbox(54,8) -> 13;
-sbox(55,8) -> 0;
-sbox(56,8) -> 15;
-sbox(57,8) -> 3;
-sbox(58,8) -> 3;
-sbox(59,8) -> 5;
-sbox(60,8) -> 5;
-sbox(61,8) -> 6;
-sbox(62,8) -> 8;
-sbox(63,8) -> 11.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_extract.erl b/lib/hipe/test/bs_SUITE_data/bs_extract.erl
deleted file mode 100644
index 0492689fa8..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_extract.erl
+++ /dev/null
@@ -1,94 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Among testing other things, this module shows why performing LCM on
-%% SPARC is currently problematic. SPARC does not mark untagged values
-%% as dead when they are live over function calls which in turn causes
-%% them to be traced by the garbage collector leading to crashes.
-%%
-%% A simple way to get this behaviour is to compile just the function
-%%
-%% {bsextract,tid_internal_storage,2}
-%%
-%% with the compiler option "rtl_lcm" on and without.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(bs_extract).
-
--export([test/0]).
-
--include("bs_decode_extract.hrl").
-
--define(PDU, <<30,16,0,90,0,1,0,0,255,255,255,255,81,67,101,7,0,0,0,96,
- 6,12,146,18,14,0,15,252,16,0,0,17,0,0,128,0,2,241,33,131,
- 0,20,7,97,112,110,48,49,51,97,8,101,114,105,99,115,115,
- 111,110,2,115,101,132,0,20,128,192,35,16,1,5,0,16,5,117,
- 115,101,114,53,5,112,97,115,115,53,133,0,4,172,28,12,1,
- 133,0,4,172,28,12,3,134,0,8,145,148,113,129,0,0,0,0>>).
-
--define(RES, {ok, {mvsgT_imsi, <<81,67,101,7,0,0,0,240>>}}).
-
-test() ->
- ?RES = extract_v0_opt(1000, ?PDU),
- ok.
-
-extract_v0_opt(0, Pdu) ->
- get_external_id(Pdu);
-extract_v0_opt(N, Pdu) ->
- {ok,_} = get_external_id(Pdu),
- extract_v0_opt(N-1, Pdu).
-
-get_external_id(<<0:3,_:4,0:1,1:8,_Length:16,SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- _TID:8/binary-unit:8,_InformationElements/binary>>) ->
- {echo,#sesT_echoReqV0{},SequenceNumber};
-%% Create PDP Context Request
-%% GTP97, SNN=0
-%% (No SNDCP N-PDU number)
-get_external_id(<<0:3,_:4,0:1,16:8,_Length:16,_SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,_InformationElements/binary>>) ->
- {ok,_IMSI} = extract_imsi(TID);
-%%% Update PDP Context Request
-%%% GTP97, SNN=0
-%%% (No SNDCP N-PDU number)
-get_external_id(<<0:3,_:4,0:1,18:8,_Length:16,_SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,_InformationElements/binary>>) ->
- {ok,_IMSI} = extract_imsi(TID);
-%%% Delete PDP Context Request
-%%% GTP97, SNN=0
-%%% (No SNDCP N-PDU number)
-get_external_id(<<0:3,_:4,0:1,20:8,_Length:16,_SequenceNumber:16,
- _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
- TID:8/binary-unit:8,_InformationElements/binary>>) ->
- {ok,_IMSI} = extract_imsi(TID);
-%%% Error handling: GTP Message Too Short
-%%% Error handling: Unknown GTP Signalling message.
-%%% Error handling: Unexpected GTP Signalling message.
-get_external_id(_GTP_Message) ->
- fault.
-
-%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%% extract_imsi/1
-%% Get the IMSI element from TID
-extract_imsi(TID) ->
- {ok,#mvsgT_tid{imsi=IMSI}} = tid_internal_storage(TID,[]),
- {ok,IMSI}.
-
-%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-%%% tid_internal_storage/3
-%%% Convert TID binary to internal datatype
-tid_internal_storage(Bin,_) ->
- Size = byte_size(Bin) - 1,
- <<Front:Size/binary,NSAPI:4,DigitN:4>> = Bin,
- Result =
- case DigitN of
- 2#1111 ->
- #mvsgT_tid{imsi = #mvsgT_imsi{value=Front}, nsapi = NSAPI};
- _ ->
- Value = <<Front/binary,2#1111:4,DigitN:4>>,
- #mvsgT_tid{imsi = #mvsgT_imsi{value = Value}, nsapi = NSAPI}
- end,
- {ok,Result}.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_flatb.erl b/lib/hipe/test/bs_SUITE_data/bs_flatb.erl
deleted file mode 100644
index 6163917965..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_flatb.erl
+++ /dev/null
@@ -1,29 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------------
-%% Program which resulted in a badarg crash when compiled to native code.
-%% The problem was that hipe_icode_primops was stating that the primop
-%% {bs_start_match, ok_matchstate} could not fail which made the icode_type
-%% pass removing the third clause of flatb/1.
-%%
-%% (The program was working correctly with hipe option 'no_icode_type'.)
-%%
-%% Reported by Andreas Sandberg on 3/1/2011 and fixed by Kostis on 5/1/2011
-%% with the help of Per Gustafsson.
-%% --------------------------------------------------------------------------
--module(bs_flatb).
-
--export([hipe_options/0, test/0]).
-
-hipe_options() ->
- [icode_type].
-
-test() ->
- [] = flatb([<<>>], []),
- ok.
-
-flatb(<<X:8, Rest/binary>>, Acc) ->
- flatb(Rest, [X|Acc]);
-flatb(<<>>, Acc) ->
- Acc;
-flatb([V], Acc) ->
- flatb(V, Acc).
diff --git a/lib/hipe/test/bs_SUITE_data/bs_id3.erl b/lib/hipe/test/bs_SUITE_data/bs_id3.erl
deleted file mode 100644
index a6152f05cd..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_id3.erl
+++ /dev/null
@@ -1,75 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%==========================================================================
-%% From: Tomas Stejskal -- 23/02/2008
-%% I've found some strange behavior regarding binary matching. The module's
-%% purpose is reading an id3 version 1 or version 1.1 tag from an mp3 bin.
-%% When I use the function read_v1_or_v11_tag on a mp3 binary containing
-%% version 1 tag, it returns an error. However, when the function
-%% read_only_v1_tag is applied on the same file, it reads the tag data
-%% correctly. The only difference between these two functions is that the
-%% former has an extra branch to read version 1.1 tag.
-%% This was a BEAM compiler bug which was fixed by a patch to beam_dead.
-%%==========================================================================
-
--module(bs_id3).
-
--export([test/0]).
-
--define(BIN, <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,68,97,110,105,101,108,32,76,97,110,
- 100,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,101,115,116,
- 32,79,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 50,48,48,48,50,48,48,48,32,45,32,66,101,115,116,32,79,102,
- 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,12>>).
-
-test() ->
- R1 = parse_only_v1_tag(?BIN),
- R2 = parse_v1_or_v11_tag(?BIN),
- %% io:format("~p\n~p\n", [R1, R2]),
- R1 = R2, % crash if not equal
- ok.
-
-parse_only_v1_tag(<<"TAG", Title:30/binary,
- Artist:30/binary, Album:30/binary,
- _Year:4/binary, _Comment:30/binary,
- _Genre:8>>) ->
- {ok,
- {"ID3v1",
- [{title, trim(Title)},
- {artist, trim(Artist)},
- {album, trim(Album)}]}};
-parse_only_v1_tag(_) ->
- error.
-
-parse_v1_or_v11_tag(<<"TAG", Title:30/binary,
- Artist:30/binary, Album:30/binary,
- _Year:4/binary, _Comment:28/binary,
- 0:8, Track:8, _Genre:8>>) ->
- {ok,
- {"ID3v1.1",
- [{track, Track}, {title, trim(Title)},
- {artist, trim(Artist)}, {album, trim(Album)}]}};
-parse_v1_or_v11_tag(<<"TAG", Title:30/binary,
- Artist:30/binary, Album:30/binary,
- _Year:4/binary, _Comment:30/binary,
- _Genre:8>>) ->
- {ok,
- {"ID3v1",
- [{title, trim(Title)},
- {artist, trim(Artist)},
- {album, trim(Album)}]}};
-parse_v1_or_v11_tag(_) ->
- error.
-
-trim(Bin) ->
- list_to_binary(trim_blanks(binary_to_list(Bin))).
-
-trim_blanks(L) ->
- lists:reverse(skip_blanks_and_zero(lists:reverse(L))).
-
-skip_blanks_and_zero([$\s|T]) ->
- skip_blanks_and_zero(T);
-skip_blanks_and_zero([0|T]) ->
- skip_blanks_and_zero(T);
-skip_blanks_and_zero(L) ->
- L.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_match.erl b/lib/hipe/test/bs_SUITE_data/bs_match.erl
deleted file mode 100644
index b241ea8d35..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_match.erl
+++ /dev/null
@@ -1,289 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_match.erl
-%%% Authors : Per Gustafsson <pergu@it.uu.se>, Kostis Sagonas <kostis@it.uu.se>
-%%% Purpose : Tests matching and construction of binaries
-%%% TODO : Add binary and float tests
-%%% Created : 20 Feb 2004
-%%%-------------------------------------------------------------------
--module(bs_match).
-
--export([test/0]).
-
-test() ->
- Funs = [fun test_aligned/0, fun test_unaligned/0,
- fun test_zero_tail/0, fun test_integer_matching/0,
- fun test_writable_bin/0, fun test_match_huge_bin/0],
- lists:foreach(fun (F) -> ok = F() end, Funs).
-
-%%-------------------------------------------------------------------
-%% Test aligned accesses
-
-test_aligned() ->
- 10 = aligned_skip_bits_all(1, <<10,11,12>>),
- ok = aligned().
-
-aligned_skip_bits_all(N, Bin) ->
- <<X:N/integer-unit:8, _/binary>> = Bin,
- X.
-
-aligned() ->
- Tail1 = mkbin([]),
- {258, Tail1} = al_get_tail_used(mkbin([1,2])),
- Tail2 = mkbin(lists:seq(1, 127)),
- {35091, Tail2} = al_get_tail_used(mkbin([137,19|Tail2])),
- 64896 = al_get_tail_unused(mkbin([253,128])),
- 64895 = al_get_tail_unused(mkbin([253,127|lists:seq(42, 255)])),
- Tail3 = mkbin(lists:seq(0, 19)),
- {0, Tail1} = get_dyn_tail_used(Tail1, 0),
- {0, Tail3} = get_dyn_tail_used(mkbin([Tail3]), 0),
- {73, Tail3} = get_dyn_tail_used(mkbin([73|Tail3]), 8),
- 0 = get_dyn_tail_unused(mkbin([]), 0),
- 233 = get_dyn_tail_unused(mkbin([233]), 8),
- 23 = get_dyn_tail_unused(mkbin([23,22,2]), 8),
- ok.
-
-mkbin(L) when is_list(L) -> list_to_binary(L).
-
-al_get_tail_used(<<A:16,T/binary>>) -> {A, T}.
-
-al_get_tail_unused(<<A:16,_/binary>>) -> A.
-
-%%-------------------------------------------------------------------
-%% Test unaligned accesses
-
-test_unaligned() ->
- 10 = unaligned_skip_bits_all(8, <<10,11,12>>),
- ok = unaligned().
-
-unaligned_skip_bits_all(N, Bin) ->
- <<X:N, _/binary>> = Bin,
- X.
-
-unaligned() ->
- {'EXIT', {function_clause,_}} = (catch get_tail_used(mkbin([42]))),
- {'EXIT', {{badmatch,_},_}} = (catch get_dyn_tail_used(mkbin([137]), 3)),
- {'EXIT', {function_clause,_}} = (catch get_tail_unused(mkbin([42,33]))),
- {'EXIT', {{badmatch,_},_}} = (catch get_dyn_tail_unused(mkbin([44]), 7)),
- ok.
-
-get_tail_used(<<A:1, T/binary>>) -> {A, T}.
-
-get_tail_unused(<<A:15, _/binary>>) -> A.
-
-get_dyn_tail_used(Bin, Sz) ->
- <<A:Sz, T/binary>> = Bin,
- {A,T}.
-
-get_dyn_tail_unused(Bin, Sz) ->
- <<A:Sz, _T/binary>> = Bin,
- A.
-
-%%-------------------------------------------------------------------
-%% Test zero tail
-
-test_zero_tail() ->
- 42 = zt8(mkbin([42])),
- {'EXIT', {function_clause, _}} = (catch zt8(mkbin([1,2]))),
- {'EXIT', {function_clause, _}} = (catch zt44(mkbin([1,2]))),
- ok.
-
-zt8(<<A:8>>) -> A.
-
-zt44(<<_:4,_:4>>) -> ok.
-
-%%-------------------------------------------------------------------
-%% Test integer matching
-
-test_integer_matching() ->
- ok = test_static_integer_matching_1(),
- ok = test_static_integer_matching_2(),
- ok = test_static_integer_matching_3(),
- ok = test_static_integer_matching_4(),
- DynFun = fun (N) -> ok = test_dynamic_integer_matching(N) end,
- lists:foreach(DynFun, [28, 27, 9, 17, 25, 8, 16, 24, 32]).
-
-test_static_integer_matching_1() ->
- <<0:6, -25:28/integer-signed, 0:6>> = s11(),
- <<0:6, -25:28/integer-little-signed, 0:6>> = s12(),
- <<0:6, 25:28/integer-little, 0:6>> = s13(),
- <<0:6, 25:28, 0:6>> = s14(),
- ok.
-
-s11() ->
- <<0:6, -25:28/integer-signed, 0:6>>.
-s12() ->
- <<0:6, -25:28/integer-little-signed, 0:6>>.
-s13() ->
- <<0:6, 25:28/integer-little, 0:6>>.
-s14() ->
- <<0:6, 25:28, 0:6>>.
-
-test_static_integer_matching_2() ->
- <<0:6, -25:20/integer-signed, 0:6>> = s21(),
- <<0:6, -25:20/integer-little-signed, 0:6>> = s22(),
- <<0:6, 25:20/integer-little, 0:6>> = s23(),
- <<0:6, 25:20, 0:6>> = s24(),
- ok.
-
-s21() ->
- <<0:6, -25:20/integer-signed, 0:6>>.
-s22() ->
- <<0:6, -25:20/integer-little-signed, 0:6>>.
-s23() ->
- <<0:6, 25:20/integer-little, 0:6>>.
-s24() ->
- <<0:6, 25:20, 0:6>>.
-
-test_static_integer_matching_3() ->
- <<0:6, -25:12/integer-signed, 0:6>> = s31(),
- <<0:6, -25:12/integer-little-signed, 0:6>> = s32(),
- <<0:6, 25:12/integer-little, 0:6>> = s33(),
- <<0:6, 25:12, 0:6>> = s34(),
- ok.
-
-s31() ->
- <<0:6, -25:12/integer-signed, 0:6>>.
-s32() ->
- <<0:6, -25:12/integer-little-signed, 0:6>>.
-s33() ->
- <<0:6, 25:12/integer-little, 0:6>>.
-s34() ->
- <<0:6, 25:12, 0:6>>.
-
-test_static_integer_matching_4() ->
- <<0:6, -3:4/integer-signed, 0:6>> = s41(),
- <<0:6, -3:4/integer-little-signed, 0:6>> = s42(),
- <<0:6, 7:4/integer-little, 0:6>> = s43(),
- <<0:6, 7:4, 0:6>> = s44(),
- ok.
-
-s41() ->
- <<0:6, -3:4/integer-signed, 0:6>>.
-s42() ->
- <<0:6, -3:4/integer-little-signed, 0:6>>.
-s43() ->
- <<0:6, 7:4/integer-little, 0:6>>.
-s44() ->
- <<0:6, 7:4, 0:6>>.
-
-test_dynamic_integer_matching(N) ->
- S = 32 - N,
- <<-12:N/integer-signed, 0:S>> = <<-12:N/integer-signed, 0:S>>,
- <<-12:N/integer-little-signed, 0:S>> = <<-12:N/integer-little-signed, 0:S>>,
- <<12:N/integer, 0:S>> = <<12:N/integer, 0:S>>,
- <<12:N/integer-little, 0:S>> = <<12:N/integer-little, 0:S>>,
- ok.
-
-%%-------------------------------------------------------------------
-%% Test writable bin -- added by Sverker Eriksson
-
-test_writable_bin() ->
- test_writable_bin(<<>>, 0),
- ok.
-
-test_writable_bin(Bin, 128) ->
- Bin;
-test_writable_bin(Bin0, N) when N < 128 ->
- Bin1 = <<Bin0/binary, N>>,
- <<_/utf8, _/binary>> = Bin1,
- test_writable_bin(Bin1, N+1).
-
-%%-------------------------------------------------------------------
-%% Test matching with a huge bin -- taken from bs_match_bin_SUITE
-
-test_match_huge_bin() ->
- Bin = <<0:(1 bsl 27),13:8>>,
- skip_huge_bin_1(1 bsl 27, Bin),
- 16777216 = match_huge_bin_1(1 bsl 27, Bin),
- %% Test overflowing the size of a binary field.
- nomatch = overflow_huge_bin_skip_32(Bin),
- nomatch = overflow_huge_bin_32(Bin),
- nomatch = overflow_huge_bin_skip_64(Bin),
- nomatch = overflow_huge_bin_64(Bin),
- %% Size in variable
- ok = overflow_huge_bin(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
- ok = overflow_huge_bin_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
- ok.
-
-overflow_huge_bin(Bin, [Sz0|Sizes]) ->
- Sz = id(1 bsl Sz0),
- case Bin of
- <<_:Sz/binary-unit:8,0,_/binary>> ->
- {error,Sz};
- _ ->
- case Bin of
- <<NewBin:Sz/binary-unit:8,0,_/binary>> ->
- {error,Sz,size(NewBin)};
- _ ->
- overflow_huge_bin(Bin, Sizes)
- end
- end;
-overflow_huge_bin(_, []) -> ok.
-
-overflow_huge_bin_unit128(Bin, [Sz0|Sizes]) ->
- Sz = id(1 bsl Sz0),
- case Bin of
- <<_:Sz/binary-unit:128,0,_/binary>> ->
- {error,Sz};
- _ ->
- case Bin of
- <<NewBin:Sz/binary-unit:128,0,_/binary>> ->
- {error,Sz,size(NewBin)};
- _ ->
- overflow_huge_bin_unit128(Bin, Sizes)
- end
- end;
-overflow_huge_bin_unit128(_, []) -> ok.
-
-skip_huge_bin_1(I, Bin) ->
- <<_:I/binary-unit:1,13>> = Bin,
- ok.
-
-match_huge_bin_1(I, Bin) ->
- case Bin of
- <<Val:I/binary-unit:1,13>> -> size(Val);
- _ -> nomatch
- end.
-
-overflow_huge_bin_skip_32(<<_:4294967296/binary,0,_/binary>>) -> 1; % 1 bsl 32
-overflow_huge_bin_skip_32(<<_:33554432/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
-overflow_huge_bin_skip_32(<<_:67108864/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
-overflow_huge_bin_skip_32(<<_:134217728/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
-overflow_huge_bin_skip_32(<<_:268435456/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
-overflow_huge_bin_skip_32(<<_:536870912/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
-overflow_huge_bin_skip_32(<<_:1073741824/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
-overflow_huge_bin_skip_32(<<_:2147483648/binary-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
-overflow_huge_bin_skip_32(_) -> nomatch.
-
-overflow_huge_bin_32(<<Bin:4294967296/binary,_/binary>>) -> {1,Bin}; % 1 bsl 32
-overflow_huge_bin_32(<<Bin:33554432/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 25
-overflow_huge_bin_32(<<Bin:67108864/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 26
-overflow_huge_bin_32(<<Bin:134217728/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 27
-overflow_huge_bin_32(<<Bin:268435456/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 28
-overflow_huge_bin_32(<<Bin:536870912/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 29
-overflow_huge_bin_32(<<Bin:1073741824/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 30
-overflow_huge_bin_32(<<Bin:2147483648/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 31
-overflow_huge_bin_32(_) -> nomatch.
-
-overflow_huge_bin_skip_64(<<_:18446744073709551616/binary,0,_/binary>>) -> 1; % 1 bsl 64
-overflow_huge_bin_skip_64(<<_:144115188075855872/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 57
-overflow_huge_bin_skip_64(<<_:288230376151711744/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 58
-overflow_huge_bin_skip_64(<<_:576460752303423488/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 59
-overflow_huge_bin_skip_64(<<_:1152921504606846976/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 60
-overflow_huge_bin_skip_64(<<_:2305843009213693952/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 61
-overflow_huge_bin_skip_64(<<_:4611686018427387904/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 62
-overflow_huge_bin_skip_64(<<_:9223372036854775808/binary-unit:8,_/binary>>) -> 8; % 1 bsl 63
-overflow_huge_bin_skip_64(_) -> nomatch.
-
-overflow_huge_bin_64(<<Bin:18446744073709551616/binary,_/binary>>) -> {1,Bin}; % 1 bsl 64
-overflow_huge_bin_64(<<Bin:144115188075855872/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 57
-overflow_huge_bin_64(<<Bin:288230376151711744/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 58
-overflow_huge_bin_64(<<Bin:576460752303423488/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 59
-overflow_huge_bin_64(<<Bin:1152921504606846976/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 60
-overflow_huge_bin_64(<<Bin:2305843009213693952/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 61
-overflow_huge_bin_64(<<Bin:4611686018427387904/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 62
-overflow_huge_bin_64(<<Bin:9223372036854775808/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 63
-overflow_huge_bin_64(_) -> nomatch.
-
-id(I) -> I.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_match_compiler.erl b/lib/hipe/test/bs_SUITE_data/bs_match_compiler.erl
deleted file mode 100644
index 4cb48ff57e..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_match_compiler.erl
+++ /dev/null
@@ -1,1235 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_match_compiler.erl
-%%%
-%%%-------------------------------------------------------------------
--module(bs_match_compiler).
--compile(nowarn_shadow_vars).
-
--export([test/0]).
--export([exported_id/1, exported_id/2]). %% needed by a test
-
-test() ->
- Funs = [fun fun_shadow/0, fun int_float/0, fun otp_5269/0, fun null_fields/0,
- fun wiger/0, fun bin_tail/0, fun save_restore/0,
- fun partitioned_bs_match/0, fun function_clause/0, fun unit/0,
- fun shared_sub_bins/0, fun bin_and_float/0, fun dec_subidentifiers/0,
- fun skip_optional_tag/0, fun wfbm/0, fun degenerated_match/0,
- fun bs_sum/0, fun coverage/0, fun multiple_uses/0, fun zero_label/0,
- fun followed_by_catch/0, fun matching_meets_construction/0,
- fun simon/0, fun matching_and_andalso/0,
- fun otp_7188/0, fun otp_7233/0, fun otp_7240/0, fun otp_7498/0,
- fun match_string/0, fun zero_width/0, fun bad_size/0, fun haystack/0,
- fun cover_beam_bool/0, fun matched_out_size/0, fun follow_fail_br/0,
- fun no_partition/0, fun calling_a_binary/0, fun binary_in_map/0,
- fun match_string_opt/0, fun map_and_binary/0,
- fun unsafe_branch_caching/0],
- lists:foreach(fun (F) -> ok = F() end, Funs).
-
-
-%%--------------------------------------------------------------------
-%% OTP-5270
-
-fun_shadow() ->
- 7 = fun_shadow_1(),
- 7 = fun_shadow_2(8),
- 7 = fun_shadow_3(),
- no = fun_shadow_4(8),
- ok.
-
-fun_shadow_1() ->
- L = 8,
- F = fun(<<L:L,B:L>>) -> B end,
- F(<<16:8, 7:16>>).
-
-fun_shadow_2(L) ->
- F = fun(<<L:L,B:L>>) -> B end,
- F(<<16:8, 7:16>>).
-
-fun_shadow_3() ->
- L = 8,
- F = fun(<<L:L,B:L,L:L>>) -> B end,
- F(<<16:8, 7:16,16:16>>).
-
-fun_shadow_4(L) ->
- F = fun(<<L:L,B:L,L:L>>) -> B;
- (_) -> no end,
- F(<<16:8, 7:16,15:16>>).
-
-%%--------------------------------------------------------------------
-%% OTP-5323
-
-int_float() ->
- <<103133.0:64/float>> = <<103133:64/float>>,
- <<103133:64/float>> = <<103133:64/float>>,
- ok.
-
-%%--------------------------------------------------------------------
-%% Stolen from erl_eval_SUITE and modified.
-%% OTP-5269. Bugs in the bit syntax.
-
-otp_5269() ->
- check(fun() -> L = 8, F = fun(<<A:L,B:A>>) -> B end, F(<<16:8, 7:16>>) end, 7),
- check(fun() -> L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end, 7),
- check(fun() -> U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end, 32),
- check(fun() -> U = 8, [U || <<U:U>> <- [<<32:8>>]] end, [32]),
- check(fun() -> [X || <<A:8, B:A>> <- [<<16:8,19:16>>],
- <<X:8>> <- [<<B:8>>]] end,
- [19]),
- check(fun() -> A = 4, B = 28, _ = bit_size(<<13:(A+(X=B))>>), X end, 28),
- check(fun() ->
- <<Size,B:Size/binary,Rest/binary>> = <<2,"AB","CD">>,
- {Size,B,Rest}
- end, {2,<<"AB">>,<<"CD">>}),
- check(fun() -> X = 32, [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
- %% "binsize variable" ^
- [1,2]),
- check(fun() ->
- (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) ->
- case A of
- B -> wrong;
- _ -> ok
- end
- end)(<<1,2,3,4>>) end,
- ok),
- ok.
-
-%%--------------------------------------------------------------------
-
-null_fields() ->
- check(fun() ->
- W = id(0),
- F = fun(<<_:W>>) -> tail;
- (<<>>) -> empty
- end,
- F(<<>>)
- end, tail),
- check(fun() ->
- F = fun(<<_/binary>>) -> tail;
- (<<>>) -> empty
- end,
- F(<<>>)
- end, tail),
- ok.
-
-%%--------------------------------------------------------------------
-
-wiger() ->
- ok1 = wcheck(<<3>>),
- ok2 = wcheck(<<1,2,3>>),
- ok3 = wcheck(<<4>>),
- {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
- {error,<<>>} = wcheck(<<>>),
- ok.
-
-wcheck(<<A>>) when A==3->
- ok1;
-wcheck(<<_,_:2/binary>>) ->
- ok2;
-wcheck(<<_>>) ->
- ok3;
-wcheck(Other) ->
- {error,Other}.
-
-%%--------------------------------------------------------------------
-
-bin_tail() ->
- S = <<"abcde">>,
- $a = bin_tail_c(S, 0),
- $c = bin_tail_c(S, 2),
- $e = bin_tail_c(S, 4),
- {'EXIT',_} = (catch bin_tail_c(S, 5)),
- {'EXIT',_} = (catch bin_tail_c_var(S, 5)),
-
- $a = bin_tail_d(S, 0),
- $b = bin_tail_d(S, 8),
- $d = bin_tail_d(S, 3*8),
- {'EXIT',_} = (catch bin_tail_d_dead(S, 1)),
- {'EXIT',_} = (catch bin_tail_d_dead(S, 9)),
- {'EXIT',_} = (catch bin_tail_d_dead(S, 5*8)),
- {'EXIT',_} = (catch bin_tail_d_var(S, 1)),
-
- ok = bin_tail_e(<<2:2,0:1,1:5>>),
- ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>),
- error = bin_tail_e(<<3:2,1:1,1:5,42:64>>),
- error = bin_tail_e(<<>>),
- ok.
-
-bin_tail_c(Bin, Offset) ->
- Res = bin_tail_c_dead(Bin, Offset),
- <<_:Offset/binary,_,Tail/binary>> = Bin,
- {Res,Tail} = bin_tail_c_var(Bin, Offset),
- Res.
-
-bin_tail_c_dead(Bin, Offset) ->
- <<_:Offset/binary,C,_/binary>> = Bin,
- C.
-
-bin_tail_c_var(Bin, Offset) ->
- <<_:Offset/binary,C,Tail/binary>> = Bin,
- {C,Tail}.
-
-bin_tail_d(Bin, BitOffset) ->
- Res = bin_tail_d_dead(Bin, BitOffset),
- <<_:BitOffset,_:8,Tail/binary>> = Bin,
- {Res,Tail} = bin_tail_d_var(Bin, BitOffset),
- Res.
-
-bin_tail_d_dead(Bin, BitOffset) ->
- <<_:BitOffset,C,_/binary>> = Bin,
- C.
-
-bin_tail_d_var(Bin, BitOffset) ->
- <<_:BitOffset,C,Tail/binary>> = Bin,
- {C,Tail}.
-
-bin_tail_e(Bin) ->
- case bin_tail_e_dead(Bin) of
- ok ->
- <<_,Tail/binary>> = Bin,
- Tail = bin_tail_e_var(Bin),
- ok;
- error ->
- bin_tail_e_var(Bin)
- end.
-
-bin_tail_e_dead(Bin) ->
- case Bin of
- %% The binary is aligned at the end; neither the bs_skip_bits2 nor
- %% bs_test_tail2 instructions are needed.
- <<2:2,_:1,1:5,_/binary>> -> ok;
- _ -> error
- end.
-
-bin_tail_e_var(Bin) ->
- case Bin of
- %% The binary is aligned at the end; neither the bs_skip_bits2 nor
- %% bs_test_tail2 instructions are needed.
- <<2:2,_:1,1:5,Tail/binary>> -> Tail;
- _ -> error
- end.
-
-%%--------------------------------------------------------------------
-
-save_restore() ->
- 0 = save_restore_1(<<0:2,42:6>>),
- {1,3456} = save_restore_1(<<1:2,3456:14>>),
- {2,7981234} = save_restore_1(<<2:2,7981234:30>>),
- {3,763967493838} = save_restore_1(<<0:2,763967493838:62>>),
-
- A = <<" x">>,
- B = <<".x">>,
- C = <<"-x">>,
-
- {" ",<<"x">>} = lll(A),
- {" ",<<"x">>} = mmm(A),
- {" ",<<"x">>} = nnn(A),
- {" ",<<"x">>} = ooo(A),
-
- {".",<<"x">>} = lll(B),
- {".",<<"x">>} = mmm(B),
- {".",<<"x">>} = nnn(B),
- {".",<<"x">>} = ooo(B),
-
- {"-",<<"x">>} = lll(C),
- {"-",<<"x">>} = mmm(C),
- {"-",<<"x">>} = nnn(C),
- {"-",<<"x">>} = ooo(C),
-
- Bin = <<-1:64>>,
- case bad_float_unpack_match(Bin) of
- -1 -> ok;
- _Other -> bad_return_value_probably_NaN
- end.
-
-save_restore_1(Bin) ->
- case Bin of
- <<0:2,_:6>> -> 0;
- <<1:2,A:14>> -> {1,A};
- <<2:2,A:30>> -> {2,A};
- <<A:64>> -> {3,A}
- end.
-
-lll(<<Char, Tail/binary>>) -> {[Char],Tail}.
-
-mmm(<<$.,$.,$., Tail/binary>>) -> Tail;
-mmm(<<$\s,$-,$\s, Tail/binary>>) -> Tail;
-mmm(<<Char, Tail/binary>>) -> {[Char],Tail}. %% Buggy Tail!
-
-nnn(<<"...", Tail/binary>>) -> Tail;
-nnn(<<" - ", Tail/binary>>) -> Tail;
-nnn(<<Char, Tail/binary>>) -> {[Char],Tail}. %% Buggy Tail!
-
-ooo(<<" - ", Tail/binary>>) -> Tail;
-ooo(<<Char, Tail/binary>>) -> {[Char],Tail}.
-
-bad_float_unpack_match(<<F:64/float>>) -> F;
-bad_float_unpack_match(<<I:64/integer-signed>>) -> I.
-
-%%--------------------------------------------------------------------
-
-partitioned_bs_match() ->
- <<1,2,3>> = partitioned_bs_match(blurf, <<42,1,2,3>>),
- error = partitioned_bs_match(10, <<7,8,15,13>>),
- error = partitioned_bs_match(100, {a,tuple,is,'not',a,binary}),
- ok = partitioned_bs_match(0, <<>>),
- fc(partitioned_bs_match, [-1,blurf],
- catch partitioned_bs_match(-1, blurf)),
- fc(partitioned_bs_match, [-1,<<1,2,3>>],
- catch partitioned_bs_match(-1, <<1,2,3>>)),
- {17,<<1,2,3>>} = partitioned_bs_match_2(1, <<17,1,2,3>>),
- {7,<<1,2,3>>} = partitioned_bs_match_2(7, <<17,1,2,3>>),
-
- fc(partitioned_bs_match_2, [4,<<0:17>>],
- catch partitioned_bs_match_2(4, <<0:17>>)),
-
- anything = partitioned_bs_match_3(anything, <<42>>),
- ok = partitioned_bs_match_3(1, 2),
- ok.
-
-partitioned_bs_match(_, <<42:8,T/binary>>) -> T;
-partitioned_bs_match(N, _) when N > 0 -> error;
-partitioned_bs_match(_, <<>>) -> ok.
-
-partitioned_bs_match_2(1, <<B:8,T/binary>>) -> {B,T};
-partitioned_bs_match_2(Len, <<_:8,T/binary>>) -> {Len,T}.
-
-partitioned_bs_match_3(Var, <<_>>) -> Var;
-partitioned_bs_match_3(1, 2) -> ok.
-
-%%--------------------------------------------------------------------
-
-function_clause() ->
- ok = function_clause_1(<<0,7,0,7,42>>),
- fc(function_clause_1, [<<0,1,2,3>>],
- catch function_clause_1(<<0,1,2,3>>)),
- fc(function_clause_1, [<<0,1,2,3>>],
- catch function_clause_1(<<0,7,0,1,2,3>>)),
-
- ok = function_clause_2(<<0,7,0,7,42>>),
- ok = function_clause_2(<<255>>),
- ok = function_clause_2(<<13:4>>),
- fc(function_clause_2, [<<0,1,2,3>>],
- catch function_clause_2(<<0,1,2,3>>)),
- fc(function_clause_2, [<<0,1,2,3>>],
- catch function_clause_2(<<0,7,0,1,2,3>>)),
- ok.
-
-function_clause_1(<<0:8,7:8,T/binary>>) ->
- function_clause_1(T);
-function_clause_1(<<_:8>>) ->
- ok.
-
-function_clause_2(<<0:8,7:8,T/binary>>) ->
- function_clause_2(T);
-function_clause_2(<<_:8>>) ->
- ok;
-function_clause_2(<<_:4>>) ->
- ok.
-
-%%--------------------------------------------------------------------
-
-unit() ->
- 42 = peek1(<<42>>),
- 43 = peek1(<<43,1,2>>),
- 43 = peek1(<<43,1,2,(-1):1>>),
- 43 = peek1(<<43,1,2,(-1):2>>),
- 43 = peek1(<<43,1,2,(-1):7>>),
-
- 99 = peek8(<<99>>),
- 100 = peek8(<<100,101>>),
- fc(peek8, [<<100,101,0:1>>], catch peek8(<<100,101,0:1>>)),
-
- 37484 = peek16(<<37484:16>>),
- 37489 = peek16(<<37489:16,5566:16>>),
- fc(peek16, [<<8>>], catch peek16(<<8>>)),
- fc(peek16, [<<42:15>>], catch peek16(<<42:15>>)),
- fc(peek16, [<<1,2,3,4,5>>], catch peek16(<<1,2,3,4,5>>)),
-
- 127 = peek7(<<127:7>>),
- 100 = peek7(<<100:7,19:7>>),
- fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)),
- ok.
-
-peek1(<<B:8,_/bitstring>>) -> B.
-
-peek7(<<B:7,_/binary-unit:7>>) -> B.
-
-peek8(<<B:8,_/binary>>) -> B.
-
-peek16(<<B:16,_/binary-unit:16>>) -> B.
-
-%%--------------------------------------------------------------------
-
-shared_sub_bins() ->
- {15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0),
- ok.
-
-sum(<<B,T/binary>>, Acc, Sum) ->
- sum(T, [T|Acc], Sum+B);
-sum(<<>>, Last, Sum) -> {Sum,Last}.
-
-%%--------------------------------------------------------------------
-
-bin_and_float() ->
- 14.0 = bin_and_float(<<1.0/float,2.0/float,3.0/float>>, 0.0),
- ok.
-
-bin_and_float(<<X/float,Y/float,Z/float,T/binary>>, Sum) when is_float(X),
- is_float(Y),
- is_float(Z) ->
- bin_and_float(T, Sum+X*X+Y*Y+Z*Z);
-bin_and_float(<<>>, Sum) -> Sum.
-
-%%--------------------------------------------------------------------
-
-dec_subidentifiers() ->
- {[],<<1,2,3>>} =
- do_dec_subidentifiers(<<1:1,42:7,1:1,99:7,1,2,3>>, 0, [], 2),
- {[5389],<<1,2,3>>} =
- do_dec_subidentifiers(<<1:1,42:7,0:1,13:7,1,2,3>>, 0, [], 2),
- {[3,2,1],not_a_binary} = dec_subidentifiers(not_a_binary, any, [1,2,3], 0),
- ok.
-
-do_dec_subidentifiers(Buffer, Av, Al, Len) ->
- Res = dec_subidentifiers(Buffer, Av, Al, Len),
- Res = dec_subidentifiers2(Buffer, Av, Al, Len),
- Res = dec_subidentifiers4(Buffer, Av, Al, Len),
- Res = dec_subidentifiers3(Buffer, Av, Al, Len).
-
-dec_subidentifiers(Buffer, _Av, Al, 0) ->
- {lists:reverse(Al),Buffer};
-dec_subidentifiers(<<1:1,H:7,T/binary>>, Av, Al, Len) ->
- dec_subidentifiers(T, (Av bsl 7) bor H, Al, Len-1);
-dec_subidentifiers(<<H,T/binary>>, Av, Al, Len) ->
- dec_subidentifiers(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
-
-dec_subidentifiers2(<<Buffer/binary>>, _Av, Al, 0) ->
- {lists:reverse(Al),Buffer};
-dec_subidentifiers2(<<1:1,H:7,T/binary>>, Av, Al, Len) ->
- dec_subidentifiers2(T, (Av bsl 7) bor H, Al, Len-1);
-dec_subidentifiers2(<<H,T/binary>>, Av, Al, Len) ->
- dec_subidentifiers2(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
-
-dec_subidentifiers3(Buffer, _Av, Al, 0) when is_binary(Buffer) ->
- {lists:reverse(Al),Buffer};
-dec_subidentifiers3(<<1:1,H:7,T/binary>>, Av, Al, Len) ->
- dec_subidentifiers3(T, (Av bsl 7) bor H, Al, Len-1);
-dec_subidentifiers3(<<H,T/binary>>, Av, Al, Len) ->
- dec_subidentifiers3(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
-
-dec_subidentifiers4(<<1:1,H:7,T/binary>>, Av, Al, Len) when Len =/= 0 ->
- dec_subidentifiers4(T, (Av bsl 7) bor H, Al, Len-1);
-dec_subidentifiers4(<<H,T/binary>>, Av, Al, Len) when Len =/= 0 ->
- dec_subidentifiers4(T, 0, [((Av bsl 7) bor H)|Al], Len-1);
-dec_subidentifiers4(Buffer, _Av, Al, 0) ->
- {lists:reverse(Al),Buffer}.
-
-%%--------------------------------------------------------------------
-
-skip_optional_tag() ->
- {ok,<<>>} = skip_optional_tag(<<42>>, <<42>>),
- {ok,<<>>} = skip_optional_tag(<<42,1>>, <<42,1>>),
- {ok,<<1,2,3>>} = skip_optional_tag(<<42>>, <<42,1,2,3>>),
- missing = skip_optional_tag(<<2:3>>, blurf),
- ok.
-
-skip_optional_tag(<<>>, Binary) ->
- {ok,Binary};
-skip_optional_tag(<<Tag,RestTag/binary>>, <<Tag,Rest/binary>>) ->
- skip_optional_tag(RestTag, Rest);
-skip_optional_tag(_, _) -> missing.
-
-%%--------------------------------------------------------------------
-
--define(DATELEN, 16).
-
-wfbm() ->
- %% check_for_dot_or_space and get_tail is from wfbm4 by Steve Vinoski,
- %% with modifications.
- {nomatch,0} = check_for_dot_or_space(<<" ">>),
- {nomatch,0} = check_for_dot_or_space(<<" abc">>),
- {ok,<<"abcde">>} = check_for_dot_or_space(<<"abcde 34555">>),
- {nomatch,0} = check_for_dot_or_space(<<".gurka">>),
- {nomatch,1} = check_for_dot_or_space(<<"g.urka">>),
- nomatch = get_tail(<<>>),
- {ok,<<"2007/10/23/blurf">>} = get_tail(<<"200x/2007/10/23/blurf ">>),
- {skip,?DATELEN+5} = get_tail(<<"200x/2007/10/23/blurf.">>),
- nomatch = get_tail(<<"200y.2007.10.23.blurf ">>),
- {'EXIT',_} = (catch get_tail({no,binary,at,all})),
- {'EXIT',_} = (catch get_tail(no_binary)),
- ok.
-
-check_for_dot_or_space(Bin) ->
- check_for_dot_or_space(Bin, 0).
-
-check_for_dot_or_space(<<$\s, _/binary>>, 0) ->
- {nomatch,0};
-check_for_dot_or_space(Bin, Len) ->
- case Bin of
- <<Front:Len/binary, $\s, _/binary>> ->
- {ok,Front};
- <<_:Len/binary, $., _/binary>> ->
- {nomatch,Len};
- _ ->
- check_for_dot_or_space(Bin, Len+1)
- end.
-
-get_tail(<<>>) ->
- nomatch;
-get_tail(Bin) ->
- <<Front:?DATELEN/binary, Tail/binary>> = Bin,
- case Front of
- <<_:3/binary,"x/",Y:4/binary,$/,M:2/binary,$/,D:2/binary,$/>> ->
- case check_for_dot_or_space(Tail) of
- {ok,Match} ->
- {ok,<<Y/binary,$/,M/binary,$/,D/binary,$/, Match/binary>>};
- {nomatch,Skip} -> {skip,?DATELEN + Skip}
- end;
- _ -> nomatch
- end.
-
-%%--------------------------------------------------------------------
-
-degenerated_match() ->
- error = degenerated_match_1(<<>>),
- 1 = degenerated_match_1(<<1:1>>),
- 2 = degenerated_match_1(<<42,43>>),
-
- error = degenerated_match_2(<<>>),
- no_split = degenerated_match_2(<<1,2>>),
- {<<1,2,3,4>>,<<5>>} = degenerated_match_2(<<1,2,3,4,5>>),
- ok.
-
-degenerated_match_1(<<>>) -> error;
-degenerated_match_1(Bin) -> byte_size(Bin).
-
-degenerated_match_2(<<>>) -> error;
-degenerated_match_2(Bin) ->
- case byte_size(Bin) > 4 of
- true -> split_binary(Bin, 4);
- false -> no_split
- end.
-
-%%--------------------------------------------------------------------
-
-bs_sum() ->
- 0 = bs_sum_1([]),
- 0 = bs_sum_1(<<>>),
- 42 = bs_sum_1([42]),
- 1 = bs_sum_1(<<1>>),
- 10 = bs_sum_1([1,2,3,4]),
- 15 = bs_sum_1(<<1,2,3,4,5>>),
- 21 = bs_sum_1([1,2,3|<<4,5,6>>]),
- 15 = bs_sum_1([1,2,3|{4,5}]),
- 6 = bs_sum_1([1,2,3|zero]),
- 6 = bs_sum_1([1,2,3|0]),
- 7 = bs_sum_1([1,2,3|one]),
-
- fc(catch bs_sum_1({too,big,tuple})),
- fc(catch bs_sum_1([1,2,3|{too,big,tuple}])),
-
- [] = sneaky_alias(<<>>),
- [559,387655] = sneaky_alias(id(<<559:32,387655:32>>)),
- fc(sneaky_alias, [<<1>>], catch sneaky_alias(id(<<1>>))),
- fc(sneaky_alias, [[1,2,3,4]], catch sneaky_alias(lists:seq(1, 4))),
- ok.
-
-bs_sum_1(<<H,T/binary>>) -> H+bs_sum_1(T);
-bs_sum_1([H|T]) -> H+bs_sum_1(T);
-bs_sum_1({A,B}=_Tuple=_AliasForNoGoodReason) -> A+B;
-bs_sum_1(0) -> 0;
-bs_sum_1(zero=_Zero) -> 0;
-bs_sum_1(one) -> 1;
-bs_sum_1([]) -> 0;
-bs_sum_1(<<>>) -> 0.
-
-sneaky_alias(<<>>=L) -> binary_to_list(L);
-sneaky_alias(<<From:32,L/binary>>) -> [From|sneaky_alias(L)].
-
-%%--------------------------------------------------------------------
-
-coverage() ->
- 0 = coverage_fold(fun(B, A) -> A+B end, 0, <<>>),
- 6 = coverage_fold(fun(B, A) -> A+B end, 0, <<1,2,3>>),
- fc(catch coverage_fold(fun(B, A) -> A+B end, 0, [a,b,c])),
-
- {<<42.0:64/float>>,float} = coverage_build(<<>>, <<42>>, float),
- {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple),
- {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} =
- coverage_build(<<>>, <<16#7,16#A>>, {x,y,z}),
-
- [<<2>>,<<1>>] = coverage_bc(<<1,2>>, []),
-
- {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}),
-
- [42] = coverage_apply(<<42>>, [exported_id]),
- 42 = coverage_external(<<42>>),
-
- do_coverage_bin_to_term_list([]),
- do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]),
- fc(coverage_bin_to_term_list, [<<0,0,0,7>>],
- catch do_coverage_bin_to_term_list_1(<<7:32>>)),
-
- <<>> = coverage_per_key(<<4:32>>),
- <<$a,$b,$c>> = coverage_per_key(<<7:32,"abc">>),
-
- ok.
-
-coverage_fold(Fun, Acc, <<H,T/binary>>) ->
- IdFun = fun id/1,
- coverage_fold(Fun, Fun(IdFun(H), IdFun(Acc)), T);
-coverage_fold(Fun, Acc, <<>>) when is_function(Fun, 2) -> Acc.
-
-coverage_build(Acc0, <<H,T/binary>>, float) ->
- Float = id(<<H:64/float>>),
- Acc = <<Acc0/binary,Float/binary>>,
- coverage_build(Acc, T, float);
-coverage_build(Acc0, <<H,T/binary>>, Tuple0) ->
- Str = id(<<H:(id(4)),(H-1):4,"abc">>),
- Acc = id(<<Acc0/bitstring,Str/bitstring>>),
- Tuple = setelement(2, setelement(3, Tuple0, 43), 42),
- if
- byte_size(Acc) > 0 ->
- coverage_build(Acc, T, Tuple)
- end;
-coverage_build(Acc, <<>>, Tuple) -> {Acc,Tuple}.
-
-coverage_bc(<<H,T/binary>>, Acc) ->
- B = << <<C:8>> || C <- [H] >>,
- coverage_bc(T, [B|Acc]);
-coverage_bc(<<>>, Acc) -> Acc.
-
-coverage_setelement(<<H,T1/binary>>, Tuple) when element(1, Tuple) =:= x ->
- setelement(H, Tuple, T1).
-
-coverage_apply(<<H,T/binary>>, [F|Fs]) ->
- [?MODULE:F(H)|coverage_apply(T, Fs)];
-coverage_apply(<<>>, []) -> [].
-
-coverage_external(<<H,T/binary>>) ->
- ?MODULE:exported_id(T, T),
- H.
-
-exported_id(I) -> id(I).
-
-exported_id(_, _) -> ok.
-
-do_coverage_bin_to_term_list(L) ->
- Bin = << <<(begin BinTerm = term_to_binary(Term),
- <<(byte_size(BinTerm)):32,BinTerm/binary>> end)/binary>> ||
- Term <- L >>,
- L = do_coverage_bin_to_term_list_1(Bin),
- L = do_coverage_bin_to_term_list_1(<<Bin/binary,7:32,"garbage">>),
- L = do_coverage_bin_to_term_list_1(<<7:32,"garbage",Bin/binary>>).
-
-do_coverage_bin_to_term_list_1(Bin) ->
- Res = coverage_bin_to_term_list(Bin),
- Res = coverage_bin_to_term_list(Bin, []),
- Res = coverage_bin_to_term_list_catch(Bin),
- Res = coverage_bin_to_term_list_catch(Bin, []).
-
-coverage_bin_to_term_list(<<Sz:32,BinTerm:Sz/binary,T/binary>>) ->
- try binary_to_term(BinTerm) of
- Term -> [Term|coverage_bin_to_term_list(T)]
- catch
- error:badarg -> coverage_bin_to_term_list(T)
- end;
-coverage_bin_to_term_list(<<>>) -> [].
-
-coverage_bin_to_term_list(<<Sz:32,BinTerm:Sz/binary,T/binary>>, Acc) ->
- try binary_to_term(BinTerm) of
- Term -> coverage_bin_to_term_list(T, [Term|Acc])
- catch
- error:badarg -> coverage_bin_to_term_list(T, Acc)
- end;
-coverage_bin_to_term_list(<<>>, Acc) -> lists:reverse(Acc).
-
-coverage_bin_to_term_list_catch(<<Sz:32,BinTerm:Sz/binary,T/binary>>) ->
- case catch binary_to_term(BinTerm) of
- {'EXIT',_} -> coverage_bin_to_term_list_catch(T);
- Term -> [Term|coverage_bin_to_term_list_catch(T)]
- end;
-coverage_bin_to_term_list_catch(<<>>) -> [].
-
-coverage_bin_to_term_list_catch(<<Sz:32,BinTerm:Sz/binary,T/binary>>, Acc) ->
- case catch binary_to_term(BinTerm) of
- {'EXIT',_} -> coverage_bin_to_term_list_catch(T, Acc);
- Term -> coverage_bin_to_term_list_catch(T, [Term|Acc])
- end;
-coverage_bin_to_term_list_catch(<<>>, Acc) -> lists:reverse(Acc).
-
-coverage_per_key(<<BinSize:32,Bin/binary>> = B) ->
- true = (byte_size(B) =:= BinSize),
- Bin.
-
-%%--------------------------------------------------------------------
-
-multiple_uses() ->
- {344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
- true = multiple_uses_2(<<0,0,197,18>>),
- <<42,43>> = multiple_uses_3(<<0,0,42,43>>, fun id/1),
- ok.
-
-multiple_uses_1(<<X:16,Tail/binary>>) ->
- %% NOT OPTIMIZED: sub binary is matched or used in more than one place
- {Y,Z} = multiple_uses_match(Tail),
- {X,Y,Z,Tail}.
-
-multiple_uses_2(<<_:16,Tail/binary>>) ->
- %% NOT OPTIMIZED: sub binary is matched or used in more than one place
- multiple_uses_cmp(Tail, Tail).
-
-multiple_uses_3(<<_:16,Tail/binary>>, Fun) ->
- %% NOT OPTIMIZED: sub binary is used or returned
- Fun(Tail).
-
-multiple_uses_match(<<Y:16,Z:16>>) -> {Y,Z}.
-
-multiple_uses_cmp(<<Y:16>>, <<Y:16>>) -> true;
-multiple_uses_cmp(<<_:16>>, <<_:16>>) -> false.
-
-%%--------------------------------------------------------------------
-
-zero_label() ->
- <<"nosemouth">> = read_pols(<<"FACE","nose","mouth">>),
- <<"CE">> = read_pols(<<"noFACE">>),
- ok.
-
-read_pols(Data) ->
- <<PolygonType:4/binary,Rest/binary>> = Data,
- %% Intentional warning.
- _ = (PolygonType == <<"FACE">>) or (PolygonType == <<"PTCH">>),
- Rest.
-
-%%--------------------------------------------------------------------
-
-followed_by_catch() ->
- ok = handle(<<0,1,2,3,4,5>>).
-
--record(rec,{field}).
-handle(<<>>) -> ok;
-handle(Msg) ->
- <<_DataLen:16, Rest/binary>> = Msg,
- case catch fooX:func() of
- [X] ->
- X#rec.field;
- _ ->
- ok
- end,
- handle(Rest).
-
-%%--------------------------------------------------------------------
-
-matching_meets_construction() ->
- Bin = id(<<"abc">>),
- Len = id(2),
- Tail0 = id(<<1,2,3,4,5>>),
- <<_:Len/binary,Tail/binary>> = Tail0,
- Res = <<Tail/binary,Bin/binary>>,
- <<3,4,5,"abc">> = Res,
- {'EXIT',{badarg,_}} = (catch matching_meets_construction_1(<<"Abc">>)),
- {'EXIT',{badarg,_}} = (catch matching_meets_construction_2(<<"Abc">>)),
- <<"Bbc">> = matching_meets_construction_3(<<"Abc">>),
- <<1,2>> = encode_octet_string(<<1,2,3>>, 2),
- ok.
-
-matching_meets_construction_1(<<"A",H/binary>>) -> <<"B",H>>.
-
-matching_meets_construction_2(<<"A",H/binary>>) -> <<"B",H/float>>.
-
-matching_meets_construction_3(<<"A",H/binary>>) -> <<"B",H/binary>>.
-
-encode_octet_string(<<OctetString/binary>>, Len) ->
- <<OctetString:Len/binary-unit:8>>.
-
-%%--------------------------------------------------------------------
-
-simon() ->
- one = simon(blurf, <<>>),
- two = simon(0, <<42>>),
- fc(simon, [17,<<1>>], catch simon(17, <<1>>)),
- fc(simon, [0,<<1,2,3>>], catch simon(0, <<1,2,3>>)),
-
- one = simon2(blurf, <<9>>),
- two = simon2(0, <<9,1>>),
- fc(simon2, [0,<<9,10,11>>], catch simon2(0, <<9,10,11>>)),
- ok.
-
-simon(_, <<>>) -> one;
-simon(0, <<_>>) -> two.
-
-simon2(_, <<9>>) -> one;
-simon2(0, <<_:16>>) -> two.
-
-%%--------------------------------------------------------------------
-%% OTP-7113: Crash in v3_codegen.
-
-matching_and_andalso() ->
- ok = matching_and_andalso_1(<<1,2,3>>, 3),
- {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, -8)),
- {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, blurf)),
- {'EXIT',{function_clause,_}} = (catch matching_and_andalso_1(<<1,2,3>>, 19)),
-
- {"abc",<<"xyz">>} = matching_and_andalso_2("abc", <<"-xyz">>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($a-1)>>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($z+1)>>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($A-1)>>),
- {"abc",<<"">>} = matching_and_andalso_2("abc", <<($Z+1)>>),
- error = matching_and_andalso_2([], <<>>),
- error = matching_and_andalso_2([], <<$A>>),
- error = matching_and_andalso_2([], <<$Z>>),
- error = matching_and_andalso_2([], <<$a>>),
- error = matching_and_andalso_2([], <<$z>>),
- ok.
-
-matching_and_andalso_1(<<Bitmap/binary>>, K)
- when is_integer(K) andalso size(Bitmap) >= K andalso 0 < K -> ok.
-
-matching_and_andalso_2(Datetime, <<H,T/binary>>)
- when not ((H >= $a) andalso (H =< $z)) andalso
- not ((H >= $A) andalso (H =< $Z)) ->
- {Datetime,T};
-matching_and_andalso_2(_, _) -> error.
-
-%%--------------------------------------------------------------------
-%% Thanks to Tomas Stejskal.
-
-otp_7188() ->
- MP3 = <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,68,97,110,105,101,108,32,76,
- 97,110,100,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,
- 101,115,116,32,79,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,50,48,48,48,50,48,48,48,32,45,32,66,101,115,
- 116,32,79,102,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
- 32,32,12>>,
- {ok,{"ID3v1",
- [{title,<<68,117,154,105,232,107,121>>},
- {artist,<<"Daniel Landa">>},
- {album,<<"Best Of">>}]}} = parse_v1_or_v11_tag(MP3),
- ok.
-
-parse_v1_or_v11_tag(<<"TAG", Title:30/binary,
- Artist:30/binary, Album:30/binary,
- _Year:4/binary, _Comment:28/binary,
- 0:8, Track:8, _Genre:8>>) ->
- {ok,
- {"ID3v1.1",
- [{track, Track}, {title, trim(Title)},
- {artist, trim(Artist)}, {album, trim(Album)}]}};
-parse_v1_or_v11_tag(<<"TAG", Title:30/binary,
- Artist:30/binary, Album:30/binary,
- _Year:4/binary, _Comment:30/binary,
- _Genre:8>>) ->
- {ok,
- {"ID3v1",
- [{title, trim(Title)},
- {artist, trim(Artist)},
- {album, trim(Album)}]}};
-parse_v1_or_v11_tag(_) ->
- error.
-
-trim(Bin) ->
- list_to_binary(trim_blanks(binary_to_list(Bin))).
-
-trim_blanks(L) ->
- lists:reverse(skip_blanks_and_zero(lists:reverse(L))).
-
-skip_blanks_and_zero([$\s|T]) ->
- skip_blanks_and_zero(T);
-skip_blanks_and_zero([0|T]) ->
- skip_blanks_and_zero(T);
-skip_blanks_and_zero(L) ->
- L.
-
-%%--------------------------------------------------------------------
-%% OTP-7233. Record and binary matching optimizations clashed.
-%% Thanks to Vladimir Klebansky.
-
--record(rec_otp_7233, {key, val}).
-
-otp_7233() ->
- otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[{"xxxxxxxx",42}]}),
- [<<"XXabcde">>,{"xxxxxxxx",42}] = get(io_format),
- erase(io_format),
- otp_7233_1(#rec_otp_7233{key = <<"XXabcde">>,val=[]}),
- undefined = get(io_format),
- ok.
-
-otp_7233_1(Rec) ->
- <<K:2/binary,_Rest:5/binary>> = Rec#rec_otp_7233.key,
- case K of
- <<"XX">> ->
- Value = Rec#rec_otp_7233.val,
- case lists:keysearch("xxxxxxxx", 1, Value) of
- {value,T} -> put(io_format, [Rec#rec_otp_7233.key,T]);
- false -> ok
- end;
- _ -> ok
- end.
-
-%%--------------------------------------------------------------------
-
-otp_7240() ->
- a = otp_7240_a(0, <<>>),
- b = otp_7240_a(1, 2),
-
- a = otp_7240_b(anything, <<>>),
- b = otp_7240_b(1, {x,y}),
-
- a = otp_7240_c(anything, <<>>),
- b = otp_7240_c(1, <<2>>),
-
- a = otp_7240_d(anything, <<>>),
- b = otp_7240_d(again, <<2>>),
-
- a = otp_7240_e(anything, <<>>),
- b = otp_7240_e(1, 41),
-
- a = otp_7240_f(anything, <<>>),
- b = otp_7240_f(1, {}),
-
- ok.
-
-otp_7240_a(_, <<>>) -> a;
-otp_7240_a(1, 2) -> b.
-
-otp_7240_b(_, <<>>) -> a;
-otp_7240_b(1, {_,_}) -> b.
-
-otp_7240_c(_, <<>>) -> a;
-otp_7240_c(1, <<2>>) -> b.
-
-otp_7240_d(_, <<>>) -> a;
-otp_7240_d(_, <<2>>) -> b.
-
-otp_7240_e(_, <<>>) -> a;
-otp_7240_e(1, B) when B < 42 -> b.
-
-otp_7240_f(_, <<>>) -> a;
-otp_7240_f(1, B) when is_tuple(B) -> b.
-
-%%--------------------------------------------------------------------
-
-otp_7498() ->
- <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 0),
- <<2,3>> = otp_7498_foo(<<1,2,3>>, 1),
- <<1,2,3>> = otp_7498_foo(<<1,2,3>>, 2),
-
- <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 0),
- <<2,3>> = otp_7498_bar(<<1,2,3>>, 1),
- <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 2),
- <<>> = otp_7498_bar(<<>>, 2),
- <<1,2,3>> = otp_7498_bar(<<1,2,3>>, 3),
- ok.
-
-otp_7498_foo(Bin, 0) ->
- otp_7498_foo(Bin, 42);
-otp_7498_foo(<<_A, Rest/bitstring>>, 1) ->
- otp_7498_foo(Rest, 43);
-otp_7498_foo(Bin, _I) ->
- Bin.
-
-otp_7498_bar(Bin, 0) ->
- otp_7498_bar(Bin, 42);
-otp_7498_bar(<<_A, Rest/bitstring>>, 1) ->
- otp_7498_bar(Rest, 43);
-otp_7498_bar(<<>>, 2) ->
- otp_7498_bar(<<>>, 44);
-otp_7498_bar(Bin, _I) ->
- Bin.
-
-%%--------------------------------------------------------------------
-
-match_string() ->
- %% To make sure that native endian really is handled correctly
- %% (i.e. that the compiler does not attempt to use bs_match_string/4
- %% instructions for native segments), running this test is not enough.
- %% Either examine the generated for do_match_string_native/1 or
- %% check the coverage for the v3_kernel module.
- case erlang:system_info(endian) of
- little ->
- do_match_string_native(<<$a,0,$b,0>>);
- big ->
- do_match_string_native(<<0,$a,0,$b>>)
- end,
- do_match_string_big(<<0,$a,0,$b>>),
- do_match_string_little(<<$a,0,$b,0>>),
-
- do_match_string_big_signed(<<255,255>>),
- do_match_string_little_signed(<<255,255>>),
-
- plain = no_match_string_opt(<<"abc">>),
- strange = no_match_string_opt(<<$a:9,$b:9,$c:9>>),
- ok.
-
-do_match_string_native(<<$a:16/native,$b:16/native>>) -> ok.
-
-do_match_string_big(<<$a:16/big,$b:16/big>>) -> ok.
-
-do_match_string_little(<<$a:16/little,$b:16/little>>) -> ok.
-
-do_match_string_big_signed(<<(-1):16/signed>>) -> ok.
-
-do_match_string_little_signed(<<(-1):16/little-signed>>) -> ok.
-
-no_match_string_opt(<<"abc">>) -> plain;
-no_match_string_opt(<<$a:9,$b:9,$c:9>>) -> strange.
-
-%%--------------------------------------------------------------------
-%% OTP-7591: A zero-width segment in matching would crash the compiler.
-
-zero_width() ->
- <<Len:16/little, Str:Len/binary, 0:0>> = <<2, 0, $h, $i, 0:0>>,
- 2 = Len,
- Str = <<"hi">>,
- %% Match sure that values that cannot fit in a segment will not match.
- case id(<<0:8>>) of
- <<256:8>> -> error;
- _ -> ok
- end.
-
-%%--------------------------------------------------------------------
-%% OTP_7650: A invalid size for binary segments could crash the compiler.
-
-bad_size() ->
- Tuple = {a,b,c},
- {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Tuple>> = id(<<>>)),
- Binary = <<1,2,3>>,
- {'EXIT',{{badmatch,<<>>},_}} = (catch <<32:Binary>> = id(<<>>)),
- ok.
-
-%%--------------------------------------------------------------------
-
-haystack() ->
- <<0:10/unit:8>> = haystack_1(<<0:10/unit:8>>),
- [<<0:10/unit:8>>,
- <<0:20/unit:8>>] = haystack_2(<<1:8192>>),
- ok.
-
-%% Used to crash the compiler.
-haystack_1(Haystack) ->
- Subs = [10],
- [begin
- <<B:Y/binary>> = Haystack,
- B
- end || Y <- Subs],
- Haystack.
-
-%% There would be an incorrect badmatch exception.
-haystack_2(Haystack) ->
- Subs = [{687,10},{369,20}],
- [begin
- <<_:X/binary,B:Y/binary,_/binary>> = Haystack,
- B
- end || {X,Y} <- Subs].
-
-fc({'EXIT',{function_clause,_}}) -> ok.
-
-fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args,_}|_]}}) -> ok;
-fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity,_}|_]}})
- when length(Args) =:= Arity ->
- true = test_server:is_native(?MODULE).
-
-%%--------------------------------------------------------------------
-%% Cover the clause handling bs_context to binary in
-%% beam_block:initialized_regs/2.
-cover_beam_bool() ->
- ok = do_cover_beam_bool(<<>>, 3),
- <<19>> = do_cover_beam_bool(<<19>>, 2),
- <<42>> = do_cover_beam_bool(<<42>>, 1),
- <<17>> = do_cover_beam_bool(<<13,17>>, 0),
- ok.
-
-do_cover_beam_bool(Bin, X) when X > 0 ->
- if
- X =:= 1; X =:= 2 ->
- Bin;
- true ->
- ok
- end;
-do_cover_beam_bool(<<_,Bin/binary>>, X) ->
- do_cover_beam_bool(Bin, X+1).
-
-%%--------------------------------------------------------------------
-
-matched_out_size() ->
- {253,16#DEADBEEF} = mos_int(<<8,253,16#DEADBEEF:32>>),
- {6,16#BEEFDEAD} = mos_int(<<3,6:3,16#BEEFDEAD:32>>),
- {53,16#CAFEDEADBEEFCAFE} = mos_int(<<16,53:16,16#CAFEDEADBEEFCAFE:64>>),
- {23,16#CAFEDEADBEEFCAFE} = mos_int(<<5,23:5,16#CAFEDEADBEEFCAFE:64>>),
-
- {<<1,2,3>>,4} = mos_bin(<<3,1,2,3,4,3>>),
- {<<1,2,3,7>>,19,42} = mos_bin(<<4,1,2,3,7,19,4,42>>),
- <<1,2,3,7>> = mos_bin(<<4,1,2,3,7,"abcdefghij">>),
- ok.
-
-mos_int(<<L,I:L,X:32>>) ->
- {I,X};
-mos_int(<<L,I:L,X:64>>) ->
- {I,X}.
-
-mos_bin(<<L,Bin:L/binary,X:8,L>>) ->
- L = byte_size(Bin),
- {Bin,X};
-mos_bin(<<L,Bin:L/binary,X:8,L,Y:8>>) ->
- L = byte_size(Bin),
- {Bin,X,Y};
-mos_bin(<<L,Bin:L/binary,"abcdefghij">>) ->
- L = byte_size(Bin),
- Bin.
-
-%%--------------------------------------------------------------------
-
-follow_fail_br() ->
- 42 = ffb_1(<<0,1>>, <<0>>),
- 8 = ffb_1(<<0,1>>, [a]),
- 42 = ffb_2(<<0,1>>, <<0>>, 17),
- 8 = ffb_2(<<0,1>>, [a], 0),
- ok.
-
-ffb_1(<<_,T/bitstring>>, List) ->
- case List of
- <<_>> ->
- 42;
- [_|_] ->
- %% The fail branch of the bs_start_match2 instruction pointing
- %% to here would be ignored, making the compiler incorrectly
- %% assume that the delayed sub-binary optimization was safe.
- bit_size(T)
- end.
-
-ffb_2(<<_,T/bitstring>>, List, A) ->
- case List of
- <<_>> when A =:= 17 -> 42;
- [_|_] -> bit_size(T)
- end.
-
-%%--------------------------------------------------------------------
-
-no_partition() ->
- one = no_partition_1(<<"string">>, a1),
- {two,<<"string">>} = no_partition_1(<<"string">>, a2),
- {two,<<>>} = no_partition_1(<<>>, a2),
- {two,a} = no_partition_1(a, a2),
- three = no_partition_1(undefined, a3),
- {four,a,[]} = no_partition_1([a], a4),
- {five,a,b} = no_partition_1({a,b}, a5),
-
- one = no_partition_2(<<"string">>, a1),
- two = no_partition_2(<<"string">>, a2),
- two = no_partition_2(<<>>, a2),
- two = no_partition_2(a, a2),
- three = no_partition_2(undefined, a3),
- four = no_partition_2(42, a4),
- five = no_partition_2([], a5),
- six = no_partition_2(42.0, a6),
- ok.
-
-no_partition_1(<<"string">>, a1) -> one;
-no_partition_1(V, a2) -> {two,V};
-no_partition_1(undefined, a3) -> three;
-no_partition_1([H|T], a4) -> {four,H,T};
-no_partition_1({A,B}, a5) -> {five,A,B}.
-
-no_partition_2(<<"string">>, a1) -> one;
-no_partition_2(_, a2) -> two;
-no_partition_2(undefined, a3) -> three;
-no_partition_2(42, a4) -> four;
-no_partition_2([], a5) -> five;
-no_partition_2(42.0, a6) -> six.
-
-%%--------------------------------------------------------------------
-
-calling_a_binary() ->
- [] = call_binary(<<>>, []),
- {'EXIT',{badarg,_}} = (catch call_binary(<<1>>, [])),
- {'EXIT',{badarg,_}} = (catch call_binary(<<1,2,3>>, [])),
- ok.
-
-call_binary(<<>>, Acc) ->
- Acc;
-call_binary(<<H,T/bits>>, Acc) ->
- T(<<Acc/binary,H>>).
-
-%%--------------------------------------------------------------------
-
-binary_in_map() ->
- ok = match_binary_in_map(#{key => <<42:8>>}),
- {'EXIT',{{badmatch,#{key := 1}},_}} =
- (catch match_binary_in_map(#{key => 1})),
- {'EXIT',{{badmatch,#{key := <<1023:16>>}},_}} =
- (catch match_binary_in_map(#{key => <<1023:16>>})),
- {'EXIT',{{badmatch,#{key := <<1:8>>}},_}} =
- (catch match_binary_in_map(#{key => <<1:8>>})),
- {'EXIT',{{badmatch,not_a_map},_}} =
- (catch match_binary_in_map(not_a_map)),
- ok.
-
-match_binary_in_map(Map) ->
- case 8 of
- N ->
- #{key := <<42:N>>} = Map,
- ok
- end.
-
-%%--------------------------------------------------------------------
-
-match_string_opt() ->
- {x,<<1,2,3>>,{<<1>>,{v,<<1,2,3>>}}} = match_string_opt({<<1>>,{v,<<1,2,3>>}}),
- ok.
-
-match_string_opt({<<1>>,{v,V}}=T) ->
- {x,V,T}.
-
-%%--------------------------------------------------------------------
-%% If 'bin_opt_info' was given the warning would lack filename and
-%% line number.
-
-map_and_binary() ->
- {<<"10">>,<<"37">>,<<"am">>} = do_map_and_binary(<<"10:37am">>),
- Map1 = #{time => "noon"},
- {ok,Map1} = do_map_and_binary(Map1),
- Map2 = #{hour => 8, min => 42},
- {8,42,Map2} = do_map_and_binary(Map2),
- ok.
-
-do_map_and_binary(<<Hour:2/bytes, $:, Min:2/bytes, Rest/binary>>) ->
- {Hour, Min, Rest};
-do_map_and_binary(#{time := _} = T) ->
- {ok, T};
-do_map_and_binary(#{hour := Hour, min := Min} = T) ->
- {Hour, Min, T}.
-
-%%--------------------------------------------------------------------
-%% Unsafe caching of branch outcomes in beam_bsm would cause the
-%% delayed creation of sub-binaries optimization to be applied even
-%% when it was unsafe.
-
-unsafe_branch_caching() ->
- <<>> = do_unsafe_branch_caching(<<42,1>>),
- <<>> = do_unsafe_branch_caching(<<42,2>>),
- <<>> = do_unsafe_branch_caching(<<42,3>>),
- <<17,18>> = do_unsafe_branch_caching(<<42,3,17,18>>),
- <<>> = do_unsafe_branch_caching(<<1,3,42,2>>),
- ok.
-
-do_unsafe_branch_caching(<<Code/integer, Bin/binary>>) ->
- <<C1/integer, B1/binary>> = Bin,
- case C1 of
- X when X =:= 1 orelse X =:= 2 ->
- Bin2 = <<>>;
- _ ->
- Bin2 = B1
- end,
- case Code of
- 1 -> do_unsafe_branch_caching(Bin2);
- _ -> Bin2
- end.
-
-%%--------------------------------------------------------------------
-
-check(F, R) ->
- R = F().
-
-id(I) -> I.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_native_float.erl b/lib/hipe/test/bs_SUITE_data/bs_native_float.erl
deleted file mode 100644
index 15fe0bf0c6..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_native_float.erl
+++ /dev/null
@@ -1,22 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------
-%% File : bs_native_float.erl
-%% Author : Kostis Sagonas
-%% Description : Test sent by Bjorn Gustavsson to report a bug in the
-%% handling of the 'native' endian specifier.
-%% Created : 28 Nov 2004
-%%-------------------------------------------------------------------
--module(bs_native_float).
-
--export([test/0]).
-
-test() ->
- BeamRes = mk_bin(1.0, 2.0, 3.0),
- hipe:c(?MODULE), %% Original was: hipe:c({?MODULE,vs_to_bin,1}, [o2]),
- HipeRes = mk_bin(1.0, 2.0, 3.0),
- %% io:format("Beam result = ~w\nHiPE result = ~w\n", [BeamRes,HipeRes]),
- BeamRes = HipeRes,
- ok.
-
-mk_bin(X, Y, Z) ->
- <<X:64/native-float, Y:64/native-float, Z:64/native-float>>.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_orber.erl b/lib/hipe/test/bs_SUITE_data/bs_orber.erl
deleted file mode 100644
index c80ab8928d..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_orber.erl
+++ /dev/null
@@ -1,26 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : Checks that labels are handled properly from Core
-%%% Created : 2 Nov 2004
-%%%-------------------------------------------------------------------
--module(bs_orber).
-
--export([test/0]).
-
-test() ->
- 1 = dec_giop_message_header(<<1,1:32/little-integer>>),
- 1 = dec_giop_message_header(<<0,1:32/big-integer>>),
- {2, 1} = dec_giop_message_header(<<2,1:32/little-integer>>),
- {3, 1} = dec_giop_message_header(<<3,1:32/big-integer>>),
- ok.
-
-dec_giop_message_header(<<1:8, MessSize:32/little-integer>>) ->
- MessSize;
-dec_giop_message_header(<<0:8, MessSize:32/big-integer>>) ->
- MessSize;
-dec_giop_message_header(<<Flags:8, MessSize:32/little-integer>>) when
- ((Flags band 16#03) =:= 16#02) ->
- {Flags, MessSize};
-dec_giop_message_header(<<Flags:8, MessSize:32/big-integer>>) ->
- {Flags, MessSize}.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_pmatch.erl b/lib/hipe/test/bs_SUITE_data/bs_pmatch.erl
deleted file mode 100644
index 9474ffea4a..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_pmatch.erl
+++ /dev/null
@@ -1,269 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Tests that basic cases of binary pattern matching work
-%%--------------------------------------------------------------------
--module(bs_pmatch).
-
--export([test/0]).
-
-test() ->
- %% construct some binaries
- Bin42 = <<42>>,
- Bin = <<12,17,42,0,0,0>>,
- BinSS = <<0,1,0,0,0>>,
- %% do some pattern matching
- ok = pm_const(Bin42),
- <<17,42,0,0,0>> = pm_tail(Bin),
- 42 = pm_little(<<0:1,42:7>>),
- 42 = pm_rec(Bin),
- 30 = pm_rec_acc(<<1,2,3,4,5,6,7,8,9,10>>, 0),
- 42 = pm_binary_tuple(Bin42),
- -1 = pm_with_illegal_float(),
- %% do some pattern matching with bound segments
- ok = pm_bound_var(),
- ok = pm_bound_tail(),
- %% do some tests with floating point numbers
- ok = pm_float(),
- ok = pm_float_little(),
- %% do some pattern matching with segments of unknown sizes
- {<<17>>, <<42,0,0,0>>} = pm_body_s(Bin, 1),
- {<<17>>, <<42,0,0,0>>} = pm_body_ss(Bin, 1, 4),
- {<<45>>, <<>>} = pm_size_split(<<1:16,45>>),
- {<<45>>, <<46,47>>} = pm_size_split(<<1:16,45,46,47>>),
- {<<45,46>>, <<47>>} = pm_size_split(<<2:16,45,46,47>>),
- {<<45,46>>, <<47>>} = pm_size_split_2(2, <<2:16,45,46,47>>),
- {'EXIT',{function_clause,_}} = (catch pm_size_split_2(42, <<2:16,45,46,47>>)),
- {<<45,46,47>>, <<48>>} = pm_sizes_split(<<16:8,3:16,45,46,47,48>>),
- <<"cdef">> = pm_skip_segment(<<2:8, "abcdef">>),
- -1 = pm_double_size_in_head(BinSS),
- -1 = pm_double_size_in_body(BinSS),
- %% and finally some cases which were problematic for various reasons
- ok = pm_bigs(),
- ok = pm_sean(),
- ok = pm_bin8(<<1,2,3,4,5,6,7,8>>),
- ok = pm_bs_match_string(),
- ok = pm_till_gc(),
- ok.
-
-%%--------------------
-%% Test cases below
-%%--------------------
-
-pm_const(<<42>>) ->
- ok.
-
-pm_tail(<<12, Bin/binary>>) ->
- Bin.
-
-pm_little(<<_:1, X:15/little>>) ->
- {wrong, X};
-pm_little(<<_:1, X:7/little>>) ->
- X.
-
-pm_rec(<<12, Bin/binary>>) ->
- pm_rec(Bin);
-pm_rec(<<17, Word:4/little-signed-integer-unit:8>>) ->
- Word.
-
-pm_rec_acc(<<_:4, A:4, Rest/binary>>, Acc) ->
- case Rest of
- <<X, Y, 9, NewRest/binary>> ->
- pm_rec_acc(NewRest, X+Y+Acc);
- <<X, 5, NewRest/binary>> ->
- pm_rec_acc(NewRest, X+Acc);
- <<2, NewRest/binary>> ->
- pm_rec_acc(NewRest, 1+Acc);
- <<NewRest/binary>> ->
- pm_rec_acc(NewRest, A+Acc)
- end;
-pm_rec_acc(<<>>, Acc) ->
- Acc.
-
-pm_binary_tuple(<<X>>) ->
- X;
-pm_binary_tuple({Y, Z}) ->
- Y + Z.
-
-pm_with_illegal_float() ->
- Bin = <<-1:64>>, % create a binary which is illegal as float
- pm_float_integer(Bin). % try to match it out as a float
-
-pm_float_integer(<<F:64/float>>) -> F;
-pm_float_integer(<<I:64/integer-signed>>) -> I.
-
-%%--------------------------------------------------------------------
-%% Some tests with bound variables in segments
-
-pm_bound_var() ->
- ok = pm_bound_var(42, 13, <<42,13>>),
- no = pm_bound_var(42, 13, <<42,255>>),
- no = pm_bound_var(42, 13, <<154,255>>),
- ok.
-
-pm_bound_var(A, B, <<A:8, B:8>>) -> ok;
-pm_bound_var(_, _, _) -> no.
-
-pm_bound_tail() ->
- ok = pm_bound_tail(<<>>, <<13,14>>),
- ok = pm_bound_tail(<<2,3>>, <<1,1,2,3>>),
- no = pm_bound_tail(<<2,3>>, <<1,1,2,7>>),
- no = pm_bound_tail(<<2,3>>, <<1,1,2,3,4>>),
- no = pm_bound_tail(<<2,3>>, <<>>),
- ok.
-
-pm_bound_tail(T, <<_:16, T/binary>>) -> ok;
-pm_bound_tail(_, _) -> no.
-
-%%--------------------------------------------------------------------
-%% Floating point tests
-
-pm_float() ->
- F = f1(),
- G = f_one(),
- G = match_float(<<63,128,0,0>>, 32, 0),
- G = match_float(<<63,240,0,0,0,0,0,0>>, 64, 0),
- fcmp(F, match_float(<<F:32/float>>, 32, 0)),
- fcmp(F, match_float(<<F:64/float>>, 64, 0)),
- fcmp(F, match_float(<<1:1,F:32/float,127:7>>, 32, 1)),
- fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
- fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)),
- fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
- ok.
-
-fcmp(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok.
-
-match_float(Bin0, Fsz, I) ->
- Bin = make_sub_bin(Bin0),
- Bsz = bit_size(Bin),
- Tsz = Bsz - Fsz - I,
- <<_:I,F:Fsz/float,_:Tsz>> = Bin,
- F.
-
-pm_float_little() ->
- F = f2(),
- G = f_one(),
- G = match_float_little(<<0,0,0,0,0,0,240,63>>, 64, 0),
- G = match_float_little(<<0,0,128,63>>, 32, 0),
- fcmp(F, match_float_little(<<F:32/float-little>>, 32, 0)),
- fcmp(F, match_float_little(<<F:64/float-little>>, 64, 0)),
- fcmp(F, match_float_little(<<1:1,F:32/float-little,127:7>>, 32, 1)),
- fcmp(F, match_float_little(<<1:1,F:64/float-little,127:7>>, 64, 1)),
- fcmp(F, match_float_little(<<1:13,F:32/float-little,127:3>>, 32, 13)),
- fcmp(F, match_float_little(<<1:13,F:64/float-little,127:3>>, 64, 13)),
- ok.
-
-match_float_little(Bin0, Fsz, I) ->
- Bin = make_sub_bin(Bin0),
- Bsz = bit_size(Bin),
- Tsz = Bsz - Fsz - I,
- <<_:I, F:Fsz/float-little, _:Tsz>> = Bin,
- F.
-
-make_sub_bin(Bin0) ->
- Sz = byte_size(Bin0),
- Bin1 = <<37,Bin0/binary,38,39>>,
- <<_:8,Bin:Sz/binary,_:8,_:8>> = Bin1,
- Bin.
-
-f1() -> 3.1415.
-
-f2() -> 2.7133.
-
-f_one() -> 1.0.
-
-%%--------------------------------------------------------------------
-%% Some tests using size fields specified within the binary
-pm_body_s(Bin, S1) ->
- <<12, B1:S1/binary, B2:4/binary>> = Bin, %% 4 is hard-coded
- {B1, B2}.
-
-pm_body_ss(Bin, S1, S2) ->
- <<12, B1:S1/binary, B2:S2/binary>> = Bin,
- {B1, B2}.
-
-pm_size_split(<<N:16, B:N/binary, T/binary>>) ->
- {B, T}.
-
-pm_size_split_2(N, <<N:16, B:N/binary, T/binary>>) ->
- {B, T}.
-
-pm_sizes_split(<<N0:8, N:N0, B:N/binary, T/binary>>) ->
- {B, T}.
-
-pm_skip_segment(<<N:8, _:N/binary, T/binary>>) -> T.
-
-%%--------------------------------------------------------------------
-%% Some tests using multiple occurrences of size fields
-pm_double_size_in_head(<<S:16, _:S/binary, _:S/binary, _/binary>>) ->
- -S.
-
-pm_double_size_in_body(Bin) ->
- <<S:16, _:S/binary, _:S/binary, _/binary>> = Bin,
- -S.
-
-%%--------------------------------------------------------------------
-%% matching with 64-bit integers which become big nums
--define(BIG, 16#7fffffff7fffffff).
-
-pm_bigs() ->
- <<X:64/little>> = <<?BIG:64/little>>,
- true = (X =:= big()),
- <<Y:64>> = <<?BIG:64>>,
- true = (Y =:= big()),
- ok.
-
-big() -> ?BIG.
-
-%%--------------------------------------------------------------------
-
-pm_sean() ->
- small = sean1(<<>>),
- small = sean1(<<1>>),
- small = sean1(<<1,2>>),
- small = sean1(<<1,2,3>>),
- large = sean1(<<1,2,3,4>>),
- small = sean1(<<4>>),
- small = sean1(<<4,5>>),
- small = sean1(<<4,5,6>>),
- {'EXIT', {function_clause, _}} = (catch sean1(<<4,5,6,7>>)),
- ok.
-
-sean1(<<B/binary>>) when byte_size(B) < 4 -> small;
-sean1(<<1, _/binary>>) -> large.
-
-%%--------------------------------------------------------------------
-%% Crashed on SPARC due to a bug in linear scan register allocator
-pm_bin8(<<A, B, C, D, E, F, G, H>>) ->
- 10 = add4(A, B, C, D),
- 26 = add4(E, F, G, H),
- ok.
-
-add4(X, Y, Z, W) ->
- X + Y + Z + W.
-
-%%--------------------------------------------------------------------
-%% Cases that exposed bugs in the handling of bs_match_string with an
-%% empty destination list. Reported on 2013/2/12 and fixed 2013/3/10.
-
-pm_bs_match_string() ->
- Bin = <<42,42>>,
- Bin = pm_match_string_head(Bin),
- ok = (pm_match_string_fun())(Bin).
-
-pm_match_string_head(<<42, _/bits>> = B) -> B.
-
-pm_match_string_fun() ->
- fun (<<X, _/bits>>) when X =:= 42 -> ok end.
-
-%%--------------------------------------------------------------------
-%% Match a lot to force a garbage collection which exposed a bug
-
-pm_till_gc() ->
- Bin = <<16#76543210:32>>,
- 16#76543210 = pm_a_lot(Bin, 1000000),
- ok.
-
-pm_a_lot(<<X:32>>, 0) ->
- X;
-pm_a_lot(<<X:32>>, N) ->
- pm_a_lot(<<X:32>>, N-1).
diff --git a/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl b/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
deleted file mode 100644
index d9f3278b45..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
+++ /dev/null
@@ -1,115 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
--module(bs_pmatch_bugs).
-
--export([test/0]).
-
-test() ->
- Bin = <<"123.123">>,
- <<49,50,51>> = lex_digits1(Bin, 1, []),
- <<49,50,51>> = lex_digits2(Bin, 1, []),
- ok = var_bind_bug(<<1, 2, 3, 4, 5, 6, 7, 8>>),
- ok = bs_match_string_bug(),
- ok.
-
-%%--------------------------------------------------------------------
-%% One of the lex_digits functions below gave incorrect results due to
-%% incorrect pattern matching compilation of binaries by the byte code
-%% compiler. Fixed by Bjorn Gustavsson on 5/3/2003.
-%% --------------------------------------------------------------------
-lex_digits1(<<$., Rest/binary>>, _Val, _Acc) ->
- Rest;
-lex_digits1(<<N, Rest/binary>>, Val, Acc) when N >= $0, N =< $9 ->
- lex_digits1(Rest, Val * 10 + dec(N), Acc);
-lex_digits1(_Other, _Val, _Acc) ->
- not_ok.
-
-lex_digits2(<<N, Rest/binary>>,Val, Acc) when N >= $0, N =< $9 ->
- lex_digits2(Rest, Val * 10 + dec(N), Acc);
-lex_digits2(<<$., Rest/binary>>, _Val, _Acc) ->
- Rest;
-lex_digits2(_Other, _Val, _Acc) ->
- not_ok.
-
-dec(A) ->
- A - $0.
-
-%%--------------------------------------------------------------------
-%% From: Bernard Duggan
-%% Date: 11/3/2011
-%%
-%% I've just run into an interesting little bit of behaviour that
-%% doesn't seem quite right. erlc gives me the warning
-%%
-%% 43: Warning: this clause cannot match because a previous
-%% clause at line 42 always matches
-%% (line 42 is the "B -> wrong;" line).
-%%
-%% And sure enough, if you run test/0 you get 'wrong' back.
-%%
-%% That, in itself, is curious to me since by my understanding B should
-%% be bound by the function header, and have no guarantee of being the
-%% same as A. I can't see how it could be unbound.
-%%
-%% Doubly curious, is that if I stop using B as the size specifier of C,
-%% like this:
-%%
-%% match(<<A:1/binary, B:8/integer, _C:1/binary, _Rest/binary>>) ->
-%%
-%% the warning goes away. And the result becomes 'ok' (in spite of
-%% nothing in the body having changed, and the only thing changing in
-%% the header being the size of an unused variable at the tail of the
-%% binary).
-%%--------------------------------------------------------------------
-var_bind_bug(<<A:1/binary, B:8/integer, _C:B/binary, _Rest/binary>>) ->
- case A of
- B -> wrong;
- _ -> ok
- end.
-
-%%--------------------------------------------------------------------
-%% From: Andreas Schultz
-%% Date: 2/11/2016
-%%
-%% Either HiPE is messing up binary matches in some cases or I'm not
-%% seeing the problem. ... <SNIP PROGRAM - CLEANED UP VERSION BELOW>
-%% With Erlang 19.1.3 the HiPE compiled version behaves differently
-%% than the non-HiPE version: ... <SNIP TEST RUNS>
-%% So, do I do something wrong here or is this a legitimate HiPE bug?
-%%
-%% Yes, this was a legitimate HiPE bug: The BEAM to ICode tranaslation
-%% of the bs_match_string instruction, written long ago for binaries
-%% (i.e., with byte-sized strings), tried to do a `clever' translation
-%% of even bit-sized strings using a HiPE primop that took a `Size'
-%% argument expressed in *bytes*. ICode is not really the place to do
-%% such a thing, and moreover there is really no reason for the HiPE
-%% primop not to take a Size argument expressed in *bits* instead.
-%% The bug was fixed by changing the `Size' argument to be in bits,
-%% postponing the translation of the bs_match_string primop until RTL
-%% and doing a proper translation using bit-sized quantities there.
-%%--------------------------------------------------------------------
-
-bs_match_string_bug() ->
- ok = test0(<<50>>),
- Bin = data(),
- ok = test1(Bin),
- ok = test2(Bin),
- ok.
-
-%% Minimal test case showing the problem matching with strings
-test0(<<6:5, 0:1, 0:2>>) -> weird;
-test0(<<6:5, _:1, _:2>>) -> ok;
-test0(_) -> default.
-
-data() -> <<50,16,0>>.
-
-%% This was the problematic test case in HiPE: 'default' was returned
-test1(<<1:3, 1:1, _:1, 0:1, 0:1, 0:1, _/binary>>) -> weird;
-test1(<<1:3, 1:1, _:1, _:1, _:1, _:1, _/binary>>) -> ok;
-test1(_) -> default.
-
-%% This variation of test1/1 above worked OK, even in HiPE
-test2(<<1:3, 1:1, _:1, A:1, B:1, C:1, _/binary>>)
- when A =:= 1; B =:= 1; C =:= 1 -> ok;
-test2(<<1:3, 1:1, _:1, 0:1, 0:1, 0:1, _/binary>>) -> weird;
-test2(_) -> default.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_pmatch_in_guards.erl b/lib/hipe/test/bs_SUITE_data/bs_pmatch_in_guards.erl
deleted file mode 100644
index 159227bb92..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_pmatch_in_guards.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Tests that basic cases of binary pattern matching in guards work
-%%--------------------------------------------------------------------
--module(bs_pmatch_in_guards).
-
--export([test/0]).
-
-test() ->
- 1 = in_guard(<<16#74ad:16>>, 16#e95, 5),
- 2 = in_guard(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>),
- 3 = in_guard(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415),
- nope = in_guard(<<1>>, 42, b),
- nope = in_guard(<<1>>, a, b),
- nope = in_guard(<<1,2>>, 1, 1),
- nope = in_guard(<<4,5>>, 1, 2.71),
- nope = in_guard(<<4,5>>, 1, <<12,13>>),
- ok.
-
-in_guard(Bin, A, B) when <<A:13,B:3>> == Bin -> 1;
-in_guard(Bin, A, B) when <<A:16,B/binary>> == Bin -> 2;
-in_guard(Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3;
-in_guard(_, _, _) -> nope.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_potpurri.erl b/lib/hipe/test/bs_SUITE_data/bs_potpurri.erl
deleted file mode 100644
index 8bc4fe5c88..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_potpurri.erl
+++ /dev/null
@@ -1,200 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
--module(bs_potpurri).
-
--export([test/0]).
-
-test() ->
- ok = integer(),
- ok = signed_integer(),
- ok = dynamic(),
- ok = more_dynamic(),
- ok = mml(),
- ok.
-
-%% compile(Opts0) ->
-%% case proplists:get_bool(core, Opts0) of
-%% true ->
-%% test:note(?MODULE, "disabling compilation from core - BUG"),
-%% Opts = [{core,false}|Opts0];
-%% false ->
-%% Opts = Opts0
-%% end,
-%% hipe:c(?MODULE, Opts).
-
-integer() ->
- 0 = get_int(mkbin([])),
- 0 = get_int(mkbin([0])),
- 42 = get_int(mkbin([42])),
- 255 = get_int(mkbin([255])),
- 256 = get_int(mkbin([1,0])),
- 257 = get_int(mkbin([1,1])),
- 258 = get_int(mkbin([1,2])),
- 258 = get_int(mkbin([1,2])),
- 65534 = get_int(mkbin([255,254])),
- 16776455 = get_int(mkbin([255,253,7])),
- 4245492555 = get_int(mkbin([253,13,19,75])),
- L = [200,1,19,128,222,42,97,111,200,1,19,128,222,42,97,111],
- ok = cmp128(mkbin(L), uint(L)),
- ok = fun_clause(catch get_int(mkbin(lists:seq(1,5)))),
- ok.
-
-get_int(<<I:0>>) -> I;
-get_int(<<I:8>>) -> I;
-get_int(<<I:16>>) -> I;
-get_int(<<I:24>>) -> I;
-get_int(<<I:32>>) -> I.
-
-cmp128(<<I:128>>, I) -> ok;
-cmp128(_Bin, _I) -> not_ok.
-
-signed_integer() ->
- {no_match,_} = sint(mkbin([])),
- {no_match,_} = sint(mkbin([1,2,3])),
- 127 = sint(mkbin([127])),
- -1 = sint(mkbin([255])),
- -128 = sint(mkbin([128])),
- 42 = sint(mkbin([42,255])),
- 127 = sint(mkbin([127,255])),
- ok.
-
-sint(Bin) ->
- case Bin of
- <<I:8/signed>> -> I;
- <<I:8/signed,_:3,_:5>> -> I;
- Other -> {no_match,Other}
- end.
-
-uint(L) -> uint(L, 0).
-
-uint([H|T], Acc) -> uint(T, Acc bsl 8 bor H);
-uint([], Acc) -> Acc.
-
-dynamic() ->
- ok = dynamic(mkbin([255]), 8),
- ok = dynamic(mkbin([255,255]), 16),
- ok = dynamic(mkbin([255,255,255]), 24),
- ok = dynamic(mkbin([255,255,255,255]), 32),
- ok.
-
-dynamic(Bin, S1) when S1 >= 0 ->
- S2 = bit_size(Bin) - S1,
- dynamic(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1),
- dynamic(Bin, S1-1);
-dynamic(_Bin, _) -> ok.
-
-dynamic(Bin, S1, S2, A, B) ->
- %% io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
- case Bin of
- <<A:S1,B:S2>> ->
- %% io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
- ok;
- <<A1:S1,B2:S2>> -> erlang:error(badmatch, [Bin,S1,S2,A,B,A1,B2])
- end.
-
-more_dynamic() ->
- %% Unsigned big-endian numbers.
- Unsigned = fun(Bin, List, SkipBef, N) ->
- SkipAft = bit_size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N,_I2:SkipAft>> = Bin,
- Int = make_int(List, N, 0)
- end,
- ok = more_dynamic1(Unsigned, funny_binary(42)),
-
- %% Signed big-endian numbers.
- Signed = fun(Bin, List, SkipBef, N) ->
- SkipAft = bit_size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N/signed,_I2:SkipAft>> = Bin,
- case make_signed_int(List, N) of
- Int -> ok;
- Other ->
- io:format("Bin = ~p,", [Bin]),
- io:format("SkipBef = ~p, N = ~p", [SkipBef,N]),
- io:format("Expected ~p, got ~p", [Int,Other]),
- exit(Other)
- end
- end,
- ok = more_dynamic1(Signed, funny_binary(43)),
-
- %% Unsigned little-endian numbers.
- UnsLittle = fun(Bin, List, SkipBef, N) ->
- SkipAft = bit_size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N/little,_I2:SkipAft>> = Bin,
- Int = make_int(big_to_little(List, N), N, 0)
- end,
- more_dynamic1(UnsLittle, funny_binary(44)),
-
- %% Signed little-endian numbers.
- SignLittle = fun(Bin, List, SkipBef, N) ->
- SkipAft = bit_size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N/signed-little,_I2:SkipAft>> = Bin,
- Little = big_to_little(List, N),
- Int = make_signed_int(Little, N)
- end,
- ok = more_dynamic1(SignLittle, funny_binary(45)),
-
- ok.
-
-funny_binary(N) ->
- B0 = erlang:md5([N]),
- {B1,_B2} = split_binary(B0, byte_size(B0) div 2),
- B1.
-
-more_dynamic1(Action, Bin) ->
- BitList = bits_to_list(binary_to_list(Bin), 16#80),
- more_dynamic2(Action, Bin, BitList, 0).
-
-more_dynamic2(Action, Bin, [_|T]=List, Bef) ->
- more_dynamic3(Action, Bin, List, Bef, bit_size(Bin)),
- more_dynamic2(Action, Bin, T, Bef+1);
-more_dynamic2(_Action, _Bin, [], _Bef) -> ok.
-
-more_dynamic3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
- %% io:format("~p, ~p", [Bef,Aft-Bef]),
- Action(Bin, List, Bef, Aft-Bef),
- more_dynamic3(Action, Bin, List, Bef, Aft-1);
-more_dynamic3(_, _, _, _, _) -> ok.
-
-big_to_little(List, N) -> big_to_little(List, N, []).
-
-big_to_little([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc) when N >= 8 ->
- big_to_little(T, N-8, [B0,B1,B2,B3,B4,B5,B6,B7|Acc]);
-big_to_little(List, N, Acc) -> lists:sublist(List, 1, N) ++ Acc.
-
-make_signed_int(_List, 0) -> 0;
-make_signed_int([0|_]=List, N) -> make_int(List, N, 0);
-make_signed_int([1|_]=List0, N) ->
- List1 = reversed_sublist(List0, N, []),
- List2 = two_complement_and_reverse(List1, 1, []),
- -make_int(List2, length(List2), 0).
-
-reversed_sublist(_List, 0, Acc) -> Acc;
-reversed_sublist([H|T], N, Acc) -> reversed_sublist(T, N-1, [H|Acc]).
-
-two_complement_and_reverse([H|T], Carry, Acc) ->
- Sum = 1 - H + Carry,
- two_complement_and_reverse(T, Sum div 2, [Sum rem 2|Acc]);
-two_complement_and_reverse([], Carry, Acc) -> [Carry|Acc].
-
-make_int(_List, 0, Acc) -> Acc;
-make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
-
-bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
-bits_to_list([H|_]=List, Mask) ->
- [case H band Mask of
- 0 -> 0;
- _ -> 1
- end|bits_to_list(List, Mask bsr 1)];
-bits_to_list([], _) -> [].
-
-fun_clause({'EXIT',{function_clause,_}}) -> ok.
-
-mkbin(L) when is_list(L) -> list_to_binary(L).
-
-mml() ->
- single_byte_binary = mml_choose(<<42>>),
- multi_byte_binary = mml_choose(<<42,43>>),
- ok.
-
-mml_choose(<<_:8>>) -> single_byte_binary;
-mml_choose(<<_:8, _T/binary>>) -> multi_byte_binary.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_remove3.erl b/lib/hipe/test/bs_SUITE_data/bs_remove3.erl
deleted file mode 100644
index a98b0b5b28..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_remove3.erl
+++ /dev/null
@@ -1,104 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_remove3.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose :
-%%%
-%%% Created : 13 Apr 2004 by Per Gustafsson
-%%%-------------------------------------------------------------------
--module(bs_remove3).
-
--export([test/0]).
-
--define(A, <<56,0,120,0,0,31,255,255,102,42,12,0,3,3,16,5,24,3,240,0,0,32,0,196,
- 2,128,4,0,255,255,254,33,68,96,0,8,8,213,40,192,31,196,0,4,0,0>>).
--define(B, <<28,32,0,96,0,8,0,7,255,255,212,33,98,12,0,0,1,0,48,72,66,3,0,7,240,
- 64,0,0,8,0,0,224,0,10,128,0,64,0,63,255,254,133,10,80,96,0,0,8,1,6,
- 18,4,24,0,63,128,0,0,4,64,0,0>>).
-
-test() ->
- Bin1 = <<30,16,0,90,0,1,0,0,255,255,255,255,81,67,101,7,0,
- 0,0,96,6,12,146,18,14,0,15,252,16,0,0,17,0,0>>,
- Bin = <<Bin1/binary, Bin1/binary>>,
- ?A = loop(Bin, 10, fun run_list/1),
- ?A = loop(Bin, 10, fun run_bin/1),
- ?B = loop(Bin, 10, fun r31/1),
- ok.
-
-loop(Arg, 0, F) ->
- F(Arg);
-loop(Arg, N, F) ->
- F(Arg),
- loop(Arg, N-1, F).
-
-run_list(Bin) ->
- List = run1(Bin),
- list_to_binary(List).
-
-run1(<<A1:2,_:1,A2:2,_:1,A3:2,_:1,A4:2,_:1,
- A5:2,_:1,A6:2,_:1,A7:2,_:1,A8:2,_:1,Rest/binary>>) ->
- [<<A1:2,A2:2,A3:2,A4:2,A5:2,A6:2,A7:2,A8:2>>, run2(Rest)];
-run1(<<A1:2,_:1,A2:2,_:1,A3:2,_:1,A4:2,_:1,A5:2,_:1,A6:1>>) ->
- [<<A1:2,A2:2,A3:2,A4:2,A5:2,A6:1,0:5>>];
-run1(<<A1:2,_:1,A2:2,_:1,A3:2>>) ->
- [<<A1:2,A2:2,A3:2,0:2>>];
-run1(<<>>) ->
- [].
-
-run_bin(Bin) ->
- run2(Bin).
-
-run2(<<A1:2,_:1,A2:2,_:1,A3:2,_:1,A4:2,_:1,
- A5:2,_:1,A6:2,_:1,A7:2,_:1,A8:2,_:1,Rest/binary>>) ->
- Bin = run2(Rest),
- <<A1:2,A2:2,A3:2,A4:2,A5:2,A6:2,A7:2,A8:2,Bin/binary>>;
-run2(<<A1:2,_:1,A2:2,_:1,A3:2,_:1,A4:2,_:1,A5:2,_:1,A6:1>>) ->
- <<A1:2,A2:2,A3:2,A4:2,A5:2,A6:1,0:5>>;
-run2(<<A1:2,_:1,A2:2,_:1,A3:2>>) ->
- <<A1:2,A2:2,A3:2,0:2>>;
-run2(<<>>) ->
- <<>>.
-
-r31(Bin) ->
- List = remove3rd1(0, 0, Bin, [-1]),
- build(List, Bin, 0, <<>>).
-
-build([N1, N2|Rest], Bin, N, Present) ->
- X = N1+1, Y = N2-X,
- S = rest(N2),
- <<_:X,A:Y,_:S,_/binary>> = Bin,
- S1 = rest(N+Y),
- NewPresent = <<Present:N/binary-unit:1, A:Y, 0:S1>>,
- build([N2|Rest], Bin, N+Y, NewPresent);
-
-build([_], _Bin, _N, Present) ->
- Present.
-
-rest(X) ->
- case 8 - (X rem 8) of
- 8 -> 0;
- H -> H
- end.
-
-remove3rd1(N, 2, Bin, List) ->
- S = rest(N+1),
- case Bin of
- <<_:N, 1:1, _:S,_/binary>> ->
- remove3rd1(N+1, 0, Bin, [N|List]);
- <<_:N, 0:1, _:S,_/binary>> ->
- remove3rd1(N+1, 2, Bin, List);
- _ ->
- Size = byte_size(Bin) * 8,
- lists:reverse([Size|List])
- end;
-remove3rd1(N, I, Bin, List) ->
- S = rest(N+1),
- case Bin of
- <<_:N, 1:1, _:S,_/binary>> ->
- remove3rd1(N+1, I+1, Bin, List);
- <<_:N, 0:1, _:S,_/binary>> ->
- remove3rd1(N+1, I, Bin, List);
- _ ->
- Size = byte_size(Bin) * 8,
- lists:reverse([Size|List])
- end.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_save.erl b/lib/hipe/test/bs_SUITE_data/bs_save.erl
deleted file mode 100644
index fe2b1105f2..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_save.erl
+++ /dev/null
@@ -1,21 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_save.erl
-%%% Author : Per Gustafsson
-%%% Purpose : Tests that compilation works for bs_save
-%%% Created : 1 Nov 2007
-%%%-------------------------------------------------------------------
--module(bs_save).
-
--export([test/0]).
-
-test() ->
- {[16257, 1], <<0>>} = inc_on_ones(<<255,1,128,1,128,0>>, 0, [], 5),
- ok.
-
-inc_on_ones(Buffer, _Av, Al, 0) ->
- {lists:reverse(Al), Buffer};
-inc_on_ones(<<1:1, H:7, T/binary>>, Av, Al, Len) ->
- inc_on_ones(T, (Av bsl 7) bor H, Al, Len-1);
-inc_on_ones(<<H, T/binary>>, Av, Al, Len) ->
- inc_on_ones(T, 0, [((Av bsl 7) bor H)|Al], Len-1).
diff --git a/lib/hipe/test/bs_SUITE_data/bs_shell_native.erl b/lib/hipe/test/bs_SUITE_data/bs_shell_native.erl
deleted file mode 100644
index b438f8d9ef..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_shell_native.erl
+++ /dev/null
@@ -1,275 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_shell_native.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : Tests that the Erlang shell works well when in native
-%%% Created : 6 Sep 2006
-%%%-------------------------------------------------------------------
--module(bs_shell_native).
-
--export([prepare_for_test/0, test/0]).
-%% These need to be exported so that we emulate calling them from the shell
--export([parse_and_eval/1, receiver/1, receiver_alot/1, send_alot/3]).
-
-%% This makes sure the shell runs native code
-prepare_for_test() ->
- lists:foreach(fun (M) -> {ok, M} = hipe:c(M) end, [erl_bits, erl_eval]).
-
-test() ->
- ok = eval_bits_in_shell(),
- ok = eval_bin_comp_in_shell(),
- ok.
-
-%%--------------------------------------------------------------------
-%% Tests for bit stream operations including matching, construction
-%% and binary_to_list, list_to_binary in the shell
-eval_bits_in_shell() ->
- <<1:100>> = parse_and_eval("<<1:100>> = <<1:100>>."),
- ok = match(7),
- ok = match(9),
- ok = match1(15),
- ok = match1(31),
- ok = horrid_match(),
- ok = test_bitstr(),
- ok = test_bitsize(),
- ok = asymmetric_tests(),
- ok = big_asymmetric_tests(),
- ok = binary_to_and_from_list(),
- ok = big_binary_to_and_from_list(),
- ok = send_and_receive(),
- ok = send_and_receive_alot(),
- ok.
-
-parse_and_eval(String) ->
- {ok, Toks, _} = erl_scan:string(String),
- {ok, Exprs} = erl_parse:parse_exprs(Toks),
- Bnds = erl_eval:new_bindings(),
- case erl_eval:exprs(Exprs, Bnds) of
- {value, V, _} ->
- V;
- V ->
- V
- end.
-
-match(N) ->
- Str = "N =" ++ integer_to_list(N) ++ ", <<0:N>> = <<0:N>>.",
- <<0:N>> = parse_and_eval(Str),
- ok.
-
-match1(N) ->
- Str = "N =" ++ integer_to_list(N) ++ ", <<42:N/little>> = <<42:N/little>>.",
- <<42:N/little>> = parse_and_eval(Str),
- ok.
-
-test_bitsize() ->
- 101 = parse_and_eval("101 = erlang:bit_size(<<1:101>>)."),
- 1001 = parse_and_eval("1001 = erlang:bit_size(<<1:1001>>)."),
- 80 = parse_and_eval("80 = erlang:bit_size(<<1:80>>)."),
- 800 = parse_and_eval("800 = erlang:bit_size(<<1:800>>)."),
- S =
- "Bin = <<0:16#1000000>>,"
- "BigBin = list_to_bitstring([Bin||_ <- lists:seq(1,16#10)] ++ [<<1:1>>]),"
- "16#10000001 = erlang:bit_size(BigBin).",
- 16#10000001 = parse_and_eval(S),
- %% Only run these on computers with lots of memory
- %% HugeBin = list_to_bitstring([BigBin||_ <- lists:seq(1,16#10)]++[<<1:1>>]),
- %% 16#100000011 = erlang:bit_size(HugeBin),
- 0 = parse_and_eval("0 = erlang:bit_size(<<>>)."),
- ok.
-
-horrid_match() ->
- S = "<<1:4,B:24/bitstring>> = <<1:4,42:24/little>>, <<42:24/little>> = B.",
- <<42:24/little>> = parse_and_eval(S),
- ok.
-
-test_bitstr() ->
- S =
- "<<1:7,B/bitstring>> = <<1:7,<<1:1,6>>/bitstring>>,"
- "<<1:1,6>> = B,"
- "B = <<1:1,6>>.",
- <<1:1,6>> = parse_and_eval(S),
- ok.
-
-asymmetric_tests() ->
- <<1:12>> = parse_and_eval("<<1:12>> = <<0,1:4>>."),
- <<0,1:4>> = parse_and_eval("<<0,1:4>> = <<1:12>>."),
- S1 =
- "<<1:1,X/bitstring>> = <<128,255,0,0:2>>,"
- "<<1,254,0,0:1>> = X,"
- "X = <<1,254,0,0:1>>.",
- <<1,254,0,0:1>> = parse_and_eval(S1),
- S2 =
- "<<1:1,X1:25/bitstring>> = <<128,255,0,0:2>>,"
- "<<1,254,0,0:1>> = X1,"
- "X1 = <<1,254,0,0:1>>.",
- <<1,254,0,0:1>> = parse_and_eval(S2),
- ok.
-
-big_asymmetric_tests() ->
- <<1:875,1:12>> = parse_and_eval("<<1:875,1:12>> = <<1:875,0,1:4>>."),
- <<1:875,0,1:4>> = parse_and_eval("<<1:875,0,1:4>> = <<1:875,1:12>>."),
- S1 =
- "<<1:1,X/bitstring>> = <<128,255,0,0:2,1:875>>,"
- "<<1,254,0,0:1,1:875>> = X,"
- "X = <<1,254,0,0:1,1:875>>.",
- <<1,254,0,0:1,1:875>> = parse_and_eval(S1),
- S2 =
- "<<1:1,X1:900/bitstring>> = <<128,255,0,0:2,1:875>>,"
- "<<1,254,0,0:1,1:875>> = X1,"
- "X1 = <<1,254,0,0:1,1:875>>.",
- parse_and_eval(S2),
- ok.
-
-binary_to_and_from_list() ->
- <<1:7>> = parse_and_eval("list_to_bitstring(bitstring_to_list(<<1:7>>))."),
- <<1,2,3,4,1:1>> = parse_and_eval("list_to_bitstring(bitstring_to_list(<<1,2,3,4,1:1>>))."),
- [1,2,3,4,<<1:1>>] = parse_and_eval("bitstring_to_list(<<1,2,3,4,1:1>>)."),
- <<1:1,1,2,3,4>> = parse_and_eval("list_to_bitstring([<<1:1>>,1,2,3,4])."),
- [128,129,1,130,<<0:1>>] = parse_and_eval("bitstring_to_list(<<1:1,1,2,3,4>>)."),
- ok.
-
-big_binary_to_and_from_list() ->
- S1 = "erlang:list_to_bitstring(bitstring_to_list(<<1:800,2,3,4,1:1>>)).",
- <<1:800,2,3,4,1:1>> = parse_and_eval(S1),
- S2 = "erlang:bitstring_to_list(<<1,2,3,4,1:800,1:1>>).",
- [1,2,3,4|_Rest1] = parse_and_eval(S2),
- S3 = "erlang:list_to_bitstring([<<1:801>>,1,2,3,4]).",
- <<1:801,1,2,3,4>> = parse_and_eval(S3),
- ok.
-
-send_and_receive() ->
- S =
- "Bin = <<1,2:7>>,"
- "Pid = spawn(fun() -> bs_shell_native:receiver(Bin) end),"
- "Pid ! {self(),<<1:7,8:5,Bin/bitstring>>},"
- "receive ok -> ok end.",
- parse_and_eval(S).
-
-receiver(Bin) ->
- receive
- {Pid, <<1:7,8:5,Bin/bitstring>>} ->
- Pid ! ok
- end.
-
-send_and_receive_alot() ->
- S =
- "Bin = <<1:1000001>>,"
- "Pid = spawn(fun() -> bs_shell_native:receiver_alot(Bin) end),"
- "bs_shell_native:send_alot(100,Bin,Pid).",
- parse_and_eval(S).
-
-send_alot(N,Bin,Pid) when N > 0 ->
- Pid ! {self(),<<1:7,8:5,Bin/bitstring>>},
- receive
- ok ->
- ok
- end,
- send_alot(N-1,Bin,Pid);
-send_alot(0,_Bin,Pid) ->
- Pid ! no_more,
- ok.
-
-receiver_alot(Bin) ->
- receive
- {Pid, <<1:7,8:5,Bin/bitstring>>} ->
- Pid ! ok;
- no_more -> ok
- end,
- receiver_alot(Bin).
-
-%%--------------------------------------------------------------------
-
-eval_bin_comp_in_shell() ->
- ok = byte_aligned(),
- ok = bit_aligned(),
- ok = extended_byte_aligned(),
- ok = extended_bit_aligned(),
- ok = mixed(),
- ok.
-
-byte_aligned() ->
- <<"abcdefg">> =
- parse_and_eval("<<\"abcdefg\">> = << <<(X+32)>> || <<X>> <= <<\"ABCDEFG\">> >>."),
- <<1:32/little,2:32/little,3:32/little,4:32/little>> =
- parse_and_eval("<<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || <<X:32>> <= <<1:32,2:32,3:32,4:32>> >>."),
- <<1:32/little,2:32/little,3:32/little,4:32/little>> =
- parse_and_eval("<<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || <<X:16>> <= <<1:16,2:16,3:16,4:16>> >>."),
- ok.
-
-bit_aligned() ->
- <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
- parse_and_eval("<<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
- << <<(X+32):7>> || <<X>> <= <<\"ABCDEFG\">> >>."),
- <<"ABCDEFG">> =
- parse_and_eval("<<\"ABCDEFG\">> =
- << <<(X-32)>> || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> >>."),
- <<1:31/little,2:31/little,3:31/little,4:31/little>> =
- parse_and_eval("<<1:31/little,2:31/little,3:31/little,4:31/little>> =
- << <<X:31/little>> || <<X:31>> <= <<1:31,2:31,3:31,4:31>> >>."),
- <<1:31/little,2:31/little,3:31/little,4:31/little>> =
- parse_and_eval("<<1:31/little,2:31/little,3:31/little,4:31/little>> =
- << <<X:31/little>> || <<X:15>> <= <<1:15,2:15,3:15,4:15>> >>."),
- ok.
-
-extended_byte_aligned() ->
- <<"abcdefg">> =
- parse_and_eval("<<\"abcdefg\">> = << <<(X+32)>> || X <- \"ABCDEFG\" >>."),
- "abcdefg" =
- parse_and_eval("\"abcdefg\" = [(X+32) || <<X>> <= <<\"ABCDEFG\">>]."),
- <<1:32/little,2:32/little,3:32/little,4:32/little>> =
- parse_and_eval("<<1:32/little,2:32/little,3:32/little,4:32/little>> =
- << <<X:32/little>> || X <- [1,2,3,4] >>."),
- [256,512,768,1024] =
- parse_and_eval("[256,512,768,1024] =
- [X || <<X:16/little>> <= <<1:16,2:16,3:16,4:16>>]."),
- ok.
-
-extended_bit_aligned() ->
- <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
- parse_and_eval("<<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
- << <<(X+32):7>> || X <- \"ABCDEFG\" >>."),
- "ABCDEFG" =
- parse_and_eval("\"ABCDEFG\" = [(X-32) || <<X:7>> <=
-<<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>]."),
- <<1:31/little,2:31/little,3:31/little,4:31/little>> =
- parse_and_eval("<<1:31/little,2:31/little,3:31/little,4:31/little>> =
- << <<X:31/little>> || X <- [1,2,3,4] >>."),
- [256,512,768,1024] =
- parse_and_eval("[256,512,768,1024] =
- [X || <<X:15/little>> <= <<1:15,2:15,3:15,4:15>>]."),
- ok.
-
-mixed() ->
- <<2,3,3,4,4,5,5,6>> =
- parse_and_eval("<<2,3,3,4,4,5,5,6>> =
- << <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>> >>."),
- <<2,3,3,4,4,5,5,6>> =
- parse_and_eval("<<2,3,3,4,4,5,5,6>> =
- << <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, Y <- [1,2] >>."),
- <<2,3,3,4,4,5,5,6>> =
- parse_and_eval("<<2,3,3,4,4,5,5,6>> =
- << <<(X+Y)>> || X <- [1,2,3,4], Y <- [1,2] >>."),
- [2,3,3,4,4,5,5,6] =
- parse_and_eval("[2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>>]."),
- [2,3,3,4,4,5,5,6] =
- parse_and_eval("[2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X>> <= <<1,2,3,4>>, Y <- [1,2]]."),
- <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- parse_and_eval("<<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- << <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>> >>."),
- <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- parse_and_eval("<<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- << <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2] >>."),
- <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- parse_and_eval("<<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
- << <<(X+Y):3>> || X <- [1,2,3,4], Y <- [1,2] >>."),
- [2,3,3,4,4,5,5,6] =
- parse_and_eval("[2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>]."),
- [2,3,3,4,4,5,5,6] =
- parse_and_eval("[2,3,3,4,4,5,5,6] =
- [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2]]."),
- ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_split.erl b/lib/hipe/test/bs_SUITE_data/bs_split.erl
deleted file mode 100644
index 617543f789..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_split.erl
+++ /dev/null
@@ -1,105 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-
--module(bs_split).
-
--export([test/0]).
-
-test() ->
- Funs = [fun byte_split_binary/0, fun bit_split_binary/0, fun z_split/0],
- lists:foreach(fun (F) -> ok = F() end, Funs).
-
-%%--------------------------------------------------------------------
-
-byte_split_binary() ->
- L = lists:seq(0, 57),
- B = mkbin(L),
- byte_split(L, B, byte_size(B)).
-
-byte_split(L, B, Pos) when Pos >= 0 ->
- Sz1 = Pos,
- Sz2 = byte_size(B) - Pos,
- bs1(L, B, Pos, Sz1, Sz2);
-byte_split(_, _, _) -> ok.
-
-bs1(L, B, Pos, Sz1, Sz2) ->
- <<B1:Sz1/binary, B2:Sz2/binary>> = B,
- bs2(L, B, Pos, B1, B2).
-
-bs2(L, B, Pos, B1, B2) ->
- B1 = list_to_binary(lists:sublist(L, 1, Pos)),
- bs3(L, B, Pos, B2).
-
-bs3(L, B, Pos, B2) ->
- B2 = list_to_binary(lists:nthtail(Pos, L)),
- byte_split(L, B, Pos - 1).
-
-%%--------------------------------------------------------------------
-
-bit_split_binary() ->
- Fun = fun(Bin, List, SkipBef, N) ->
- SkipAft = bit_size(Bin) - N - SkipBef,
- %% io:format("~p, ~p, ~p", [SkipBef,N,SkipAft]),
- <<_I1:SkipBef,OutBin:N/binary-unit:1,_I2:SkipAft>> = Bin,
- OutBin = make_bin_from_list(List, N)
- end,
- bit_split_binary1(Fun, erlang:md5(<<1,2,3>>)).
-
-bit_split_binary1(Action, Bin) ->
- BitList = bits_to_list(binary_to_list(Bin), 16#80),
- bit_split_binary2(Action, Bin, BitList, 0).
-
-bit_split_binary2(Action, Bin, [_|T]=List, Bef) ->
- bit_split_binary3(Action, Bin, List, Bef, bit_size(Bin)),
- bit_split_binary2(Action, Bin, T, Bef+1);
-bit_split_binary2(_Action, _Bin, [], _Bef) -> ok.
-
-bit_split_binary3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
- Action(Bin, List, Bef, (Aft-Bef) div 8 * 8),
- bit_split_binary3(Action, Bin, List, Bef, Aft - 8);
-bit_split_binary3(_, _, _, _, _) -> ok.
-
-make_bin_from_list(_List, 0) ->
- mkbin([]);
-make_bin_from_list(List, N) ->
- list_to_binary([make_int(List, 8, 0),
- make_bin_from_list(lists:nthtail(8, List), N - 8)]).
-
-make_int(_List, 0, Acc) -> Acc;
-make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
-
-bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
-bits_to_list([H|_]=List, Mask) ->
- [case H band Mask of
- 0 -> 0;
- _ -> 1
- end|bits_to_list(List, Mask bsr 1)];
-bits_to_list([], _) -> [].
-
-mkbin(L) when is_list(L) -> list_to_binary(L).
-
-%%--------------------------------------------------------------------
-%% Splits a series of null terminated segments of a binary without
-%% creating any new sub-binaries until the zero is found.
-
-z_split() ->
- [<<61,62,63>>] = z_split(<<61,62,63>>),
- [<<61,62,63>>, <<>>] = z_split(<<61,62,63,0>>),
- [<<61,62,63>>, <<64>>] = z_split(<<61,62,63,0,64>>),
- [<<61,62,63>>, <<64,65,66>>] = z_split(<<61,62,63,0,64,65,66>>),
- [<<61,62>>, <<64>>, <<>>, <<65,66>>] = z_split(<<61,62,0,64,0,0,65,66>>),
- ok.
-
-z_split(B) when is_binary(B) ->
- z_split(B, 0).
-
-z_split(B, N) ->
- case B of
- <<_B1:N/binary,0,_B2/binary>> -> % use skip_bits for B1, B2
- <<B1:N/binary,_,B2/binary>> = B, % and postpone the matching
- [B1 | z_split(B2)];
- <<_:N/binary>> ->
- [B];
- _ ->
- z_split(B, N + 1)
- end.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_system_limit_32.erl b/lib/hipe/test/bs_SUITE_data/bs_system_limit_32.erl
deleted file mode 100644
index eccb0083bd..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_system_limit_32.erl
+++ /dev/null
@@ -1,26 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% File : bs_system_limit_32.erl
-%%% Author : Per Gustafsson <pergu@it.uu.se>
-%%% Purpose : Checks binary system limits on 32-bit machines
-%%% Created : 14 May 2008
-%%%-------------------------------------------------------------------
--module(bs_system_limit_32).
-
--export([test/0]).
-
-test() ->
- case erlang:system_info(wordsize) of
- 4 -> system_limit_32();
- 8 -> ok
- end.
-
-system_limit_32() ->
- {'EXIT', {badarg, _}} = (catch <<42:(id(-1))>>),
- {'EXIT', {badarg, _}} = (catch <<42:(id(-389739873536870912))/unit:8>>),
- {'EXIT', {system_limit, _}} = (catch <<32:536870912/unit:8>>),
- {'EXIT', {system_limit, _}} = (catch <<42:(id(536870912))/unit:8>>),
- {'EXIT', {system_limit, _}} = (catch <<42:(id(536870912))/unit:8,1:1>>),
- ok.
-
-id(X) -> X.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_utf.erl b/lib/hipe/test/bs_SUITE_data/bs_utf.erl
deleted file mode 100644
index 368ad0cd20..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_utf.erl
+++ /dev/null
@@ -1,356 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------
-%% Purpose: test support for UTF datatypes in binaries
-%%
-%% Most of it taken from emulator/test/bs_utf_SUITE.erl
-%%-------------------------------------------------------------------
-
--module(bs_utf).
-
--export([test/0]).
-
--include_lib("common_test/include/ct.hrl").
-
-test() ->
- ok = utf8_cm65(),
- ok = utf8_roundtrip(),
- ok = utf16_roundtrip(),
- ok = utf32_roundtrip(),
- %% The following were problematic for the LLVM backend
- ok = utf8_illegal_sequences(),
- ok = utf16_illegal_sequences(),
- ok = utf32_illegal_sequences(),
- ok.
-
-%%-------------------------------------------------------------------
-%% A test with construction and matching
-
-utf8_cm65() ->
- <<65>> = b65utf8(),
- ok = m(<<65>>).
-
-b65utf8() ->
- <<65/utf8>>.
-
-m(<<65/utf8>>) ->
- ok.
-
-%%-------------------------------------------------------------------
-
-utf8_roundtrip() ->
- ok = utf8_roundtrip(0, 16#D7FF),
- ok = utf8_roundtrip(16#E000, 16#10FFFF),
- ok.
-
-utf8_roundtrip(First, Last) when First =< Last ->
- Bin = int_to_utf8(First),
- Bin = id(<<First/utf8>>),
- Bin = id(<<(id(<<>>))/binary,First/utf8>>),
- Unaligned = id(<<3:2,First/utf8>>),
- <<_:2,Bin/binary>> = Unaligned,
- <<First/utf8>> = Bin,
- <<First/utf8>> = make_unaligned(Bin),
- utf8_roundtrip(First+1, Last);
-utf8_roundtrip(_, _) ->
- ok.
-
-%%-------------------------------------------------------------------
-
-utf16_roundtrip() ->
- Big = fun utf16_big_roundtrip/1,
- Little = fun utf16_little_roundtrip/1,
- PidRefs = [spawn_monitor(fun() -> do_utf16_roundtrip(Fun) end) ||
- Fun <- [Big,Little]],
- [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end ||
- {Pid, Ref} <- PidRefs],
- ok.
-
-do_utf16_roundtrip(Fun) ->
- do_utf16_roundtrip(0, 16#D7FF, Fun),
- do_utf16_roundtrip(16#E000, 16#10FFFF, Fun).
-
-do_utf16_roundtrip(First, Last, Fun) when First =< Last ->
- Fun(First),
- do_utf16_roundtrip(First+1, Last, Fun);
-do_utf16_roundtrip(_, _, _) -> ok.
-
-utf16_big_roundtrip(Char) ->
- Bin = id(<<Char/utf16>>),
- Bin = id(<<(id(<<>>))/binary,Char/utf16>>),
- Unaligned = id(<<3:2,Char/utf16>>),
- <<_:2,Bin/binary>> = Unaligned,
- <<Char/utf16>> = Bin,
- <<Char/utf16>> = make_unaligned(Bin),
- ok.
-
-utf16_little_roundtrip(Char) ->
- Bin = id(<<Char/little-utf16>>),
- Bin = id(<<(id(<<>>))/binary,Char/little-utf16>>),
- Unaligned = id(<<3:2,Char/little-utf16>>),
- <<_:2,Bin/binary>> = Unaligned,
- <<Char/little-utf16>> = Bin,
- <<Char/little-utf16>> = make_unaligned(Bin),
- ok.
-
-%%-------------------------------------------------------------------
-
-utf32_roundtrip() ->
- Big = fun utf32_big_roundtrip/1,
- Little = fun utf32_little_roundtrip/1,
- PidRefs = [spawn_monitor(fun() -> do_utf32_roundtrip(Fun) end) ||
- Fun <- [Big,Little]],
- [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end ||
- {Pid, Ref} <- PidRefs],
- ok.
-
-do_utf32_roundtrip(Fun) ->
- do_utf32_roundtrip(0, 16#D7FF, Fun),
- do_utf32_roundtrip(16#E000, 16#10FFFF, Fun).
-
-do_utf32_roundtrip(First, Last, Fun) when First =< Last ->
- Fun(First),
- do_utf32_roundtrip(First+1, Last, Fun);
-do_utf32_roundtrip(_, _, _) -> ok.
-
-utf32_big_roundtrip(Char) ->
- Bin = id(<<Char/utf32>>),
- Bin = id(<<(id(<<>>))/binary,Char/utf32>>),
- Unaligned = id(<<3:2,Char/utf32>>),
- <<_:2,Bin/binary>> = Unaligned,
- <<Char/utf32>> = Bin,
- <<Char/utf32>> = make_unaligned(Bin),
- ok.
-
-utf32_little_roundtrip(Char) ->
- Bin = id(<<Char/little-utf32>>),
- Bin = id(<<(id(<<>>))/binary,Char/little-utf32>>),
- Unaligned = id(<<3:2,Char/little-utf32>>),
- <<_:2,Bin/binary>> = Unaligned,
- <<Char/little-utf32>> = Bin,
- <<Char/little-utf32>> = make_unaligned(Bin),
- ok.
-
-%%-------------------------------------------------------------------
-
-utf8_illegal_sequences() ->
- fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large.
- fail_range(16#D800, 16#DFFF), % Reserved for UTF-16.
-
- %% Illegal first character.
- [fail(<<I,16#8F,16#8F,16#8F>>) || I <- lists:seq(16#80, 16#BF)],
-
- %% Short sequences.
- short_sequences(16#80, 16#10FFFF),
-
- %% Overlong sequences. (Using more bytes than necessary
- %% is not allowed.)
- overlong(0, 127, 2),
- overlong(128, 16#7FF, 3),
- overlong(16#800, 16#FFFF, 4),
- ok.
-
-fail_range(Char, End) when Char =< End ->
- {'EXIT', _} = (catch <<Char/utf8>>),
- Bin = int_to_utf8(Char),
- fail(Bin),
- fail_range(Char+1, End);
-fail_range(_, _) -> ok.
-
-short_sequences(Char, End) ->
- Step = (End - Char) div erlang:system_info(schedulers) + 1,
- PidRefs = short_sequences_1(Char, Step, End),
- [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end ||
- {Pid, Ref} <- PidRefs],
- ok.
-
-short_sequences_1(Char, Step, End) when Char =< End ->
- CharEnd = lists:min([Char+Step-1,End]),
- [spawn_monitor(fun() ->
- %% io:format("~p - ~p\n", [Char, CharEnd]),
- do_short_sequences(Char, CharEnd)
- end)|short_sequences_1(Char+Step, Step, End)];
-short_sequences_1(_, _, _) -> [].
-
-do_short_sequences(Char, End) when Char =< End ->
- short_sequence(Char),
- do_short_sequences(Char+1, End);
-do_short_sequences(_, _) -> ok.
-
-short_sequence(I) ->
- case int_to_utf8(I) of
- <<S0:3/binary,_:8>> ->
- <<S1:2/binary,R1:8>> = S0,
- <<S2:1/binary,_:8>> = S1,
- fail(S0),
- fail(S1),
- fail(S2),
- fail(<<S2/binary,16#7F,R1,R1>>),
- fail(<<S1/binary,16#7F,R1>>),
- fail(<<S0/binary,16#7F>>);
- <<S0:2/binary,_:8>> ->
- <<S1:1/binary,R1:8>> = S0,
- fail(S0),
- fail(S1),
- fail(<<S0/binary,16#7F>>),
- fail(<<S1/binary,16#7F>>),
- fail(<<S1/binary,16#7F,R1>>);
- <<S:1/binary,_:8>> ->
- fail(S),
- fail(<<S/binary,16#7F>>)
- end.
-
-overlong(Char, Last, NumBytes) when Char =< Last ->
- overlong(Char, NumBytes),
- overlong(Char+1, Last, NumBytes);
-overlong(_, _, _) -> ok.
-
-overlong(Char, NumBytes) when NumBytes < 5 ->
- case int_to_utf8(Char, NumBytes) of
- <<Char/utf8>>=Bin ->
- ?t:fail({illegal_encoding_accepted,Bin,Char});
- <<OtherChar/utf8>>=Bin ->
- ?t:fail({illegal_encoding_accepted,Bin,Char,OtherChar});
- _ -> ok
- end,
- overlong(Char, NumBytes+1);
-overlong(_, _) -> ok.
-
-fail(Bin) ->
- fail_1(Bin),
- fail_1(make_unaligned(Bin)).
-
-fail_1(<<Char/utf8>> = Bin) ->
- ?t:fail({illegal_encoding_accepted, Bin, Char});
-fail_1(_) -> ok.
-
-%%-------------------------------------------------------------------
-
-utf16_illegal_sequences() ->
- utf16_fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large.
- utf16_fail_range(16#D800, 16#DFFF), % Reserved for UTF-16.
- lonely_hi_surrogate(16#D800, 16#DFFF),
- leading_lo_surrogate(16#DC00, 16#DFFF),
- ok.
-
-utf16_fail_range(Char, End) when Char =< End ->
- {'EXIT', _} = (catch <<Char/big-utf16>>),
- {'EXIT', _} = (catch <<Char/little-utf16>>),
- utf16_fail_range(Char+1, End);
-utf16_fail_range(_, _) -> ok.
-
-lonely_hi_surrogate(Char, End) when Char =< End ->
- BinBig = <<Char:16/big>>,
- BinLittle = <<Char:16/little>>,
- case {BinBig,BinLittle} of
- {<<Bad/big-utf16>>,_} ->
- ?t:fail({lonely_hi_surrogate_accepted,Bad});
- {_,<<Bad/little-utf16>>} ->
- ?t:fail({lonely_hi_surrogate_accepted,Bad});
- {_,_} ->
- ok
- end,
- lonely_hi_surrogate(Char+1, End);
-lonely_hi_surrogate(_, _) -> ok.
-
-leading_lo_surrogate(Char, End) when Char =< End ->
- leading_lo_surrogate(Char, 16#D800, 16#DFFF),
- leading_lo_surrogate(Char+1, End);
-leading_lo_surrogate(_, _) -> ok.
-
-leading_lo_surrogate(HiSurr, LoSurr, End) when LoSurr =< End ->
- BinBig = <<HiSurr:16/big,LoSurr:16/big>>,
- BinLittle = <<HiSurr:16/little,LoSurr:16/little>>,
- case {BinBig,BinLittle} of
- {<<Bad/big-utf16,_/bits>>,_} ->
- ?t:fail({leading_lo_surrogate_accepted,Bad});
- {_,<<Bad/little-utf16,_/bits>>} ->
- ?t:fail({leading_lo_surrogate_accepted,Bad});
- {_,_} ->
- ok
- end,
- leading_lo_surrogate(HiSurr, LoSurr+1, End);
-leading_lo_surrogate(_, _, _) -> ok.
-
-%%-------------------------------------------------------------------
-
-utf32_illegal_sequences() ->
- utf32_fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large.
- utf32_fail_range(16#D800, 16#DFFF), % Reserved for UTF-16.
- utf32_fail_range(-100, -1),
- ok.
-
-utf32_fail_range(Char, End) when Char =< End ->
- {'EXIT', _} = (catch <<Char/big-utf32>>),
- {'EXIT', _} = (catch <<Char/little-utf32>>),
- case {<<Char:32>>,<<Char:32/little>>} of
- {<<Unexpected/utf32>>,_} ->
- ?t:fail(Unexpected);
- {_,<<Unexpected/little-utf32>>} ->
- ?t:fail(Unexpected);
- {_,_} -> ok
- end,
- utf32_fail_range(Char+1, End);
-utf32_fail_range(_, _) -> ok.
-
-%%-------------------------------------------------------------------
-%% This function intentionally allows construction of UTF-8 sequence
-%% in illegal ranges.
-
-int_to_utf8(I) when I =< 16#7F ->
- <<I>>;
-int_to_utf8(I) when I =< 16#7FF ->
- B2 = I,
- B1 = (I bsr 6),
- <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
-int_to_utf8(I) when I =< 16#FFFF ->
- B3 = I,
- B2 = (I bsr 6),
- B1 = (I bsr 12),
- <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
-int_to_utf8(I) when I =< 16#3FFFFF ->
- B4 = I,
- B3 = (I bsr 6),
- B2 = (I bsr 12),
- B1 = (I bsr 18),
- <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>;
-int_to_utf8(I) when I =< 16#3FFFFFF ->
- B5 = I,
- B4 = (I bsr 6),
- B3 = (I bsr 12),
- B2 = (I bsr 18),
- B1 = (I bsr 24),
- <<1:1,1:1,1:1,1:1,1:1,0:1,B1:2,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6,
- 1:1,0:1,B5:6>>.
-
-%% int_to_utf8(I, NumberOfBytes) -> Binary.
-%% This function can be used to construct overlong sequences.
-int_to_utf8(I, 1) ->
- <<I>>;
-int_to_utf8(I, 2) ->
- B2 = I,
- B1 = (I bsr 6),
- <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
-int_to_utf8(I, 3) ->
- B3 = I,
- B2 = (I bsr 6),
- B1 = (I bsr 12),
- <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
-int_to_utf8(I, 4) ->
- B4 = I,
- B3 = (I bsr 6),
- B2 = (I bsr 12),
- B1 = (I bsr 18),
- <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>.
-
-%%-------------------------------------------------------------------
-
-make_unaligned(Bin0) when is_binary(Bin0) ->
- Bin1 = <<0:3,Bin0/binary,31:5>>,
- Sz = byte_size(Bin0),
- <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
- Bin.
-
-%%-------------------------------------------------------------------
-%% Just to prevent compiler optimizations
-
-id(X) -> X.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_var_segs.erl b/lib/hipe/test/bs_SUITE_data/bs_var_segs.erl
deleted file mode 100644
index a20df04b53..0000000000
--- a/lib/hipe/test/bs_SUITE_data/bs_var_segs.erl
+++ /dev/null
@@ -1,76 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%--------------------------------------------------------------------
-%% Author : Kostis Sagonas
-%% Purpose : These tests are intended to test the construction and
-%% matching of binaries using variable sizes
-%% Notes :
-%% - Added test that crashed BEAM compiler
-%% - Added test that crashed when segments of size zero were used
-%% and one that did not convert integers to floats when constructing
-%% binaries.
-%% - Added a construction test which crashed from core because of
-%% problems with the effect flag (2004/11/15)
-%%--------------------------------------------------------------------
--module(bs_var_segs).
-
--export([test/0]).
-
-test() ->
- N1 = 18,
- A1 = 2,
- A1 = match1(N1, <<1:12, 2:N1, A1:2>>),
- A1 = match2(N1, <<1:12, 2:N1/integer-little, A1:2>>),
- N3 = 3,
- A3 = <<1,2,3>>,
- B3 = 2,
- {A3, B3} = match3(N3, <<1:12, A3:N3/binary, B3:4>>),
- N4 = 12,
- B4 = <<1,2,3>>,
- A4 = 2,
- {A4, B4} = match4(N4, <<1:N4, A4:4, B4/binary>>),
- Y = <<5>>,
- Y = match5(a, Y),
- <<73>> = gen1(8, 0, <<73>>),
- <<171>> = gen2(8, 7, 2#10101010101010101),
- <<0:64>> = construct(),
- <<0:32>> = construct2(0),
- ok = in_guard(<<16#BCD:14,3:2>>, 16#BCD),
- ok.
-
-construct() ->
- <<0:64/float>>.
-
-construct2(X) ->
- <<X:32/little>>.
-
-match1(N, Bin) ->
- <<1:12, 2:N, A:2>>=Bin,
- A.
-
-match2(N, Bin) ->
- <<1:12, 2:N/integer-little, A:2>>=Bin,
- A.
-
-match3(N, Bin) ->
- <<1:12, A:N/binary, B:4>>=Bin,
- {A,B}.
-
-match4(N, Bin) ->
- <<1:N, A:4, B/binary>>=Bin,
- {A,B}.
-
-match5(X, Y) ->
- case X of
- a ->
- Y2 = 8
- end,
- <<5:Y2>> = Y.
-
-gen1(N, S, A) ->
- <<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>.
-
-gen2(N, S, A) ->
- <<A:S/little, A:(N-S)/little>>.
-
-in_guard(Bin, A) when <<A:14,3:2>> == Bin -> ok;
-in_guard(_, _) -> no.
diff --git a/lib/hipe/test/hipe.spec b/lib/hipe/test/hipe.spec
deleted file mode 100644
index 2894f40354..0000000000
--- a/lib/hipe/test/hipe.spec
+++ /dev/null
@@ -1,6 +0,0 @@
-%% -*- erlang -*-
-
-{alias, tests, "../hipe_test"}.
-
-{suites, tests, all}.
-
diff --git a/lib/hipe/test/hipe_SUITE.erl b/lib/hipe/test/hipe_SUITE.erl
deleted file mode 100644
index b9adb660f2..0000000000
--- a/lib/hipe/test/hipe_SUITE.erl
+++ /dev/null
@@ -1,57 +0,0 @@
-%% ``Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
--module(hipe_SUITE).
-
--export([all/0, groups/0,
- init_per_suite/1, end_per_suite/1,
- init_per_group/2, end_per_group/2,
- app/0, app/1, appup/0, appup/1]).
-
--include_lib("common_test/include/ct.hrl").
-
-all() ->
- [app, appup].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- case erlang:system_info(hipe_architecture) of
- undefined -> {skip, "HiPE not available or enabled"};
- _ -> Config
- end.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-app() ->
- [{doc, "Test that the hipe app file is ok"}].
-app(Config) when is_list(Config) ->
- ok = ?t:app_test(hipe, tolerant).
-
-appup() ->
- [{doc, "Test that the hipe appup file is ok"}].
-appup(Config) when is_list(Config) ->
- AppupFile = "hipe.appup",
- AppupPath = filename:join([code:lib_dir(hipe), "ebin", AppupFile]),
- {ok, [{_Vsn, [], []}]} = file:consult(AppupPath).
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
deleted file mode 100644
index c506dd5e1d..0000000000
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ /dev/null
@@ -1,185 +0,0 @@
--module(hipe_testsuite_driver).
-
--export([create_all_suites/1, run/3]).
-
--include_lib("kernel/include/file.hrl").
-
--type testcase() :: atom().
--type file_type() :: 'device' | 'directory' | 'regular' | 'other'.
--type ext_posix() :: file:posix() | 'badarg'.
-
--define(suite_suffix, "_SUITE").
--define(data_folder, "_data").
--define(suite_data, ?suite_suffix ++ ?data_folder).
-
--record(suite, {suitename :: string(),
- outputfile :: file:io_device(),
- testcases :: [testcase()]}).
-
--spec create_all_suites([string()]) -> 'ok'.
-
-create_all_suites(SuitesWithSuiteSuffix) ->
- Suites = get_suites(SuitesWithSuiteSuffix),
- lists:foreach(fun create_suite/1, Suites).
-
--spec get_suites([string()]) -> [string()].
-
-get_suites(SuitesWithSuiteSuffix) ->
- Prefixes = [suffix(F, ?suite_suffix) || F <- SuitesWithSuiteSuffix],
- [S || {yes, S} <- Prefixes].
-
-suffix(String, Suffix) ->
- case string:split(String, Suffix, trailing) of
- [Prefix,[]] -> {yes, Prefix};
- _ -> no
- end.
-
--spec file_type(file:filename()) -> {ok, file_type()} | {error, ext_posix()}.
-
-file_type(Filename) ->
- case file:read_file_info(Filename) of
- {ok, FI} -> {ok, FI#file_info.type};
- Error -> Error
- end.
-
--spec create_suite(string()) -> 'ok'.
-
-create_suite(SuiteName) ->
- {ok, Cwd} = file:get_cwd(),
- SuiteDirN = filename:join(Cwd, SuiteName ++ ?suite_data),
- OutputFile = generate_suite_file(Cwd, SuiteName),
- generate_suite(SuiteName, OutputFile, SuiteDirN).
-
-generate_suite_file(Cwd, SuiteName) ->
- F = filename:join(Cwd, SuiteName ++ ?suite_suffix ++ ".erl"),
- case file:open(F, [write]) of
- {ok, IoDevice} -> IoDevice;
- {error, _} = E -> exit({E, F})
- end.
-
-generate_suite(SuiteName, OutputFile, SuiteDirN) ->
- TestCases = list_testcases(SuiteDirN),
- Suite = #suite{suitename = SuiteName, outputfile = OutputFile,
- testcases = TestCases},
- write_suite(Suite),
- file:close(OutputFile).
-
-list_testcases(Dirname) ->
- {ok, Files} = list_dir(Dirname, ".erl", true),
- [list_to_atom(filename:basename(F, ".erl")) || F <- Files].
-
--spec list_dir(file:filename(), string(), boolean()) ->
- {error, ext_posix()} | {ok, [file:filename()]}.
-
-list_dir(Dir, Extension, Dirs) ->
- case file:list_dir(Dir) of
- {error, _} = Error -> Error;
- {ok, Filenames} ->
- FullFilenames = [filename:join(Dir, F) || F <- Filenames],
- Matches1 = case Dirs of
- true ->
- [F || F <- FullFilenames,
- file_type(F) =:= {ok, 'directory'}];
- false -> []
- end,
- Matches2 = [F || F <- FullFilenames,
- file_type(F) =:= {ok, 'regular'},
- filename:extension(F) =:= Extension],
- {ok, lists:sort(Matches1 ++ Matches2)}
- end.
-
-write_suite(Suite) ->
- write_header(Suite),
- write_testcases(Suite).
-
-write_header(#suite{suitename = SuiteName, outputfile = OutputFile,
- testcases = TestCases}) ->
- Exports = format_export(TestCases),
- TimeLimit = 6, %% with 1, 2, or 3 it fails on some slow machines...
- io:format(OutputFile,
- "%% ATTENTION!\n"
- "%% This is an automatically generated file. Do not edit.\n\n"
- "-module(~s).\n\n"
- "-export([suite/0, init_per_suite/0, init_per_suite/1,\n"
- " end_per_suite/1, all/0]).\n"
- "~s\n\n"
- "-include_lib(\"common_test/include/ct.hrl\").\n\n"
- "suite() ->\n"
- " [{timetrap, {minutes, ~w}}].\n\n"
- "init_per_suite() ->\n"
- " [].\n\n"
- "init_per_suite(Config) ->\n"
- " case erlang:system_info(hipe_architecture) of\n"
- " undefined -> {skip, \"HiPE not available or enabled\"};\n"
- " _ -> Config\n"
- " end.\n\n"
- "end_per_suite(_Config) ->\n"
- " ok.\n\n"
- "all() ->\n"
- " ~p.\n\n"
- "test(Config, TestCase) ->\n"
- " Dir = ?config(data_dir, Config),\n"
- " OutDir = ?config(priv_dir, Config),\n"
- " hipe_testsuite_driver:run(TestCase, Dir, OutDir)."
- "\n\n",
- [SuiteName ++ ?suite_suffix, Exports, TimeLimit, TestCases]).
-
-format_export(TestCases) ->
- TL = [list_to_atom(atom_to_list(N)++"/1") || N <- TestCases],
- TestCaseString = io_lib:format("-export(~p).", [TL]),
- strip_quotes(lists:flatten(TestCaseString), []).
-
-strip_quotes([], Result) ->
- lists:reverse(Result);
-strip_quotes([$' |Rest], Result) ->
- strip_quotes(Rest, Result);
-strip_quotes([$\, |Rest], Result) ->
- strip_quotes(Rest, [$\ , $\, |Result]);
-strip_quotes([C|Rest], Result) ->
- strip_quotes(Rest, [C|Result]).
-
-write_testcases(#suite{outputfile = OutputFile, testcases = TestCases}) ->
- lists:foreach(fun (T) -> write_testcase(OutputFile, T) end, TestCases).
-
-write_testcase(OutputFile, TestCase) ->
- io:format(OutputFile,
- "~p(Config) ->\n"
- " test(Config, ~p).\n\n",
- [TestCase, TestCase]).
-
--spec run(atom(), string(), string()) -> 'ok'.
-
-run(TestCase, Dir, _OutDir) ->
- F = filename:join(Dir, atom_to_list(TestCase) ++ ".erl"),
- {ok, TestCase} = compile:file(F),
- ok = try TestCase:prepare_for_test() catch _:_ -> ok end,
- %% DataFiles = try TestCase:datafiles() catch _:_ -> [] end,
- %% lists:foreach(fun (DF) ->
- %% Src = filename:join(Dir, DF),
- %% Dst = filename:join(OutDir, DF),
- %% {ok, _} = file:copy(Src, Dst)
- %% end, DataFiles),
- %% try
- ok = TestCase:test(),
- HiPEOpts0 = try TestCase:hipe_options() catch error:undef -> [] end,
- HiPEOpts = HiPEOpts0 ++ hipe_options(),
- {ok, TestCase} = hipe:c(TestCase, HiPEOpts),
- ok = TestCase:test(),
- {ok, TestCase} = hipe:c(TestCase, [o1|HiPEOpts]),
- ok = TestCase:test(),
- {ok, TestCase} = hipe:c(TestCase, [o0|HiPEOpts]),
- ok = TestCase:test(),
- ToLLVM = try TestCase:to_llvm() catch error:undef -> true end,
- case ToLLVM andalso hipe:erllvm_is_supported() of
- true ->
- {ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]),
- ok = TestCase:test();
- false -> ok
- end.
- %% after
- %% lists:foreach(fun (DF) -> ok end, % = file:delete(DF) end,
- %% [filename:join(OutDir, D) || D <- DataFiles])
- %% end.
-
-hipe_options() ->
- [verify_gcsafe].
diff --git a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_aliasing.erl b/lib/hipe/test/maps_SUITE_data/maps_build_and_match_aliasing.erl
deleted file mode 100644
index 14d8320cdf..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_aliasing.erl
+++ /dev/null
@@ -1,20 +0,0 @@
--module(maps_build_and_match_aliasing).
--export([test/0]).
-
-test() ->
- M1 = id(#{a=>1,b=>2,c=>3,d=>4}),
- #{c:=C1=_=_=C2} = M1,
- true = C1 =:= C2,
- #{a:=A,a:=A,a:=A,b:=B,b:=B} = M1,
- #{a:=A,a:=A,a:=A,b:=B,b:=B,b:=2} = M1,
- #{a:=A=1,a:=A,a:=A,b:=B=2,b:=B,b:=2} = M1,
- #{c:=C1, c:=_, c:=3, c:=_, c:=C2} = M1,
- #{c:=C=_=3=_=C} = M1,
-
- M2 = id(#{"a"=>1,"b"=>2,"c"=>3,"d"=>4}),
- #{"a":=A2,"a":=A2,"a":=A2,"b":=B2,"b":=B2,"b":=2} = M2,
- #{"a":=_,"a":=_,"a":=_,"b":=_,"b":=_,"b":=2} = M2,
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_empty_val.erl b/lib/hipe/test/maps_SUITE_data/maps_build_and_match_empty_val.erl
deleted file mode 100644
index 2abfa4e5b3..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_empty_val.erl
+++ /dev/null
@@ -1,17 +0,0 @@
--module(maps_build_and_match_empty_val).
--export([test/0]).
-
-test() ->
- F = fun(#{ "hi":=_,{1,2}:=_,1337:=_}) -> ok end,
- ok = F(id(#{"hi"=>ok,{1,2}=>ok,1337=>ok})),
-
- %% error case
- case (catch (F(id(#{"hi"=>ok})))) of
- {'EXIT',{function_clause,_}} -> ok;
- {'EXIT', {{case_clause,_},_}} -> {comment,inlined};
- Other ->
- test_server:fail({no_match, Other})
- end.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_literals.erl b/lib/hipe/test/maps_SUITE_data/maps_build_and_match_literals.erl
deleted file mode 100644
index dc2c63fab2..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_literals.erl
+++ /dev/null
@@ -1,40 +0,0 @@
--module(maps_build_and_match_literals).
--export([test/0]).
-
-test() ->
- #{} = id(#{}),
- #{1:=a} = id(#{1=>a}),
- #{1:=a,2:=b} = id(#{1=>a,2=>b}),
- #{1:=a,2:=b,3:="c"} = id(#{1=>a,2=>b,3=>"c"}),
- #{1:=a,2:=b,3:="c","4":="d"} = id(#{1=>a,2=>b,3=>"c","4"=>"d"}),
- #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>} =
- id(#{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>}),
- #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>,{"6",7}:="f"} =
- id(#{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>,{"6",7}=>"f"}),
- #{1:=a,2:=b,3:="c","4":="d",<<"5">>:=<<"e">>,{"6",7}:="f",8:=g} =
- id(#{1=>a,2=>b,3=>"c","4"=>"d",<<"5">>=><<"e">>,{"6",7}=>"f",8=>g}),
-
- #{<<"hi all">> := 1} = id(#{<<"hi",32,"all">> => 1}),
-
- #{a:=X,a:=X=3,b:=4} = id(#{a=>3,b=>4}), % weird but ok =)
-
- #{ a:=#{ b:=#{c := third, b:=second}}, b:=first} =
- id(#{ b=>first, a=>#{ b=>#{c => third, b=> second}}}),
-
- M = #{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first},
- M = #{ map_1:=#{ map_2:=#{value_3 := third}, value_2:= second}, value_1:=first} =
- id(#{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first}),
-
- %% nil key
- #{[]:=ok,1:=2} = id(#{[]=>ok,1=>2}),
-
- %% error case
- {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3,x:=2} = id(#{x=>3}))),
- {'EXIT',{{badmatch,_},_}} = (catch (#{x:=2} = id(#{x=>3}))),
- {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id({a,b,c}))),
- {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{y=>3}))),
- {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{x=>"three"}))),
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_over_alloc.erl b/lib/hipe/test/maps_SUITE_data/maps_build_and_match_over_alloc.erl
deleted file mode 100644
index dae6f64e5f..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_over_alloc.erl
+++ /dev/null
@@ -1,16 +0,0 @@
--module(maps_build_and_match_over_alloc).
--export([test/0]).
-
-test() ->
- Ls = id([1,2,3]),
- V0 = [a|Ls],
- M0 = id(#{ "a" => V0 }),
- #{ "a" := V1 } = M0,
- V2 = id([c|Ls]),
- M2 = id(#{ "a" => V2 }),
- #{ "a" := V3 } = M2,
- {[a,1,2,3],[c,1,2,3]} = id({V1,V3}),
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_val.erl b/lib/hipe/test/maps_SUITE_data/maps_build_and_match_val.erl
deleted file mode 100644
index 284f69e06c..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_build_and_match_val.erl
+++ /dev/null
@@ -1,23 +0,0 @@
--module(maps_build_and_match_val).
--export([test/0]).
-
-test() ->
- F = fun
- (#{ "hi" := first, v := V}) -> {1,V};
- (#{ "hi" := second, v := V}) -> {2,V}
- end,
-
-
- {1,"hello"} = F(id(#{"hi"=>first,v=>"hello"})),
- {2,"second"} = F(id(#{"hi"=>second,v=>"second"})),
-
- %% error case
- case (catch (F(id(#{"hi"=>ok})))) of
- {'EXIT',{function_clause,_}} -> ok;
- {'EXIT', {{case_clause,_},_}} -> {comment,inlined};
- Other ->
- test_server:fail({no_match, Other})
- end.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_expand_map_update.erl b/lib/hipe/test/maps_SUITE_data/maps_expand_map_update.erl
deleted file mode 100644
index df0f77ea47..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_expand_map_update.erl
+++ /dev/null
@@ -1,7 +0,0 @@
--module(maps_expand_map_update).
--export([test/0]).
-
-test() ->
- M = #{<<"hello">> => <<"world">>}#{<<"hello">> := <<"les gens">>},
- #{<<"hello">> := <<"les gens">>} = M,
- ok.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_export.erl b/lib/hipe/test/maps_SUITE_data/maps_export.erl
deleted file mode 100644
index 4d43fc96ed..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_export.erl
+++ /dev/null
@@ -1,11 +0,0 @@
--module(maps_export).
--export([test/0]).
-
-test() ->
- Raclette = id(#{}),
- case brie of brie -> Fromage = Raclette end,
- Raclette = Fromage#{},
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_get_map_elements.erl b/lib/hipe/test/maps_SUITE_data/maps_get_map_elements.erl
deleted file mode 100644
index b2d749796a..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_get_map_elements.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------------
--module(maps_get_map_elements).
-
--export([test/0]).
-
-test() ->
- {A, B} = id({"hej", <<123>>}),
- Map = maps:from_list([{a, A}, {b, B}]),
- #{a := A, b := B} = id(Map),
- false = test_pattern(Map),
- true = test_pattern(#{b => 1, a => "hej"}),
- case Map of
- #{a := C, b := <<124>>} -> yay;
- _ -> C = B, nay
- end,
- C = id(B),
- ok.
-
-id(X) -> X.
-
-test_pattern(#{a := _, b := 1}) -> true;
-test_pattern(#{}) -> false.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_guard_bifs.erl b/lib/hipe/test/maps_SUITE_data/maps_guard_bifs.erl
deleted file mode 100644
index 61a0eaa1e7..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_guard_bifs.erl
+++ /dev/null
@@ -1,31 +0,0 @@
--module(maps_guard_bifs).
--export([test/0]).
-
-test() ->
- true = map_guard_empty(),
- true = map_guard_empty_2(),
- true = map_guard_head(#{a=>1}),
- false = map_guard_head([]),
- true = map_guard_body(#{a=>1}),
- false = map_guard_body({}),
- true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
- false = map_guard_pattern("list"),
- true = map_guard_tautology(),
- true = map_guard_ill_map_size(),
- ok.
-
-map_guard_empty() when is_map(#{}); false -> true.
-
-map_guard_empty_2() when true; #{} andalso false -> true.
-
-map_guard_head(M) when is_map(M) -> true;
-map_guard_head(_) -> false.
-
-map_guard_body(M) -> is_map(M).
-
-map_guard_pattern(#{}) -> true;
-map_guard_pattern(_) -> false.
-
-map_guard_tautology() when #{} =:= #{}; true -> true.
-
-map_guard_ill_map_size() when true; map_size(0) -> true.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_guard_fun.erl b/lib/hipe/test/maps_SUITE_data/maps_guard_fun.erl
deleted file mode 100644
index 9f6eb3a04e..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_guard_fun.erl
+++ /dev/null
@@ -1,36 +0,0 @@
--module(maps_guard_fun).
--export([test/0]).
-
-test() ->
- F1 = fun
- (#{s:=v,v:=V}) -> {v,V};
- (#{s:=t,v:={V,V}}) -> {t,V};
- (#{s:=l,v:=[V,V]}) -> {l,V}
- end,
-
- F2 = fun
- (#{s:=T,v:={V,V}}) -> {T,V};
- (#{s:=T,v:=[V,V]}) -> {T,V};
- (#{s:=T,v:=V}) -> {T,V}
- end,
- V = <<"hi">>,
-
- {v,V} = F1(#{s=>v,v=>V}),
- {t,V} = F1(#{s=>t,v=>{V,V}}),
- {l,V} = F1(#{s=>l,v=>[V,V]}),
-
- {v,V} = F2(#{s=>v,v=>V}),
- {t,V} = F2(#{s=>t,v=>{V,V}}),
- {l,V} = F2(#{s=>l,v=>[V,V]}),
-
- %% error case
- case (catch F1(#{s=>none,v=>none})) of
- {'EXIT', {function_clause,[{?MODULE,_,[#{s:=none,v:=none}],_}|_]}} -> ok;
- {'EXIT', {function_clause,[{?MODULE,_,1,[#{s:=none,v:=none}]}|_]}} -> ok;
- {'EXIT', {function_clause,[Frame|_]}}
- when is_tuple(Frame), element(1, Frame) =:= ?MODULE ->
- test_server:comment("Unexpected trace format, probably using HiPE");
- {'EXIT', {{case_clause,_},_}} -> {comment,inlined};
- Other ->
- test_server:fail({no_match, Other})
- end.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_guard_receive.erl b/lib/hipe/test/maps_SUITE_data/maps_guard_receive.erl
deleted file mode 100644
index f84ba19c86..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_guard_receive.erl
+++ /dev/null
@@ -1,54 +0,0 @@
--module(maps_guard_receive).
--export([test/0]).
-
-test() ->
- M0 = #{ id => 0 },
- Pid = spawn_link(fun() -> guard_receive_loop() end),
- Big = 36893488147419103229,
- B1 = <<"some text">>,
- B2 = <<"was appended">>,
- B3 = <<B1/binary, B2/binary>>,
-
- #{id:=1, res:=Big} = M1 = call(Pid, M0#{op=>sub,in=>{1 bsl 65, 3}}),
- #{id:=2, res:=26} = M2 = call(Pid, M1#{op=>idiv,in=>{53,2}}),
- #{id:=3, res:=832} = M3 = call(Pid, M2#{op=>imul,in=>{26,32}}),
- #{id:=4, res:=4} = M4 = call(Pid, M3#{op=>add,in=>{1,3}}),
- #{id:=5, res:=Big} = M5 = call(Pid, M4#{op=>sub,in=>{1 bsl 65, 3}}),
- #{id:=6, res:=B3} = M6 = call(Pid, M5#{op=>"append",in=>{B1,B2}}),
- #{id:=7, res:=4} = _ = call(Pid, M6#{op=>add,in=>{1,3}}),
-
-
- %% update old maps and check id update
- #{id:=2, res:=B3} = call(Pid, M1#{op=>"append",in=>{B1,B2}}),
- #{id:=5, res:=99} = call(Pid, M4#{op=>add,in=>{33, 66}}),
-
- %% cleanup
- done = call(Pid, done),
- ok.
-
-call(Pid, M) ->
- Pid ! {self(), M}, receive {Pid, Res} -> Res end.
-
-guard_receive_loop() ->
- receive
- {Pid, #{ id:=Id, op:="append", in:={X,Y}}=M} when is_binary(X), is_binary(Y) ->
- Pid ! {self(), M#{ id=>Id+1, res=><<X/binary,Y/binary>>}},
- guard_receive_loop();
- {Pid, #{ id:=Id, op:=add, in:={X,Y}}} ->
- Pid ! {self(), #{ id=>Id+1, res=>X+Y}},
- guard_receive_loop();
- {Pid, #{ id:=Id, op:=sub, in:={X,Y}}=M} ->
- Pid ! {self(), M#{ id=>Id+1, res=>X-Y}},
- guard_receive_loop();
- {Pid, #{ id:=Id, op:=idiv, in:={X,Y}}=M} ->
- Pid ! {self(), M#{ id=>Id+1, res=>X div Y}},
- guard_receive_loop();
- {Pid, #{ id:=Id, op:=imul, in:={X,Y}}=M} ->
- Pid ! {self(), M#{ id=>Id+1, res=>X * Y}},
- guard_receive_loop();
- {Pid, done} ->
- Pid ! {self(), done};
- {Pid, Other} ->
- Pid ! {error, Other},
- guard_receive_loop()
- end.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_guard_sequence.erl b/lib/hipe/test/maps_SUITE_data/maps_guard_sequence.erl
deleted file mode 100644
index 4eb18dcea1..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_guard_sequence.erl
+++ /dev/null
@@ -1,35 +0,0 @@
--module(maps_guard_sequence).
--export([test/0]).
-
-test() ->
- {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
- {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
- {3, "c"} = map_guard_sequence_1(#{seq=>3,val=>id("c")}),
- {4, "d"} = map_guard_sequence_1(#{seq=>4,val=>id("d")}),
- {5, "e"} = map_guard_sequence_1(#{seq=>5,val=>id("e")}),
-
- {1,M1} = map_guard_sequence_2(M1 = id(#{a=>3})),
- {2,M2} = map_guard_sequence_2(M2 = id(#{a=>4, b=>4})),
- {3,gg,M3} = map_guard_sequence_2(M3 = id(#{a=>gg, b=>4})),
- {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(#{a=>sc, b=>3, c=>sc2})),
- {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(#{a=>kk, b=>other, c=>sc2})),
-
- %% error case
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>id("e")})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
- ok.
-
-map_guard_sequence_1(#{seq:=1=Seq, val:=Val}) -> {Seq,Val};
-map_guard_sequence_1(#{seq:=2=Seq, val:=Val}) -> {Seq,Val};
-map_guard_sequence_1(#{seq:=3=Seq, val:=Val}) -> {Seq,Val};
-map_guard_sequence_1(#{seq:=4=Seq, val:=Val}) -> {Seq,Val};
-map_guard_sequence_1(#{seq:=5=Seq, val:=Val}) -> {Seq,Val}.
-
-map_guard_sequence_2(#{ a:=3 }=M) -> {1, M};
-map_guard_sequence_2(#{ a:=4 }=M) -> {2, M};
-map_guard_sequence_2(#{ a:=X, a:=X, b:=4 }=M) -> {3,X,M};
-map_guard_sequence_2(#{ a:=X, a:=Y, b:=3 }=M) when X =:= Y -> {4,X,Y,M};
-map_guard_sequence_2(#{ a:=X, a:=Y }=M) when X =:= Y -> {5,X,Y,M}.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_guard_update.erl b/lib/hipe/test/maps_SUITE_data/maps_guard_update.erl
deleted file mode 100644
index 254c1c2984..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_guard_update.erl
+++ /dev/null
@@ -1,14 +0,0 @@
--module(maps_guard_update).
--export([test/0]).
-
-test() ->
- error = map_guard_update(#{},#{}),
- first = map_guard_update(#{}, #{x=>first}),
- second = map_guard_update(#{y=>old}, #{x=>second,y=>old}),
- third = map_guard_update(#{x=>old,y=>old}, #{x=>third,y=>old}),
- ok.
-
-map_guard_update(M1, M2) when M1#{x=>first} =:= M2 -> first;
-map_guard_update(M1, M2) when M1#{x=>second} =:= M2 -> second;
-map_guard_update(M1, M2) when M1#{x:=third} =:= M2 -> third;
-map_guard_update(_, _) -> error.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_has_map_fields.erl b/lib/hipe/test/maps_SUITE_data/maps_has_map_fields.erl
deleted file mode 100644
index 61653aa519..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_has_map_fields.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------------
--module(maps_has_map_fields).
-
--export([test/0]).
-
-test() ->
- false = has_a_field(#{}),
- false = has_a_field(#{b => 2}),
- true = has_a_field(#{a => 3}),
- true = has_a_field(#{b => c, a => false}),
-
- false = has_a_b_field(#{a => true}),
- false = has_a_b_field(#{b => a}),
- true = has_a_b_field(#{a => 1, b => 2}),
- true = has_a_b_field(#{b => 3, a => 4}),
-
- false = has_binary_field(#{}),
- false = has_binary_field(#{#{} => yay}),
- true = has_binary_field(#{<<"true">> => false}),
-
- false = has_binary_but_no_map_field(#{}),
- false = has_map_but_no_binary_field(#{}),
- false = has_binary_but_no_map_field(#{#{} => 1}),
- false = has_map_but_no_binary_field(#{<<"true">> => true}),
- true = has_binary_but_no_map_field(#{<<"true">> => false}),
- true = has_map_but_no_binary_field(#{#{} => 1}),
- false = has_binary_but_no_map_field(#{<<"true">> => true, #{} => 1}),
- false = has_map_but_no_binary_field(#{<<"true">> => true, #{} => 1}),
- ok.
-
-has_a_field(#{a := _}) -> true;
-has_a_field(#{}) -> false.
-
-has_a_b_field(#{a := _, b := _}) -> true;
-has_a_b_field(#{}) -> false.
-
-has_binary_field(#{<<"true">> := _}) -> true;
-has_binary_field(#{}) -> false.
-
-has_map_but_no_binary_field(#{<<"true">> := _}) -> false;
-has_map_but_no_binary_field(#{} = M) -> maps:is_key(#{}, M).
-
-has_binary_but_no_map_field(#{<<"true">> := _} = M) ->
- not maps:is_key(#{}, M);
-has_binary_but_no_map_field(#{}) -> false.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_is_map.erl b/lib/hipe/test/maps_SUITE_data/maps_is_map.erl
deleted file mode 100644
index e84f4b8c44..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_is_map.erl
+++ /dev/null
@@ -1,24 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------------
--module(maps_is_map).
-
--export([test/0]).
-
-test() ->
- true = test_is_map(#{}),
- false = test_is_map(<<"hej">>),
- true = test_is_map_guard(#{a => b}),
- false = test_is_map_guard(3),
- true = test_is_map_with_binary_guard(#{"a" => <<"b">>}),
- false = test_is_map_with_binary_guard(12),
- ok.
-
-test_is_map(X) ->
- is_map(X).
-
-test_is_map_guard(Map) when is_map(Map) -> true;
-test_is_map_guard(_) -> false.
-
-test_is_map_with_binary_guard(B) when is_binary(B) -> false;
-test_is_map_with_binary_guard(#{}) -> true;
-test_is_map_with_binary_guard(_) -> false.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_list_comprehension.erl b/lib/hipe/test/maps_SUITE_data/maps_list_comprehension.erl
deleted file mode 100644
index ad2c726d65..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_list_comprehension.erl
+++ /dev/null
@@ -1,6 +0,0 @@
--module(maps_list_comprehension).
--export([test/0]).
-
-test() ->
- [#{k:=1},#{k:=2},#{k:=3}] = [#{k=>I} || I <- [1,2,3]],
- ok.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_map_size.erl b/lib/hipe/test/maps_SUITE_data/maps_map_size.erl
deleted file mode 100644
index 3cd2d90dfb..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_map_size.erl
+++ /dev/null
@@ -1,29 +0,0 @@
--module(maps_map_size).
--export([test/0]).
-
-test() ->
- 0 = map_size(id(#{})),
- 1 = map_size(id(#{a=>1})),
- 1 = map_size(id(#{a=>"wat"})),
- 2 = map_size(id(#{a=>1, b=>2})),
- 3 = map_size(id(#{a=>1, b=>2, b=>"3","33"=><<"n">>})),
-
- true = map_is_size(#{a=>1}, 1),
- true = map_is_size(#{a=>1, a=>2}, 1),
- M = #{ "a" => 1, "b" => 2},
- true = map_is_size(M, 2),
- false = map_is_size(M, 3),
- true = map_is_size(M#{ "a" => 2}, 2),
- false = map_is_size(M#{ "c" => 2}, 2),
-
- %% Error cases.
- {'EXIT',{{badmap,[]},_}} = (catch map_size([])),
- {'EXIT',{{badmap,<<1,2,3>>},_}} = (catch map_size(<<1,2,3>>)),
- {'EXIT',{{badmap,1},_}} = (catch map_size(1)),
- ok.
-
-map_is_size(M,N) when map_size(M) =:= N -> true;
-map_is_size(_,_) -> false.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_map_sort_literals.erl b/lib/hipe/test/maps_SUITE_data/maps_map_sort_literals.erl
deleted file mode 100644
index ccacbfe5c8..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_map_sort_literals.erl
+++ /dev/null
@@ -1,42 +0,0 @@
--module(maps_map_sort_literals).
--export([test/0]).
-
-test() ->
- % test relation
-
- %% size order
- true = #{ a => 1, b => 2} < id(#{ a => 1, b => 1, c => 1}),
- true = #{ b => 1, a => 1} < id(#{ c => 1, a => 1, b => 1}),
- false = #{ c => 1, b => 1, a => 1} < id(#{ c => 1, a => 1}),
-
- %% key order
- true = #{ a => 1 } < id(#{ b => 1}),
- false = #{ b => 1 } < id(#{ a => 1}),
- true = #{ a => 1, b => 1, c => 1 } < id(#{ b => 1, c => 1, d => 1}),
- true = #{ b => 1, c => 1, d => 1 } > id(#{ a => 1, b => 1, c => 1}),
- true = #{ c => 1, b => 1, a => 1 } < id(#{ b => 1, c => 1, d => 1}),
- true = #{ "a" => 1 } < id(#{ <<"a">> => 1}),
- false = #{ <<"a">> => 1 } < id(#{ "a" => 1}),
- true = #{ 1 => 1 } < id(#{ 1.0 => 1}),
- false = #{ 1.0 => 1 } < id(#{ 1 => 1}),
-
- %% value order
- true = #{ a => 1 } < id(#{ a => 2}),
- false = #{ a => 2 } < id(#{ a => 1}),
- false = #{ a => 2, b => 1 } < id(#{ a => 1, b => 3}),
- true = #{ a => 1, b => 1 } < id(#{ a => 1, b => 3}),
- false = #{ a => 1 } < id(#{ a => 1.0}),
- false = #{ a => 1.0 } < id(#{ a => 1}),
-
- true = #{ "a" => "hi", b => 134 } == id(#{ b => 134,"a" => "hi"}),
-
- %% lists:sort
-
- SortVs = [#{"a"=>1},#{a=>2},#{1=>3},#{<<"a">>=>4}],
- [#{1:=ok},#{a:=ok},#{"a":=ok},#{<<"a">>:=ok}] = lists:sort([#{"a"=>ok},#{a=>ok},#{1=>ok},#{<<"a">>=>ok}]),
- [#{1:=3},#{a:=2},#{"a":=1},#{<<"a">>:=4}] = lists:sort(SortVs),
- [#{1:=3},#{a:=2},#{"a":=1},#{<<"a">>:=4}] = lists:sort(lists:reverse(SortVs)),
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_match_and_update_literals.erl b/lib/hipe/test/maps_SUITE_data/maps_match_and_update_literals.erl
deleted file mode 100644
index 29a6a29290..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_match_and_update_literals.erl
+++ /dev/null
@@ -1,24 +0,0 @@
--module(maps_match_and_update_literals).
--export([test/0]).
-
-test() ->
- Map = #{x=>0,y=>"untouched",z=>"also untouched",q=>1},
- #{x:=16,q:=21,y:="untouched",z:="also untouched"} = loop_match_and_update_literals_x_q(Map, [
- {1,2},{3,4},{5,6},{7,8}
- ]),
- M0 = id(#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
- 4 => number, 18446744073709551629 => wat}),
- M1 = id(#{}),
- M2 = M1#{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
- 4 => number, 18446744073709551629 => wat},
- M0 = M2,
-
- #{ 4 := another_number, int := 3 } = M2#{ 4 => another_number },
- ok.
-
-loop_match_and_update_literals_x_q(Map, []) -> Map;
-loop_match_and_update_literals_x_q(#{q:=Q0,x:=X0} = Map, [{X,Q}|Vs]) ->
- loop_match_and_update_literals_x_q(Map#{q=>Q0+Q,x=>X0+X},Vs).
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_put_map_assoc.erl b/lib/hipe/test/maps_SUITE_data/maps_put_map_assoc.erl
deleted file mode 100644
index 2fe4f204d1..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_put_map_assoc.erl
+++ /dev/null
@@ -1,23 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------------
--module(maps_put_map_assoc).
-
--export([test/0]).
-
-test() ->
- true = assoc_guard(#{}),
- false = assoc_guard(not_a_map),
- #{a := true} = assoc_update(#{}),
- {'EXIT', {{badmap, not_a_map}, [{?MODULE, assoc_update, 1, _}|_]}}
- = (catch assoc_update(not_a_map)),
- ok = assoc_guard_clause(#{}),
- {'EXIT', {function_clause, [{?MODULE, assoc_guard_clause, _, _}|_]}}
- = (catch assoc_guard_clause(not_a_map)),
- ok.
-
-assoc_guard(M) when is_map(M#{a => b}) -> true;
-assoc_guard(_) -> false.
-
-assoc_update(M) -> M#{a => true}.
-
-assoc_guard_clause(M) when is_map(M#{a => 3}) -> ok.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_put_map_exact.erl b/lib/hipe/test/maps_SUITE_data/maps_put_map_exact.erl
deleted file mode 100644
index 3c85289a36..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_put_map_exact.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%-------------------------------------------------------------------------
--module(maps_put_map_exact).
-
--export([test/0]).
-
-test() ->
- false = exact_guard(#{b => a}),
- false = exact_guard(not_a_map),
- true = exact_guard(#{a => false}),
- #{a := true} = exact_update(#{a => false}),
- {'EXIT', {{badmap, not_a_map}, [{?MODULE, exact_update, 1, _}|_]}}
- = (catch exact_update(not_a_map)),
- {'EXIT', {{badkey, a}, [{?MODULE, exact_update, 1, _}|_]}}
- = (catch exact_update(#{})),
- ok = exact_guard_clause(#{a => yes}),
- {'EXIT', {function_clause, [{?MODULE, exact_guard_clause, _, _}|_]}}
- = (catch exact_guard_clause(#{})),
- {'EXIT', {function_clause, [{?MODULE, exact_guard_clause, _, _}|_]}}
- = (catch exact_guard_clause(not_a_map)),
- ok.
-
-exact_guard(M) when is_map(M#{a := b}) -> true;
-exact_guard(_) -> false.
-
-exact_update(M) -> M#{a := true}.
-
-exact_guard_clause(M) when is_map(M#{a := 42}) -> ok.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
deleted file mode 100644
index 17c3acd6af..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
+++ /dev/null
@@ -1,14 +0,0 @@
--module(maps_redundant_branch_is_key).
--export([test/0]).
-
-test() ->
- ok = thingy(#{a => 1}),
- ok = thingy(#{a => 2}),
- ok.
-
-thingy(Map) ->
- try
- #{a := _} = Map,
- ok
- catch _ -> error
- end.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_update_assoc.erl b/lib/hipe/test/maps_SUITE_data/maps_update_assoc.erl
deleted file mode 100644
index 99228a1927..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_update_assoc.erl
+++ /dev/null
@@ -1,22 +0,0 @@
--module(maps_update_assoc).
--export([test/0]).
-
-test() ->
- M0 = id(#{1=>a,2=>b,3.0=>c,4=>d,5=>e}),
-
- M1 = M0#{1=>42,2=>100,4=>[a,b,c]},
- #{1:=42,2:=100,3.0:=c,4:=[a,b,c],5:=e} = M1,
- #{1:=42,2:=b,4:=d,5:=e,2.0:=100,3.0:=c,4.0:=[a,b,c]} = M0#{1.0=>float,1:=42,2.0=>wrong,2.0=>100,4.0=>[a,b,c]},
-
- M2 = M0#{3.0=>new},
- #{1:=a,2:=b,3.0:=new,4:=d,5:=e} = M2,
- M2 = M0#{3.0:=wrong,3.0=>new},
-
- %% Errors cases.
- BadMap = id(badmap),
- {'EXIT',{{badmap,badmap},_}} = (catch BadMap#{nonexisting=>val}),
-
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_update_exact.erl b/lib/hipe/test/maps_SUITE_data/maps_update_exact.erl
deleted file mode 100644
index 1c38820a7c..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_update_exact.erl
+++ /dev/null
@@ -1,32 +0,0 @@
--module(maps_update_exact).
--export([test/0]).
-
-test() ->
- M0 = id(#{1=>a,2=>b,3.0=>c,4=>d,5=>e}),
-
- M1 = M0#{1:=42,2:=100,4:=[a,b,c]},
- #{1:=42,2:=100,3.0:=c,4:=[a,b,c],5:=e} = M1,
- M1 = M0#{1:=wrong,1=>42,2=>wrong,2:=100,4:=[a,b,c]},
-
- M2 = M0#{3.0:=new},
- #{1:=a,2:=b,3.0:=new,4:=d,5:=e} = M2,
- M2 = M0#{3.0=>wrong,3.0:=new},
- true = M2 =/= M0#{3=>right,3.0:=new},
- #{ 3 := right, 3.0 := new } = M0#{3=>right,3.0:=new},
-
- M3 = id(#{ 1 => val}),
- #{1 := update2,1.0 := new_val4} = M3#{
- 1.0 => new_val1, 1 := update, 1=> update3,
- 1 := update2, 1.0 := new_val2, 1.0 => new_val3,
- 1.0 => new_val4 },
-
- %% Errors cases.
- {'EXIT',{{badmap,nil},_}} = (catch ((id(nil))#{ a := b })),
- {'EXIT',{{badkey,nonexisting},_}} = (catch M0#{nonexisting:=val}),
- {'EXIT',{{badkey,_},_}} = (catch M0#{1.0:=v,1.0=>v2}),
- {'EXIT',{{badkey,_},_}} = (catch M0#{42.0:=v,42:=v2}),
- {'EXIT',{{badkey,_},_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_update_literals.erl b/lib/hipe/test/maps_SUITE_data/maps_update_literals.erl
deleted file mode 100644
index 87aea3d8e1..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_update_literals.erl
+++ /dev/null
@@ -1,13 +0,0 @@
--module(maps_update_literals).
--export([test/0]).
-
-test() ->
- Map = #{x=>1,y=>2,z=>3,q=>4},
- #{x:="d",q:="4"} = loop_update_literals_x_q(Map, [
- {"a","1"},{"b","2"},{"c","3"},{"d","4"}
- ]),
- ok.
-
-loop_update_literals_x_q(Map, []) -> Map;
-loop_update_literals_x_q(Map, [{X,Q}|Vs]) ->
- loop_update_literals_x_q(Map#{q=>Q,x=>X},Vs).
diff --git a/lib/hipe/test/maps_SUITE_data/maps_update_map_expressions.erl b/lib/hipe/test/maps_SUITE_data/maps_update_map_expressions.erl
deleted file mode 100644
index 213fc33d97..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_update_map_expressions.erl
+++ /dev/null
@@ -1,32 +0,0 @@
--module(maps_update_map_expressions).
--export([test/0]).
-
-test() ->
- M = maps:new(),
- X = id(fondue),
- M1 = #{ a := 1 } = M#{a => 1},
- #{ b := {X} } = M1#{ a := 1, b => {X} },
-
- #{ b := 2 } = (maps:new())#{ b => 2 },
-
- #{ a :=42, b:=42, c:=42 } = (maps:from_list([{a,1},{b,2},{c,3}]))#{ a := 42, b := 42, c := 42 },
- #{ "a" :=1, "b":=42, "c":=42 } = (maps:from_list([{"a",1},{"b",2}]))#{ "b" := 42, "c" => 42 },
-
- %% Test need to be in a fun.
- %% This tests that let expr optimisation in sys_core_fold
- %% covers maps correctly.
- F = fun() ->
- M0 = id(#{ "a" => [1,2,3] }),
- #{ "a" := _ } = M0,
- M0#{ "a" := b }
- end,
-
- #{ "a" := b } = F(),
-
- %% Error cases.
- {'EXIT',{{badmap,<<>>},_}} = (catch (id(<<>>))#{ a := 42, b => 2 }),
- {'EXIT',{{badmap,[]},_}} = (catch (id([]))#{ a := 42, b => 2 }),
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_update_values.erl b/lib/hipe/test/maps_SUITE_data/maps_update_values.erl
deleted file mode 100644
index bbad5ac19e..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_update_values.erl
+++ /dev/null
@@ -1,28 +0,0 @@
--module(maps_update_values).
--export([test/0]).
-
-test() ->
- V0 = id(1337),
- M0 = #{ a => 1, val => V0},
- V1 = get_val(M0),
- M1 = M0#{ val := [V0,V1], "wazzup" => 42 },
- [1337, {some_val, 1337}] = get_val(M1),
-
- N = 110,
- List = [{[I,1,2,3,I],{1,2,3,"wat",I}}|| I <- lists:seq(1,N)],
-
- {_,_,#{val2 := {1,2,3,"wat",N}, val1 := [N,1,2,3,N]}} = lists:foldl(fun
- ({V2,V3},{Old2,Old3,Mi}) ->
- ok = check_val(Mi,Old2,Old3),
- #{ val1 := Old2, val2 := Old3 } = Mi,
- {V2,V3, Mi#{ val1 := id(V2), val2 := V1, val2 => id(V3)}}
- end, {none, none, #{val1=>none,val2=>none}},List),
- ok.
-
-get_val(#{ "wazzup" := _, val := V}) -> V;
-get_val(#{ val := V }) -> {some_val, V}.
-
-check_val(#{val1:=V1, val2:=V2},V1,V2) -> ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_warn_pair_key_overloaded.erl b/lib/hipe/test/maps_SUITE_data/maps_warn_pair_key_overloaded.erl
deleted file mode 100644
index cce91530f4..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_warn_pair_key_overloaded.erl
+++ /dev/null
@@ -1,26 +0,0 @@
--module(maps_warn_pair_key_overloaded).
--export([test/0]).
-
-test() ->
- #{ "hi1" := 42 } = id(#{ "hi1" => 1, "hi1" => 42 }),
-
- #{ "hi1" := 1337, "hi2" := [2], "hi3" := 3 } = id(#{
- "hi1" => erlang:atom_to_binary(?MODULE,utf8),
- "hi1" => erlang:binary_to_atom(<<"wazzup">>,utf8),
- "hi1" => erlang:binary_to_float(<<"3.1416">>),
- "hi1" => erlang:float_to_binary(3.1416),
- "hi2" => erlang:pid_to_list(self()),
- "hi3" => erlang:float_to_binary(3.1416),
- "hi2" => lists:subtract([1,2],[1]),
- "hi3" => +3,
- "hi1" => erlang:min(1,2),
- "hi1" => erlang:phash({1,2},33),
- "hi1" => erlang:phash2({1,2},34),
- "hi1" => erlang:integer_to_binary(1337),
- "hi1" => erlang:binary_to_integer(<<"1337">>),
- "hi4" => erlang:float_to_binary(3.1416)
- }),
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/maps_SUITE_data/maps_warn_useless_build.erl b/lib/hipe/test/maps_SUITE_data/maps_warn_useless_build.erl
deleted file mode 100644
index 6cb0366314..0000000000
--- a/lib/hipe/test/maps_SUITE_data/maps_warn_useless_build.erl
+++ /dev/null
@@ -1,9 +0,0 @@
--module(maps_warn_useless_build).
--export([test/0]).
-
-test() ->
- [#{ a => id(I)} || I <- [1,2,3]],
- ok.
-
-%% Use this function to avoid compile-time evaluation of an expression.
-id(I) -> I.
diff --git a/lib/hipe/test/opt_verify_SUITE.erl b/lib/hipe/test/opt_verify_SUITE.erl
deleted file mode 100644
index 24f43af275..0000000000
--- a/lib/hipe/test/opt_verify_SUITE.erl
+++ /dev/null
@@ -1,65 +0,0 @@
--module(opt_verify_SUITE).
-
--export([all/0, groups/0,
- init_per_suite/1, end_per_suite/1,
- init_per_group/2, end_per_group/2,
- call_elim/0, call_elim/1]).
-
-all() ->
- [call_elim].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- case erlang:system_info(hipe_architecture) of
- undefined -> {skip, "HiPE not available or enabled"};
- _ -> Config
- end.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-call_elim() ->
- [{doc, "Test that the call elimination optimization pass is ok"}].
-call_elim(Config) ->
- DataDir = test_server:lookup_config(data_dir, Config),
- F1 = filename:join(DataDir, "call_elim_test.erl"),
- Icode1 = call_elim_test_file(Config, F1, icode_call_elim),
- 0 = substring_count(binary:bin_to_list(Icode1), "is_key"),
- Icode2 = call_elim_test_file(Config, F1, no_icode_call_elim),
- true = (0 /= substring_count(binary:bin_to_list(Icode2), "is_key")),
- F2 = filename:join(DataDir, "call_elim_test_branches_no_opt_poss.erl"),
- Icode3 = call_elim_test_file(Config, F2, icode_call_elim),
- 3 = substring_count(binary:bin_to_list(Icode3), "is_key"),
- Icode4 = call_elim_test_file(Config, F2, no_icode_call_elim),
- 3 = substring_count(binary:bin_to_list(Icode4), "is_key"),
- F3 = filename:join(DataDir, "call_elim_test_branches_opt_poss.erl"),
- Icode5 = call_elim_test_file(Config, F3, icode_call_elim),
- 0 = substring_count(binary:bin_to_list(Icode5), "is_key"),
- Icode6 = call_elim_test_file(Config, F3, no_icode_call_elim),
- 2 = substring_count(binary:bin_to_list(Icode6), "is_key"),
- ok.
-
-call_elim_test_file(Config, FileName, Option) ->
- PrivDir = test_server:lookup_config(priv_dir, Config),
- TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
- {ok, TestCase} = compile:file(FileName),
- {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
- {ok, Icode} = file:read_file(TempOut),
- ok = file:delete(TempOut),
- Icode.
-
-substring_count(Icode, Substring) ->
- substring_count(Icode, Substring, 0).
-substring_count(Icode, Substring, N) ->
- case string:find(Icode, Substring) of
- nomatch -> N;
- Prefix -> substring_count(string:prefix(Prefix, Substring), Substring, N+1)
- end.
diff --git a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test.erl b/lib/hipe/test/opt_verify_SUITE_data/call_elim_test.erl
deleted file mode 100644
index 8b725f8ffe..0000000000
--- a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test.erl
+++ /dev/null
@@ -1,12 +0,0 @@
--module(call_elim_test).
-
--export([test/0]).
-
-test() ->
- true = has_1_field(#{1=>true}),
- true = has_1_field(#{1=>"hej", b=>2}),
- true = has_1_field(#{b=>3, 1=>4}),
- ok.
-
-has_1_field(#{1:=_}) -> true;
-has_1_field(#{}) -> false.
diff --git a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_no_opt_poss.erl b/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_no_opt_poss.erl
deleted file mode 100644
index 7ffae86797..0000000000
--- a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_no_opt_poss.erl
+++ /dev/null
@@ -1,32 +0,0 @@
--module(call_elim_test_branches_no_opt_poss).
-
--export([test/1]).
-
-test(A) ->
- if A > 0 ->
- false = has_a_field(#{b=>true}),
- true = has_a_field(#{b=>1, a=>"2"}),
- false = has_a_field(#{b=>5, c=>4}),
- false = has_tuple_field(#{{ab, 2}=><<"qq">>, 1 =>0}),
- false = has_tuple_field(#{up =>down, {ab, 2}=>[]}),
- false = has_tuple_field(#{{ab, 2}=>42});
- A =< 0 ->
- true = has_a_field(#{a=>q, 'A' =>nej}),
- true = has_a_field(#{a=>"hej", false=>true}),
- true = has_a_field(#{a=>3}),
- true = has_tuple_field(#{{ab, 1}=>q, 'A' =>nej}),
- true = has_tuple_field(#{{ab, 1}=>"hej", false=>true}),
- true = has_tuple_field(#{{ab, 1}=>3})
- end,
- true = has_nil_field(#{[] =>3, b=>"seven"}),
- true = has_nil_field(#{"seventeen"=>17}),
- ok.
-
-has_tuple_field(#{{ab, 1}:=_}) -> true;
-has_tuple_field(#{}) -> false.
-
-has_a_field(#{a:=_}) -> true;
-has_a_field(#{}) -> false.
-
-has_nil_field(#{[]:=_}) -> true;
-has_nil_field(#{}) -> false.
diff --git a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl b/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl
deleted file mode 100644
index 12875f41af..0000000000
--- a/lib/hipe/test/opt_verify_SUITE_data/call_elim_test_branches_opt_poss.erl
+++ /dev/null
@@ -1,26 +0,0 @@
--module(call_elim_test_branches_opt_poss).
-
--export([test/1]).
-
-test(A) ->
- if A > 0 ->
- true = has_a_field(#{a=>true}),
- true = has_a_field(#{b=>1, a=>"2"}),
- true = has_a_field(#{a=>5, c=>4});
- A =< 0 ->
- true = has_a_field(#{a=>q, 'A' =>nej}),
- true = has_a_field(#{a=>"hej", false=>true}),
- true = has_a_field(#{a=>3})
- end,
- true = has_nil_field(#{[] =>3, b =>"seven"}),
- true = has_nil_field(#{"seventeen"=>17, []=>nil}),
- ok.
-
-has_tuple_field(#{{ab, 1}:=_}) -> true;
-has_tuple_field(#{}) -> false.
-
-has_a_field(#{a:=_}) -> true;
-has_a_field(#{}) -> false.
-
-has_nil_field(#{[]:=_}) -> true;
-has_nil_field(#{}) -> false.
diff --git a/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl b/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl
deleted file mode 100644
index 9f0830574f..0000000000
--- a/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%----------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Tests that when the native code compilation times out or gets killed
-%%% for some other reason, the parent process does not also get killed.
-%%%
-%%% Problem discovered by Bjorn G. on 1/12/2003 and fixed by Kostis.
-%%%----------------------------------------------------------------------
-
--module(sanity_comp_timeout).
-
--export([test/0, to_llvm/0]).
-
-test() ->
- ok = write_dummy_mod(),
- error_logger:tty(false), % disable printouts of error reports
- Self = self(), % get the parent process
- c:c(dummy_mod, [native, {hipe, [{timeout, 1}]}]), % This will kill the process
- Self = self(), % make sure the parent process stays the same
- ok.
-
-to_llvm() -> false.
-
-write_dummy_mod() ->
- Prog = <<"-module(dummy_mod).\n-export([test/0]).\ntest() -> ok.\n">>,
- ok = file:write_file("dummy_mod.erl", Prog).
-
diff --git a/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl b/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl
deleted file mode 100644
index 87e746042e..0000000000
--- a/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl
+++ /dev/null
@@ -1,21 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%----------------------------------------------------------------------
-%%% Author: Per Gustafsson
-%%%
-%%% Checks that HiPE's concurrent compilation does not leave any zombie
-%%% processes around after compilation has finished.
-%%%
-%%% This was a bug reported on erlang-bugs (Oct 25, 2007).
-%%%----------------------------------------------------------------------
-
--module(sanity_no_zombies).
-
--export([test/0, to_llvm/0]).
-
-test() ->
- L = length(processes()),
- hipe:c(?MODULE, [concurrent_comp]), % force concurrent compilation
- L = length(processes()),
- ok.
-
-to_llvm() -> false.
diff --git a/lib/hipe/tools/Makefile b/lib/hipe/tools/Makefile
deleted file mode 100644
index 7a62896c31..0000000000
--- a/lib/hipe/tools/Makefile
+++ /dev/null
@@ -1,114 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2002-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = hipe_profile hipe_jit
-# hipe_timer
-
-HRL_FILES=
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars +warn_missing_spec +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-distclean: clean
-realclean: clean
-
-
-# ----------------------------------------------------
-# Include dependencies
-# ----------------------------------------------------
-
-$(EBIN)/hipe_ceach.beam: ../main/hipe.hrl
-
diff --git a/lib/hipe/tools/hipe_jit.erl b/lib/hipe/tools/hipe_jit.erl
deleted file mode 100644
index 5b937a9789..0000000000
--- a/lib/hipe/tools/hipe_jit.erl
+++ /dev/null
@@ -1,82 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2002 by Erik Johansson.
-%% ====================================================================
-%% Module : hipe_jit
-%% Purpose :
-%% Notes :
-%% History : * 2002-03-14 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%% @doc
-%% A tool to enable using the HiPE compiler as an automatic JIT
-%% compiler rather than a user-controlled one.
-%% @end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_jit).
-
--export([start/0]).
-
--record(state, {mode = start :: 'sleep' | 'start' | 'wait',
- threshold = 5000 :: non_neg_integer(),
- sleep = 5000 :: non_neg_integer(),
- time = 1000 :: non_neg_integer()}).
-
-%%---------------------------------------------------------------------
-
--spec start() -> pid().
-%% @doc
-%% Starts an Erlang process which calls the HiPE compiler every
-%% now and then (when it sees it fit to do so).
-%% @end
-start() ->
- spawn(fun () -> loop(#state{}) end).
-
-loop(State) ->
- case State#state.mode of
- start ->
- start(State);
- wait ->
- wait(State);
- _ ->
- sleep(State)
- end.
-
-sleep(State) ->
- receive
- quit -> ok
- after State#state.sleep ->
- loop(State#state{mode=start})
- end.
-
-start(State) ->
- catch hipe_profile:prof(),
- catch hipe_profile:clear(),
- loop(State#state{mode=wait}).
-
-wait(State) ->
- receive
- quit -> ok
- after State#state.time ->
- R = [M || {M,C} <- (catch hipe_profile:mods_res()),
- C > State#state.threshold],
- catch hipe_profile:prof_off(),
- lists:foreach(fun(M) ->
- io:format("Compile ~w\n",[M]),
- hipe:c(M,[o2,verbose])
- end, R)
- end,
- loop(State#state{mode=sleep}).
diff --git a/lib/hipe/tools/hipe_profile.erl b/lib/hipe/tools/hipe_profile.erl
deleted file mode 100644
index f790dc6ebb..0000000000
--- a/lib/hipe/tools/hipe_profile.erl
+++ /dev/null
@@ -1,185 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Module : hipe_profile
-%% Purpose :
-%% History : * 2001-07-12 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_profile).
-
--export([%% profile/1, mods_profile/1,
- prof/0, prof_off/0, clear/0, res/0,
- mods_res/0,
- %% clear_module/1, res_module/1,
- prof_module/1, prof_module_off/1]).
-
-%% %% @spec mods_profile(F) -> [{mod(),calls()}]
-%% %% F = () -> term()
-%% %% mod() = atom()
-%% %% calls()= integer()
-%% %%
-%% %% @doc Returns the number of calls per module generated by
-%% %% applying F().
-%% %% The resulting lists is sorted with the most called
-%% %% module first.
-%% mods_profile(F) ->
-%% F(),
-%% prof(),
-%% clear(),
-%% F(),
-%% R = mods_res(),
-%% prof_off(),
-%% R.
-
--spec mods_res() -> [{atom(), non_neg_integer()}].
-%% @doc Returns the number of calls per module currently
-%% recordeed since hipe_bifs:call_count_on().
-%% The resulting list is sorted with the most called
-%% module first.
-mods_res() ->
- lists:reverse(lists:keysort(2, calls())).
-
--spec calls() -> [{atom(), non_neg_integer()}].
-%% @doc Returns the number of calls per module currently
-%% recordeed since hipe_bifs:call_count_on().
-calls() ->
- [{Mod, total_calls(Mod)} || Mod <- mods(),
- total_calls(Mod) > 1,
- Mod =/= hipe_profile].
-
-%% %% @spec profile(F) -> [{mfa(),calls()}]
-%% %% F = () -> term()
-%% %% mfa() = {mod(),function(),arity()}
-%% %% function() = atom()
-%% %% arity() = intger()
-%% %%
-%% %% @doc Returns the number of calls per module generated by
-%% %% applying F().
-%% %% The resulting lists is sorted with the most called
-%% %% module first.
-%% profile(F) ->
-%% %% Make sure all code is loaded.
-%% F(),
-%% %% Turn profiling on.
-%% prof(),
-%% clear(),
-%% %% Apply the closure to profile.
-%% F(),
-%% %% Get result.
-%% R = res(),
-%% %% Turn off profiling.
-%% prof_off(),
-%% R.
-
--spec prof() -> 'ok'.
-%% @doc Turns on profiling of all loaded modules.
-prof() ->
- lists:foreach(fun prof_module/1, mods()).
-
--spec prof_off() -> 'ok'.
-%% @doc Turns off profiling of all loaded modules.
- prof_off() ->
- lists:foreach(fun prof_module_off/1, mods()).
-
--spec clear() -> 'ok'.
-%% @doc Clears all counters.
-clear() ->
- lists:foreach(fun clear_module/1, mods()).
-
--spec res() -> [{mfa(), non_neg_integer()}].
-%% @doc Returns a list of the numbers of calls to each profiled function.
-%% The list is sorted with the most called function first.
-res() ->
- lists:reverse(lists:keysort(2, lists:flatten([res_module(M) || M <- mods()]))).
-
-%% --------------------------------------------------------------------
--spec mods() -> [atom()].
-%% @doc Returns a list of all loaded modules.
-%@ --------------------------------------------------------------------
-
-mods() ->
- [Mod || {Mod,_} <- code:all_loaded()].
-
-%% --------------------------------------------------------------------
--spec prof_module(atom()) -> 'ok'.
-%% @doc Turns on profiling for given module.
-%@ ____________________________________________________________________
-
-prof_module(Mod) ->
- Funs = Mod:module_info(functions),
- lists:foreach(fun ({F,A}) -> catch hipe_bifs:call_count_on({Mod,F,A}) end,
- Funs),
- ok.
-
-%% --------------------------------------------------------------------
--spec prof_module_off(atom()) -> 'ok'.
-%% @doc Turns off profiling of the module Mod.
-%@ --------------------------------------------------------------------
-
-prof_module_off(Mod) ->
- Funs = Mod:module_info(functions),
- lists:foreach(fun ({F,A}) -> catch hipe_bifs:call_count_off({Mod,F,A}) end,
- Funs),
- ok.
-
-%% --------------------------------------------------------------------
--spec clear_module(atom()) -> 'ok'.
-%% @doc Clears the call counters for all functions in module Mod.
-%@ --------------------------------------------------------------------
-
-clear_module(Mod) ->
- Funs = Mod:module_info(functions),
- lists:foreach(fun ({F,A}) -> catch hipe_bifs:call_count_clear({Mod,F,A}) end,
- Funs),
- ok.
-
-%% --------------------------------------------------------------------
--spec res_module(atom()) -> [{mfa(), non_neg_integer()}].
-%% @doc Returns the number of profiled calls to each function (MFA)
-%% in the module Mod.
-%@ --------------------------------------------------------------------
-
-res_module(Mod) ->
- Fun = fun ({F,A}) when is_atom(F), is_integer(A) ->
- MFA = {Mod,F,A},
- {MFA, try hipe_bifs:call_count_get(MFA) of
- N when is_integer(N) -> N;
- false -> 0
- catch
- _:_ -> 0
- end
- }
- end,
- lists:reverse(lists:keysort(2, [Fun(FA) || FA <- Mod:module_info(functions)])).
-
--spec total_calls(atom()) -> non_neg_integer().
-
-total_calls(Mod) ->
- Funs = Mod:module_info(functions),
- SumF = fun ({F,A}, Acc) ->
- MFA = {Mod,F,A},
- try hipe_bifs:call_count_get(MFA) of
- N when is_integer(N) -> N+Acc;
- false -> Acc
- catch
- _:_ -> Acc
- end;
- (_, Acc) -> Acc
- end,
- lists:foldl(SumF, 0, Funs).
diff --git a/lib/hipe/tools/hipe_timer.erl b/lib/hipe/tools/hipe_timer.erl
deleted file mode 100644
index 13dbeb6f87..0000000000
--- a/lib/hipe/tools/hipe_timer.erl
+++ /dev/null
@@ -1,153 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Module : hipe_timer
-%% Purpose :
-%% Notes :
-%% History : * 2001-03-15 Erik Johansson (happi@it.uu.se): Created.
-%% ====================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_timer).
-
--export([tr/1, t/1, timer/1, time/1, empty_time/0]).
--export([advanced/2]).
-
-t(F) ->
- {EWT,ERT} = empty_time(),
- {WT,RT} = time(F),
- {WT-EWT,(RT-ERT)/1000}.
-
-tr(F) ->
- {EWT,ERT} = empty_time(),
- {R,{WT,RT}} = timer(F),
- {R,{WT-EWT,(RT-ERT)/1000}}.
-
-empty_time() ->
- WTA = erlang:monotonic_time(),
- {A,_} = erlang:statistics(runtime),
- WTB = erlang:monotonic_time(),
- {B,_} = erlang:statistics(runtime),
- {(WTB-WTA)/erlang:convert_time_unit(1, second, native),B-A}.
-
-time(F) ->
- WTA = erlang:monotonic_time(),
- {A,_} = erlang:statistics(runtime),
- F(),
- WTB = erlang:monotonic_time(),
- {B,_} = erlang:statistics(runtime),
- {(WTB-WTA)/erlang:convert_time_unit(1, second, native),B-A}.
-
-timer(F) ->
- WTA = erlang:monotonic_time(),
- {A,_} = erlang:statistics(runtime),
- R = F(),
- WTB = erlang:monotonic_time(),
- {B,_} = erlang:statistics(runtime),
- {R,{(WTB-WTA)/erlang:convert_time_unit(1, second, native),B-A}}.
-
-advanced(_Fun, I) when I < 2 -> false;
-advanced(Fun, Iterations) ->
- R = Fun(),
- Measurements = [t(Fun) || _ <- lists:seq(1, Iterations)],
- {Wallclock, RunTime} = split(Measurements),
- WMin = lists:min(Wallclock),
- RMin = lists:min(RunTime),
- WMax = lists:max(Wallclock),
- RMax = lists:max(RunTime),
- WMean = mean(Wallclock),
- RMean = mean(RunTime),
- WMedian = median(Wallclock),
- RMedian = median(RunTime),
- WVariance = variance(Wallclock),
- RVariance = variance(RunTime),
- WStddev = stddev(Wallclock),
- RStddev = stddev(RunTime),
- WVarCoff = 100 * WStddev / WMean,
- RVarCoff = 100 * RStddev / RMean,
- WSum = lists:sum(Wallclock),
- RSum = lists:sum(RunTime),
- [{wallclock,[{min, WMin},
- {max, WMax},
- {mean, WMean},
- {median, WMedian},
- {variance, WVariance},
- {stdev, WStddev},
- {varcoff, WVarCoff},
- {sum, WSum},
- {values, Wallclock}]},
- {runtime,[{min, RMin},
- {max, RMax},
- {mean, RMean},
- {median, RMedian},
- {variance, RVariance},
- {stdev, RStddev},
- {varcoff, RVarCoff},
- {sum, RSum},
- {values, RunTime}]},
- {iterations, Iterations},
- {result, R}].
-
-split(M) ->
- split(M, [], []).
-
-split([{W,R}|More], AccW, AccR) ->
- split(More, [W|AccW], [R|AccR]);
-split([], AccW, AccR) ->
- {AccW, AccR}.
-
-mean(L) ->
- mean(L, 0, 0).
-
-mean([V|Vs], No, Sum) ->
- mean(Vs, No+1, Sum+V);
-mean([], No, Sum) when No > 0 ->
- Sum/No;
-mean([], _No, _Sum) ->
- exit(empty_list).
-
-median(L) ->
- S = length(L),
- SL = lists:sort(L),
- case even(S) of
- true ->
- (lists:nth((S div 2), SL) + lists:nth((S div 2) + 1, SL)) / 2;
- false ->
- lists:nth((S div 2), SL)
- end.
-
-even(S) ->
- (S band 1) =:= 0.
-
-%% diffs(L, V) ->
-%% [X - V || X <- L].
-
-square_diffs(L, V) ->
- [(X - V) * (X - V) || X <- L].
-
-variance(L) ->
- Mean = mean(L),
- N = length(L),
- if N > 1 ->
- lists:sum(square_diffs(L,Mean)) / (N-1);
- true -> exit('too few values')
- end.
-
-stddev(L) ->
- math:sqrt(variance(L)).
diff --git a/lib/hipe/util/Makefile b/lib/hipe/util/Makefile
deleted file mode 100644
index e2771a9bc4..0000000000
--- a/lib/hipe/util/Makefile
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-ifdef HIPE_ENABLED
-HIPE_MODULES = hipe_vectors
-else
-HIPE_MODULES =
-endif
-MODULES = hipe_timing hipe_digraph hipe_dsets $(HIPE_MODULES)
-
-HRL_FILES=
-ERL_FILES= $(MODULES:%=%.erl)
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC= $(APP_FILE).src
-# APP_TARGET= $(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC= $(APPUP_FILE).src
-# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars +warn_missing_spec +warn_untyped_record
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/util"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)/util"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-
-$(EBIN)/hipe_timing.beam: ../main/hipe.hrl
diff --git a/lib/hipe/util/hipe_digraph.erl b/lib/hipe/util/hipe_digraph.erl
deleted file mode 100644
index 0976395262..0000000000
--- a/lib/hipe/util/hipe_digraph.erl
+++ /dev/null
@@ -1,235 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%-----------------------------------------------------------------------
-%% File : hipe_digraph.erl
-%% Author : Tobias Lindahl <tobiasl@it.uu.se>
-%% Purpose : Provides a simple implementation of a directed graph.
-%%
-%% Created : 9 Feb 2005 by Tobias Lindahl <tobiasl@it.uu.se>
-%%-----------------------------------------------------------------------
--module(hipe_digraph).
-
--export([new/0, add_edge/3, add_node/2, add_node_list/2,
- from_list/1, to_list/1, get_parents/2, get_children/2]).
--export([reverse_preorder_sccs/1]).
-
--export_type([hdg/0]).
-
-%%------------------------------------------------------------------------
-
--type ordset(T) :: [T]. % XXX: temporarily
-
--record(hipe_digraph, {edges = dict:new() :: dict:dict(),
- rev_edges = dict:new() :: dict:dict(),
- leaves = ordsets:new() :: ordset(_), % ???
- nodes = sets:new() :: sets:set()}).
-
--opaque hdg() :: #hipe_digraph{}.
-
-%%------------------------------------------------------------------------
-
--spec new() -> hdg().
-
-new() ->
- #hipe_digraph{edges = dict:new(), rev_edges = dict:new(),
- leaves = ordsets:new(), nodes = sets:new()}.
-
--spec from_list([_]) -> hdg().
-
-from_list(List) ->
- Edges = lists:foldl(fun({From, To}, Dict) ->
- Fun = fun(Set) -> ordsets:add_element(To, Set) end,
- dict:update(From, Fun, [To], Dict)
- end,
- dict:new(), List),
- RevEdges = lists:foldl(fun({From, To}, Dict) ->
- Fun = fun(Set) ->
- ordsets:add_element(From, Set)
- end,
- dict:update(To, Fun, [From], Dict)
- end,
- dict:new(), List),
- Keys1 = sets:from_list(dict:fetch_keys(Edges)),
- Keys2 = sets:from_list(dict:fetch_keys(RevEdges)),
- Nodes = sets:union(Keys1, Keys2),
- #hipe_digraph{edges = Edges, rev_edges = RevEdges,
- leaves = [], nodes = Nodes}.
-
--spec to_list(hdg()) -> [_].
-
-to_list(#hipe_digraph{edges = Edges}) ->
- List1 = dict:to_list(Edges),
- List2 = lists:foldl(fun({From, ToList}, Acc) ->
- [[{From, To} || To <- ToList]|Acc]
- end, [], List1),
- lists:flatten(List2).
-
--spec add_node(_, hdg()) -> hdg().
-
-add_node(NewNode, DG = #hipe_digraph{nodes=Nodes}) ->
- DG#hipe_digraph{nodes = sets:add_element(NewNode, Nodes)}.
-
--spec add_node_list([_], hdg()) -> hdg().
-
-add_node_list(NewNodes, DG = #hipe_digraph{nodes=Nodes}) ->
- Set = sets:from_list(NewNodes),
- DG#hipe_digraph{nodes = sets:union(Set, Nodes)}.
-
--spec add_edge(_, _, hdg()) -> hdg().
-
-add_edge(From, To, #hipe_digraph{edges = Edges, rev_edges = RevEdges,
- leaves = Leaves, nodes = Nodes}) ->
- Fun1 = fun(Set) -> ordsets:add_element(To, Set) end,
- NewEdges = dict:update(From, Fun1, [To], Edges),
- Fun2 = fun(Set) -> ordsets:add_element(From, Set) end,
- NewRevEdges = dict:update(To, Fun2, [From], RevEdges),
- NewLeaves = ordsets:del_element(From, Leaves),
- #hipe_digraph{edges = NewEdges,
- rev_edges = NewRevEdges,
- leaves = NewLeaves,
- nodes = sets:add_element(From, sets:add_element(To, Nodes))}.
-
-%%-------------------------------------------------------------------------
-
--spec take_indep_scc(hdg()) -> 'none' | {'ok', [_], hdg()}.
-
-take_indep_scc(DG = #hipe_digraph{edges = Edges, rev_edges = RevEdges,
- leaves = Leaves, nodes = Nodes}) ->
- case sets:size(Nodes) =:= 0 of
- true -> none;
- false ->
- {SCC, NewLeaves} =
- case Leaves of
- [H|T] ->
- {[H], T};
- [] ->
- case find_all_leaves(Edges) of
- [] ->
- {[Node|_], _} = dfs(Nodes, RevEdges),
- {SCC1, _} = dfs(Node, Edges),
- {SCC1, []};
- [H|T] ->
- {[H], T}
- end
- end,
- NewEdges = remove_edges(SCC, Edges, RevEdges),
- NewRevEdges = remove_edges(SCC, RevEdges, Edges),
- NewNodes = sets:subtract(Nodes, sets:from_list(SCC)),
- {ok, reverse_preorder(SCC, Edges),
- DG#hipe_digraph{edges = NewEdges, rev_edges = NewRevEdges,
- leaves = NewLeaves, nodes = NewNodes}}
- end.
-
-find_all_leaves(Edges) ->
- List = dict:fold(fun(Key, [Key], Acc) -> [Key|Acc];
- (_, _, Acc) -> Acc
- end, [], Edges),
- ordsets:from_list(List).
-
-remove_edges(Nodes0, Edges, RevEdges) ->
- Nodes = ordsets:from_list(Nodes0),
- Fun = fun(N, Dict) -> dict:erase(N, Dict) end,
- Edges1 = lists:foldl(Fun, Edges, Nodes),
- remove_edges_in(Nodes, Edges1, RevEdges).
-
-remove_edges_in([Node|Nodes], Edges, RevEdges) ->
- NewEdges =
- case dict:find(Node, RevEdges) of
- error ->
- Edges;
- {ok, Set} ->
- Fun = fun(Key, Dict) ->
- case dict:find(Key, Dict) of
- error ->
- Dict;
- {ok, OldTo} ->
- case ordsets:del_element(Node, OldTo) of
- [] -> dict:store(Key, [Key], Dict);
- NewSet -> dict:store(Key, NewSet, Dict)
- end
- end
- end,
- lists:foldl(Fun, Edges, Set)
- end,
- remove_edges_in(Nodes, NewEdges, RevEdges);
-remove_edges_in([], Edges, _RevEdges) ->
- Edges.
-
-reverse_preorder([_] = Nodes, _Edges) ->
- Nodes;
-reverse_preorder([N|_] = Nodes, Edges) ->
- NodeSet = sets:from_list(Nodes),
- {PreOrder, _} = dfs(N, Edges),
- DFS = [X || X <- PreOrder, sets:is_element(X, NodeSet)],
- lists:reverse(DFS).
-
-%%---------------------------------------------------------------------
-
--spec reverse_preorder_sccs(hdg()) -> [[_]].
-
-reverse_preorder_sccs(DG) ->
- reverse_preorder_sccs(DG, []).
-
-reverse_preorder_sccs(DG, Acc) ->
- case take_indep_scc(DG) of
- none -> lists:reverse(Acc);
- {ok, SCC, DG1} -> reverse_preorder_sccs(DG1, [SCC|Acc])
- end.
-
-%%---------------------------------------------------------------------
-
--spec get_parents(_, hdg()) -> [_].
-
-get_parents(Node, #hipe_digraph{rev_edges = RevEdges}) ->
- case dict:is_key(Node, RevEdges) of
- true -> dict:fetch(Node, RevEdges);
- false -> []
- end.
-
--spec get_children(_, hdg()) -> [_].
-
-get_children(Node, #hipe_digraph{edges = Edges}) ->
- case dict:is_key(Node, Edges) of
- true -> dict:fetch(Node, Edges);
- false -> []
- end.
-
-%%---------------------------------------------------------------------
-%% dfs/2 returns a preordered depth first search and the nodes visited.
-
-dfs(Node, Edges) ->
- case sets:is_set(Node) of
- true ->
- dfs(sets:to_list(Node), Edges, sets:new(), []);
- false ->
- dfs([Node], Edges, sets:new(), [])
- end.
-
-dfs([Node|Left], Edges, Visited, Order) ->
- case sets:is_element(Node, Visited) of
- true ->
- dfs(Left, Edges, Visited, Order);
- false ->
- NewVisited = sets:add_element(Node, Visited),
- case dict:find(Node, Edges) of
- error ->
- dfs(Left, Edges, NewVisited, [Node|Order]);
- {ok, Succ} ->
- {NewOrder, NewVisited1} = dfs(Succ, Edges, NewVisited, Order),
- dfs(Left, Edges, NewVisited1, [Node|NewOrder])
- end
- end;
-dfs([], _Edges, Visited, Order) ->
- {Order, Visited}.
diff --git a/lib/hipe/util/hipe_dsets.erl b/lib/hipe/util/hipe_dsets.erl
deleted file mode 100644
index 9492cab0ff..0000000000
--- a/lib/hipe/util/hipe_dsets.erl
+++ /dev/null
@@ -1,84 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%@doc
-%% IMMUTABLE DISJOINT SETS OF ARBITRARY TERMS
-%%
-%% The disjoint set forests data structure, for elements of arbitrary types.
-%% Note that the find operation mutates the set.
-%%
-%% We could do this more efficiently if we restricted the elements to integers,
-%% and used the (mutable) hipe arrays. For arbitrary terms ETS could be used,
-%% for a persistent interface (which isn't that nice when even accessors return
-%% modified copies), the array module could be used.
--module(hipe_dsets).
-
--export([new/1, find/2, union/3, to_map/1, to_rllist/1]).
--export_type([dsets/1]).
-
--opaque dsets(X) :: #{X => {node, X} | {root, non_neg_integer()}}.
-
--spec new([E]) -> dsets(E).
-new(Elems) -> maps:from_list([{E,{root,0}} || E <- Elems]).
-
--spec find(E, dsets(E)) -> {E, dsets(E)}.
-find(E, DS0) ->
- case DS0 of
- #{E := {root,_}} -> {E, DS0};
- #{E := {node,N}} ->
- case find(N, DS0) of
- {N, _}=T -> T;
- {R, DS1} -> {R, DS1#{E := {node,R}}}
- end;
- _ -> error(badarg, [E, DS0])
- end.
-
--spec union(E, E, dsets(E)) -> dsets(E).
-union(X, Y, DS0) ->
- {XRoot, DS1} = find(X, DS0),
- case find(Y, DS1) of
- {XRoot, DS2} -> DS2;
- {YRoot, DS2} ->
- #{XRoot := {root,XRR}, YRoot := {root,YRR}} = DS2,
- if XRR < YRR -> DS2#{XRoot := {node,YRoot}};
- XRR > YRR -> DS2#{YRoot := {node,XRoot}};
- true -> DS2#{YRoot := {node,XRoot}, XRoot := {root,XRR+1}}
- end
- end.
-
--spec to_map(dsets(E)) -> {#{Elem::E => Root::E}, dsets(E)}.
-to_map(DS) ->
- to_map(maps:keys(DS), DS, #{}).
-
-to_map([], DS, Acc) -> {Acc, DS};
-to_map([K|Ks], DS0, Acc) ->
- {KR, DS} = find(K, DS0),
- to_map(Ks, DS, Acc#{K => KR}).
-
--spec to_rllist(dsets(E)) -> {[{Root::E, Elems::[E]}], dsets(E)}.
-to_rllist(DS0) ->
- {Lists, DS} = to_rllist(maps:keys(DS0), #{}, DS0),
- {maps:to_list(Lists), DS}.
-
-to_rllist([], Acc, DS) -> {Acc, DS};
-to_rllist([E|Es], Acc, DS0) ->
- {ERoot, DS} = find(E, DS0),
- to_rllist(Es, map_append(ERoot, E, Acc), DS).
-
-map_append(Key, Elem, Map) ->
- case Map of
- #{Key := List} -> Map#{Key := [Elem|List]};
- #{} -> Map#{Key => [Elem]}
- end.
diff --git a/lib/hipe/util/hipe_timing.erl b/lib/hipe/util/hipe_timing.erl
deleted file mode 100644
index 3ebde7b1b5..0000000000
--- a/lib/hipe/util/hipe_timing.erl
+++ /dev/null
@@ -1,126 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%====================================================================
-%% Note: Uses the process keys:
-%% hipe_time - Indicates what to time.
-%% hipe_timers - A stack of timers.
-%% {hipe_timer,T} - Delata times for named timers.
-%% T - Acc times for all named timers T.
-%%====================================================================
-
--module(hipe_timing).
--export([start/2, stop/2,
- %% start_timer/0, stop_timer/1,
- %% get_hipe_timer_val/1, set_hipe_timer_val/2,
- %% start_hipe_timer/1, stop_hipe_timer/1,
- start_optional_timer/2, stop_optional_timer/2]).
-
--include("../main/hipe.hrl").
-
-%%=====================================================================
-
--spec start(string(), atom()) -> 'ok'.
-
-start(Text, Mod) when is_atom(Mod) ->
- Timers =
- case get(hipe_timers) of
- undefined -> [];
- Ts -> Ts
- end,
- Space = [$| || _ <- Timers],
- Total = start_timer(),
- put(hipe_timers, [Total|Timers]),
- ?msg("[@~7w]" ++ Space ++ "> ~s~n", [Total,Text]).
-
--spec stop(string(), atom()) -> 'ok'.
-
-stop(Text, Mod) when is_atom(Mod) ->
- {Total,_Last} = erlang:statistics(runtime),
- case get(hipe_timers) of
- [StartTime|Timers] ->
- Space = [$| || _ <- Timers],
- put(hipe_timers,Timers),
- ?msg("[@~7w]" ++ Space ++ "< ~s: ~w~n", [Total, Text, Total-StartTime]);
- _ ->
- put(hipe_timers, []),
- ?msg("[@~7w]< ~s: ~w~n", [Total, Text, Total])
- end.
-
--spec start_optional_timer(string(), atom()) -> 'ok'.
-
-start_optional_timer(Text, Mod) ->
- case get(hipe_time) of
- true -> start(Text, Mod);
- all -> start(Text, Mod);
- Mod -> start(Text, Mod);
- List when is_list(List) ->
- case lists:member(Mod, List) of
- true -> start(Text, Mod);
- false -> ok
- end;
- _ -> ok
- end.
-
--spec stop_optional_timer(string(), atom()) -> 'ok'.
-
-stop_optional_timer(Text, Mod) ->
- case get(hipe_time) of
- true -> stop(Text, Mod);
- all -> stop(Text, Mod);
- Mod -> stop(Text, Mod);
- List when is_list(List) ->
- case lists:member(Mod, List) of
- true -> stop(Text, Mod);
- false -> ok
- end;
- _ -> ok
- end.
-
--spec start_timer() -> non_neg_integer().
-
-start_timer() ->
- {Total, _Last} = erlang:statistics(runtime),
- Total.
-
-%% stop_timer(T) ->
-%% {Total, _Last} = erlang:statistics(runtime),
-%% Total - T.
-%%
-%% start_hipe_timer(Timer) ->
-%% Time = erlang:statistics(runtime),
-%% put({hipe_timer,Timer}, Time).
-%%
-%% stop_hipe_timer(Timer) ->
-%% {T2, _} = erlang:statistics(runtime),
-%% T1 =
-%% case get({hipe_timer,Timer}) of
-%% {T0, _} -> T0;
-%% _ -> 0
-%% end,
-%% AccT =
-%% case get(Timer) of
-%% T when is_integer(T) -> T;
-%% _ -> 0
-%% end,
-%% put(Timer,AccT+T2-T1).
-%%
-%% get_hipe_timer_val(Timer) ->
-%% case get(Timer) of
-%% T when is_integer(T) -> T;
-%% _ -> 0
-%% end.
-%%
-%% set_hipe_timer_val(Timer, Val) ->
-%% put(Timer, Val).
diff --git a/lib/hipe/util/hipe_vectors.erl b/lib/hipe/util/hipe_vectors.erl
deleted file mode 100644
index 788dacd11b..0000000000
--- a/lib/hipe/util/hipe_vectors.erl
+++ /dev/null
@@ -1,129 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% VECTORS IN ERLANG
-%%
-%% Abstract interface to vectors, indexed from 0 to size-1.
-
--module(hipe_vectors).
--export([new/2,
- set/3,
- get/2,
- size/1,
- vector_to_list/1,
- %% list_to_vector/1,
- list/1]).
-
-%%-define(USE_TUPLES, true).
-%%-define(USE_GBTREES, true).
--define(USE_ARRAYS, true).
-
--type vector() :: vector(_).
--export_type([vector/0, vector/1]).
-
--spec new(non_neg_integer(), V) -> vector(E) when V :: E.
--spec set(vector(E), non_neg_integer(), V :: E) -> vector(E).
--spec get(vector(E), non_neg_integer()) -> E.
--spec size(vector(_)) -> non_neg_integer().
--spec vector_to_list(vector(E)) -> [E].
-%% -spec list_to_vector([E]) -> vector(E).
--spec list(vector(E)) -> [{non_neg_integer(), E}].
-
-%% ---------------------------------------------------------------------
-
--ifdef(USE_TUPLES).
--opaque vector(_) :: tuple().
-
-new(N, V) ->
- erlang:make_tuple(N, V).
-
-size(V) -> erlang:tuple_size(V).
-
-list(Vec) ->
- index(tuple_to_list(Vec), 0).
-
-index([X|Xs],N) ->
- [{N,X} | index(Xs,N+1)];
-index([],_) ->
- [].
-
-%% list_to_vector(Xs) ->
-%% list_to_tuple(Xs).
-
-vector_to_list(V) ->
- tuple_to_list(V).
-
-set(Vec, Ix, V) ->
- setelement(Ix+1, Vec, V).
-
-get(Vec, Ix) -> element(Ix+1, Vec).
-
--endif. %% ifdef USE_TUPLES
-
-%% ---------------------------------------------------------------------
-
--ifdef(USE_GBTREES).
--opaque vector(E) :: gb_trees:tree(non_neg_integer(), E).
-
-new(N, V) when is_integer(N), N >= 0 ->
- gb_trees:from_orddict(mklist(N, V)).
-
-mklist(N, V) ->
- mklist(0, N, V).
-
-mklist(M, N, V) when M < N ->
- [{M, V} | mklist(M+1, N, V)];
-mklist(_, _, _) ->
- [].
-
-size(V) -> gb_trees:size(V).
-
-list(Vec) ->
- gb_trees:to_list(Vec).
-
-%% list_to_vector(Xs) ->
-%% gb_trees:from_orddict(index(Xs, 0)).
-%%
-%% index([X|Xs], N) ->
-%% [{N, X} | index(Xs, N+1)];
-%% index([],_) ->
-%% [].
-
-vector_to_list(V) ->
- gb_trees:values(V).
-
-set(Vec, Ix, V) ->
- gb_trees:update(Ix, V, Vec).
-
-get(Vec, Ix) ->
- gb_trees:get(Ix, Vec).
-
--endif. %% ifdef USE_GBTREES
-
-%% ---------------------------------------------------------------------
-
--ifdef(USE_ARRAYS).
--opaque vector(E) :: array:array(E).
-
-new(N, V) -> array:new(N, {default, V}).
-size(V) -> array:size(V).
-list(Vec) -> array:to_orddict(Vec).
-%% list_to_vector(Xs) -> array:from_list(Xs).
-vector_to_list(V) -> array:to_list(V).
-set(Vec, Ix, V) -> array:set(Ix, V, Vec).
-get(Vec, Ix) -> array:get(Ix, Vec).
-
--endif. %% ifdef USE_ARRAYS
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
deleted file mode 100644
index ea01a6aeb4..0000000000
--- a/lib/hipe/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-HIPE_VSN = 4.0.1
diff --git a/lib/hipe/x86/Makefile b/lib/hipe/x86/Makefile
deleted file mode 100644
index 84edeaebe7..0000000000
--- a/lib/hipe/x86/Makefile
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-ifndef EBIN
-EBIN = ../ebin
-endif
-
-ifndef DOCS
-DOCS = ../doc
-endif
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(HIPE_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-# Please keep this list sorted.
-MODULES=hipe_rtl_to_x86 \
- hipe_x86 \
- hipe_x86_assemble \
- hipe_x86_cfg \
- hipe_x86_defuse \
- hipe_x86_encode \
- hipe_x86_frame \
- hipe_x86_liveness \
- hipe_x86_main \
- hipe_x86_postpass \
- hipe_x86_pp \
- hipe_x86_ra \
- hipe_x86_ra_finalise \
- hipe_x86_ra_ls \
- hipe_x86_ra_naive \
- hipe_x86_ra_postconditions \
- hipe_x86_registers \
- hipe_x86_spill_restore \
- hipe_x86_subst \
- hipe_x86_x87
-
-HRL_FILES=hipe_x86.hrl
-ERL_FILES=$(MODULES:%=%.erl)
-TARGET_FILES=$(MODULES:%=$(EBIN)/%.$(EMULATOR))
-DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
-
-# APP_FILE=
-# APP_SRC=$(APP_FILE).src
-# APP_TARGET=$(EBIN)/$(APP_FILE)
-#
-# APPUP_FILE=
-# APPUP_SRC=$(APPUP_FILE).src
-# APPUP_TARGET=$(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-include ../native.mk
-
-ERL_COMPILE_FLAGS += -Werror +warn_export_vars
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-# Moved docs target to edocs so the standard docs rule work properly.
-edocs: $(DOC_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-distclean: clean
-realclean: clean
-
-$(DOCS)/%.html:%.erl
- erl -noshell -run edoc_run file '"$<"' '[{dir, "$(DOCS)"}]' -s init stop
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-# Please keep this list sorted.
-$(EBIN)/hipe_rtl_to_x86.beam: ../rtl/hipe_rtl.hrl
-$(EBIN)/hipe_x86_assemble.beam: ../main/hipe.hrl ../rtl/hipe_literals.hrl ../misc/hipe_sdi.hrl
-$(EBIN)/hipe_x86_cfg.beam: ../flow/cfg.hrl ../flow/cfg.inc
-$(EBIN)/hipe_x86_frame.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_x86_liveness.beam: ../flow/liveness.inc
-$(EBIN)/hipe_x86_main.beam: ../main/hipe.hrl
-$(EBIN)/hipe_x86_ra: ../main/hipe.hrl
-$(EBIN)/hipe_x86_ra_dummy.beam: ../main/hipe.hrl
-$(EBIN)/hipe_x86_ra_ls.beam: ../main/hipe.hrl
-$(EBIN)/hipe_x86_ra_postconditions.beam: ../main/hipe.hrl
-$(EBIN)/hipe_x86_registers.beam: ../rtl/hipe_literals.hrl
-$(EBIN)/hipe_x86_spill_restore.beam: ../main/hipe.hrl ../flow/cfg.hrl
-$(EBIN)/hipe_x86_x87.beam: ../main/hipe.hrl
-
-$(TARGET_FILES): hipe_x86.hrl ../misc/hipe_consttab.hrl
diff --git a/lib/hipe/x86/NOTES.OPTIM b/lib/hipe/x86/NOTES.OPTIM
deleted file mode 100644
index c518ea3481..0000000000
--- a/lib/hipe/x86/NOTES.OPTIM
+++ /dev/null
@@ -1,198 +0,0 @@
-Partial x86 code optimisation guide
-===================================
-Priority should be given to P6 and P4, then K7,
-then P5, and last to K6.
-
-Rules that are blatantly obvious or irrelevant for HiPE are
-generally not listed. These includes things like alignment
-of basic data types, store-forwarding rules when alignment
-or sizes don't match, and partial register stalls.
-
-Intel P4
---------
-The P6 4-1-1 insn decode template no longer applies.
-
-Simple insns (add/sub/cmp/test/and/or/xor/neg/not/mov/sahf)
-are twice as fast as in P6.
-
-Shifts are "movsx" (sign-extend) are slower than in P6.
-
-Always avoid "inc" and "dec", use "add" and "sub" instead,
-due to condition codes dependencies overhead.
-
-"fxch" is slightly more expensive than in P6, where it was free.
-
-Use "setcc" or "cmov" to eliminate unpredictable branches.
-
-For hot code executing out of the trace cache, alignment of
-branch targets is less of an issue compared to P6.
-
-Do use "fxch" to simulate a flat FP register file, but only
-for that purpose, not for manual scheduling for parallelism.
-
-Using "lea" is highly recommended.
-
-Eliminate redundant loads. Use regs as much as possible.
-
-Left shifts up to 3 have longer latencies than the equivalent
-sequence of adds.
-
-Do utilise the addressing modes, to save registers and trace
-cache bandwidth.
-
-"xor reg,reg" or "sub reg,reg" preferred over moving zero to reg.
-
-"test reg,reg" preferred over "cmp" with zero or "and".
-
-Avoid explicit cmp/test;jcc if the preceeding insn (alu, but not
-mov or lea) set the condition codes.
-
-Load-execute alu insns (mem src) are Ok.
-
-Add-reg-to-mem slightly better than add-mem-to-reg.
-
-Add-reg-to-mem is better than load;add;store.
-
-Intel P6
---------
-4-1-1 instruction decoding template: can decode one semi-complex
-(max 4 uops) and two simple (1 uop) insns per clock; follow a
-complex insn by two simple ones, otherwise the decoders will stall.
-
-Load-execute (mem src) alu insns are 2 uops.
-Read-modify-write (mem dst) alu insns are 4 uops.
-
-Insns longer than 7 bytes block parallel decoding.
-Avoid insns longer than 7 bytes.
-
-Lea is useful.
-
-"movzx" is preferred for zero-extension; the xor;mov alternative
-causes a partial register stall.
-
-Use "test" instead of "cmp" with zero.
-
-Pull address calculations into load and store insn addressing modes.
-
-Clear a reg with "xor", not by moving zero to it.
-
-Many alu insns set the condition codes. Replace "alu;cmp;jcc"
-with "alu;jcc". This is not applicable for "mov" or "lea".
-
-For FP code, simulate a flat register file on the x87 stack by
-using fxch to reorder it.
-
-AMD K7
-------
-Select DirectPath insns. Avoid VectorPath insns due to slower decode.
-
-Alu insns with mem src are very efficient.
-Alu insns with mem dst are very efficient.
-
-Fetches from I-cache are 16-byte aligned. Align functions and frequently
-used labels at or near the start of 16-byte aligned blocks.
-
-"movzx" preferred over "xor;mov" for zero-extension.
-
-"push mem" preferred over "load;push reg".
-
-"xor reg,reg" preferred over moving zero to the reg.
-
-"test" preferred over "cmp".
-
-"pop" insns are VectorPath. "pop mem" has latency 3, "pop reg" has
-latency 4.
-
-"push reg" and "push imm" are DirectPath, "push mem" is VectorPath.
-The latency is 3 clocks.
-
-Intel P5
---------
-If a loop header is less than 8 bytes away from a 16-byte
-boundary, align it to the 16-byte boundary.
-
-If a return address is less than 8 bytes away from a 16-byte
-boundary, align it to the 16-byte boundary.
-
-Align function entry points to 16-byte boundaries.
-
-Ensure that doubles are 64-bit aligned.
-
-Data cache line size is 32 bytes. The whole line is brought
-in on a read miss.
-
-"push mem" is not pairable; loading a temp reg and pushing
-the reg pairs better -- this is also faster on the 486.
-
-No conditional move instruction.
-
-Insns longer than 7 bytes can't go down the V-pipe or share
-the insn FIFO with other insns.
-Avoid insns longer than 7 bytes.
-
-Lea is useful when it replaces several other add/shift insns.
-Lea is not a good replacement for a single shl since a scaled
-index requires a disp32 (or base), making the insn longer.
-
-"movzx" is worse than the xor;mov alternative -- the opcode
-prefix causes a slowdown and it is not pariable.
-
-Use "test" instead of "cmp" with zero.
-
-"test eax,imm" and "test reg,reg" are pairable, other forms are not.
-
-Pull address calculations into load and store insn addressing modes.
-
-Clear a reg with "xor", not by moving zero to it.
-
-Many alu insns set the condition codes. Replace "alu;cmp;jcc"
-with "alu;jcc". This is not applicable for "mov" or "lea".
-
-For FP code, simulate a flat register file on the x87 stack by
-using fxch to reorder it.
-
-"neg" and "not" are not pairable. "test imm,reg" and "test imm,mem"
-are not pairable. Shifts by "cl" are not pairable. Shifts by "1" or
-"imm" are pairable but only execute in the U-pipe.
-
-AMD K6
-------
-The insn size predecoder has a 3-byte window. Insns with both prefix
-and SIB bytes cannot be short-decoded.
-
-Use short and simple insns, including mem src alu insns.
-
-Avoid insns longer than 7 bytes. They cannot be short-decoded.
-Short-decode: max 7 bytes, max 2 uops.
-Long-decode: max 11 bytes, max 4 uops.
-Vector-decode: longer than 11 bytes or more than 4 uops.
-
-Prefer read-modify-write alu insns (mem dst) over "load;op;store"
-sequences, for code density and register pressure reasons.
-
-Avoid the "(esi)" addressing mode: it forces the insn to be vector-decoded.
-Use a different reg or add an explicit zero displacement.
-
-"add reg,reg" preferred over a shl by 1, it parallelises better.
-
-"movzx" preferred over "xor;mov" for zero-extension.
-
-Moving zero to a reg preferred over "xor reg,reg" due to dependencies
-and condition codes overhead.
-
-"push mem" preferred over "load;push reg" due to code density and
-register pressure. (Page 64.)
-Explicit moves preferred when pushing args for fn calls, due to
-%esp dependencies and random access possibility. (Page 58.)
-[hmm, these two are in conflict]
-
-There is no penalty for seg reg prefix unless there are multiple prefixes.
-
-Align function entries and frequent branch targets to 16-byte boundaries.
-
-Shifts by imm only go down one of the pipes.
-
-"test reg,reg" preferred over "cmp" with zero.
-"test reg,imm" is a long-decode insn.
-
-No conditional move insn.
diff --git a/lib/hipe/x86/NOTES.RA b/lib/hipe/x86/NOTES.RA
deleted file mode 100644
index 173eaf229e..0000000000
--- a/lib/hipe/x86/NOTES.RA
+++ /dev/null
@@ -1,30 +0,0 @@
-Register Allocation
-===================
-
-These are the rules that HiPE x86 register allocators must abide by.
-
-- Before RA, every Temp (precoloured or pseudo) is semantically
- equivalent to Reg. Any operand may be Temp.
-
-- Before RA, only FIXED registers may occur in precoloured Temps.
- Exception 1 is move: src or dst may be an argument register.
- Exception 2 is call: the dst (if any) must be %eax.
-
-- After RA, an operand (src or dst) may refer to at most one memory cell.
- Therefore, a pseudo-Temp MAY NOT occur as base or offset in an
- explicit memory operand after RA.
-
-- After RA, a binary operation (alu, cmp, move) may refer to at most
- one memory cell. Therefore, AT MOST ONE of src and dst may be a
- pseudo-Temp after RA. If one of the operands (src or dst) is an
- explicit memory operand, then the other operand MUST NOT be a
- pseudo-Temp after RA.
-
-- After RA, the index in a jmp_switch must be a register.
-
-- After RA, the temp in a lea must be a register.
-
-- After RA, the temp in an imul must be a register.
-
-- After RA, a function's formal parameters must reside on the stack.
- Therefore, the RA MUST NOT map the formals to actual registers.
diff --git a/lib/hipe/x86/TODO b/lib/hipe/x86/TODO
deleted file mode 100644
index 7c93f7daf3..0000000000
--- a/lib/hipe/x86/TODO
+++ /dev/null
@@ -1,31 +0,0 @@
-rtl_to_x86:
-* recognise alub(X,X,sub,1,lt,L1,L2,P) and turn it into 'dec',
- this might improve the reduction test code slightly (X is
- the pseudo for FCALLS)
-* recognise alu(Z,X,add,Y) and turn it into 'lea'.
-* rewrite tailcalls as parallel assignments before regalloc
-
-x86:
-* Use separate constructors for real regs (x86_reg) and pseudos (x86_temp).
-
-Frame:
-* drop tailcall rewrite
-
-Registers:
-* make the 2 regs now reserved for frame's tailcall rewrite available for arg passing
-
-Optimizations:
-* replace jcc cc,L1; jmp L0; L1: with jcc <not cc> L0; L1: (length:len/2)
-* Kill move X,X insns, either in frame or finalise
-* Instruction scheduling module
-* We can now choose to not have HP in %esi. However, this currently loses
- performance due to (a) repeated moves to/from P_HP(P), and (b) spills of
- the temp that contains a copy of P_HP(P). Both of these problems should be
- fixed, and then, if we don't have any noticeable performance degradation, we
- should permanently change to a non-reserved HP strategy.
-
-Loader:
-
-Assembler:
-
-Encode:
diff --git a/lib/hipe/x86/hipe_rtl_to_x86.erl b/lib/hipe/x86/hipe_rtl_to_x86.erl
deleted file mode 100644
index 22947da148..0000000000
--- a/lib/hipe/x86/hipe_rtl_to_x86.erl
+++ /dev/null
@@ -1,936 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Translate 3-address RTL code to 2-address pseudo-x86 code.
-
--ifdef(HIPE_AMD64).
--define(HIPE_RTL_TO_X86, hipe_rtl_to_amd64).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(ECX, rcx).
--define(EAX, rax).
--else.
--define(HIPE_RTL_TO_X86, hipe_rtl_to_x86).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(ECX, ecx).
--define(EAX, eax).
--endif.
-
--module(?HIPE_RTL_TO_X86).
--export([translate/1]).
-
--include("../rtl/hipe_rtl.hrl").
-
-translate(RTL) -> % RTL function -> x86 defun
- hipe_gensym:init(x86),
- hipe_gensym:set_var(x86, ?HIPE_X86_REGISTERS:first_virtual()),
- hipe_gensym:set_label(x86, hipe_gensym:get_label(rtl)),
- Map0 = vmap_empty(),
- {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),
- OldData = hipe_rtl:rtl_data(RTL),
- {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),
- {RegFormals,_} = split_args(Formals),
- Code =
- case RegFormals of
- [] -> Code0;
- _ -> [hipe_x86:mk_label(hipe_gensym:get_next_label(x86)) |
- move_formals(RegFormals, Code0)]
- end,
- IsClosure = hipe_rtl:rtl_is_closure(RTL),
- IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
- hipe_x86:mk_defun(hipe_rtl:rtl_fun(RTL),
- Formals,
- IsClosure,
- IsLeaf,
- Code,
- NewData,
- [],
- []).
-
-conv_insn_list([H|T], Map, Data) ->
- {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),
- %% io:format("~w \n ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),
- {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),
- {NewH ++ NewT, NewData2};
-conv_insn_list([], _, Data) ->
- {[], Data}.
-
-conv_insn(I, Map, Data) ->
- case I of
- #alu{} ->
- %% dst = src1 binop src2
- BinOp = conv_binop(hipe_rtl:alu_op(I)),
- {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),
- {FixSrc1, Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),
- {FixSrc2, Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),
- I2 =
- case hipe_rtl:is_shift_op(hipe_rtl:alu_op(I)) of
- true ->
- conv_shift(Dst, Src1, BinOp, Src2);
- false ->
- conv_alu_nocc(Dst, Src1, BinOp, Src2, [])
- end,
- {FixSrc1++FixSrc2++I2, Map2, Data};
- #alub{} ->
- %% dst = src1 op src2; if COND goto label
- BinOp = conv_binop(hipe_rtl:alub_op(I)),
- {FixSrc1, Src1, Map0} = conv_src(hipe_rtl:alub_src1(I), Map),
- {FixSrc2, Src2, Map1} = conv_src(hipe_rtl:alub_src2(I), Map0),
- Cc = conv_cond(hipe_rtl:alub_cond(I)),
- BranchOp = conv_branchop(BinOp),
- HasDst = hipe_rtl:alub_has_dst(I),
- {I2, Map3} =
- case (not HasDst) andalso BranchOp =/= none of
- true ->
- {conv_branch(Src1, BranchOp, Src2, Cc,
- hipe_rtl:alub_true_label(I),
- hipe_rtl:alub_false_label(I),
- hipe_rtl:alub_pred(I)), Map1};
- false ->
- {Dst, Map2} =
- case HasDst of
- false -> {new_untagged_temp(), Map1};
- true -> conv_dst(hipe_rtl:alub_dst(I), Map1)
- end,
- I1 = [hipe_x86:mk_pseudo_jcc(Cc,
- hipe_rtl:alub_true_label(I),
- hipe_rtl:alub_false_label(I),
- hipe_rtl:alub_pred(I))],
- {conv_alu(Dst, Src1, BinOp, Src2, I1), Map2}
- end,
- {FixSrc1++FixSrc2++I2, Map3, Data};
- #call{} ->
- %% push <arg1>
- %% ...
- %% push <argn>
- %% eax := call <Fun>; if exn goto <Fail> else goto Next
- %% Next:
- %% <Dst> := eax
- %% goto <Cont>
- {FixArgs, Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),
- {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),
- {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),
- I2 = conv_call(Dsts, Fun, Args,
- hipe_rtl:call_continuation(I),
- hipe_rtl:call_fail(I),
- hipe_rtl:call_type(I)),
- {FixArgs++I2, Map2, Data};
- #comment{} ->
- I2 = [hipe_x86:mk_comment(hipe_rtl:comment_text(I))],
- {I2, Map, Data};
- #enter{} ->
- {FixArgs, Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),
- {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),
- I2 = conv_tailcall(Fun, Args, hipe_rtl:enter_type(I)),
- {FixArgs++I2, Map1, Data};
- #goto{} ->
- I2 = [hipe_x86:mk_jmp_label(hipe_rtl:goto_label(I))],
- {I2, Map, Data};
- #label{} ->
- I2 = [hipe_x86:mk_label(hipe_rtl:label_name(I))],
- {I2, Map, Data};
- #load{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),
- {FixSrc, Src, Map1} = conv_src_noimm(hipe_rtl:load_src(I), Map0),
- {FixOff, Off, Map2} = conv_src(hipe_rtl:load_offset(I), Map1),
- I2 = case {hipe_rtl:load_size(I), hipe_rtl:load_sign(I)} of
- {byte, signed} ->
- [hipe_x86:mk_movsx(hipe_x86:mk_mem(Src, Off, 'byte'), Dst)];
- {byte, unsigned} ->
- [hipe_x86:mk_movzx(hipe_x86:mk_mem(Src, Off, 'byte'), Dst)];
- {int16, signed} ->
- [hipe_x86:mk_movsx(hipe_x86:mk_mem(Src, Off, 'int16'), Dst)];
- {int16, unsigned} ->
- [hipe_x86:mk_movzx(hipe_x86:mk_mem(Src, Off, 'int16'), Dst)];
- {LoadSize, LoadSign} ->
- mk_load(LoadSize, LoadSign, Src, Off, Dst)
- end,
- {FixSrc++FixOff++I2, Map2, Data};
- #load_address{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map),
- Addr = hipe_rtl:load_address_addr(I),
- Type = hipe_rtl:load_address_type(I),
- Src = hipe_x86:mk_imm_from_addr(Addr, Type),
- I2 = mk_load_address(Type, Src, Dst),
- {I2, Map0, Data};
- #load_atom{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map),
- Src = hipe_x86:mk_imm_from_atom(hipe_rtl:load_atom_atom(I)),
- I2 = [hipe_x86:mk_move(Src, Dst)],
- {I2, Map0, Data};
- #move{src=Dst, dst=Dst} -> {[], Map, Data};
- #move{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map),
- {FixSrc, Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0),
- I2 = [hipe_x86:mk_move(Src, Dst)],
- {FixSrc++I2, Map1, Data};
- #return{} ->
- {FixArgs, Args, Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map),
- %% frame will fill in npop later, hence the "mk_ret(-1)"
- I2 = move_retvals(Args, [hipe_x86:mk_ret(-1)]),
- {FixArgs++I2, Map0, Data};
- #store{} ->
- {FixPtr, Ptr, Map0} = conv_src_noimm(hipe_rtl:store_base(I), Map),
- {FixSrc, Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0),
- {FixOff, Off, Map2} = conv_src(hipe_rtl:store_offset(I), Map1),
- I2 = mk_store(hipe_rtl:store_size(I), Src, Ptr, Off),
- {FixPtr++FixSrc++FixOff++I2, Map2, Data};
- #switch{} -> % this one also updates Data :-(
- %% from hipe_rtl2sparc, but we use a hairy addressing mode
- %% instead of doing the arithmetic manually
- Labels = hipe_rtl:switch_labels(I),
- LMap = [{label,L} || L <- Labels],
- {NewData, JTabLab} =
- case hipe_rtl:switch_sort_order(I) of
- [] ->
- hipe_consttab:insert_block(Data, word, LMap);
- SortOrder ->
- hipe_consttab:insert_sorted_block(
- Data, word, LMap, SortOrder)
- end,
- %% no immediates allowed here
- {Index, Map1} = conv_dst(hipe_rtl:switch_src(I), Map),
- I2 = mk_jmp_switch(Index, JTabLab, Labels),
- {I2, Map1, NewData};
- #fload{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:fload_dst(I), Map),
- {[], Src, Map1} = conv_src_noimm(hipe_rtl:fload_src(I), Map0),
- {[], Off, Map2} = conv_src(hipe_rtl:fload_offset(I), Map1),
- I2 = [hipe_x86:mk_fmove(hipe_x86:mk_mem(Src, Off, 'double'),Dst)],
- {I2, Map2, Data};
- #fstore{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:fstore_base(I), Map),
- {[], Src, Map1} = conv_src(hipe_rtl:fstore_src(I), Map0),
- {[], Off, Map2} = conv_src(hipe_rtl:fstore_offset(I), Map1),
- I2 = [hipe_x86:mk_fmove(Src, hipe_x86:mk_mem(Dst, Off, 'double'))],
- {I2, Map2, Data};
- #fp{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:fp_dst(I), Map),
- {[], Src1, Map1} = conv_src(hipe_rtl:fp_src1(I), Map0),
- {[], Src2, Map2} = conv_src(hipe_rtl:fp_src2(I), Map1),
- FpBinOp = conv_fp_binop(hipe_rtl:fp_op(I)),
- I2 = conv_fp_binary(Dst, Src1, FpBinOp, Src2),
- {I2, Map2, Data};
- #fp_unop{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:fp_unop_dst(I), Map),
- {[], Src, Map1} = conv_src(hipe_rtl:fp_unop_src(I), Map0),
- FpUnOp = conv_fp_unop(hipe_rtl:fp_unop_op(I)),
- I2 = conv_fp_unary(Dst, Src, FpUnOp),
- {I2, Map1, Data};
- #fmove{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:fmove_dst(I), Map),
- {[], Src, Map1} = conv_src(hipe_rtl:fmove_src(I), Map0),
- I2 = [hipe_x86:mk_fmove(Src, Dst)],
- {I2, Map1, Data};
- #fconv{} ->
- {Dst, Map0} = conv_dst(hipe_rtl:fconv_dst(I), Map),
- {[], Src, Map1} = conv_src(hipe_rtl:fconv_src(I), Map0),
- I2 = conv_fconv(Dst, Src),
- {I2, Map1, Data};
- X ->
- %% gctest??
- %% jmp, jmp_link, jsr, esr, multimove,
- %% stackneed, pop_frame, restore_frame, save_frame
- throw({?MODULE, {"unknown RTL instruction", X}})
- end.
-
-%%% Finalise the conversion of a 3-address ALU operation, taking
-%%% care to not introduce more temps and moves than necessary.
-
-conv_alu_nocc(Dst, Src1, 'add', Src2, Tail) ->
- case (not same_opnd(Dst, Src1)) andalso (not same_opnd(Dst, Src2))
- %% We could use orelse instead of xor here to generate lea T1(T2), T3, but
- %% they seem to move coalesce so well that move+add is better for them.
- andalso (hipe_x86:is_temp(Src1) xor hipe_x86:is_temp(Src2))
- of
- false -> conv_alu(Dst, Src1, 'add', Src2, Tail);
- true -> % Use LEA
- Type = typeof_dst(Dst),
- Mem = case hipe_x86:is_temp(Src1) of
- true -> hipe_x86:mk_mem(Src1, Src2, Type);
- false -> hipe_x86:mk_mem(Src2, Src1, Type)
- end,
- [hipe_x86:mk_lea(Mem, Dst) | Tail]
- end;
-conv_alu_nocc(Dst, Src1, 'sub', Src2, Tail) ->
- case (not same_opnd(Dst, Src1)) andalso hipe_x86:is_temp(Src1)
- andalso (not hipe_x86:is_temp(Src2))
- of
- false -> conv_alu(Dst, Src1, 'sub', Src2, Tail);
- true -> % Use LEA
- Imm = hipe_x86:mk_imm(-hipe_x86:imm_value(Src2)),
- Mem = hipe_x86:mk_mem(Src1, Imm, typeof_dst(Dst)),
- [hipe_x86:mk_lea(Mem, Dst) | Tail]
- end;
-conv_alu_nocc(Dst, Src1, BinOp, Src2, Tail) ->
- conv_alu(Dst, Src1, BinOp, Src2, Tail).
-
-conv_alu(Dst, Src1, 'imul', Src2, Tail) ->
- mk_imul(Src1, Src2, Dst, Tail);
-conv_alu(Dst, Src1, BinOp, Src2, Tail) ->
- case same_opnd(Dst, Src1) of
- true -> % x = x op y
- [hipe_x86:mk_alu(BinOp, Src2, Dst) | Tail]; % x op= y
- false -> % z = x op y, where z != x
- case same_opnd(Dst, Src2) of
- false -> % z = x op y, where z != x && z != y
- [hipe_x86:mk_move(Src1, Dst), % z = x
- hipe_x86:mk_alu(BinOp, Src2, Dst) | Tail]; % z op= y
- true -> % y = x op y, where y != x
- case binop_commutes(BinOp) of
- true -> % y = y op x
- [hipe_x86:mk_alu(BinOp, Src1, Dst) | Tail]; % y op= x
- false -> % y = x op y, where op doesn't commute
- Tmp = clone_dst(Dst),
- [hipe_x86:mk_move(Src1, Tmp), % t = x
- hipe_x86:mk_alu(BinOp, Src2, Tmp), % t op= y
- hipe_x86:mk_move(Tmp, Dst) | Tail] % y = t
- end
- end
- end.
-
-mk_imul(Src1, Src2, Dst, Tail) ->
- case hipe_x86:is_imm(Src1) of
- true ->
- case hipe_x86:is_imm(Src2) of
- true ->
- mk_imul_iit(Src1, Src2, Dst, Tail);
- _ ->
- mk_imul_itt(Src1, Src2, Dst, Tail)
- end;
- _ ->
- case hipe_x86:is_imm(Src2) of
- true ->
- mk_imul_itt(Src2, Src1, Dst, Tail);
- _ ->
- mk_imul_ttt(Src1, Src2, Dst, Tail)
- end
- end.
-
-mk_imul_iit(Src1, Src2, Dst, Tail) ->
- io:format("~w: RTL mul with two immediates\n", [?MODULE]),
- Tmp2 = new_untagged_temp(),
- [hipe_x86:mk_move(Src2, Tmp2) |
- mk_imul_itt(Src1, Tmp2, Dst, Tail)].
-
-mk_imul_itt(Src1, Src2, Dst, Tail) ->
- [hipe_x86:mk_imul(Src1, Src2, Dst) | Tail].
-
-mk_imul_ttt(Src1, Src2, Dst, Tail) ->
- case same_opnd(Dst, Src1) of
- true ->
- [hipe_x86:mk_imul([], Src2, Dst) | Tail];
- false ->
- case same_opnd(Dst, Src2) of
- true ->
- [hipe_x86:mk_imul([], Src1, Dst) | Tail];
- false ->
- [hipe_x86:mk_move(Src1, Dst),
- hipe_x86:mk_imul([], Src2, Dst) | Tail]
- end
- end.
-
-conv_shift(Dst, Src1, BinOp, Src2) ->
- {NewSrc2,I1} =
- case hipe_x86:is_imm(Src2) of
- true ->
- {Src2, []};
- false ->
- NewSrc = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:?ECX(), 'untagged'),
- {NewSrc, [hipe_x86:mk_move(Src2, NewSrc)]}
- end,
- I2 = case same_opnd(Dst, Src1) of
- true -> % x = x op y
- [hipe_x86:mk_shift(BinOp, NewSrc2, Dst)]; % x op= y
- false -> % z = x op y, where z != x
- case same_opnd(Dst, Src2) of
- false -> % z = x op y, where z != x && z != y
- [hipe_x86:mk_move(Src1, Dst), % z = x
- hipe_x86:mk_shift(BinOp, NewSrc2, Dst)];% z op= y
- true -> % y = x op y, no shift op commutes
- Tmp = clone_dst(Dst),
- [hipe_x86:mk_move(Src1, Tmp), % t = x
- hipe_x86:mk_shift(BinOp, NewSrc2, Tmp), % t op= y
- hipe_x86:mk_move(Tmp, Dst)] % y = t
- end
- end,
- I1 ++ I2.
-
-%%% Finalise the conversion of a conditional branch operation, taking
-%%% care to not introduce more temps and moves than necessary.
-
-conv_branchop('sub') -> 'cmp';
-conv_branchop('and') -> 'test';
-conv_branchop(_) -> none.
-
-branchop_commutes('cmp') -> false;
-branchop_commutes('test') -> true.
-
-conv_branch(Src1, Op, Src2, Cc, TrueLab, FalseLab, Pred) ->
- case hipe_x86:is_imm(Src1) of
- false ->
- mk_branch(Src1, Op, Src2, Cc, TrueLab, FalseLab, Pred);
- true ->
- case hipe_x86:is_imm(Src2) of
- false ->
- NewCc = case branchop_commutes(Op) of
- true -> Cc;
- false -> commute_cc(Cc)
- end,
- mk_branch(Src2, Op, Src1, NewCc, TrueLab, FalseLab, Pred);
- true ->
- %% two immediates, let the optimiser clean it up
- Tmp = new_untagged_temp(),
- [hipe_x86:mk_move(Src1, Tmp) |
- mk_branch(Tmp, Op, Src2, Cc, TrueLab, FalseLab, Pred)]
- end
- end.
-
-mk_branch(Src1, Op, Src2, Cc, TrueLab, FalseLab, Pred) ->
- %% PRE: not(is_imm(Src1))
- [mk_branchtest(Src1, Op, Src2),
- hipe_x86:mk_pseudo_jcc(Cc, TrueLab, FalseLab, Pred)].
-
-mk_branchtest(Src1, cmp, Src2) -> hipe_x86:mk_cmp(Src2, Src1);
-mk_branchtest(Src1, test, Src2) -> hipe_x86:mk_test(Src2, Src1).
-
-%%% Convert an RTL ALU or ALUB binary operator.
-
-conv_binop(BinOp) ->
- case BinOp of
- 'add' -> 'add';
- 'sub' -> 'sub';
- 'or' -> 'or';
- 'and' -> 'and';
- 'xor' -> 'xor';
- 'sll' -> 'shl';
- 'srl' -> 'shr';
- 'sra' -> 'sar';
- 'mul' -> 'imul';
- %% andnot ???
- _ -> exit({?MODULE, {"unknown binop", BinOp}})
- end.
-
-binop_commutes(BinOp) ->
- case BinOp of
- 'add' -> true;
- 'or' -> true;
- 'and' -> true;
- 'xor' -> true;
- _ -> false
- end.
-
-%%% Convert an RTL conditional operator.
-
-conv_cond(Cond) ->
- case Cond of
- eq -> 'e';
- ne -> 'ne';
- gt -> 'g';
- gtu -> 'a';
- ge -> 'ge';
- geu -> 'ae';
- lt -> 'l';
- ltu -> 'b';
- le -> 'le';
- leu -> 'be';
- overflow -> 'o';
- not_overflow -> 'no';
- _ -> exit({?MODULE, {"unknown rtl cond", Cond}})
- end.
-
-commute_cc(Cc) -> % if x Cc y, then y commute_cc(Cc) x
- case Cc of
- 'e' -> 'e'; % ==, ==
- 'ne' -> 'ne'; % !=, !=
- 'g' -> 'l'; % >, <
- 'a' -> 'b'; % >u, <u
- 'ge' -> 'le'; % >=, <=
- 'ae' -> 'be'; % >=u, <=u
- 'l' -> 'g'; % <, >
- 'b' -> 'a'; % <u, >u
- 'le' -> 'ge'; % <=, >=
- 'be' -> 'ae'; % <=u, >=u
- %% overflow/not_overflow: n/a
- _ -> exit({?MODULE, {"unknown cc", Cc}})
- end.
-
-%%% Test if Dst and Src are the same operand.
-
-same_opnd(Dst, Src) -> Dst =:= Src.
-
-%%% Finalise the conversion of a tailcall instruction.
-
-conv_tailcall(Fun, Args, Linkage) ->
- Arity = length(Args),
- {RegArgs,StkArgs} = split_args(Args),
- move_actuals(RegArgs,
- [hipe_x86:mk_pseudo_tailcall_prepare(),
- hipe_x86:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]).
-
-split_args(Args) ->
- split_args(0, ?HIPE_X86_REGISTERS:nr_args(), Args, []).
-split_args(I, N, [Arg|Args], RegArgs) when I < N ->
- Reg = ?HIPE_X86_REGISTERS:arg(I),
- Temp = hipe_x86:mk_temp(Reg, 'tagged'),
- split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]);
-split_args(_, _, StkArgs, RegArgs) ->
- {RegArgs, StkArgs}.
-
-move_actuals([], Rest) -> Rest;
-move_actuals([{Src,Dst}|Actuals], Rest) ->
- move_actuals(Actuals, [hipe_x86:mk_move(Src, Dst) | Rest]).
-
-move_formals([], Rest) -> Rest;
-move_formals([{Dst,Src}|Formals], Rest) ->
- move_formals(Formals, [hipe_x86:mk_move(Src, Dst) | Rest]).
-
-%%% Finalise the conversion of a call instruction.
-
-conv_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- case hipe_x86:is_prim(Fun) of
- true ->
- conv_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);
- false ->
- conv_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)
- end.
-
-conv_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->
- case hipe_x86:prim_prim(Prim) of
- 'fwait' ->
- conv_fwait_call(Dsts, Args, ContLab, ExnLab, Linkage);
- _ ->
- conv_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)
- end.
-
-conv_fwait_call([], [], [], [], not_remote) ->
- [hipe_x86:mk_fp_unop('fwait', [])].
-
-conv_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->
- %% The backend does not support pseudo_calls without a
- %% continuation label, so we make sure each call has one.
- {RealContLab, Tail} =
- case do_call_results(Dsts) of
- [] ->
- %% Avoid consing up a dummy basic block if the moves list
- %% is empty, as is typical for calls to suspend/0.
- %% This should be subsumed by a general "optimise the CFG"
- %% module, and could probably be removed.
- case ContLab of
- [] ->
- NewContLab = hipe_gensym:get_next_label(x86),
- {NewContLab, [hipe_x86:mk_label(NewContLab)]};
- _ ->
- {ContLab, []}
- end;
- Moves ->
- %% Change the call to continue at a new basic block.
- %% In this block move the result registers to the Dsts,
- %% then continue at the call's original continuation.
- %%
- %% This should be fixed to propagate "fallthrough calls"
- %% When the rest of the backend supports them.
- NewContLab = hipe_gensym:get_next_label(x86),
- case ContLab of
- [] ->
- %% This is just a fallthrough
- %% No jump back after the moves.
- {NewContLab,
- [hipe_x86:mk_label(NewContLab) |
- Moves]};
- _ ->
- %% The call has a continuation
- %% jump to it.
- {NewContLab,
- [hipe_x86:mk_label(NewContLab) |
- Moves ++
- [hipe_x86:mk_jmp_label(ContLab)]]}
- end
- end,
- SDesc = hipe_x86:mk_sdesc(ExnLab, 0, length(Args), {}),
- CallInsn = hipe_x86:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage),
- {RegArgs,StkArgs} = split_args(Args),
- do_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).
-
-do_push_args([Arg|Args], Tail) ->
- [hipe_x86:mk_push(Arg) | do_push_args(Args, Tail)];
-do_push_args([], Tail) ->
- Tail.
-
-%%% Move return values from the return value registers.
-
-do_call_results(DstList) ->
- do_call_results(DstList, 0, []).
-
-do_call_results([Dst|DstList], I, Rest) ->
- Src = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:ret(I), 'tagged'),
- Move = hipe_x86:mk_move(Src, Dst),
- do_call_results(DstList, I+1, [Move|Rest]);
-do_call_results([], _, Insns) -> Insns.
-
-%%% Move return values to the return value registers.
-
-move_retvals(SrcLst, Rest) ->
- move_retvals(SrcLst, 0, Rest).
-
-move_retvals([Src|SrcLst], I, Rest) ->
- Dst = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:ret(I), 'tagged'),
- Move = hipe_x86:mk_move(Src, Dst),
- move_retvals(SrcLst, I+1, [Move|Rest]);
-move_retvals([], _, Insns) -> Insns.
-
-%%% Convert a 'fun' operand (MFA, prim, or temp)
-
-conv_fun(Fun, Map) ->
- case hipe_rtl:is_var(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- case hipe_rtl:is_reg(Fun) of
- true ->
- conv_dst(Fun, Map);
- false ->
- case Fun of
- Prim when is_atom(Prim) ->
- {hipe_x86:mk_prim(Prim), Map};
- {M,F,A} when is_atom(M), is_atom(F), is_integer(A) ->
- {hipe_x86:mk_mfa(M,F,A), Map};
- _ ->
- exit({?MODULE,conv_fun,Fun})
- end
- end
- end.
-
-conv_src_noimm(Opnd, Map) ->
- R={FixSrc0, Src, NewMap} = conv_src(Opnd, Map),
- case hipe_x86:is_imm(Src) of
- false -> R;
- true ->
- Tmp = new_untagged_temp(),
- {FixSrc0 ++ [hipe_x86:mk_move(Src, Tmp)],
- Tmp, NewMap}
- end.
-
-%%% Convert an RTL source operand (imm/var/reg).
-
-conv_src(Opnd, Map) ->
- case hipe_rtl:is_imm(Opnd) of
- true ->
- conv_imm(Opnd, Map);
- false ->
- {NewOpnd,NewMap} = conv_dst(Opnd, Map),
- {[], NewOpnd, NewMap}
- end.
-
--ifdef(HIPE_AMD64).
-conv_imm(Opnd, Map) ->
- ImmVal = hipe_rtl:imm_value(Opnd),
- case is_imm64(ImmVal) of
- true ->
- Temp = hipe_x86:mk_new_temp('untagged'),
- {[hipe_x86:mk_move64(hipe_x86:mk_imm(ImmVal), Temp)], Temp, Map};
- false ->
- {[], hipe_x86:mk_imm(ImmVal), Map}
- end.
-
-is_imm64(Value) when is_integer(Value) ->
- (Value < -(1 bsl (32 - 1))) or (Value > (1 bsl (32 - 1)) - 1);
-is_imm64({_,atom}) -> false; % Atoms are 32 bits.
-is_imm64({_,c_const}) -> true; % c_consts are 64 bits.
-is_imm64({_,_}) -> true . % Other relocs are 64 bits.
--else.
-conv_imm(Opnd, Map) ->
- {[], hipe_x86:mk_imm(hipe_rtl:imm_value(Opnd)), Map}.
--endif.
-
-conv_src_list([O|Os], Map) ->
- {NewInstr, V, Map1} = conv_src(O, Map),
- {Instrs, Vs, Map2} = conv_src_list(Os, Map1),
- {Instrs++NewInstr, [V|Vs], Map2};
-conv_src_list([], Map) ->
- {[], [], Map}.
-
-%%% Convert an RTL destination operand (var/reg).
-
-conv_dst(Opnd, Map) ->
- {Name, Type} =
- case hipe_rtl:is_var(Opnd) of
- true ->
- {hipe_rtl:var_index(Opnd), 'tagged'};
- false ->
- case hipe_rtl:is_fpreg(Opnd) of
- true ->
- {hipe_rtl:fpreg_index(Opnd), 'double'};
- false ->
- {hipe_rtl:reg_index(Opnd), 'untagged'}
- end
- end,
- case ?HIPE_X86_REGISTERS:is_precoloured(Name) of
- true ->
- case ?HIPE_X86_REGISTERS:proc_offset(Name) of
- false ->
- {hipe_x86:mk_temp(Name, Type), Map};
- Offset ->
- Preg = ?HIPE_X86_REGISTERS:proc_pointer(),
- Pbase = hipe_x86:mk_temp(Preg, 'untagged'),
- Poff = hipe_x86:mk_imm(Offset),
- {hipe_x86:mk_mem(Pbase, Poff, Type), Map}
- end;
- false ->
- case vmap_lookup(Map, Opnd) of
- {value, NewTemp} ->
- {NewTemp, Map};
- _ ->
- NewTemp = hipe_x86:mk_new_temp(Type),
- {NewTemp, vmap_bind(Map, Opnd, NewTemp)}
- end
- end.
-
-conv_dst_list([O|Os], Map) ->
- {Dst, Map1} = conv_dst(O, Map),
- {Dsts, Map2} = conv_dst_list(Os, Map1),
- {[Dst|Dsts], Map2};
-conv_dst_list([], Map) ->
- {[], Map}.
-
-conv_formals(Os, Map) ->
- conv_formals(?HIPE_X86_REGISTERS:nr_args(), Os, Map, []).
-
-conv_formals(N, [O|Os], Map, Res) ->
- Type =
- case hipe_rtl:is_var(O) of
- true -> 'tagged';
- false ->'untagged'
- end,
- Dst =
- if N > 0 -> hipe_x86:mk_new_temp(Type); % allocatable
- true -> hipe_x86:mk_new_nonallocatable_temp(Type)
- end,
- Map1 = vmap_bind(Map, O, Dst),
- conv_formals(N-1, Os, Map1, [Dst|Res]);
-conv_formals(_, [], Map, Res) ->
- {lists:reverse(Res), Map}.
-
-%%% typeof_src -- what's src's type?
-
-typeof_src(Src) ->
- case hipe_x86:is_imm(Src) of
- true ->
- 'untagged';
- _ ->
- typeof_dst(Src)
- end.
-
-%%% typeof_dst -- what's dst's type?
-
-typeof_dst(Dst) ->
- case hipe_x86:is_temp(Dst) of
- true ->
- hipe_x86:temp_type(Dst);
- _ ->
- hipe_x86:mem_type(Dst)
- end.
-
-%%% clone_dst -- conjure up a scratch reg with same type as dst
-
-clone_dst(Dst) ->
- hipe_x86:mk_new_temp(typeof_dst(Dst)).
-
-%%% new_untagged_temp -- conjure up an untagged scratch reg
-
-new_untagged_temp() ->
- hipe_x86:mk_new_temp('untagged').
-
-%%% Map from RTL var/reg operands to x86 temps.
-
-vmap_empty() ->
- gb_trees:empty().
-
-vmap_lookup(Map, Key) ->
- gb_trees:lookup(Key, Map).
-
-vmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-%%% Finalise the conversion of an Integer-to-Float operation.
-
-conv_fconv(Dst, Src) ->
- case hipe_x86:is_imm(Src) of
- false ->
- [hipe_x86:mk_fmove(Src, Dst)];
- true ->
- %% cvtsi2sd does not allow src to be an immediate
- Tmp = new_untagged_temp(),
- [hipe_x86:mk_move(Src, Tmp),
- hipe_x86:mk_fmove(Tmp, Dst)]
- end.
-
-%%% Finalise the conversion of a 2-address FP operation.
-
--ifdef(HIPE_AMD64).
-conv_fp_unary(Dst, Src, 'fchs') ->
- Tmp = new_untagged_temp(),
- case same_opnd(Dst, Src) of
- true ->
- [];
- _ ->
- [hipe_x86:mk_fmove(Src, Dst)]
- end ++
- mk_load_address(c_const, hipe_x86:mk_imm({sse2_fnegate_mask, c_const}), Tmp) ++
- [hipe_x86:mk_fp_binop('xorpd', hipe_x86:mk_mem(Tmp, hipe_x86:mk_imm(0), double), Dst)].
--else.
-conv_fp_unary(Dst, Src, FpUnOp) ->
- case same_opnd(Dst, Src) of
- true ->
- [hipe_x86:mk_fp_unop(FpUnOp, Dst)];
- _ ->
- [hipe_x86:mk_fmove(Src, Dst),
- hipe_x86:mk_fp_unop(FpUnOp, Dst)]
- end.
--endif.
-
-conv_fp_unop(RtlFpUnOp) ->
- case RtlFpUnOp of
- 'fchs' -> 'fchs'
- end.
-
-%%% Finalise the conversion of a 3-address FP operation.
-
-conv_fp_binary(Dst, Src1, FpBinOp, Src2) ->
- case same_opnd(Dst, Src1) of
- true -> % x = x op y
- [hipe_x86:mk_fp_binop(FpBinOp, Src2, Dst)]; % x op= y
- false -> % z = x op y, where z != x
- case same_opnd(Dst, Src2) of
- false -> % z = x op y, where z != x && z != y
- [hipe_x86:mk_fmove(Src1, Dst), % z = x
- hipe_x86:mk_fp_binop(FpBinOp, Src2, Dst)]; % z op= y
- true -> % y = x op y, where y != x
- case fp_binop_commutes(FpBinOp) of
- true -> % y = y op x
- [hipe_x86:mk_fp_binop(FpBinOp, Src1, Dst)]; % y op= x
- false -> % y = x op y, where op doesn't commute
- RevFpBinOp = reverse_fp_binop(FpBinOp),
- [hipe_x86:mk_fp_binop(RevFpBinOp, Src1, Dst)]
- end
- end
- end.
-
-%%% Convert an RTL FP binary operator.
-
-conv_fp_binop(RtlFpBinOp) ->
- case RtlFpBinOp of
- 'fadd' -> 'fadd';
- 'fdiv' -> 'fdiv';
- 'fmul' -> 'fmul';
- 'fsub' -> 'fsub'
- end.
-
-fp_binop_commutes(FpBinOp) ->
- case FpBinOp of
- 'fadd' -> true;
- 'fmul' -> true;
- _ -> false
- end.
-
-reverse_fp_binop(FpBinOp) ->
- case FpBinOp of
- 'fsub' -> 'fsubr';
- 'fdiv' -> 'fdivr'
- end.
-
-%%% Create a jmp_switch instruction.
-
--ifdef(HIPE_AMD64).
-mk_jmp_switch(Index, JTabLab, Labels) ->
- JTabReg = hipe_x86:mk_new_temp('untagged'),
- JTabImm = hipe_x86:mk_imm_from_addr(JTabLab, constant),
- [hipe_x86:mk_move64(JTabImm, JTabReg),
- hipe_x86:mk_jmp_switch(Index, JTabReg, Labels)].
--else.
-mk_jmp_switch(Index, JTabLab, Labels) ->
- %% this is equivalent to "jmp *JTabLab(,Index,4)"
- %% ("r = Index; r *= 4; r += &JTab; jmp *r" isn't as nice)
- [hipe_x86:mk_jmp_switch(Index, JTabLab, Labels)].
--endif.
-
-%%% Finalise the translation of a load_address instruction.
-
--ifdef(HIPE_AMD64).
-mk_load_address(_Type, Src, Dst) ->
- [hipe_x86:mk_move64(Src, Dst)].
--else.
-mk_load_address(_Type, Src, Dst) ->
- [hipe_x86:mk_move(Src, Dst)].
--endif.
-
-%%% Translate 32-bit and larger loads.
-
--ifdef(HIPE_AMD64).
-mk_load(LoadSize, LoadSign, Src, Off, Dst) ->
- case {LoadSize, LoadSign} of
- {int32, signed} ->
- [hipe_x86:mk_movsx(hipe_x86:mk_mem(Src, Off, 'int32'), Dst)];
- {int32, unsigned} ->
- %% The processor zero-extends for us. No need for 'movzx'.
- [hipe_x86:mk_move(hipe_x86:mk_mem(Src, Off, 'int32'), Dst)];
- {_, _} ->
- mk_load_word(Src, Off, Dst)
- end.
--else.
-mk_load(_LoadSize, _LoadSign, Src, Off, Dst) ->
- mk_load_word(Src, Off, Dst).
--endif.
-
-mk_load_word(Src, Off, Dst) ->
- Type = typeof_dst(Dst),
- [hipe_x86:mk_move(hipe_x86:mk_mem(Src, Off, Type), Dst)].
-
-%%% Finalise the translation of a store instruction.
-
--ifdef(HIPE_AMD64).
-mk_store(RtlStoreSize, Src, Ptr, Off) ->
- Type = case RtlStoreSize of
- word ->
- typeof_src(Src);
- OtherType ->
- OtherType
- end,
- [hipe_x86:mk_move(Src, hipe_x86:mk_mem(Ptr, Off, Type))].
--else.
-mk_store(RtlStoreSize, Src, Ptr, Off) ->
- case RtlStoreSize of
- word ->
- Type = typeof_src(Src),
- [hipe_x86:mk_move(Src, hipe_x86:mk_mem(Ptr, Off, Type))];
- int32 ->
- Type = typeof_src(Src),
- [hipe_x86:mk_move(Src, hipe_x86:mk_mem(Ptr, Off, Type))];
- int16 ->
- Type = 'int16',
- [hipe_x86:mk_move(Src, hipe_x86:mk_mem(Ptr, Off, Type))];
- byte ->
- Type = 'byte',
- {NewSrc, I1} = conv_small_store(Src),
- I1 ++ [hipe_x86:mk_move(NewSrc, hipe_x86:mk_mem(Ptr, Off, Type))]
- end.
-
-conv_small_store(Src) ->
- case hipe_x86:is_imm(Src) of
- true ->
- {Src, []};
- false ->
- NewSrc = hipe_x86:mk_temp(hipe_x86_registers:eax(), 'untagged'),
- {NewSrc, [hipe_x86:mk_move(Src, NewSrc)]}
- end.
--endif.
diff --git a/lib/hipe/x86/hipe_x86.erl b/lib/hipe/x86/hipe_x86.erl
deleted file mode 100644
index f514dd1ded..0000000000
--- a/lib/hipe/x86/hipe_x86.erl
+++ /dev/null
@@ -1,508 +0,0 @@
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% representation of 2-address pseudo-amd64 code
-
--module(hipe_x86).
-
--include("hipe_x86.hrl").
-
-%% Commented out are interface functions which are currently not used.
--export([mk_temp/2,
- %% mk_nonallocatable_temp/2,
- mk_new_temp/1,
- mk_new_nonallocatable_temp/1,
- is_temp/1,
- temp_reg/1,
- temp_type/1,
- temp_is_allocatable/1,
-
- mk_imm/1,
- mk_imm_from_addr/2,
- mk_imm_from_atom/1,
- is_imm/1,
- imm_value/1,
-
- mk_mem/3,
- %% is_mem/1,
- %% mem_base/1,
- %% mem_off/1,
- mem_type/1,
-
- mk_fpreg/1,
- mk_fpreg/2,
- %% is_fpreg/1,
- %% fpreg_is_pseudo/1,
- %% fpreg_reg/1,
-
- mk_mfa/3,
- %% is_mfa/1,
-
- mk_prim/1,
- is_prim/1,
- prim_prim/1,
-
- mk_sdesc/4,
-
- %% insn_type/1,
-
- mk_alu/3,
- %% is_alu/1,
- alu_op/1,
- alu_src/1,
- alu_dst/1,
-
- mk_call/3,
- %% is_call/1,
- call_fun/1,
- call_sdesc/1,
- call_linkage/1,
-
- %% mk_cmovcc/3,
- %% is_cmovcc/1,
- cmovcc_cc/1,
- cmovcc_src/1,
- cmovcc_dst/1,
-
- mk_cmp/2,
- %% is_cmp/1,
- cmp_src/1,
- cmp_dst/1,
-
- mk_comment/1,
- %% is_comment/1,
- %% comment_term/1,
-
- mk_fmove/2,
- is_fmove/1,
- fmove_src/1,
- fmove_dst/1,
-
- mk_fp_unop/2,
- %% is_fp_unop/1,
- fp_unop_arg/1,
- fp_unop_op/1,
-
- mk_fp_binop/3,
- %% is_fp_binop/1,
- fp_binop_src/1,
- fp_binop_dst/1,
- fp_binop_op/1,
-
- mk_imul/3,
- imul_imm_opt/1,
- imul_src/1,
- imul_temp/1,
-
- mk_jcc/2,
- %% is_jcc/1,
- jcc_cc/1,
- jcc_label/1,
-
- mk_jmp_fun/2,
- %% is_jmp_fun/1,
- jmp_fun_fun/1,
- jmp_fun_linkage/1,
-
- mk_jmp_label/1,
- %% is_jmp_label/1,
- jmp_label_label/1,
-
- mk_jmp_switch/3,
- %% is_jmp_switch/1,
- jmp_switch_temp/1,
- jmp_switch_jtab/1,
- %% jmp_switch_labels/1,
-
- mk_label/1,
- is_label/1,
- label_label/1,
-
- mk_lea/2,
- %% is_lea/1,
- lea_mem/1,
- lea_temp/1,
-
- mk_move/2,
- is_move/1,
- move_src/1,
- move_dst/1,
- mk_move64/2,
- %% is_move64/1,
- move64_src/1,
- move64_dst/1,
-
- mk_movsx/2,
- %% is_movsx/1,
- movsx_src/1,
- movsx_dst/1,
-
- mk_movzx/2,
- %% is_movzx/1,
- movzx_src/1,
- movzx_dst/1,
-
- mk_pseudo_call/4,
- %% is_pseudo_call/1,
- pseudo_call_fun/1,
- pseudo_call_sdesc/1,
- pseudo_call_contlab/1,
- pseudo_call_linkage/1,
-
- mk_pseudo_jcc/4,
- %% is_pseudo_jcc/1,
- %% pseudo_jcc_cc/1,
- %% pseudo_jcc_true_label/1,
- %% pseudo_jcc_false_label/1,
- %% pseudo_jcc_pred/1,
-
- mk_pseudo_spill/1,
-
- mk_pseudo_spill_fmove/3,
- is_pseudo_spill_fmove/1,
-
- mk_pseudo_spill_move/3,
- is_pseudo_spill_move/1,
-
- mk_pseudo_tailcall/4,
- %% is_pseudo_tailcall/1,
- pseudo_tailcall_fun/1,
- %% pseudo_tailcall_arity/1,
- pseudo_tailcall_stkargs/1,
- pseudo_tailcall_linkage/1,
-
- mk_pseudo_tailcall_prepare/0,
- %% is_pseudo_tailcall_prepare/1,
-
- mk_push/1,
- %% is_push/1,
- push_src/1,
-
- %% mk_pop/1,
- pop_dst/1,
-
- mk_ret/1,
- %% is_ret/1,
- ret_npop/1,
-
- mk_shift/3,
- %% is_shift/1,
- shift_op/1,
- shift_src/1,
- shift_dst/1,
-
- mk_test/2,
- test_src/1,
- test_dst/1,
-
- mk_defun/8,
- defun_mfa/1,
- defun_formals/1,
- defun_is_closure/1,
- defun_is_leaf/1,
- defun_code/1,
- defun_data/1,
- defun_var_range/1
- %% defun_label_range/1,
-
- %% highest_temp/1
- ]).
-
-%% Other utilities
--export([neg_cc/1
- ]).
-
-%%%
-%%% Low-level accessors.
-%%%
-
-mk_temp(Reg, Type) when is_integer(Reg) ->
- #x86_temp{reg=Reg, type=Type, allocatable=true}.
-mk_nonallocatable_temp(Reg, Type) when is_integer(Reg) ->
- #x86_temp{reg=Reg, type=Type, allocatable=false}.
-mk_new_temp(Type) ->
- mk_temp(hipe_gensym:get_next_var(x86), Type).
-mk_new_nonallocatable_temp(Type) ->
- mk_nonallocatable_temp(hipe_gensym:get_next_var(x86), Type).
-is_temp(X) -> case X of #x86_temp{} -> true; _ -> false end.
-temp_reg(#x86_temp{reg=Reg}) when is_integer(Reg) -> Reg.
-temp_type(#x86_temp{type=Type}) -> Type.
-temp_is_allocatable(#x86_temp{allocatable=A}) -> A.
-
-mk_imm(Value) -> #x86_imm{value=Value}.
-mk_imm_from_addr(Addr, Type) ->
- mk_imm({Addr, Type}).
-mk_imm_from_atom(Atom) ->
- mk_imm(Atom).
-is_imm(X) -> case X of #x86_imm{} -> true; _ -> false end.
-imm_value(#x86_imm{value=Value}) -> Value.
-
-mk_mem(Base, Off, Type) -> #x86_mem{base=Base, off=Off, type=Type}.
-%% is_mem(X) -> case X of #x86_mem{} -> true; _ -> false end.
-%% mem_base(#x86_mem{base=Base}) -> Base.
-%% mem_off(#x86_mem{off=Off}) -> Off.
-mem_type(#x86_mem{type=Type}) -> Type.
-
-mk_fpreg(Reg) -> #x86_fpreg{reg=Reg, pseudo=true}.
-mk_fpreg(Reg, Pseudo) -> #x86_fpreg{reg=Reg, pseudo=Pseudo}.
-%% is_fpreg(F) -> case F of #x86_fpreg{} -> true;_ -> false end.
-%% fpreg_is_pseudo(#x86_fpreg{pseudo=Pseudo}) -> Pseudo.
-%% fpreg_reg(#x86_fpreg{reg=Reg}) -> Reg.
-
-mk_mfa(M, F, A) -> #x86_mfa{m=M, f=F, a=A}.
-%% is_mfa(X) -> case X of #x86_mfa{} -> true; _ -> false end.
-
-mk_prim(Prim) -> #x86_prim{prim=Prim}.
-is_prim(X) -> case X of #x86_prim{} -> true; _ -> false end.
-prim_prim(#x86_prim{prim=Prim}) -> Prim.
-
-mk_sdesc(ExnLab, FSize, Arity, Live) ->
- #x86_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}.
-
-insn_type(Insn) ->
- element(1, Insn).
-
-is_insn_type(Insn, Type) ->
- case insn_type(Insn) of
- Type -> true;
- _ -> false
- end.
-
-mk_alu(Op, Src, Dst) -> #alu{aluop=Op, src=Src, dst=Dst}.
-%% is_alu(Insn) -> is_insn_type(Insn, alu).
-alu_op(#alu{aluop=Op}) -> Op.
-alu_src(#alu{src=Src}) -> Src.
-alu_dst(#alu{dst=Dst}) -> Dst.
-
-mk_call(Fun, SDesc, Linkage) ->
- check_linkage(Linkage),
- #call{'fun'=Fun, sdesc=SDesc, linkage=Linkage}.
-%% is_call(Insn) -> is_insn_type(Insn, call).
-call_fun(#call{'fun'=Fun}) -> Fun.
-call_sdesc(#call{sdesc=SDesc}) -> SDesc.
-call_linkage(#call{linkage=Linkage}) -> Linkage.
-
-check_linkage(Linkage) ->
- case Linkage of
- remote -> [];
- not_remote -> []
- end.
-
-%% mk_cmovcc(Cc, Src, Dst) -> #cmovcc{cc=Cc, src=Src, dst=Dst}.
-%% is_cmovcc(Insn) -> is_insn_type(Insn, cmovcc).
-cmovcc_cc(#cmovcc{cc=Cc}) -> Cc.
-cmovcc_src(#cmovcc{src=Src}) -> Src.
-cmovcc_dst(#cmovcc{dst=Dst}) -> Dst.
-
-mk_cmp(Src, Dst) -> #cmp{src=Src, dst=Dst}.
-%% is_cmp(Insn) -> is_insn_type(Insn, cmp).
-cmp_src(#cmp{src=Src}) -> Src.
-cmp_dst(#cmp{dst=Dst}) -> Dst.
-
-mk_test(Src, Dst) -> #test{src=Src, dst=Dst}.
-test_src(#test{src=Src}) -> Src.
-test_dst(#test{dst=Dst}) -> Dst.
-
-mk_comment(Term) -> #comment{term=Term}.
-%% is_comment(Insn) -> is_insn_type(Insn, comment).
-%% comment_term(#comment{term=Term}) -> Term.
-
-mk_fmove(Src, Dst) -> #fmove{src=Src, dst=Dst}.
-is_fmove(F) -> is_insn_type(F, fmove).
-fmove_src(#fmove{src=Src}) -> Src.
-fmove_dst(#fmove{dst=Dst}) -> Dst.
-
-mk_fp_unop(Op, Arg) -> #fp_unop{op=Op, arg=Arg}.
-%% is_fp_unop(F) -> is_insn_type(F, fp_unop).
-fp_unop_arg(#fp_unop{arg=Arg}) -> Arg.
-fp_unop_op(#fp_unop{op=Op}) -> Op.
-
-mk_fp_binop(Op, Src, Dst) -> #fp_binop{op=Op, src=Src, dst=Dst}.
-%% is_fp_binop(F) -> is_insn_type(F, fp_binop).
-fp_binop_src(#fp_binop{src=Src}) -> Src.
-fp_binop_dst(#fp_binop{dst=Dst}) -> Dst.
-fp_binop_op(#fp_binop{op=Op}) -> Op.
-
-mk_imul(ImmOpt, Src, Temp) -> #imul{imm_opt=ImmOpt, src=Src, temp=Temp}.
-imul_imm_opt(#imul{imm_opt=ImmOpt}) -> ImmOpt.
-imul_src(#imul{src=Src}) -> Src.
-imul_temp(#imul{temp=Temp}) -> Temp.
-
-mk_jcc(Cc, Label) -> #jcc{cc=Cc, label=Label}.
-%% is_jcc(Insn) -> is_insn_type(Insn, jcc).
-jcc_cc(#jcc{cc=Cc}) -> Cc.
-jcc_label(#jcc{label=Label}) -> Label.
-
-mk_jmp_fun(Fun, Linkage) ->
- check_linkage(Linkage),
- #jmp_fun{'fun'=Fun, linkage=Linkage}.
-%% is_jmp_fun(Insn) -> is_insn_type(Insn, jmp_fun).
-jmp_fun_fun(#jmp_fun{'fun'=Fun}) -> Fun.
-jmp_fun_linkage(#jmp_fun{linkage=Linkage}) -> Linkage.
-
-mk_jmp_label(Label) -> #jmp_label{label=Label}.
-%% is_jmp_label(Insn) -> is_insn_type(Insn, jmp_label).
-jmp_label_label(#jmp_label{label=Label}) -> Label.
-
-mk_jmp_switch(Temp, JTab, Labels) ->
- #jmp_switch{temp=Temp, jtab=JTab, labels=Labels}.
-%% is_jmp_switch(Insn) -> is_insn_type(Insn, jmp_switch).
-jmp_switch_temp(#jmp_switch{temp=Temp}) -> Temp.
-jmp_switch_jtab(#jmp_switch{jtab=JTab}) -> JTab.
-%% jmp_switch_labels(#jmp_switch{labels=Labels}) -> Labels.
-
-mk_label(Label) -> #label{label=Label}.
-is_label(Insn) -> is_insn_type(Insn, label).
-label_label(#label{label=Label}) -> Label.
-
-mk_lea(Mem, Temp) -> #lea{mem=Mem, temp=Temp}.
-%% is_lea(Insn) -> is_insn_type(Insn, lea).
-lea_mem(#lea{mem=Mem}) -> Mem.
-lea_temp(#lea{temp=Temp}) -> Temp.
-
-mk_move(Src, Dst) -> #move{src=Src, dst=Dst}.
-is_move(Insn) -> is_insn_type(Insn, move).
-move_src(#move{src=Src}) -> Src.
-move_dst(#move{dst=Dst}) -> Dst.
-
-mk_move64(Imm, Dst) -> #move64{imm=Imm, dst=Dst}.
-%% is_move64(Insn) -> is_insn_type(Insn, move64).
-move64_src(#move64{imm=Imm}) -> Imm.
-move64_dst(#move64{dst=Dst}) -> Dst.
-
-mk_movsx(Src, Dst) -> #movsx{src=Src, dst=Dst}.
-%% is_movsx(Insn) -> is_insn_type(Insn, movsx).
-movsx_src(#movsx{src=Src}) -> Src.
-movsx_dst(#movsx{dst=Dst}) -> Dst.
-
-mk_movzx(Src, Dst) -> #movzx{src=Src, dst=Dst}.
-%% is_movzx(Insn) -> is_insn_type(Insn, movzx).
-movzx_src(#movzx{src=Src}) -> Src.
-movzx_dst(#movzx{dst=Dst}) -> Dst.
-
-mk_pseudo_call(Fun, SDesc, ContLab, Linkage) ->
- check_linkage(Linkage),
- #pseudo_call{'fun'=Fun, sdesc=SDesc, contlab=ContLab, linkage=Linkage}.
-%% is_pseudo_call(Insn) -> is_insn_type(Insn, pseudo_call).
-pseudo_call_fun(#pseudo_call{'fun'=Fun}) -> Fun.
-pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc.
-pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab.
-pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage.
-
-mk_pseudo_jcc(Cc, TrueLabel, FalseLabel, Pred) -> % 'smart' constructor
- if Pred >= 0.5 ->
- mk_pseudo_jcc_simple(neg_cc(Cc), FalseLabel, TrueLabel, 1.0-Pred);
- true ->
- mk_pseudo_jcc_simple(Cc, TrueLabel, FalseLabel, Pred)
- end.
-neg_cc(Cc) ->
- case Cc of
- 'e' -> 'ne'; % ==, !=
- 'ne' -> 'e'; % !=, ==
- 'g' -> 'le'; % >, <=
- 'a' -> 'be'; % >u, <=u
- 'ge' -> 'l'; % >=, <
- 'ae' -> 'b'; % >=u, <u
- 'l' -> 'ge'; % <, >=
- 'b' -> 'ae'; % <u, >=u
- 'le' -> 'g'; % <=, >
- 'be' -> 'a'; % <=u, >u
- 'o' -> 'no'; % overflow, not_overflow
- 'no' -> 'o'; % not_overflow, overflow
- _ -> exit({?MODULE, {"unknown cc", Cc}})
- end.
-mk_pseudo_jcc_simple(Cc, TrueLabel, FalseLabel, Pred) ->
- #pseudo_jcc{cc=Cc, true_label=TrueLabel, false_label=FalseLabel, pred=Pred}.
-%% is_pseudo_jcc(Insn) -> is_insn_type(Insn, pseudo_jcc).
-%% pseudo_jcc_cc(#pseudo_jcc{cc=Cc}) -> Cc.
-%% pseudo_jcc_true_label(#pseudo_jcc{true_label=TrueLabel}) -> TrueLabel.
-%% pseudo_jcc_false_label(#pseudo_jcc{false_label=FalseLabel}) -> FalseLabel.
-%% pseudo_jcc_pred(#pseudo_jcc{pred=Pred}) -> Pred.
-
-mk_pseudo_spill(List) ->
- #pseudo_spill{args=List}.
-
-mk_pseudo_spill_fmove(Src, Temp, Dst) ->
- #pseudo_spill_fmove{src=Src, temp=Temp, dst=Dst}.
-is_pseudo_spill_fmove(I) -> is_record(I, pseudo_spill_fmove).
-
-mk_pseudo_spill_move(Src, Temp, Dst) ->
- #pseudo_spill_move{src=Src, temp=Temp, dst=Dst}.
-is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move).
-
-mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage) ->
- check_linkage(Linkage),
- #pseudo_tailcall{'fun'=Fun, arity=Arity, stkargs=StkArgs, linkage=Linkage}.
-%% is_pseudo_tailcall(Insn) -> is_insn_type(Insn, pseudo_tailcall).
-pseudo_tailcall_fun(#pseudo_tailcall{'fun'=Fun}) -> Fun.
-%% pseudo_tailcall_arity(#pseudo_tailcall{arity=Arity}) -> Arity.
-pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs.
-pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage.
-
-mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}.
-%% is_pseudo_tailcall_prepare(Insn) -> is_insn_type(Insn, pseudo_tailcall_prepare).
-
-mk_push(Src) -> #push{src=Src}.
-%% is_push(Insn) -> is_insn_type(Insn, push).
-push_src(#push{src=Src}) -> Src.
-
-%% mk_pop(Dst) -> #pop{dst=Dst}.
-%% is_push(Insn) -> is_insn_type(Insn, push).
-pop_dst(#pop{dst=Dst}) -> Dst.
-
-mk_ret(NPop) -> #ret{npop=NPop}.
-%% is_ret(Insn) -> is_insn_type(Insn, ret).
-ret_npop(#ret{npop=NPop}) -> NPop.
-
-mk_shift(ShiftOp, Src, Dst) ->
- #shift{shiftop=ShiftOp, src=Src, dst=Dst}.
-%% is_shift(Insn) -> is_insn_type(Insn, shift).
-shift_op(#shift{shiftop=ShiftOp}) -> ShiftOp.
-shift_src(#shift{src=Src}) -> Src.
-shift_dst(#shift{dst=Dst}) -> Dst.
-
-mk_defun(MFA, Formals, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) ->
- #defun{mfa=MFA, formals=Formals, code=Code, data=Data,
- isclosure=IsClosure, isleaf=IsLeaf,
- var_range=VarRange, label_range=LabelRange}.
-defun_mfa(#defun{mfa=MFA}) -> MFA.
-defun_formals(#defun{formals=Formals}) -> Formals.
-defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure.
-defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf.
-defun_code(#defun{code=Code}) -> Code.
-defun_data(#defun{data=Data}) -> Data.
-defun_var_range(#defun{var_range=VarRange}) -> VarRange.
-%% defun_label_range(#defun{label_range=LabelRange}) -> LabelRange.
-
-%% highest_temp(Code) ->
-%% highest_temp(Code,0).
-%%
-%% highest_temp([I|Is],Max) ->
-%% Defs = hipe_x86_defuse:insn_def(I),
-%% Uses = hipe_x86_defuse:insn_use(I),
-%% highest_temp(Is,new_max(Defs++Uses,Max));
-%% highest_temp([],Max) ->
-%% Max.
-%%
-%% new_max([V|Vs],Max) ->
-%% case is_temp(V) of
-%% true ->
-%% TReg = temp_reg(V),
-%% if TReg > Max ->
-%% new_max(Vs, TReg);
-%% true ->
-%% new_max(Vs, Max)
-%% end;
-%% false ->
-%% new_max(Vs, Max)
-%% end;
-%% new_max([],Max) -> Max.
diff --git a/lib/hipe/x86/hipe_x86.hrl b/lib/hipe/x86/hipe_x86.hrl
deleted file mode 100644
index 6cd69905b2..0000000000
--- a/lib/hipe/x86/hipe_x86.hrl
+++ /dev/null
@@ -1,112 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% concrete representation of 2-address pseudo-x86 code
-
-%%%--------------------------------------------------------------------
-%%% x86 operands:
-%%%
-%%% int32 ::= <a 32-bit integer>
-%%% reg ::= <token from hipe_x86_registers module>
-%%% type ::= 'tagged' | 'untagged'
-%%% label ::= <an integer>
-%%% label_type ::= 'label' | 'constant'
-%%% aluop ::= <an atom denoting a binary alu op>
-%%% term ::= <any Erlang term>
-%%% cc ::= <an atom denoting a condition code>
-%%% pred ::= <a real number between 0.0 and 1.0 inclusive>
-%%% npop ::= <a 32-bit natural number which is a multiple of 4>
-%%%
-%%% temp ::= {x86_temp, reg, type, allocatable}
-%%% allocatable ::= 'true' | 'false'
-%%%
-%%% imm ::= {x86_imm, value}
-%%% value ::= int32 | atom | {label, label_type}
-%%%
-%%% mem ::= {x86_mem, base, off, mem_type}
-%%% base ::= temp | [] (XXX BUG: not quite true before RA)
-%%% off ::= imm | temp
-%%% mem_type ::= 'byte' | 'int16' (only valid with mov{s,z}x)
-%%% | type
-%%%
-%%% src ::= temp | mem | imm
-%%% dst ::= temp | mem
-%%% arg ::= src
-%%% args ::= <list of arg>
-%%%
-%%% mfa ::= {x86_mfa, atom, atom, byte}
-%%% prim ::= {x86_prim, atom}
-%%% fun ::= mfa | prim | temp | mem
-%%%
-%%% jtab ::= label (equiv. to {x86_imm,{label,'constant'}})
-%%%
-%%% sdesc ::= {x86_sdesc, exnlab, fsize, arity, live}
-%%% exnlab ::= [] | label
-%%% fsize ::= <int32> (frame size in words)
-%%% live ::= <tuple of int32> (word offsets)
-%%% arity ::= int32
-
--record(x86_temp, {reg, type, allocatable}).
--record(x86_imm, {value}).
--record(x86_mem, {base, off, type}).
--record(x86_fpreg, {reg, pseudo}).
--record(x86_mfa, {m::atom(), f::atom(), a::arity()}).
--record(x86_prim, {prim}).
--record(x86_sdesc, {exnlab, fsize, arity::arity(), live::tuple()}).
-
-%%% Basic instructions.
-%%% These follow the AT&T convention, i.e. op src,dst (dst := dst op src)
-%%% After register allocation, at most one operand in a binary
-%%% instruction (alu, cmp, move) may denote a memory cell.
-%%% After frame allocation, every temp must denote a physical register.
-
--record(alu, {aluop, src, dst}).
--record(call, {'fun', sdesc, linkage}).
--record(cmovcc, {cc, src, dst}).
--record(cmp, {src, dst}). % a 'sub' alu which doesn't update dst
--record(comment, {term}).
--record(fmove, {src, dst}).
--record(fp_binop, {op, src, dst}).
--record(fp_unop, {op, arg}). % arg may be [] :-(
--record(imul, {imm_opt, src, temp}). % imm_opt:[]|imm, src:temp|mem
--record(jcc, {cc, label}).
--record(jmp_fun, {'fun', linkage}). % tailcall, direct or indirect
--record(jmp_label, {label}). % local jmp, direct
--record(jmp_switch, {temp, jtab, labels}). % local jmp, indirect
--record(label, {label}).
--record(lea, {mem, temp}).
--record(move, {src, dst}).
--record(move64, {imm, dst}).
--record(movsx, {src, dst}).
--record(movzx, {src, dst}).
--record(pseudo_call, {'fun', sdesc, contlab, linkage}).
--record(pseudo_jcc, {cc, true_label, false_label, pred}).
--record(pseudo_spill, {args=[]}).
--record(pseudo_spill_move, {src, temp, dst}).
--record(pseudo_spill_fmove, {src, temp, dst}).
--record(pseudo_tailcall, {'fun', arity, stkargs, linkage}).
--record(pseudo_tailcall_prepare, {}).
--record(push, {src}).
--record(pop, {dst}).
--record(ret, {npop}). % EAX is live-in
--record(shift, {shiftop, src, dst}).
--record(test, {src, dst}).
-
-%%% Function definitions.
-
--include("../misc/hipe_consttab.hrl").
-
--record(defun, {mfa :: mfa(), formals, code,
- data :: hipe_consttab(),
- isclosure :: boolean(),
- isleaf :: boolean(),
- var_range, label_range}).
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
deleted file mode 100644
index 9d2586a14d..0000000000
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ /dev/null
@@ -1,1004 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% HiPE/x86 assembler
-%%%
-%%% TODO:
-%%% - Simplify combine_label_maps and mk_data_relocs.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_ASSEMBLE, hipe_amd64_assemble).
--define(HIPE_X86_ENCODE, hipe_amd64_encode).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_PP, hipe_amd64_pp).
--ifdef(AMD64_SIMULATE_NSP).
--define(X86_SIMULATE_NSP, ?AMD64_SIMULATE_NSP).
--endif.
--define(EAX, rax).
--define(REGArch, reg64).
--define(RMArch, rm64).
--define(EA_DISP32_ABSOLUTE, ea_disp32_sindex).
--else.
--define(HIPE_X86_ASSEMBLE, hipe_x86_assemble).
--define(HIPE_X86_ENCODE, hipe_x86_encode).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_PP, hipe_x86_pp).
--define(EAX, eax).
--define(REGArch, reg32).
--define(RMArch, rm32).
--define(EA_DISP32_ABSOLUTE, ea_disp32).
--endif.
-
--module(?HIPE_X86_ASSEMBLE).
--export([assemble/4]).
-
--define(DEBUG,true).
-
--include("../main/hipe.hrl").
--include("../x86/hipe_x86.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../rtl/hipe_literals.hrl").
--include("../misc/hipe_sdi.hrl").
--undef(ASSERT).
--define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).
-
-assemble(CompiledCode, Closures, Exports, Options) ->
- ?when_option(time, Options, ?start_timer("x86 assembler")),
- print("****************** Assembling *******************\n", [], Options),
- %%
- Code = [{MFA,
- hipe_x86:defun_code(Defun),
- hipe_x86:defun_data(Defun)}
- || {MFA, Defun} <- CompiledCode],
- %%
- {ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code),
- %%
- {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =
- encode(translate(Code, ConstMap, Options), Options),
- print("Total num bytes=~w\n", [CodeSize], Options),
- %% put(code_size, CodeSize),
- %% put(const_size, ConstSize),
- %% ?when_option(verbose, Options,
- %% ?debug_msg("Constants are ~w bytes\n",[ConstSize])),
- %%
- SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
- SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
- ConstAlign, ConstSize,
- SC,
- DataRelocs, % nee LM, LabelMap
- SSE,
- CodeSize,CodeBinary,SlimRefs,
- 0,[] % ColdCodeSize, SlimColdRefs
- ]),
- %%
- %% ?when_option(time, Options, ?stop_timer("x86 assembler")),
- Bin.
-
-%%%
-%%% Assembly Pass 1.
-%%% Process initial {MFA,Code,Data} list.
-%%% Translate each MFA's body, choosing operand & instruction kinds.
-%%%
-%%% Assembly Pass 2.
-%%% Perform short/long form optimisation for jumps.
-%%% Build LabelMap for each MFA.
-%%%
-%%% Result is {MFA,NewCode,CodeSize,LabelMap} list.
-%%%
-
-translate(Code, ConstMap, Options) ->
- translate_mfas(Code, ConstMap, [], Options).
-
-translate_mfas([{MFA,Insns,_Data}|Code], ConstMap, NewCode, Options) ->
- {NewInsns,CodeSize,LabelMap} =
- translate_insns(Insns, {MFA,ConstMap}, hipe_sdi:pass1_init(), 0, [], Options),
- translate_mfas(Code, ConstMap, [{MFA,NewInsns,CodeSize,LabelMap}|NewCode], Options);
-translate_mfas([], _ConstMap, NewCode, _Options) ->
- lists:reverse(NewCode).
-
-translate_insns([I|Insns], Context, SdiPass1, Address, NewInsns, Options) ->
- NewIs = translate_insn(I, Context, Options),
- add_insns(NewIs, Insns, Context, SdiPass1, Address, NewInsns, Options);
-translate_insns([], _Context, SdiPass1, Address, NewInsns, _Options) ->
- {LabelMap,CodeSizeIncr} = hipe_sdi:pass2(SdiPass1),
- {lists:reverse(NewInsns), Address+CodeSizeIncr, LabelMap}.
-
-add_insns([I|Is], Insns, Context, SdiPass1, Address, NewInsns, Options) ->
- NewSdiPass1 =
- case I of
- {'.label',L,_} ->
- hipe_sdi:pass1_add_label(SdiPass1, Address, L);
- {jcc_sdi,{_,{label,L}},_} ->
- SdiInfo = #sdi_info{incr=(6-2),lb=(-128)+2,ub=127+2},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo);
- {jmp_sdi,{{label,L}},_} ->
- SdiInfo = #sdi_info{incr=(5-2),lb=(-128)+2,ub=127+2},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo);
- _ ->
- SdiPass1
- end,
- Address1 = Address + insn_size(I),
- add_insns(Is, Insns, Context, NewSdiPass1, Address1, [I|NewInsns], Options);
-add_insns([], Insns, Context, SdiPass1, Address, NewInsns, Options) ->
- translate_insns(Insns, Context, SdiPass1, Address, NewInsns, Options).
-
-insn_size(I) ->
- case I of
- {'.label',_,_} -> 0;
- {'.sdesc',_,_} -> 0;
- {jcc_sdi,_,_} -> 2;
- {jmp_sdi,_,_} -> 2;
- {Op,Arg,_Orig} -> ?HIPE_X86_ENCODE:insn_sizeof(Op, Arg)
- end.
-
-translate_insn(I, Context, Options) ->
- case I of
- #alu{aluop='xor', src=#x86_temp{reg=Reg}=Src, dst=#x86_temp{reg=Reg}=Dst} ->
- [{'xor', {temp_to_reg32(Dst), temp_to_rm32(Src)}, I}];
- #alu{} ->
- Arg = resolve_alu_args(hipe_x86:alu_src(I), hipe_x86:alu_dst(I), Context),
- [{hipe_x86:alu_op(I), Arg, I}];
- #call{} ->
- translate_call(I);
- #cmovcc{} ->
- {Dst,Src} = resolve_move_args(
- hipe_x86:cmovcc_src(I), hipe_x86:cmovcc_dst(I),
- Context),
- CC = {cc,?HIPE_X86_ENCODE:cc(hipe_x86:cmovcc_cc(I))},
- Arg = {CC,Dst,Src},
- [{cmovcc, Arg, I}];
- #cmp{} ->
- Arg = resolve_alu_args(hipe_x86:cmp_src(I), hipe_x86:cmp_dst(I), Context),
- [{cmp, Arg, I}];
- #comment{} ->
- [];
- #fmove{} ->
- {Op,Arg} = resolve_sse2_fmove_args(hipe_x86:fmove_src(I),
- hipe_x86:fmove_dst(I)),
- [{Op, Arg, I}];
- #fp_binop{} ->
- case proplists:get_bool(x87, Options) of
- true -> % x87
- Arg = resolve_x87_binop_args(hipe_x86:fp_binop_src(I),
- hipe_x86:fp_binop_dst(I)),
- [{hipe_x86:fp_binop_op(I), Arg, I}];
- false -> % sse2
- Arg = resolve_sse2_binop_args(hipe_x86:fp_binop_src(I),
- hipe_x86:fp_binop_dst(I)),
- [{resolve_sse2_op(hipe_x86:fp_binop_op(I)), Arg, I}]
- end;
- #fp_unop{} ->
- case proplists:get_bool(x87, Options) of
- true -> % x87
- Arg = resolve_x87_unop_arg(hipe_x86:fp_unop_arg(I)),
- [{hipe_x86:fp_unop_op(I), Arg, I}];
- false -> % sse2
- case hipe_x86:fp_unop_op(I) of
- 'fchs' ->
- Arg = resolve_sse2_fchs_arg(hipe_x86:fp_unop_arg(I)),
- [{'xorpd', Arg, I}];
- 'fwait' -> % no op on sse2, magic on x87
- []
- end
- end;
- #imul{} ->
- translate_imul(I, Context);
- #jcc{} ->
- Cc = {cc,?HIPE_X86_ENCODE:cc(hipe_x86:jcc_cc(I))},
- Label = translate_label(hipe_x86:jcc_label(I)),
- [{jcc_sdi, {Cc,Label}, I}];
- #jmp_fun{} ->
- %% call and jmp are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case hipe_x86:jmp_fun_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- Arg = translate_fun(hipe_x86:jmp_fun_fun(I), PatchTypeExt),
- [{jmp, {Arg}, I}];
- #jmp_label{} ->
- Arg = translate_label(hipe_x86:jmp_label_label(I)),
- [{jmp_sdi, {Arg}, I}];
- #jmp_switch{} ->
- RM32 = resolve_jmp_switch_arg(I, Context),
- [{jmp, {RM32}, I}];
- #label{} ->
- [{'.label', hipe_x86:label_label(I), I}];
- #lea{} ->
- Arg = resolve_lea_args(hipe_x86:lea_mem(I), hipe_x86:lea_temp(I)),
- [{lea, Arg, I}];
- #move{} ->
- Arg = resolve_move_args(hipe_x86:move_src(I), hipe_x86:move_dst(I),
- Context),
- [{mov, Arg, I}];
- #move64{} ->
- translate_move64(I, Context);
- #movsx{} ->
- Src = resolve_movx_src(hipe_x86:movsx_src(I)),
- [{movsx, {temp_to_regArch(hipe_x86:movsx_dst(I)), Src}, I}];
- #movzx{} ->
- Src = resolve_movx_src(hipe_x86:movzx_src(I)),
- [{movzx, {temp_to_reg32(hipe_x86:movzx_dst(I)), Src}, I}];
- %% pseudo_call: eliminated before assembly
- %% pseudo_jcc: eliminated before assembly
- %% pseudo_tailcall: eliminated before assembly
- %% pseudo_tailcall_prepare: eliminated before assembly
- #pop{} ->
- Arg = translate_dst(hipe_x86:pop_dst(I)),
- [{pop, {Arg}, I}];
- #push{} ->
- Arg = translate_src(hipe_x86:push_src(I), Context),
- [{push, {Arg}, I}];
- #ret{} ->
- translate_ret(I);
- #shift{} ->
- Arg = resolve_shift_args(hipe_x86:shift_src(I), hipe_x86:shift_dst(I), Context),
- [{hipe_x86:shift_op(I), Arg, I}];
- #test{} ->
- Arg = resolve_test_args(hipe_x86:test_src(I), hipe_x86:test_dst(I), Context),
- [{test, Arg, I}]
- end.
-
--ifdef(X86_SIMULATE_NSP).
--ifdef(HIPE_AMD64).
-translate_call(I) ->
- WordSize = hipe_amd64_registers:wordsize(),
- RegSP = 2#100, % esp/rsp
- TempSP = hipe_x86:mk_temp(RegSP, untagged),
- FunOrig = hipe_x86:call_fun(I),
- Fun =
- case FunOrig of
- #x86_mem{base=#x86_temp{reg=4}, off=#x86_imm{value=Off}} ->
- FunOrig#x86_mem{off=#x86_imm{value=Off+WordSize}};
- _ -> FunOrig
- end,
- RegRA =
- begin
- RegTemp0 = hipe_amd64_registers:temp0(),
- RegTemp1 = hipe_amd64_registers:temp1(),
- case Fun of
- #x86_temp{reg=RegTemp0} -> RegTemp1;
- #x86_mem{base=#x86_temp{reg=RegTemp0}} -> RegTemp1;
- _ -> RegTemp0
- end
- end,
- TempRA = hipe_x86:mk_temp(RegRA, untagged),
- PatchTypeExt =
- case hipe_x86:call_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- JmpArg = translate_fun(Fun, PatchTypeExt),
- I4 = {'.sdesc', hipe_x86:call_sdesc(I), #comment{term=sdesc}},
- I3 = {jmp, {JmpArg}, #comment{term=call}},
- Size3 = hipe_amd64_encode:insn_sizeof(jmp, {JmpArg}),
- MovArgs = {mem_to_rmArch(hipe_x86:mk_mem(TempSP,
- hipe_x86:mk_imm(0),
- untagged)),
- temp_to_regArch(TempRA)},
- I2 = {mov, MovArgs, #comment{term=call}},
- Size2 = hipe_amd64_encode:insn_sizeof(mov, MovArgs),
- I1 = {lea, {temp_to_regArch(TempRA),
- {ea, hipe_amd64_encode:ea_disp32_rip(Size2+Size3)}},
- #comment{term=call}},
- I0 = {sub, {temp_to_rmArch(TempSP), {imm8,WordSize}}, I},
- [I0,I1,I2,I3,I4].
--else.
-translate_call(I) ->
- WordSize = ?HIPE_X86_REGISTERS:wordsize(),
- RegSP = 2#100, % esp/rsp
- TempSP = hipe_x86:mk_temp(RegSP, untagged),
- FunOrig = hipe_x86:call_fun(I),
- Fun =
- case FunOrig of
- #x86_mem{base=#x86_temp{reg=4}, off=#x86_imm{value=Off}} ->
- FunOrig#x86_mem{off=#x86_imm{value=Off+WordSize}};
- _ -> FunOrig
- end,
- PatchTypeExt =
- case hipe_x86:call_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- JmpArg = translate_fun(Fun, PatchTypeExt),
- I3 = {'.sdesc', hipe_x86:call_sdesc(I), #comment{term=sdesc}},
- I2 = {jmp, {JmpArg}, #comment{term=call}},
- Size2 = ?HIPE_X86_ENCODE:insn_sizeof(jmp, {JmpArg}),
- I1 = {mov, {mem_to_rmArch(hipe_x86:mk_mem(TempSP,
- hipe_x86:mk_imm(0),
- untagged)),
- {imm32,{?X86ABSPCREL,4+Size2}}},
- #comment{term=call}},
- I0 = {sub, {temp_to_rmArch(TempSP), {imm8,WordSize}}, I},
- [I0,I1,I2,I3].
--endif.
-
-translate_ret(I) ->
- NPOP = hipe_x86:ret_npop(I) + ?HIPE_X86_REGISTERS:wordsize(),
- RegSP = 2#100, % esp/rsp
- TempSP = hipe_x86:mk_temp(RegSP, untagged),
- RegRA = 2#011, % ebx/rbx
- TempRA = hipe_x86:mk_temp(RegRA, untagged),
- [{mov,
- {temp_to_regArch(TempRA),
- mem_to_rmArch(hipe_x86:mk_mem(TempSP,
- hipe_x86:mk_imm(0),
- untagged))},
- I},
- {add,
- {temp_to_rmArch(TempSP),
- case NPOP < 128 of
- true -> {imm8,NPOP};
- false -> {imm32,NPOP}
- end},
- #comment{term=ret}},
- {jmp,
- {temp_to_rmArch(TempRA)},
- #comment{term=ret}}].
-
--else. % not X86_SIMULATE_NSP
-
-translate_call(I) ->
- %% call and jmp are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case hipe_x86:call_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- Arg = translate_fun(hipe_x86:call_fun(I), PatchTypeExt),
- SDesc = hipe_x86:call_sdesc(I),
- [{call, {Arg}, I}, {'.sdesc', SDesc, #comment{term=sdesc}}].
-
-translate_ret(I) ->
- Arg =
- case hipe_x86:ret_npop(I) of
- 0 -> {};
- N -> {{imm16,N}}
- end,
- [{ret, Arg, I}].
-
--endif. % X86_SIMULATE_NSP
-
-translate_imul(I, Context) ->
- Temp = temp_to_regArch(hipe_x86:imul_temp(I)),
- Src = temp_or_mem_to_rmArch(hipe_x86:imul_src(I)),
- Args =
- case hipe_x86:imul_imm_opt(I) of
- [] -> {Temp,Src};
- Imm -> {Temp,Src,translate_imm(Imm, Context, true)}
- end,
- [{'imul', Args, I}].
-
-temp_or_mem_to_rmArch(Src) ->
- case Src of
- #x86_temp{} -> temp_to_rmArch(Src);
- #x86_mem{} -> mem_to_rmArch(Src)
- end.
-
-translate_label(Label) when is_integer(Label) ->
- {label,Label}. % symbolic, since offset is not yet computable
-
-translate_fun(Arg, PatchTypeExt) ->
- case Arg of
- #x86_temp{} ->
- temp_to_rmArch(Arg);
- #x86_mem{} ->
- mem_to_rmArch(Arg);
- #x86_mfa{m=M,f=F,a=A} ->
- {rel32,{PatchTypeExt,{M,F,A}}};
- #x86_prim{prim=Prim} ->
- {rel32,{PatchTypeExt,Prim}}
- end.
-
-translate_src(Src, Context) ->
- case Src of
- #x86_imm{} ->
- translate_imm(Src, Context, true);
- _ ->
- translate_dst(Src)
- end.
-
-%%% MayTrunc8 controls whether negative Imm8s should be truncated
-%%% to 8 bits or not. Truncation should always be done, except when
-%%% the caller will widen the Imm8 to an Imm32 or Imm64.
-translate_imm(#x86_imm{value=Imm}, Context, MayTrunc8) ->
- if is_atom(Imm) ->
- {imm32,{?LOAD_ATOM,Imm}};
- is_integer(Imm) ->
- case (Imm =< 127) and (Imm >= -128) of
- true ->
- Imm8 =
- case MayTrunc8 of
- true -> Imm band 16#FF;
- false -> Imm
- end,
- {imm8,Imm8};
- false ->
- {imm32,Imm}
- end;
- true ->
- Val =
- case Imm of
- {Label,constant} ->
- {MFA,ConstMap} = Context,
- ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
- {constant,ConstNo};
- {Label,closure} ->
- {closure,Label};
- {Label,c_const} ->
- {c_const,Label}
- end,
- {imm32,{?LOAD_ADDRESS,Val}}
- end.
-
-translate_dst(Dst) ->
- case Dst of
- #x86_temp{} ->
- temp_to_regArch(Dst);
- #x86_mem{type='double'} ->
- mem_to_rm64fp(Dst);
- #x86_mem{} ->
- mem_to_rmArch(Dst);
- #x86_fpreg{} ->
- fpreg_to_stack(Dst)
- end.
-
-%%%
-%%% Assembly Pass 3.
-%%% Process final {MFA,Code,CodeSize,LabelMap} list from pass 2.
-%%% Translate to a single binary code segment.
-%%% Collect relocation patches.
-%%% Build ExportMap (MFA-to-address mapping).
-%%% Combine LabelMaps to a single one (for mk_data_relocs/2 compatibility).
-%%% Return {CombinedCodeSize,BinaryCode,Relocs,CombinedLabelMap,ExportMap}.
-%%%
-
-encode(Code, Options) ->
- CodeSize = compute_code_size(Code, 0),
- ExportMap = build_export_map(Code, 0, []),
- {AccCode,Relocs} = encode_mfas(Code, 0, [], [], Options),
- CodeBinary = list_to_binary(lists:reverse(AccCode)),
- ?ASSERT(CodeSize =:= byte_size(CodeBinary)),
- CombinedLabelMap = combine_label_maps(Code, 0, gb_trees:empty()),
- {CodeSize,CodeBinary,Relocs,CombinedLabelMap,ExportMap}.
-
-nr_pad_bytes(Address) -> (4 - (Address rem 4)) rem 4. % XXX: 16 or 32 instead?
-
-align_entry(Address) -> Address + nr_pad_bytes(Address).
-
-compute_code_size([{_MFA,_Insns,CodeSize,_LabelMap}|Code], Size) ->
- compute_code_size(Code, align_entry(Size+CodeSize));
-compute_code_size([], Size) -> Size.
-
-build_export_map([{{M,F,A},_Insns,CodeSize,_LabelMap}|Code], Address, ExportMap) ->
- build_export_map(Code, align_entry(Address+CodeSize), [{Address,M,F,A}|ExportMap]);
-build_export_map([], _Address, ExportMap) -> ExportMap.
-
-combine_label_maps([{MFA,_Insns,CodeSize,LabelMap}|Code], Address, CLM) ->
- NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
- combine_label_maps(Code, align_entry(Address+CodeSize), NewCLM);
-combine_label_maps([], _Address, CLM) -> CLM.
-
-merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
- NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
- merge_label_map(Rest, MFA, Address, NewCLM);
-merge_label_map([], _MFA, _Address, CLM) -> CLM.
-
-encode_mfas([{MFA,Insns,CodeSize,LabelMap}|Code], Address, AccCode, Relocs, Options) ->
- print("Generating code for:~w\n", [MFA], Options),
- print("Offset | Opcode | Instruction\n", [], Options),
- {Address1,Relocs1,AccCode1} =
- encode_insns(Insns, Address, Address, LabelMap, Relocs, AccCode, Options),
- ExpectedAddress = align_entry(Address + CodeSize),
- ?ASSERT(Address1 =:= ExpectedAddress),
- print("Finished.\n\n", [], Options),
- encode_mfas(Code, Address1, AccCode1, Relocs1, Options);
-encode_mfas([], _Address, AccCode, Relocs, _Options) ->
- {AccCode, Relocs}.
-
-encode_insns([I|Insns], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case I of
- {'.label',L,_} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ?ASSERT(Address =:= LabelAddress), % sanity check
- print_insn(Address, [], I, Options),
- encode_insns(Insns, Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- {'.sdesc',SDesc,_} ->
- #x86_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live} = SDesc,
- ExnRA =
- case ExnLab of
- [] -> []; % don't cons up a new one
- ExnLab -> gb_trees:get(ExnLab, LabelMap) + FunAddress
- end,
- Reloc = {?SDESC, Address,
- ?STACK_DESC(ExnRA, FSize, Arity, Live)},
- encode_insns(Insns, Address, FunAddress, LabelMap, [Reloc|Relocs], AccCode, Options);
- _ ->
- {Op,Arg,_} = fix_jumps(I, Address, FunAddress, LabelMap),
- {Bytes, NewRelocs} = ?HIPE_X86_ENCODE:insn_encode(Op, Arg, Address),
- print_insn(Address, Bytes, I, Options),
- Segment = list_to_binary(Bytes),
- Size = byte_size(Segment),
- NewAccCode = [Segment|AccCode],
- encode_insns(Insns, Address+Size, FunAddress, LabelMap, NewRelocs++Relocs, NewAccCode, Options)
- end;
-encode_insns([], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case nr_pad_bytes(Address) of
- 0 ->
- {Address,Relocs,AccCode};
- NrPadBytes -> % triggers at most once per function body
- Padding = lists:duplicate(NrPadBytes, {nop,{},#comment{term=padding}}),
- encode_insns(Padding, Address, FunAddress, LabelMap, Relocs, AccCode, Options)
- end.
-
-fix_jumps(I, InsnAddress, FunAddress, LabelMap) ->
- case I of
- {jcc_sdi,{CC,{label,L}},OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ShortOffset = LabelAddress - (InsnAddress + 2),
- if is_integer(ShortOffset), ShortOffset >= -128, ShortOffset =< 127 ->
- {jcc,{CC,{rel8,ShortOffset band 16#FF}},OrigI};
- true ->
- LongOffset = LabelAddress - (InsnAddress + 6),
- {jcc,{CC,{rel32,LongOffset}},OrigI}
- end;
- {jmp_sdi,{{label,L}},OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ShortOffset = LabelAddress - (InsnAddress + 2),
- if is_integer(ShortOffset), ShortOffset >= -128, ShortOffset =< 127 ->
- {jmp,{{rel8,ShortOffset band 16#FF}},OrigI};
- true ->
- LongOffset = LabelAddress - (InsnAddress + 5),
- {jmp,{{rel32,LongOffset}},OrigI}
- end;
- _ -> I
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fpreg_to_stack(#x86_fpreg{reg=Reg}) ->
- {fpst, Reg}.
-
-temp_to_regArch(#x86_temp{reg=Reg}) ->
- {?REGArch, Reg}.
-
--ifdef(HIPE_AMD64).
-temp_to_reg64(#x86_temp{reg=Reg}) ->
- {reg64, Reg}.
--endif.
-
-temp_to_reg32(#x86_temp{reg=Reg}) ->
- {reg32, Reg}.
-temp_to_reg16(#x86_temp{reg=Reg}) ->
- {reg16, Reg}.
-temp_to_reg8(#x86_temp{reg=Reg}) ->
- {reg8, Reg}.
-
-temp_to_xmm(#x86_temp{reg=Reg}) ->
- {xmm, Reg}.
-
--ifdef(HIPE_AMD64).
-temp_to_rm8(#x86_temp{reg=Reg}) ->
- {rm8, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rm64(#x86_temp{reg=Reg}) ->
- {rm64, hipe_amd64_encode:rm_reg(Reg)}.
--else.
-temp_to_rm8(#x86_temp{reg=Reg}) ->
- true = ?HIPE_X86_ENCODE:reg_has_8bit(Reg),
- {rm8, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rm16(#x86_temp{reg=Reg}) ->
- {rm16, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
--endif.
-
-temp_to_rm32(#x86_temp{reg=Reg}) ->
- {rm32, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rmArch(#x86_temp{reg=Reg}) ->
- {?RMArch, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rm64fp(#x86_temp{reg=Reg}) ->
- {rm64fp, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-
-mem_to_ea(Mem) ->
- EA = mem_to_ea_common(Mem),
- {ea, EA}.
-
-mem_to_rm32(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm32, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-mem_to_rmArch(Mem) ->
- EA = mem_to_ea_common(Mem),
- {?RMArch, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-mem_to_rm64fp(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm64fp, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-%%%%%%%%%%%%%%%%%
-mem_to_rm8(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm8, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-mem_to_rm16(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm16, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-%%%%%%%%%%%%%%%%%
-
-mem_to_ea_common(#x86_mem{base=[], off=#x86_imm{value=Off}}) ->
- ?HIPE_X86_ENCODE:?EA_DISP32_ABSOLUTE(Off);
-mem_to_ea_common(#x86_mem{base=#x86_temp{reg=Base}, off=#x86_temp{reg=Index}}) ->
- case Base band 2#111 of
- 5 -> % ebp/rbp or r13
- case Index band 2#111 of
- 5 -> % ebp/rbp or r13
- SINDEX = ?HIPE_X86_ENCODE:sindex(0, Index),
- SIB = ?HIPE_X86_ENCODE:sib(Base, SINDEX),
- ?HIPE_X86_ENCODE:ea_disp8_sib(0, SIB);
- _ ->
- SINDEX = ?HIPE_X86_ENCODE:sindex(0, Base),
- SIB = ?HIPE_X86_ENCODE:sib(Index, SINDEX),
- ?HIPE_X86_ENCODE:ea_sib(SIB)
- end;
- _ ->
- SINDEX = ?HIPE_X86_ENCODE:sindex(0, Index),
- SIB = ?HIPE_X86_ENCODE:sib(Base, SINDEX),
- ?HIPE_X86_ENCODE:ea_sib(SIB)
- end;
-mem_to_ea_common(#x86_mem{base=#x86_temp{reg=Base}, off=#x86_imm{value=Off}}) ->
- if
- Off =:= 0 ->
- case Base of
- 4 -> %esp, use SIB w/o disp8
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_sib(SIB);
- 5 -> %ebp, use disp8 w/o SIB
- ?HIPE_X86_ENCODE:ea_disp8_base(Off, Base);
- 12 -> %r12, use SIB w/o disp8
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_sib(SIB);
- 13 -> %r13, use disp8 w/o SIB
- ?HIPE_X86_ENCODE:ea_disp8_base(Off, Base);
- _ -> %neither SIB nor disp8 needed
- ?HIPE_X86_ENCODE:ea_base(Base)
- end;
- Off >= -128, Off =< 127 ->
- Disp8 = Off band 16#FF,
- case Base of
- 4 -> %esp, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp8_sib(Disp8, SIB);
- 12 -> %r12, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp8_sib(Disp8, SIB);
- _ -> %use disp8 w/o SIB
- ?HIPE_X86_ENCODE:ea_disp8_base(Disp8, Base)
- end;
- true ->
- case Base of
- 4 -> %esp, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp32_sib(Off, SIB);
- 12 -> %r12, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp32_sib(Off, SIB);
- _ ->
- ?HIPE_X86_ENCODE:ea_disp32_base(Off, Base)
- end
- end.
-
-%% jmp_switch
--ifdef(HIPE_AMD64).
-resolve_jmp_switch_arg(I, _Context) ->
- Base = hipe_x86:temp_reg(hipe_x86:jmp_switch_jtab(I)),
- Index = hipe_x86:temp_reg(hipe_x86:jmp_switch_temp(I)),
- SINDEX = hipe_amd64_encode:sindex(3, Index),
- SIB = hipe_amd64_encode:sib(Base, SINDEX),
- EA =
- if (Base =:= 5) or (Base =:= 13) ->
- hipe_amd64_encode:ea_disp8_sib(0, SIB);
- true ->
- hipe_amd64_encode:ea_sib(SIB)
- end,
- {rm64,hipe_amd64_encode:rm_mem(EA)}.
--else.
-resolve_jmp_switch_arg(I, {MFA,ConstMap}) ->
- ConstNo = hipe_pack_constants:find_const({MFA,hipe_x86:jmp_switch_jtab(I)}, ConstMap),
- Disp32 = {?LOAD_ADDRESS,{constant,ConstNo}},
- SINDEX = ?HIPE_X86_ENCODE:sindex(2, hipe_x86:temp_reg(hipe_x86:jmp_switch_temp(I))),
- EA = ?HIPE_X86_ENCODE:ea_disp32_sindex(Disp32, SINDEX), % this creates a SIB implicitly
- {rm32,?HIPE_X86_ENCODE:rm_mem(EA)}.
--endif.
-
-%% lea reg, mem
-resolve_lea_args(Src=#x86_mem{}, Dst=#x86_temp{}) ->
- {temp_to_regArch(Dst),mem_to_ea(Src)}.
-
-resolve_sse2_op(Op) ->
- case Op of
- fadd -> addsd;
- fdiv -> divsd;
- fmul -> mulsd;
- fsub -> subsd;
- xorpd -> xorpd;
- _ -> exit({?MODULE, unknown_sse2_operator, Op})
- end.
-
-%% OP xmm, mem
-resolve_sse2_binop_args(Src=#x86_mem{type=double},
- Dst=#x86_temp{type=double}) ->
- {temp_to_xmm(Dst),mem_to_rm64fp(Src)};
-%% movsd mem, xmm
-resolve_sse2_binop_args(Src=#x86_temp{type=double},
- Dst=#x86_mem{type=double}) ->
- {mem_to_rm64fp(Dst),temp_to_xmm(Src)};
-%% OP xmm, xmm
-resolve_sse2_binop_args(Src=#x86_temp{type=double},
- Dst=#x86_temp{type=double}) ->
- {temp_to_xmm(Dst),temp_to_rm64fp(Src)}.
-
-%%% fmove -> cvtsi2sd or movsd
-resolve_sse2_fmove_args(Src, Dst) ->
- case {Src,Dst} of
- {#x86_temp{type=untagged}, #x86_temp{type=double}} -> % cvtsi2sd xmm, reg
- {cvtsi2sd, {temp_to_xmm(Dst),temp_to_rmArch(Src)}};
- {#x86_mem{type=untagged}, #x86_temp{type=double}} -> % cvtsi2sd xmm, mem
- {cvtsi2sd, {temp_to_xmm(Dst),mem_to_rmArch(Src)}};
- _ -> % movsd
- {movsd, resolve_sse2_binop_args(Src, Dst)}
- end.
-
-%%% xorpd xmm, mem
-resolve_sse2_fchs_arg(Dst=#x86_temp{type=double}) ->
- {temp_to_xmm(Dst),
- {rm64fp, {rm_mem, ?HIPE_X86_ENCODE:?EA_DISP32_ABSOLUTE(
- {?LOAD_ADDRESS,
- {c_const, sse2_fnegate_mask}})}}}.
-
-%% mov mem, imm
-resolve_move_args(#x86_imm{value=ImmSrc}, Dst=#x86_mem{type=Type}, Context) ->
- case Type of % to support byte, int16 and int32 stores
- byte ->
- ByteImm = ImmSrc band 255, %to ensure that it is a bytesized imm
- {mem_to_rm8(Dst),{imm8,ByteImm}};
- int16 ->
- {mem_to_rm16(Dst),{imm16,ImmSrc band 16#FFFF}};
- int32 ->
- {_,Imm} = translate_imm(#x86_imm{value=ImmSrc}, Context, false),
- {mem_to_rm32(Dst),{imm32,Imm}};
- _ ->
- RMArch = mem_to_rmArch(Dst),
- {_,Imm} = translate_imm(#x86_imm{value=ImmSrc}, Context, false),
- {RMArch,{imm32,Imm}}
- end;
-
-%% mov reg,mem
-resolve_move_args(Src=#x86_mem{type=Type}, Dst=#x86_temp{}, _Context) ->
- case Type of
- int32 -> % must be unsigned
- {temp_to_reg32(Dst),mem_to_rm32(Src)};
- _ ->
- {temp_to_regArch(Dst),mem_to_rmArch(Src)}
- end;
-
-%% mov mem,reg
-resolve_move_args(Src=#x86_temp{}, Dst=#x86_mem{type=Type}, _Context) ->
- case Type of % to support byte, int16 and int32 stores
- byte ->
- {mem_to_rm8(Dst),temp_to_reg8(Src)};
- int16 ->
- {mem_to_rm16(Dst),temp_to_reg16(Src)};
- int32 ->
- {mem_to_rm32(Dst),temp_to_reg32(Src)};
- tagged -> % tagged, untagged
- {mem_to_rmArch(Dst),temp_to_regArch(Src)};
- untagged -> % tagged, untagged
- {mem_to_rmArch(Dst),temp_to_regArch(Src)}
- end;
-
-%% mov reg,reg
-resolve_move_args(Src=#x86_temp{}, Dst=#x86_temp{}, _Context) ->
- {temp_to_regArch(Dst),temp_to_rmArch(Src)};
-
-%% mov reg,imm
-resolve_move_args(Src=#x86_imm{value=_ImmSrc}, Dst=#x86_temp{}, Context) ->
- {_,Imm} = translate_imm(Src, Context, false),
- imm_move_args(Dst, Imm).
-
--ifdef(HIPE_AMD64).
-imm_move_args(Dst, Imm) ->
- if is_number(Imm), Imm >= 0 ->
- {temp_to_reg32(Dst),{imm32,Imm}};
- true ->
- {temp_to_rm64(Dst),{imm32,Imm}}
- end.
--else.
-imm_move_args(Dst, Imm) ->
- {temp_to_reg32(Dst),{imm32,Imm}}.
--endif.
-
--ifdef(HIPE_AMD64).
-translate_move64(I, Context) ->
- Arg = resolve_move64_args(hipe_x86:move64_src(I),
- hipe_x86:move64_dst(I),
- Context),
- [{mov, Arg, I}].
-
-%% mov reg,imm64
-resolve_move64_args(Src=#x86_imm{}, Dst=#x86_temp{}, Context) ->
- {_,Imm} = translate_imm(Src, Context, false),
- {temp_to_reg64(Dst),{imm64,Imm}}.
--else.
-translate_move64(I, _Context) -> exit({?MODULE, I}).
--endif.
-
-%%% mov{s,z}x
-resolve_movx_src(Src=#x86_mem{type=Type}) ->
- case Type of
- byte ->
- mem_to_rm8(Src);
- int16 ->
- mem_to_rm16(Src);
- int32 ->
- mem_to_rm32(Src)
- end.
-
-%%% alu/cmp (_not_ test)
-resolve_alu_args(Src, Dst, Context) ->
- case {Src,Dst} of
- {#x86_imm{}, #x86_mem{}} ->
- {mem_to_rmArch(Dst), translate_imm(Src, Context, true)};
- {#x86_mem{}, #x86_temp{}} ->
- {temp_to_regArch(Dst), mem_to_rmArch(Src)};
- {#x86_temp{}, #x86_mem{}} ->
- {mem_to_rmArch(Dst), temp_to_regArch(Src)};
- {#x86_temp{}, #x86_temp{}} ->
- {temp_to_regArch(Dst), temp_to_rmArch(Src)};
- {#x86_imm{}, #x86_temp{reg=0}} -> % eax,imm
- NewSrc = translate_imm(Src, Context, true),
- NewDst =
- case NewSrc of
- {imm8,_} -> temp_to_rmArch(Dst);
- {imm32,_} -> ?EAX
- end,
- {NewDst, NewSrc};
- {#x86_imm{}, #x86_temp{}} ->
- {temp_to_rmArch(Dst), translate_imm(Src, Context, true)}
- end.
-
-%%% test
-resolve_test_args(Src, Dst, Context) ->
- case Src of
- %% Since we're using an 8-bit instruction, the immediate is not sign
- %% extended. Thus, we can use immediates up to 255.
- #x86_imm{value=ImmVal}
- when is_integer(ImmVal), ImmVal >= 0, ImmVal =< 255 ->
- Imm = {imm8, ImmVal},
- case Dst of
- #x86_temp{reg=0} -> {al, Imm};
- #x86_temp{} -> resolve_test_imm8_reg(Imm, Dst);
- #x86_mem{} -> {mem_to_rm8(Dst), Imm}
- end;
- #x86_imm{value=ImmVal} when is_integer(ImmVal), ImmVal >= 0 ->
- {case Dst of
- #x86_temp{reg=0} -> eax;
- #x86_temp{} -> temp_to_rm32(Dst);
- #x86_mem{} -> mem_to_rm32(Dst)
- end, {imm32, ImmVal}};
- #x86_imm{} -> % Negative ImmVal; use word-sized instr, imm32
- {_, ImmVal} = translate_imm(Src, Context, false),
- {case Dst of
- #x86_temp{reg=0} -> ?EAX;
- #x86_temp{} -> temp_to_rmArch(Dst);
- #x86_mem{} -> mem_to_rmArch(Dst)
- end, {imm32, ImmVal}};
- #x86_temp{} ->
- NewDst =
- case Dst of
- #x86_temp{} -> temp_to_rmArch(Dst);
- #x86_mem{} -> mem_to_rmArch(Dst)
- end,
- {NewDst, temp_to_regArch(Src)}
- end.
-
--ifdef(HIPE_AMD64).
-resolve_test_imm8_reg(Imm, Dst) -> {temp_to_rm8(Dst), Imm}.
--else.
-resolve_test_imm8_reg(Imm = {imm8, ImmVal}, Dst = #x86_temp{reg=Reg}) ->
- case ?HIPE_X86_ENCODE:reg_has_8bit(Reg) of
- true -> {temp_to_rm8(Dst), Imm};
- false ->
- %% Register does not exist in 8-bit version; use 16-bit instead
- {temp_to_rm16(Dst), {imm16, ImmVal}}
- end.
--endif.
-
-%%% shifts
-resolve_shift_args(Src, Dst, Context) ->
- RM32 =
- case Dst of
- #x86_temp{} -> temp_to_rmArch(Dst);
- #x86_mem{} -> mem_to_rmArch(Dst)
- end,
- Count =
- case Src of
- #x86_imm{value=1} -> 1;
- #x86_imm{} -> translate_imm(Src, Context, true); % must be imm8
- #x86_temp{reg=1} -> cl % temp must be ecx
- end,
- {RM32, Count}.
-
-%% x87_binop mem
-resolve_x87_unop_arg(Arg=#x86_mem{type=Type})->
- case Type of
- 'double' -> {mem_to_rm64fp(Arg)};
- 'untagged' -> {mem_to_rmArch(Arg)};
- _ -> ?EXIT({fmovArgNotSupported,{Arg}})
- end;
-resolve_x87_unop_arg(Arg=#x86_fpreg{}) ->
- {fpreg_to_stack(Arg)};
-resolve_x87_unop_arg([]) ->
- [].
-
-%% x87_binop mem, st(i)
-resolve_x87_binop_args(Src=#x86_fpreg{}, Dst=#x86_mem{})->
- {mem_to_rm64fp(Dst),fpreg_to_stack(Src)};
-%% x87_binop st(0), st(i)
-resolve_x87_binop_args(Src=#x86_fpreg{}, Dst=#x86_fpreg{})->
- {fpreg_to_stack(Dst),fpreg_to_stack(Src)}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%
-%%% Assembly listing support (pp_asm option).
-%%%
-
-print(String, Arglist, Options) ->
- ?when_option(pp_asm, Options, io:format(String, Arglist)).
-
-print_insn(Address, Bytes, I, Options) ->
- ?when_option(pp_asm, Options, print_insn_2(Address, Bytes, I)),
- ?when_option(pp_cxmon, Options, print_code_list_2(Bytes)).
-
-print_code_list_2([H | Tail]) ->
- print_byte(H),
- io:format(","),
- print_code_list_2(Tail);
-print_code_list_2([]) ->
- io:format("").
-
-print_insn_2(Address, Bytes, {_,_,OrigI}) ->
- io:format("~8.16b | ", [Address]),
- print_code_list(Bytes, 0),
- ?HIPE_X86_PP:pp_insn(OrigI).
-
-print_code_list([Byte|Rest], Len) ->
- print_byte(Byte),
- print_code_list(Rest, Len+1);
-print_code_list([], Len) ->
- fill_spaces(24-(Len*2)),
- io:format(" | ").
-
-print_byte(Byte) ->
- io:format("~2.16.0b", [Byte band 16#FF]).
-
-fill_spaces(N) when N > 0 ->
- io:format(" "),
- fill_spaces(N-1);
-fill_spaces(0) ->
- [].
diff --git a/lib/hipe/x86/hipe_x86_cfg.erl b/lib/hipe/x86/hipe_x86_cfg.erl
deleted file mode 100644
index 0a3c0fc9d6..0000000000
--- a/lib/hipe/x86/hipe_x86_cfg.erl
+++ /dev/null
@@ -1,162 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--module(hipe_x86_cfg).
-
--export([init/1,
- labels/1, start_label/1,
- succ/2, pred/2,
- bb/2, bb_add/3, map_bbs/2, fold_bbs/3]).
--export([postorder/1, reverse_postorder/1]).
--export([linearise/1, params/1, arity/1, redirect_jmp/3, branch_preds/1]).
-
-%%% these tell cfg.inc what to define (ugly as hell)
--define(PRED_NEEDED,true).
--define(BREADTH_ORDER,true).
--define(PARAMS_NEEDED,true).
--define(START_LABEL_UPDATE_NEEDED,true).
--define(MAP_FOLD_NEEDED,true).
-
--include("hipe_x86.hrl").
--include("../flow/cfg.hrl").
--include("../flow/cfg.inc").
-
-init(Defun) ->
- %% XXX: this assumes that the code starts with a label insn.
- %% Is that guaranteed?
- Code = hipe_x86:defun_code(Defun),
- StartLab = hipe_x86:label_label(hd(Code)),
- Data = hipe_x86:defun_data(Defun),
- IsClosure = hipe_x86:defun_is_closure(Defun),
- MFA = hipe_x86:defun_mfa(Defun),
- IsLeaf = hipe_x86:defun_is_leaf(Defun),
- Formals = hipe_x86:defun_formals(Defun),
- CFG0 = mk_empty_cfg(MFA, StartLab, Data, IsClosure, IsLeaf, Formals),
- take_bbs(Code, CFG0).
-
-is_branch(I) ->
- case I of
- #jmp_fun{} -> true;
- #jmp_label{} -> true;
- #jmp_switch{} -> true;
- #pseudo_call{} -> true;
- #pseudo_jcc{} -> true;
- #pseudo_tailcall{} -> true;
- #ret{} -> true;
- _ -> false
- end.
-
-branch_successors(Branch) ->
- case Branch of
- #jmp_fun{} -> [];
- #jmp_label{label=Label} -> [Label];
- #jmp_switch{labels=Labels} -> Labels;
- #pseudo_call{contlab=ContLab, sdesc=#x86_sdesc{exnlab=ExnLab}} ->
- case ExnLab of
- [] -> [ContLab];
- _ -> [ContLab,ExnLab]
- end;
- #pseudo_jcc{true_label=TrueLab,false_label=FalseLab} -> [FalseLab,TrueLab];
- #pseudo_tailcall{} -> [];
- #ret{} -> []
- end.
-
-branch_preds(Branch) ->
- case Branch of
- #jmp_switch{labels=Labels} ->
- Prob = 1.0/length(Labels),
- [{L, Prob} || L <- Labels];
- #pseudo_call{contlab=ContLab, sdesc=#x86_sdesc{exnlab=[]}} ->
- %% A function can still cause an exception, even if we won't catch it
- [{ContLab, 1.0-hipe_bb_weights:call_exn_pred()}];
- #pseudo_call{contlab=ContLab, sdesc=#x86_sdesc{exnlab=ExnLab}} ->
- CallExnPred = hipe_bb_weights:call_exn_pred(),
- [{ContLab, 1.0-CallExnPred}, {ExnLab, CallExnPred}];
- #pseudo_jcc{true_label=TrueLab,false_label=FalseLab,pred=Pred} ->
- [{FalseLab, 1.0-Pred}, {TrueLab, Pred}];
- _ ->
- case branch_successors(Branch) of
- [] -> [];
- [Single] -> [{Single, 1.0}]
- end
- end.
-
--ifdef(REMOVE_TRIVIAL_BBS_NEEDED).
-fails_to(_Instr) -> [].
--endif.
-
-redirect_jmp(I, Old, New) ->
- case I of
- #jmp_label{label=Label} ->
- if Old =:= Label -> I#jmp_label{label=New};
- true -> I
- end;
- #pseudo_jcc{true_label=TrueLab, false_label=FalseLab} ->
- J0 = if Old =:= TrueLab -> I#pseudo_jcc{true_label=New};
- true -> I
- end,
- if Old =:= FalseLab -> J0#pseudo_jcc{false_label=New};
- true -> J0
- end;
- %% handle pseudo_call too?
- _ -> I
- end.
-
-%%% XXX: fix if labels can occur in operands
-%% redirect_ops(_Labels, CFG, _Map) ->
-%% CFG.
-
-mk_goto(Label) ->
- hipe_x86:mk_jmp_label(Label).
-
-is_label(I) ->
- case I of #label{} -> true; _ -> false end.
-
-label_name(Label) ->
- hipe_x86:label_label(Label).
-
-mk_label(Name) ->
- hipe_x86:mk_label(Name).
-
-%% is_comment(I) ->
-%% hipe_x86:is_comment(I).
-%%
-%% is_goto(I) ->
-%% hipe_x86:is_jmp_label(I).
-
-linearise(CFG) -> % -> defun, not insn list
- MFA = function(CFG),
- Formals = params(CFG),
- Code = linearize_cfg(CFG),
- Data = data(CFG),
- VarRange = hipe_gensym:var_range(x86),
- LabelRange = hipe_gensym:label_range(x86),
- IsClosure = is_closure(CFG),
- IsLeaf = is_leaf(CFG),
- hipe_x86:mk_defun(MFA, Formals, IsClosure, IsLeaf,
- Code, Data, VarRange, LabelRange).
-
-arity(CFG) ->
- {_M,_F,A} = function(CFG),
- A.
-
-%% init_gensym(CFG) ->
-%% HighestVar = find_highest_var(CFG),
-%% HighestLabel = find_highest_label(CFG),
-%% hipe_gensym:init(),
-%% hipe_gensym:set_var(x86, HighestVar),
-%% hipe_gensym:set_label(x86, HighestLabel).
-%%
-%% highest_var(Code) ->
-%% hipe_x86:highest_temp(Code).
diff --git a/lib/hipe/x86/hipe_x86_defuse.erl b/lib/hipe/x86/hipe_x86_defuse.erl
deleted file mode 100644
index 2731836dc1..0000000000
--- a/lib/hipe/x86/hipe_x86_defuse.erl
+++ /dev/null
@@ -1,170 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% compute def/use sets for x86 insns
-%%%
-%%% TODO:
-%%% - represent EFLAGS (condition codes) use/def by a virtual reg?
-%%% - should push use/def %esp?
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_DEFUSE, hipe_amd64_defuse).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(RV, rax).
--else.
--define(HIPE_X86_DEFUSE, hipe_x86_defuse).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(RV, eax).
--endif.
-
--module(?HIPE_X86_DEFUSE).
--export([insn_def/1, insn_defs_all/1, insn_use/1]). %% src_use/1]).
--include("../x86/hipe_x86.hrl").
-
-%%%
-%%% insn_def(Insn) -- Return set of temps defined by an instruction.
-%%%
-
-insn_def(I) ->
- case I of
- #alu{dst=Dst} -> dst_def(Dst);
- #cmovcc{dst=Dst} -> dst_def(Dst);
- #fmove{dst=Dst} -> dst_def(Dst);
- #fp_binop{dst=Dst} -> dst_def(Dst);
- #fp_unop{arg=Arg} -> dst_def(Arg);
- #imul{temp=Temp} -> [Temp];
- #lea{temp=Temp} -> [Temp];
- #move{dst=Dst} -> dst_def(Dst);
- #move64{dst=Dst} -> dst_def(Dst);
- #movsx{dst=Dst} -> dst_def(Dst);
- #movzx{dst=Dst} -> dst_def(Dst);
- #pseudo_call{} -> call_clobbered();
- #pseudo_spill{} -> [];
- #pseudo_spill_fmove{temp=Temp, dst=Dst} -> [Temp, Dst];
- #pseudo_spill_move{temp=Temp, dst=Dst} -> [Temp, Dst];
- #pseudo_tailcall_prepare{} -> tailcall_clobbered();
- #shift{dst=Dst} -> dst_def(Dst);
- %% call, cmp, comment, jcc, jmp_fun, jmp_label, jmp_switch, label
- %% pseudo_jcc, pseudo_tailcall, push, ret, test
- _ -> []
- end.
-
-
-%% @doc Answers whether instruction I defines all allocatable registers. Used by
-%% hipe_regalloc_prepass.
--spec insn_defs_all(_) -> boolean().
-insn_defs_all(I) ->
- case I of
- #pseudo_call{} -> true;
- _ -> false
- end.
-
-dst_def(Dst) ->
- case Dst of
- #x86_temp{} -> [Dst];
- #x86_fpreg{} -> [Dst];
- _ -> []
- end.
-
-call_clobbered() ->
- [hipe_x86:mk_temp(R, T)
- || {R,T} <- ?HIPE_X86_REGISTERS:call_clobbered()].
-
-tailcall_clobbered() ->
- [hipe_x86:mk_temp(R, T)
- || {R,T} <- ?HIPE_X86_REGISTERS:tailcall_clobbered()].
-
-%%%
-%%% insn_use(Insn) -- Return set of temps used by an instruction.
-%%%
-
-insn_use(I) ->
- case I of
- #alu{src=Src,dst=Dst} -> addtemp(Src, addtemp(Dst, []));
- #call{'fun'=Fun} -> addtemp(Fun, []);
- #cmovcc{src=Src, dst=Dst} -> addtemp(Src, dst_use(Dst));
- #cmp{src=Src, dst=Dst} -> addtemp(Src, addtemp(Dst, []));
- #fmove{src=Src,dst=Dst} -> addtemp(Src, dst_use(Dst));
- #fp_unop{arg=Arg} -> addtemp(Arg, []);
- #fp_binop{src=Src,dst=Dst} -> addtemp(Src, addtemp(Dst, []));
- #imul{imm_opt=ImmOpt,src=Src,temp=Temp} ->
- addtemp(Src, case ImmOpt of [] -> addtemp(Temp, []); _ -> [] end);
- #jmp_fun{'fun'=Fun} -> addtemp(Fun, []);
- #jmp_switch{temp=Temp, jtab=JTab} -> addtemp(Temp, addtemp(JTab, []));
- #lea{mem=Mem} -> addtemp(Mem, []);
- #move{src=Src,dst=Dst} -> addtemp(Src, dst_use(Dst));
- #move64{} -> [];
- #movsx{src=Src,dst=Dst} -> addtemp(Src, dst_use(Dst));
- #movzx{src=Src,dst=Dst} -> addtemp(Src, dst_use(Dst));
- #pseudo_call{'fun'=Fun,sdesc=#x86_sdesc{arity=Arity}} ->
- addtemp(Fun, arity_use(Arity));
- #pseudo_spill{args=Args} -> Args;
- #pseudo_spill_fmove{src=Src} -> [Src];
- #pseudo_spill_move{src=Src} -> [Src];
- #pseudo_tailcall{'fun'=Fun,arity=Arity,stkargs=StkArgs} ->
- addtemp(Fun, addtemps(StkArgs, addtemps(tailcall_clobbered(),
- arity_use(Arity))));
- #push{src=Src} -> addtemp(Src, []);
- #ret{} -> [hipe_x86:mk_temp(?HIPE_X86_REGISTERS:?RV(), 'tagged')];
- #shift{src=Src,dst=Dst} -> addtemp(Src, addtemp(Dst, []));
- #test{src=Src, dst=Dst} -> addtemp(Src, addtemp(Dst, []));
- %% comment, jcc, jmp_label, label, pseudo_jcc, pseudo_tailcall_prepare
- _ -> []
- end.
-
-arity_use(Arity) ->
- [hipe_x86:mk_temp(R, 'tagged')
- || R <- ?HIPE_X86_REGISTERS:args(Arity)].
-
-dst_use(Dst) ->
- case Dst of
- #x86_mem{base=Base,off=Off} -> addbase(Base, addtemp(Off, []));
- _ -> []
- end.
-
-%%%
-%%% src_use(Src) -- Return set of temps used by a source operand.
-%%%
-
-%% src_use(Src) ->
-%% addtemp(Src, []).
-
-%%%
-%%% Auxiliary operations on sets of temps
-%%%
-
-addtemps([Arg|Args], Set) ->
- addtemps(Args, addtemp(Arg, Set));
-addtemps([], Set) ->
- Set.
-
-addtemp(Arg, Set) ->
- case Arg of
- #x86_temp{} -> add(Arg, Set);
- #x86_mem{base=Base,off=Off} -> addtemp(Off, addbase(Base, Set));
- #x86_fpreg{} -> add(Arg, Set);
- _ -> Set
- end.
-
-addbase(Base, Set) ->
- case Base of
- [] -> Set;
- _ -> addtemp(Base, Set)
- end.
-
-add(Arg, Set) ->
- case lists:member(Arg, Set) of
- false -> [Arg|Set];
- _ -> Set
- end.
diff --git a/lib/hipe/x86/hipe_x86_encode.erl b/lib/hipe/x86/hipe_x86_encode.erl
deleted file mode 100644
index 2662f76d0b..0000000000
--- a/lib/hipe/x86/hipe_x86_encode.erl
+++ /dev/null
@@ -1,1319 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Copyright (C) 2000-2005 Mikael Pettersson
-%%%
-%%% This is the syntax of x86 r/m operands:
-%%%
-%%% opnd ::= reg mod == 11
-%%% | MEM[ea] mod != 11
-%%%
-%%% ea ::= disp32(reg) mod == 10, r/m != ESP
-%%% | disp32 sib12 mod == 10, r/m == 100
-%%% | disp8(reg) mod == 01, r/m != ESP
-%%% | disp8 sib12 mod == 01, r/m == 100
-%%% | (reg) mod == 00, r/m != ESP and EBP
-%%% | sib0 mod == 00, r/m == 100
-%%% | disp32 mod == 00, r/m == 101 [on x86-32]
-%%% | disp32(%rip) mod == 00, r/m == 101 [on x86-64]
-%%%
-%%% // sib0: mod == 00
-%%% sib0 ::= disp32(,index,scale) base == EBP, index != ESP
-%%% | disp32 base == EBP, index == 100
-%%% | (base,index,scale) base != EBP, index != ESP
-%%% | (base) base != EBP, index == 100
-%%%
-%%% // sib12: mod == 01 or 10
-%%% sib12 ::= (base,index,scale) index != ESP
-%%% | (base) index == 100
-%%%
-%%% scale ::= 00 | 01 | 10 | 11 index << scale
-%%%
-%%% Notes:
-%%%
-%%% 1. ESP cannot be used as index register.
-%%% 2. Use of ESP as base register requires a SIB byte.
-%%% 3. disp(reg), when reg != ESP, can be represented without
-%%% [r/m == reg] or with [r/m == 100, base == reg] a SIB byte.
-%%% 4. disp32 can be represented without [mod == 00, r/m == 101]
-%%% or with [mod == 00, r/m == 100, base == 101, index == 100]
-%%% a SIB byte.
-%%% 5. x86-32 and x86-64 interpret mod==00b r/m==101b EAs differently:
-%%% on x86-32 the disp32 is an absolute address, but on x86-64 the
-%%% disp32 is relative to the %rip of the next instruction.
-%%% Absolute disp32s need a SIB on x86-64.
-
--module(hipe_x86_encode).
-
--export([% condition codes
- cc/1,
- % 8-bit registers
- %% al/0, cl/0, dl/0, bl/0, ah/0, ch/0, dh/0, bh/0,
- reg_has_8bit/1,
- % 32-bit registers
- %% eax/0, ecx/0, edx/0, ebx/0, esp/0, ebp/0, esi/0, edi/0,
- % operands
- sindex/2, sib/1, sib/2,
- ea_disp32_base/2, ea_disp32_sib/2,
- ea_disp8_base/2, ea_disp8_sib/2,
- ea_base/1,
- %% ea_disp32_sindex/1, % XXX: do not use on x86-32, only on x86-64
- ea_disp32_sindex/2,
- ea_sib/1, ea_disp32/1,
- rm_reg/1, rm_mem/1,
- % instructions
- insn_encode/3, insn_sizeof/2]).
-
-%%-define(DO_HIPE_X86_ENCODE_TEST,true).
--ifdef(DO_HIPE_X86_ENCODE_TEST).
--export([dotest/0, dotest/1]). % for testing, don't use
--endif.
-
--define(ASSERT(F,G), if G -> [] ; true -> exit({?MODULE,F}) end).
-%-define(ASSERT(F,G), []).
-
-%%% condition codes
-
--define(CC_O, 2#0000). % overflow
--define(CC_NO, 2#0001). % no overflow
--define(CC_B, 2#0010). % below, <u
--define(CC_AE, 2#0011). % above or equal, >=u
--define(CC_E, 2#0100). % equal
--define(CC_NE, 2#0101). % not equal
--define(CC_BE, 2#0110). % below or equal, <=u
--define(CC_A, 2#0111). % above, >u
--define(CC_S, 2#1000). % sign, +
--define(CC_NS, 2#1001). % not sign, -
--define(CC_PE, 2#1010). % parity even
--define(CC_PO, 2#1011). % parity odd
--define(CC_L, 2#1100). % less than, <s
--define(CC_GE, 2#1101). % greater or equal, >=s
--define(CC_LE, 2#1110). % less or equal, <=s
--define(CC_G, 2#1111). % greater than, >s
-
-cc(o) -> ?CC_O;
-cc(no) -> ?CC_NO;
-cc(b) -> ?CC_B;
-cc(ae) -> ?CC_AE;
-cc(e) -> ?CC_E;
-cc(ne) -> ?CC_NE;
-cc(be) -> ?CC_BE;
-cc(a) -> ?CC_A;
-cc(s) -> ?CC_S;
-cc(ns) -> ?CC_NS;
-cc(pe) -> ?CC_PE;
-cc(po) -> ?CC_PO;
-cc(l) -> ?CC_L;
-cc(ge) -> ?CC_GE;
-cc(le) -> ?CC_LE;
-cc(g) -> ?CC_G.
-
-%%% 8-bit registers
-
--define(AL, 2#000).
--define(CL, 2#001).
--define(DL, 2#010).
--define(BL, 2#011).
--define(AH, 2#100).
--define(CH, 2#101).
--define(DH, 2#110).
--define(BH, 2#111).
-
-%% al() -> ?AL.
-%% cl() -> ?CL.
-%% dl() -> ?DL.
-%% bl() -> ?BL.
-%% ah() -> ?AH.
-%% ch() -> ?CH.
-%% dh() -> ?DH.
-%% bh() -> ?BH.
-
-reg_has_8bit(Reg) -> Reg =< ?BL.
-
-%%% 32-bit registers
-
--define(EAX, 2#000).
--define(ECX, 2#001).
--define(EDX, 2#010).
--define(EBX, 2#011).
--define(ESP, 2#100).
--define(EBP, 2#101).
--define(ESI, 2#110).
--define(EDI, 2#111).
-
-%% eax() -> ?EAX.
-%% ecx() -> ?ECX.
-%% edx() -> ?EDX.
-%% ebx() -> ?EBX.
-%% esp() -> ?ESP.
-%% ebp() -> ?EBP.
-%% esi() -> ?ESI.
-%% edi() -> ?EDI.
-
-%%% r/m operands
-
-sindex(Scale, Index) when is_integer(Scale), is_integer(Index) ->
- ?ASSERT(sindex, Scale >= 0),
- ?ASSERT(sindex, Scale =< 3),
- ?ASSERT(sindex, Index =/= ?ESP),
- {sindex, Scale, Index}.
-
--record(sib, {sindex_opt, base :: integer()}).
-sib(Base) when is_integer(Base) -> #sib{sindex_opt=none, base=Base}.
-sib(Base, Sindex) when is_integer(Base) -> #sib{sindex_opt=Sindex, base=Base}.
-
-ea_disp32_base(Disp32, Base) when is_integer(Base) ->
- ?ASSERT(ea_disp32_base, Base =/= ?ESP),
- {ea_disp32_base, Disp32, Base}.
-ea_disp32_sib(Disp32, SIB) -> {ea_disp32_sib, Disp32, SIB}.
-ea_disp8_base(Disp8, Base) when is_integer(Base) ->
- ?ASSERT(ea_disp8_base, Base =/= ?ESP),
- {ea_disp8_base, Disp8, Base}.
-ea_disp8_sib(Disp8, SIB) -> {ea_disp8_sib, Disp8, SIB}.
-ea_base(Base) when is_integer(Base) ->
- ?ASSERT(ea_base, Base =/= ?ESP),
- ?ASSERT(ea_base, Base =/= ?EBP),
- {ea_base, Base}.
-%% ea_disp32_sindex(Disp32) -> {ea_disp32_sindex, Disp32, none}.
-ea_disp32_sindex(Disp32, Sindex) -> {ea_disp32_sindex, Disp32, Sindex}.
-ea_sib(SIB) ->
- ?ASSERT(ea_sib, SIB#sib.base =/= ?EBP),
- {ea_sib, SIB}.
-ea_disp32(Disp32) -> {ea_disp32, Disp32}.
-
-rm_reg(Reg) -> {rm_reg, Reg}.
-rm_mem(EA) -> {rm_mem, EA}.
-
-mk_modrm(Mod, RO, RM) ->
- (Mod bsl 6) bor (RO bsl 3) bor RM.
-
-mk_sib(Scale, Index, Base) ->
- (Scale bsl 6) bor (Index bsl 3) bor Base.
-
-le16(Word, Tail) ->
- [Word band 16#FF, (Word bsr 8) band 16#FF | Tail].
-
-le32(Word, Tail) when is_integer(Word) ->
- [Word band 16#FF, (Word bsr 8) band 16#FF,
- (Word bsr 16) band 16#FF, (Word bsr 24) band 16#FF | Tail];
-le32({Tag,Val}, Tail) -> % a relocatable datum
- [{le32,Tag,Val} | Tail].
-
-enc_sindex_opt({sindex,Scale,Index}) -> {Scale, Index};
-enc_sindex_opt(none) -> {2#00, 2#100}.
-
-enc_sib(#sib{sindex_opt=SindexOpt, base=Base}) ->
- {Scale, Index} = enc_sindex_opt(SindexOpt),
- mk_sib(Scale, Index, Base).
-
-enc_ea(EA, RO, Tail) ->
- case EA of
- {ea_disp32_base, Disp32, Base} ->
- [mk_modrm(2#10, RO, Base) | le32(Disp32, Tail)];
- {ea_disp32_sib, Disp32, SIB} ->
- [mk_modrm(2#10, RO, 2#100), enc_sib(SIB) | le32(Disp32, Tail)];
- {ea_disp8_base, Disp8, Base} ->
- [mk_modrm(2#01, RO, Base), Disp8 | Tail];
- {ea_disp8_sib, Disp8, SIB} ->
- [mk_modrm(2#01, RO, 2#100), enc_sib(SIB), Disp8 | Tail];
- {ea_base, Base} ->
- [mk_modrm(2#00, RO, Base) | Tail];
- {ea_disp32_sindex, Disp32, SindexOpt} ->
- {Scale, Index} = enc_sindex_opt(SindexOpt),
- SIB = mk_sib(Scale, Index, 2#101),
- MODRM = mk_modrm(2#00, RO, 2#100),
- [MODRM, SIB | le32(Disp32, Tail)];
- {ea_sib, SIB} ->
- [mk_modrm(2#00, RO, 2#100), enc_sib(SIB) | Tail];
- {ea_disp32, Disp32} ->
- [mk_modrm(2#00, RO, 2#101) | le32(Disp32, Tail)]
- end.
-
-encode_rm(RM, RO, Tail) ->
- case RM of
- {rm_reg, Reg} -> [mk_modrm(2#11, RO, Reg) | Tail];
- {rm_mem, EA} -> enc_ea(EA, RO, Tail)
- end.
-
-sizeof_ea(EA) ->
- case element(1, EA) of
- ea_disp32_base -> 5;
- ea_disp32_sib -> 6;
- ea_disp8_base -> 2;
- ea_disp8_sib -> 3;
- ea_base -> 1;
- ea_disp32_sindex -> 6;
- ea_sib -> 2;
- ea_disp32 -> 5
- end.
-
-sizeof_rm(RM) ->
- case RM of
- {rm_reg, _} -> 1;
- {rm_mem, EA} -> sizeof_ea(EA)
- end.
-
-%%% Floating point stack positions
-
--define(ST0, 2#000).
--define(ST1, 2#001).
--define(ST2, 2#010).
--define(ST3, 2#011).
--define(ST4, 2#100).
--define(ST5, 2#101).
--define(ST6, 2#110).
--define(ST7, 2#111).
-
-st(0) -> ?ST0;
-st(1) -> ?ST1;
-st(2) -> ?ST2;
-st(3) -> ?ST3;
-st(4) -> ?ST4;
-st(5) -> ?ST5;
-st(6) -> ?ST6;
-st(7) -> ?ST7.
-
-
-%%% Instructions
-%%%
-%%% Insn ::= {Op,Opnds}
-%%% Opnds ::= {Opnd1,...,Opndn} (n >= 0)
-%%% Opnd ::= eax | ax | al | 1 | cl
-%%% | {imm32,Imm32} | {imm16,Imm16} | {imm8,Imm8}
-%%% | {rm32,RM32} | {rm16,RM16} | {rm8,RM8}
-%%% | {rel32,Rel32} | {rel8,Rel8}
-%%% | {moffs32,Moffs32} | {moffs16,Moffs16} | {moffs8,Moffs8}
-%%% | {cc,CC}
-%%% | {reg32,Reg32} | {reg16,Reg16} | {reg8,Reg8}
-%%% | {ea,EA}
-
--define(PFX_OPND, 16#66).
-
-arith_binop_encode(SubOpcode, Opnds) ->
- %% add, or, adc, sbb, and, sub, xor, cmp
- case Opnds of
- {eax, {imm32,Imm32}} ->
- [16#05 bor (SubOpcode bsl 3) | le32(Imm32, [])];
- {{rm32,RM32}, {imm32,Imm32}} ->
- [16#81 | encode_rm(RM32, SubOpcode, le32(Imm32, []))];
- {{rm32,RM32}, {imm8,Imm8}} ->
- [16#83 | encode_rm(RM32, SubOpcode, [Imm8])];
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#01 bor (SubOpcode bsl 3) | encode_rm(RM32, Reg32, [])];
- {{reg32,Reg32}, {rm32,RM32}} ->
- [16#03 bor (SubOpcode bsl 3) | encode_rm(RM32, Reg32, [])]
- end.
-
-arith_binop_sizeof(Opnds) ->
- %% add, or, adc, sbb, and, sub, xor, cmp
- case Opnds of
- {eax, {imm32,_}} ->
- 1 + 4;
- {{rm32,RM32}, {imm32,_}} ->
- 1 + sizeof_rm(RM32) + 4;
- {{rm32,RM32}, {imm8,_}} ->
- 1 + sizeof_rm(RM32) + 1;
- {{rm32,RM32}, {reg32,_}} ->
- 1 + sizeof_rm(RM32);
- {{reg32,_}, {rm32,RM32}} ->
- 1 + sizeof_rm(RM32)
- end.
-
-bs_op_encode(Opcode, {{reg32,Reg32}, {rm32,RM32}}) -> % bsf, bsr
- [16#0F, Opcode | encode_rm(RM32, Reg32, [])].
-
-bs_op_sizeof({{reg32,_}, {rm32,RM32}}) -> % bsf, bsr
- 2 + sizeof_rm(RM32).
-
-bswap_encode({{reg32,Reg32}}) ->
- [16#0F, 16#C8 bor Reg32].
-
-bswap_sizeof({{reg32,_}}) ->
- 2.
-
-bt_op_encode(SubOpcode, Opnds) -> % bt, btc, btr, bts
- case Opnds of
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#0F, 16#A3 bor (SubOpcode bsl 3) | encode_rm(RM32, Reg32, [])];
- {{rm32,RM32}, {imm8,Imm8}} ->
- [16#0F, 16#BA | encode_rm(RM32, SubOpcode, [Imm8])]
- end.
-
-bt_op_sizeof(Opnds) -> % bt, btc, btr, bts
- case Opnds of
- {{rm32,RM32}, {reg32,_}} ->
- 2 + sizeof_rm(RM32);
- {{rm32,RM32}, {imm8,_}} ->
- 2 + sizeof_rm(RM32) + 1
- end.
-
-call_encode(Opnds) ->
- case Opnds of
- {{rel32,Rel32}} ->
- [16#E8 | le32(Rel32, [])];
- {{rm32,RM32}} ->
- [16#FF | encode_rm(RM32, 2#010, [])]
- end.
-
-call_sizeof(Opnds) ->
- case Opnds of
- {{rel32,_}} ->
- 1 + 4;
- {{rm32,RM32}} ->
- 1 + sizeof_rm(RM32)
- end.
-
-cbw_encode({}) ->
- [?PFX_OPND, 16#98].
-
-cbw_sizeof({}) ->
- 2.
-
-nullary_op_encode(Opcode, {}) ->
- %% cdq, clc, cld, cmc, cwde, into, leave, nop, prefix_fs, stc, std
- [Opcode].
-
-nullary_op_sizeof({}) ->
- %% cdq, clc, cld, cmc, cwde, into, leave, nop, prefix_fs, stc, std
- 1.
-
-cmovcc_encode({{cc,CC}, {reg32,Reg32}, {rm32,RM32}}) ->
- [16#0F, 16#40 bor CC | encode_rm(RM32, Reg32, [])].
-
-cmovcc_sizeof({{cc,_}, {reg32,_}, {rm32,RM32}}) ->
- 2 + sizeof_rm(RM32).
-
-incdec_encode(SubOpcode, Opnds) -> % SubOpcode is either 0 or 1
- case Opnds of
- {{rm32,RM32}} ->
- [16#FF | encode_rm(RM32, SubOpcode, [])];
- {{reg32,Reg32}} ->
- [16#40 bor (SubOpcode bsl 3) bor Reg32]
- end.
-
-incdec_sizeof(Opnds) ->
- case Opnds of
- {{rm32,RM32}} ->
- 1 + sizeof_rm(RM32);
- {{reg32,_}} ->
- 1
- end.
-
-arith_unop_encode(Opcode, {{rm32,RM32}}) -> % div, idiv, mul, neg, not
- [16#F7 | encode_rm(RM32, Opcode, [])].
-
-arith_unop_sizeof({{rm32,RM32}}) -> % div, idiv, mul, neg, not
- 1 + sizeof_rm(RM32).
-
-enter_encode({{imm16,Imm16}, {imm8,Imm8}}) ->
- [16#C8 | le16(Imm16, [Imm8])].
-
-enter_sizeof({{imm16,_}, {imm8,_}}) ->
- 1 + 2 + 1.
-
-imul_encode(Opnds) ->
- case Opnds of
- {{rm32,RM32}} -> % <edx,eax> *= rm32
- [16#F7 | encode_rm(RM32, 2#101, [])];
- {{reg32,Reg32}, {rm32,RM32}} -> % reg *= rm32
- [16#0F, 16#AF | encode_rm(RM32, Reg32, [])];
- {{reg32,Reg32}, {rm32,RM32}, {imm8,Imm8}} -> % reg := rm32 * sext(imm8)
- [16#6B | encode_rm(RM32, Reg32, [Imm8])];
- {{reg32,Reg32}, {rm32,RM32}, {imm32,Imm32}} -> % reg := rm32 * imm32
- [16#69 | encode_rm(RM32, Reg32, le32(Imm32, []))]
- end.
-
-imul_sizeof(Opnds) ->
- case Opnds of
- {{rm32,RM32}} ->
- 1 + sizeof_rm(RM32);
- {{reg32,_}, {rm32,RM32}} ->
- 2 + sizeof_rm(RM32);
- {{reg32,_}, {rm32,RM32}, {imm8,_}} ->
- 1 + sizeof_rm(RM32) + 1;
- {{reg32,_}, {rm32,RM32}, {imm32,_}} ->
- 1 + sizeof_rm(RM32) + 4
- end.
-
-jcc_encode(Opnds) ->
- case Opnds of
- {{cc,CC}, {rel8,Rel8}} ->
- [16#70 bor CC, Rel8];
- {{cc,CC}, {rel32,Rel32}} ->
- [16#0F, 16#80 bor CC | le32(Rel32, [])]
- end.
-
-jcc_sizeof(Opnds) ->
- case Opnds of
- {{cc,_}, {rel8,_}} ->
- 2;
- {{cc,_}, {rel32,_}} ->
- 2 + 4
- end.
-
-jmp8_op_encode(Opcode, {{rel8,Rel8}}) -> % jecxz, loop, loope, loopne
- [Opcode, Rel8].
-
-jmp8_op_sizeof({{rel8,_}}) -> % jecxz, loop, loope, loopne
- 2.
-
-jmp_encode(Opnds) ->
- case Opnds of
- {{rel8,Rel8}} ->
- [16#EB, Rel8];
- {{rel32,Rel32}} ->
- [16#E9 | le32(Rel32, [])];
- {{rm32,RM32}} ->
- [16#FF | encode_rm(RM32, 2#100, [])]
- end.
-
-jmp_sizeof(Opnds) ->
- case Opnds of
- {{rel8,_}} ->
- 2;
- {{rel32,_}} ->
- 1 + 4;
- {{rm32,RM32}} ->
- 1 + sizeof_rm(RM32)
- end.
-
-lea_encode({{reg32,Reg32}, {ea,EA}}) ->
- [16#8D | enc_ea(EA, Reg32, [])].
-
-lea_sizeof({{reg32,_}, {ea,EA}}) ->
- 1 + sizeof_ea(EA).
-
-mov_encode(Opnds) ->
- case Opnds of
- {{rm8,RM8}, {reg8,Reg8}} ->
- [16#88 | encode_rm(RM8, Reg8, [])];
- {{rm16,RM16}, {reg16,Reg16}} ->
- [?PFX_OPND, 16#89 | encode_rm(RM16, Reg16, [])];
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#89 | encode_rm(RM32, Reg32, [])];
- {{reg8,Reg8}, {rm8,RM8}} ->
- [16#8A | encode_rm(RM8, Reg8, [])];
- {{reg16,Reg16}, {rm16,RM16}} ->
- [?PFX_OPND, 16#8B | encode_rm(RM16, Reg16, [])];
- {{reg32,Reg32}, {rm32,RM32}} ->
- [16#8B | encode_rm(RM32, Reg32, [])];
- {al, {moffs8,Moffs8}} ->
- [16#A0 | le32(Moffs8, [])];
- {ax, {moffs16,Moffs16}} ->
- [?PFX_OPND, 16#A1 | le32(Moffs16, [])];
- {eax, {moffs32,Moffs32}} ->
- [16#A1 | le32(Moffs32, [])];
- {{moffs8,Moffs8}, al} ->
- [16#A2 | le32(Moffs8, [])];
- {{moffs16,Moffs16}, ax} ->
- [?PFX_OPND, 16#A3 | le32(Moffs16, [])];
- {{moffs32,Moffs32}, eax} ->
- [16#A3 | le32(Moffs32, [])];
- {{reg8,Reg8}, {imm8,Imm8}} ->
- [16#B0 bor Reg8, Imm8];
- {{reg16,Reg16}, {imm16,Imm16}} ->
- [?PFX_OPND, 16#B8 bor Reg16 | le16(Imm16, [])];
- {{reg32,Reg32}, {imm32,Imm32}} ->
- [16#B8 bor Reg32 | le32(Imm32, [])];
- {{rm8,RM8}, {imm8,Imm8}} ->
- [16#C6 | encode_rm(RM8, 2#000, [Imm8])];
- {{rm16,RM16}, {imm16,Imm16}} ->
- [?PFX_OPND, 16#C7 | encode_rm(RM16, 2#000, le16(Imm16, []))];
- {{rm32,RM32}, {imm32,Imm32}} ->
- [16#C7 | encode_rm(RM32, 2#000, le32(Imm32, []))]
- end.
-
-mov_sizeof(Opnds) ->
- case Opnds of
- {{rm8,RM8}, {reg8,_}} ->
- 1 + sizeof_rm(RM8);
- {{rm16,RM16}, {reg16,_}} ->
- 2 + sizeof_rm(RM16);
- {{rm32,RM32}, {reg32,_}} ->
- 1 + sizeof_rm(RM32);
- {{reg8,_}, {rm8,RM8}} ->
- 1 + sizeof_rm(RM8);
- {{reg16,_}, {rm16,RM16}} ->
- 2 + sizeof_rm(RM16);
- {{reg32,_}, {rm32,RM32}} ->
- 1 + sizeof_rm(RM32);
- {al, {moffs8,_}} ->
- 1 + 4;
- {ax, {moffs16,_}} ->
- 2 + 4;
- {eax, {moffs32,_}} ->
- 1 + 4;
- {{moffs8,_}, al} ->
- 1 + 4;
- {{moffs16,_}, ax} ->
- 2 + 4;
- {{moffs32,_}, eax} ->
- 1 + 4;
- {{reg8,_}, {imm8,_}} ->
- 2;
- {{reg16,_}, {imm16,_}} ->
- 2 + 2;
- {{reg32,_}, {imm32,_}} ->
- 1 + 4;
- {{rm8,RM8}, {imm8,_}} ->
- 1 + sizeof_rm(RM8) + 1;
- {{rm16,RM16}, {imm16,_}} ->
- 2 + sizeof_rm(RM16) + 2;
- {{rm32,RM32}, {imm32,_}} ->
- 1 + sizeof_rm(RM32) + 4
- end.
-
-movx_op_encode(Opcode, Opnds) -> % movsx, movzx
- case Opnds of
- {{reg16,Reg16}, {rm8,RM8}} ->
- [?PFX_OPND, 16#0F, Opcode | encode_rm(RM8, Reg16, [])];
- {{reg32,Reg32}, {rm8,RM8}} ->
- [16#0F, Opcode | encode_rm(RM8, Reg32, [])];
- {{reg32,Reg32}, {rm16,RM16}} ->
- [16#0F, Opcode bor 1 | encode_rm(RM16, Reg32, [])]
- end.
-
-movx_op_sizeof(Opnds) ->
- case Opnds of
- {{reg16,_}, {rm8,RM8}} ->
- 3 + sizeof_rm(RM8);
- {{reg32,_}, {rm8,RM8}} ->
- 2 + sizeof_rm(RM8);
- {{reg32,_}, {rm16,RM16}} ->
- 2 + sizeof_rm(RM16)
- end.
-
-pop_encode(Opnds) ->
- case Opnds of
- {{rm32,RM32}} ->
- [16#8F | encode_rm(RM32, 2#000, [])];
- {{reg32,Reg32}} ->
- [16#58 bor Reg32]
- end.
-
-pop_sizeof(Opnds) ->
- case Opnds of
- {{rm32,RM32}} ->
- 1 + sizeof_rm(RM32);
- {{reg32,_}} ->
- 1
- end.
-
-push_encode(Opnds) ->
- case Opnds of
- {{rm32,RM32}} ->
- [16#FF | encode_rm(RM32, 2#110, [])];
- {{reg32,Reg32}} ->
- [16#50 bor Reg32];
- {{imm8,Imm8}} -> % sign-extended
- [16#6A, Imm8];
- {{imm32,Imm32}} ->
- [16#68 | le32(Imm32, [])]
- end.
-
-push_sizeof(Opnds) ->
- case Opnds of
- {{rm32,RM32}} ->
- 1 + sizeof_rm(RM32);
- {{reg32,_}} ->
- 1;
- {{imm8,_}} ->
- 2;
- {{imm32,_}} ->
- 1 + 4
- end.
-
-shift_op_encode(SubOpcode, Opnds) -> % rcl, rcr, rol, ror, sar, shl, shr
- case Opnds of
- {{rm32,RM32}, 1} ->
- [16#D1 | encode_rm(RM32, SubOpcode, [])];
- {{rm32,RM32}, cl} ->
- [16#D3 | encode_rm(RM32, SubOpcode, [])];
- {{rm32,RM32}, {imm8,Imm8}} ->
- [16#C1 | encode_rm(RM32, SubOpcode, [Imm8])];
- {{rm16,RM16}, {imm8,Imm8}} ->
- [?PFX_OPND, 16#C1 | encode_rm(RM16, SubOpcode, [Imm8])]
- end.
-
-shift_op_sizeof(Opnds) -> % rcl, rcr, rol, ror, sar, shl, shr
- case Opnds of
- {{rm32,RM32}, 1} ->
- 1 + sizeof_rm(RM32);
- {{rm32,RM32}, cl} ->
- 1 + sizeof_rm(RM32);
- {{rm32,RM32}, {imm8,_Imm8}} ->
- 1 + sizeof_rm(RM32) + 1;
- {{rm16,RM16}, {imm8,_Imm8}} ->
- 1 + 1 + sizeof_rm(RM16) + 1
- end.
-
-ret_encode(Opnds) ->
- case Opnds of
- {} ->
- [16#C3];
- {{imm16,Imm16}} ->
- [16#C2 | le16(Imm16, [])]
- end.
-
-ret_sizeof(Opnds) ->
- case Opnds of
- {} ->
- 1;
- {{imm16,_}} ->
- 1 + 2
- end.
-
-setcc_encode({{cc,CC}, {rm8,RM8}}) ->
- [16#0F, 16#90 bor CC | encode_rm(RM8, 2#000, [])].
-
-setcc_sizeof({{cc,_}, {rm8,RM8}}) ->
- 2 + sizeof_rm(RM8).
-
-shd_op_encode(Opcode, Opnds) ->
- case Opnds of
- {{rm32,RM32}, {reg32,Reg32}, {imm8,Imm8}} ->
- [16#0F, Opcode | encode_rm(RM32, Reg32, [Imm8])];
- {{rm32,RM32}, {reg32,Reg32}, cl} ->
- [16#0F, Opcode bor 1 | encode_rm(RM32, Reg32, [])]
- end.
-
-shd_op_sizeof(Opnds) ->
- case Opnds of
- {{rm32,RM32}, {reg32,_}, {imm8,_}} ->
- 2 + sizeof_rm(RM32) + 1;
- {{rm32,RM32}, {reg32,_}, cl} ->
- 2 + sizeof_rm(RM32)
- end.
-
-test_encode(Opnds) ->
- case Opnds of
- {al, {imm8,Imm8}} ->
- [16#A8, Imm8];
- {ax, {imm16,Imm16}} ->
- [?PFX_OPND, 16#A9 | le16(Imm16, [])];
- {eax, {imm32,Imm32}} ->
- [16#A9 | le32(Imm32, [])];
- {{rm8,RM8}, {imm8,Imm8}} ->
- [16#F6 | encode_rm(RM8, 2#000, [Imm8])];
- {{rm16,RM16}, {imm16,Imm16}} ->
- [?PFX_OPND, 16#F7 | encode_rm(RM16, 2#000, le16(Imm16, []))];
- {{rm32,RM32}, {imm32,Imm32}} ->
- [16#F7 | encode_rm(RM32, 2#000, le32(Imm32, []))];
- {{rm32,RM32}, {reg32,Reg32}} ->
- [16#85 | encode_rm(RM32, Reg32, [])]
- end.
-
-test_sizeof(Opnds) ->
- case Opnds of
- {al, {imm8,_}} ->
- 1 + 1;
- {ax, {imm16,_}} ->
- 2 + 2;
- {eax, {imm32,_}} ->
- 1 + 4;
- {{rm8,RM8}, {imm8,_}} ->
- 1 + sizeof_rm(RM8) + 1;
- {{rm16,RM16}, {imm16,_}} ->
- 2 + sizeof_rm(RM16) + 2;
- {{rm32,RM32}, {imm32,_}} ->
- 1 + sizeof_rm(RM32) + 4;
- {{rm32,RM32}, {reg32,_}} ->
- 1 + sizeof_rm(RM32)
- end.
-
-fild_encode(Opnds) ->
- %% The operand cannot be a register!
- {{rm32, RM32}} = Opnds,
- [16#DB | encode_rm(RM32, 2#000, [])].
-
-fild_sizeof(Opnds) ->
- {{rm32, RM32}} = Opnds,
- 1 + sizeof_rm(RM32).
-
-fld_encode(Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DD | encode_rm(RM64fp, 2#000, [])];
- {{fpst, St}} ->
- [16#D9, 16#C0 bor st(St)]
- end.
-
-fld_sizeof(Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- 1 + sizeof_rm(RM64fp);
- {{fpst, _}} ->
- 2
- end.
-
-fp_comm_arith_encode(OpCode, Opnds) ->
- %% fadd, fmul
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DC | encode_rm(RM64fp, OpCode, [])];
- {{fpst,0}, {fpst,St}} ->
- [16#D8, (16#C0 bor (OpCode bsl 3)) bor st(St)];
- {{fpst,St}, {fpst,0}} ->
- [16#DC, (16#C0 bor (OpCode bsl 3)) bor st(St)]
- end.
-
-fp_comm_arith_pop_encode(OpCode, Opnds) ->
- %% faddp, fmulp
- case Opnds of
- [] ->
- [16#DE, 16#C0 bor (OpCode bsl 3) bor st(1)];
- {{fpst,St},{fpst,0}} ->
- [16#DE, 16#C0 bor (OpCode bsl 3) bor st(St)]
- end.
-
-fp_arith_encode(OpCode, Opnds) ->
- %% fdiv, fsub
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DC | encode_rm(RM64fp, OpCode, [])];
- {{fpst,0}, {fpst,St}} ->
- OpCode0 = OpCode band 2#110,
- [16#D8, 16#C0 bor (OpCode0 bsl 3) bor st(St)];
- {{fpst,St}, {fpst,0}} ->
- OpCode0 = OpCode bor 1,
- [16#DC, 16#C0 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-fp_arith_pop_encode(OpCode, Opnds) ->
- %% fdivp, fsubp
- OpCode0 = OpCode bor 1,
- case Opnds of
- [] ->
- [16#DE, 16#C8 bor (OpCode0 bsl 3) bor st(1)];
- {{fpst,St}, {fpst,0}} ->
- [16#DE, 16#C8 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-fp_arith_rev_encode(OpCode, Opnds) ->
- %% fdivr, fsubr
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DC | encode_rm(RM64fp, OpCode, [])];
- {{fpst,0}, {fpst,St}} ->
- OpCode0 = OpCode bor 1,
- [16#D8, 16#C0 bor (OpCode0 bsl 3) bor st(St)];
- {{fpst,St}, {fpst,0}} ->
- OpCode0 = OpCode band 2#110,
- [16#DC, 16#C0 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-fp_arith_rev_pop_encode(OpCode, Opnds) ->
- %% fdivrp, fsubrp
- OpCode0 = OpCode band 2#110,
- case Opnds of
- [] ->
- [16#DE, 16#C0 bor (OpCode0 bsl 3) bor st(1)];
- {{fpst,St}, {fpst, 0}} ->
- [16#DE, 16#C0 bor (OpCode0 bsl 3) bor st(St)]
- end.
-
-fp_arith_sizeof(Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- 1 + sizeof_rm(RM64fp);
- {{fpst,0}, {fpst,_}} ->
- 2;
- {{fpst,_}, {fpst,0}} ->
- 2
- end.
-
-fst_encode(OpCode, Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- [16#DD | encode_rm(RM64fp, OpCode, [])];
- {{fpst, St}} ->
- [16#DD, 16#C0 bor (OpCode bsl 3) bor st(St)]
- end.
-
-fst_sizeof(Opnds) ->
- case Opnds of
- {{rm64fp, RM64fp}} ->
- 1 + sizeof_rm(RM64fp);
- {{fpst, _}} ->
- 2
- end.
-
-fchs_encode() ->
- [16#D9, 16#E0].
-fchs_sizeof() ->
- 2.
-
-ffree_encode({{fpst, St}})->
- [16#DD, 16#C0 bor st(St)].
-ffree_sizeof() ->
- 2.
-
-fwait_encode() ->
- [16#9B].
-fwait_sizeof() ->
- 1.
-
-fxch_encode(Opnds) ->
- case Opnds of
- [] ->
- [16#D9, 16#C8 bor st(1)];
- {{fpst, St}} ->
- [16#D9, 16#C8 bor st(St)]
- end.
-fxch_sizeof() ->
- 2.
-
-insn_encode(Op, Opnds, Offset) ->
- Bytes = insn_encode_internal(Op, Opnds),
- case has_relocs(Bytes) of
- false -> % the common case
- {Bytes, []};
- _ ->
- fix_relocs(Bytes, Offset, [], [])
- end.
-
-has_relocs([{le32,_,_}|_]) -> true;
-has_relocs([_|Bytes]) -> has_relocs(Bytes);
-has_relocs([]) -> false.
-
-fix_relocs([{le32,Tag,Val}|Bytes], Offset, Code, Relocs) ->
- fix_relocs(Bytes, Offset+4,
- [16#00, 16#00, 16#00, 16#00 | Code],
- [{Tag,Offset,Val}|Relocs]);
-fix_relocs([Byte|Bytes], Offset, Code, Relocs) ->
- fix_relocs(Bytes, Offset+1, [Byte|Code], Relocs);
-fix_relocs([], _Offset, Code, Relocs) ->
- {lists:reverse(Code), lists:reverse(Relocs)}.
-
-insn_encode_internal(Op, Opnds) ->
- case Op of
- 'adc' -> arith_binop_encode(2#010, Opnds);
- 'add' -> arith_binop_encode(2#000, Opnds);
- 'and' -> arith_binop_encode(2#100, Opnds);
- 'bsf' -> bs_op_encode(16#BC, Opnds);
- 'bsr' -> bs_op_encode(16#BD, Opnds);
- 'bswap' -> bswap_encode(Opnds);
- 'bt' -> bt_op_encode(2#100, Opnds);
- 'btc' -> bt_op_encode(2#111, Opnds);
- 'btr' -> bt_op_encode(2#110, Opnds);
- 'bts' -> bt_op_encode(2#101, Opnds);
- 'call' -> call_encode(Opnds);
- 'cbw' -> cbw_encode(Opnds);
- 'cdq' -> nullary_op_encode(16#99, Opnds);
- 'clc' -> nullary_op_encode(16#F8, Opnds);
- 'cld' -> nullary_op_encode(16#FC, Opnds);
- 'cmc' -> nullary_op_encode(16#F5, Opnds);
- 'cmovcc' -> cmovcc_encode(Opnds);
- 'cmp' -> arith_binop_encode(2#111, Opnds);
- 'cwde' -> nullary_op_encode(16#98, Opnds);
- 'dec' -> incdec_encode(2#001, Opnds);
- 'div' -> arith_unop_encode(2#110, Opnds);
- 'enter' -> enter_encode(Opnds);
- 'fadd' -> fp_comm_arith_encode(2#000, Opnds);
- 'faddp' -> fp_comm_arith_pop_encode(2#000, Opnds);
- 'fchs' -> fchs_encode();
- 'fdiv' -> fp_arith_encode(2#110, Opnds);
- 'fdivp' -> fp_arith_pop_encode(2#110, Opnds);
- 'fdivr' -> fp_arith_rev_encode(2#111, Opnds);
- 'fdivrp' -> fp_arith_rev_pop_encode(2#111, Opnds);
- 'ffree' -> ffree_encode(Opnds);
- 'fild' -> fild_encode(Opnds);
- 'fld' -> fld_encode(Opnds);
- 'fmul' -> fp_comm_arith_encode(2#001, Opnds);
- 'fmulp' -> fp_comm_arith_pop_encode(2#001, Opnds);
- 'fst' -> fst_encode(2#010, Opnds);
- 'fstp' -> fst_encode(2#011, Opnds);
- 'fsub' -> fp_arith_encode(2#100, Opnds);
- 'fsubp' -> fp_arith_pop_encode(2#100, Opnds);
- 'fsubr' -> fp_arith_rev_encode(2#101, Opnds);
- 'fsubrp' -> fp_arith_rev_pop_encode(2#101, Opnds);
- 'fwait' -> fwait_encode();
- 'fxch' -> fxch_encode(Opnds);
- 'idiv' -> arith_unop_encode(2#111, Opnds);
- 'imul' -> imul_encode(Opnds);
- 'inc' -> incdec_encode(2#000, Opnds);
- 'into' -> nullary_op_encode(16#CE, Opnds);
- 'jcc' -> jcc_encode(Opnds);
- 'jecxz' -> jmp8_op_encode(16#E3, Opnds);
- 'jmp' -> jmp_encode(Opnds);
- 'lea' -> lea_encode(Opnds);
- 'leave' -> nullary_op_encode(16#C9, Opnds);
- 'loop' -> jmp8_op_encode(16#E2, Opnds);
- 'loope' -> jmp8_op_encode(16#E1, Opnds);
- 'loopne' -> jmp8_op_encode(16#E0, Opnds);
- 'mov' -> mov_encode(Opnds);
- 'movsx' -> movx_op_encode(16#BE, Opnds);
- 'movzx' -> movx_op_encode(16#B6, Opnds);
- 'mul' -> arith_unop_encode(2#100, Opnds);
- 'neg' -> arith_unop_encode(2#011, Opnds);
- 'nop' -> nullary_op_encode(16#90, Opnds);
- 'not' -> arith_unop_encode(2#010, Opnds);
- 'or' -> arith_binop_encode(2#001, Opnds);
- 'pop' -> pop_encode(Opnds);
- 'prefix_fs' -> nullary_op_encode(16#64, Opnds);
- 'push' -> push_encode(Opnds);
- 'rcl' -> shift_op_encode(2#010, Opnds);
- 'rcr' -> shift_op_encode(2#011, Opnds);
- 'ret' -> ret_encode(Opnds);
- 'rol' -> shift_op_encode(2#000, Opnds);
- 'ror' -> shift_op_encode(2#001, Opnds);
- 'sar' -> shift_op_encode(2#111, Opnds);
- 'sbb' -> arith_binop_encode(2#011, Opnds);
- 'setcc' -> setcc_encode(Opnds);
- 'shl' -> shift_op_encode(2#100, Opnds);
- 'shld' -> shd_op_encode(16#A4, Opnds);
- 'shr' -> shift_op_encode(2#101, Opnds);
- 'shrd' -> shd_op_encode(16#AC, Opnds);
- 'stc' -> nullary_op_encode(16#F9, Opnds);
- 'std' -> nullary_op_encode(16#FD, Opnds);
- 'sub' -> arith_binop_encode(2#101, Opnds);
- 'test' -> test_encode(Opnds);
- 'xor' -> arith_binop_encode(2#110, Opnds);
- _ -> exit({?MODULE,insn_encode,Op})
- end.
-
-insn_sizeof(Op, Opnds) ->
- case Op of
- 'adc' -> arith_binop_sizeof(Opnds);
- 'add' -> arith_binop_sizeof(Opnds);
- 'and' -> arith_binop_sizeof(Opnds);
- 'bsf' -> bs_op_sizeof(Opnds);
- 'bsr' -> bs_op_sizeof(Opnds);
- 'bswap' -> bswap_sizeof(Opnds);
- 'bt' -> bt_op_sizeof(Opnds);
- 'btc' -> bt_op_sizeof(Opnds);
- 'btr' -> bt_op_sizeof(Opnds);
- 'bts' -> bt_op_sizeof(Opnds);
- 'call' -> call_sizeof(Opnds);
- 'cbw' -> cbw_sizeof(Opnds);
- 'cdq' -> nullary_op_sizeof(Opnds);
- 'clc' -> nullary_op_sizeof(Opnds);
- 'cld' -> nullary_op_sizeof(Opnds);
- 'cmc' -> nullary_op_sizeof(Opnds);
- 'cmovcc' -> cmovcc_sizeof(Opnds);
- 'cmp' -> arith_binop_sizeof(Opnds);
- 'cwde' -> nullary_op_sizeof(Opnds);
- 'dec' -> incdec_sizeof(Opnds);
- 'div' -> arith_unop_sizeof(Opnds);
- 'enter' -> enter_sizeof(Opnds);
- 'fadd' -> fp_arith_sizeof(Opnds);
- 'faddp' -> fp_arith_sizeof(Opnds);
- 'fchs' -> fchs_sizeof();
- 'fdiv' -> fp_arith_sizeof(Opnds);
- 'fdivp' -> fp_arith_sizeof(Opnds);
- 'fdivr' -> fp_arith_sizeof(Opnds);
- 'fdivrp' -> fp_arith_sizeof(Opnds);
- 'ffree' -> ffree_sizeof();
- 'fild' -> fild_sizeof(Opnds);
- 'fld' -> fld_sizeof(Opnds);
- 'fmul' -> fp_arith_sizeof(Opnds);
- 'fmulp' -> fp_arith_sizeof(Opnds);
- 'fst' -> fst_sizeof(Opnds);
- 'fstp' -> fst_sizeof(Opnds);
- 'fsub' -> fp_arith_sizeof(Opnds);
- 'fsubp' -> fp_arith_sizeof(Opnds);
- 'fsubr' -> fp_arith_sizeof(Opnds);
- 'fsubrp' -> fp_arith_sizeof(Opnds);
- 'fwait' -> fwait_sizeof();
- 'fxch' -> fxch_sizeof();
- 'idiv' -> arith_unop_sizeof(Opnds);
- 'imul' -> imul_sizeof(Opnds);
- 'inc' -> incdec_sizeof(Opnds);
- 'into' -> nullary_op_sizeof(Opnds);
- 'jcc' -> jcc_sizeof(Opnds);
- 'jecxz' -> jmp8_op_sizeof(Opnds);
- 'jmp' -> jmp_sizeof(Opnds);
- 'lea' -> lea_sizeof(Opnds);
- 'leave' -> nullary_op_sizeof(Opnds);
- 'loop' -> jmp8_op_sizeof(Opnds);
- 'loope' -> jmp8_op_sizeof(Opnds);
- 'loopne' -> jmp8_op_sizeof(Opnds);
- 'mov' -> mov_sizeof(Opnds);
- 'movsx' -> movx_op_sizeof(Opnds);
- 'movzx' -> movx_op_sizeof(Opnds);
- 'mul' -> arith_unop_sizeof(Opnds);
- 'neg' -> arith_unop_sizeof(Opnds);
- 'nop' -> nullary_op_sizeof(Opnds);
- 'not' -> arith_unop_sizeof(Opnds);
- 'or' -> arith_binop_sizeof(Opnds);
- 'pop' -> pop_sizeof(Opnds);
- 'prefix_fs' -> nullary_op_sizeof(Opnds);
- 'push' -> push_sizeof(Opnds);
- 'rcl' -> shift_op_sizeof(Opnds);
- 'rcr' -> shift_op_sizeof(Opnds);
- 'ret' -> ret_sizeof(Opnds);
- 'rol' -> shift_op_sizeof(Opnds);
- 'ror' -> shift_op_sizeof(Opnds);
- 'sar' -> shift_op_sizeof(Opnds);
- 'sbb' -> arith_binop_sizeof(Opnds);
- 'setcc' -> setcc_sizeof(Opnds);
- 'shl' -> shift_op_sizeof(Opnds);
- 'shld' -> shd_op_sizeof(Opnds);
- 'shr' -> shift_op_sizeof(Opnds);
- 'shrd' -> shd_op_sizeof(Opnds);
- 'stc' -> nullary_op_sizeof(Opnds);
- 'std' -> nullary_op_sizeof(Opnds);
- 'sub' -> arith_binop_sizeof(Opnds);
- 'test' -> test_sizeof(Opnds);
- 'xor' -> arith_binop_sizeof(Opnds);
- _ -> exit({?MODULE,insn_sizeof,Op})
- end.
-
-%%=====================================================================
-%% testing interface
-%%=====================================================================
-
--ifdef(DO_HIPE_X86_ENCODE_TEST).
-
-say(OS, Str) ->
- file:write(OS, Str).
-
-digit16(Dig0) ->
- Dig = Dig0 band 16#F,
- if Dig >= 16#A -> $A + (Dig - 16#A);
- true -> $0 + Dig
- end.
-
-say_byte(OS, Byte) ->
- say(OS, "0x"),
- say(OS, [digit16(Byte bsr 4)]),
- say(OS, [digit16(Byte)]).
-
-init(OS) ->
- say(OS, "\t.text\n").
-
-say_bytes(OS, Byte0, Bytes0) ->
- say_byte(OS, Byte0),
- case Bytes0 of
- [] ->
- say(OS, "\n");
- [Byte1|Bytes1] ->
- say(OS, ","),
- say_bytes(OS, Byte1, Bytes1)
- end.
-
-t(OS, Op, Opnds) ->
- insn_sizeof(Op, Opnds),
- {[Byte|Bytes],[]} = insn_encode(Op, Opnds, 0),
- say(OS, "\t.byte "),
- say_bytes(OS, Byte, Bytes).
-
-dotest1(OS) ->
- init(OS),
- % exercise all rm32 types
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32(16#87654321)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_sib(sib(?ECX))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_sib(sib(?ECX,sindex(2#10,?EDI)))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sindex(16#87654321)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sindex(16#87654321,sindex(2#10,?EDI))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_base(?ECX)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp8_sib(16#03,sib(?ECX))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp8_sib(16#03,sib(?ECX,sindex(2#10,?EDI)))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp8_base(16#3,?ECX)}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sib(16#87654321,sib(?ECX))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_sib(16#87654321,sib(?ECX,sindex(2#10,?EDI)))}}),
- t(OS,lea,{{reg32,?EAX},{ea,ea_disp32_base(16#87654321,?EBP)}}),
- t(OS,call,{{rm32,rm_reg(?EAX)}}),
- t(OS,call,{{rm32,rm_mem(ea_disp32_sindex(16#87654321,sindex(2#10,?EDI)))}}),
- t(OS,call,{{rel32,-5}}),
- % default parameters for the tests below
- Word32 = 16#87654321,
- Word16 = 16#F00F,
- Word8 = 16#80,
- Imm32 = {imm32,Word32},
- Imm16 = {imm16,Word16},
- Imm8 = {imm8,Word8},
- RM32 = {rm32,rm_reg(?EDX)},
- RM16 = {rm16,rm_reg(?EDX)},
- RM8 = {rm8,rm_reg(?EDX)},
- Rel32 = {rel32,Word32},
- Rel8 = {rel8,Word8},
- Moffs32 = {moffs32,Word32},
- Moffs16 = {moffs16,Word32},
- Moffs8 = {moffs8,Word32},
- CC = {cc,?CC_G},
- Reg32 = {reg32,?EAX},
- Reg16 = {reg16,?EAX},
- Reg8 = {reg8,?AH},
- EA = {ea,ea_base(?ECX)},
- % exercise each instruction definition
- t(OS,'adc',{eax,Imm32}),
- t(OS,'adc',{RM32,Imm32}),
- t(OS,'adc',{RM32,Imm8}),
- t(OS,'adc',{RM32,Reg32}),
- t(OS,'adc',{Reg32,RM32}),
- t(OS,'add',{eax,Imm32}),
- t(OS,'add',{RM32,Imm32}),
- t(OS,'add',{RM32,Imm8}),
- t(OS,'add',{RM32,Reg32}),
- t(OS,'add',{Reg32,RM32}),
- t(OS,'and',{eax,Imm32}),
- t(OS,'and',{RM32,Imm32}),
- t(OS,'and',{RM32,Imm8}),
- t(OS,'and',{RM32,Reg32}),
- t(OS,'and',{Reg32,RM32}),
- t(OS,'bsf',{Reg32,RM32}),
- t(OS,'bsr',{Reg32,RM32}),
- t(OS,'bswap',{Reg32}),
- t(OS,'bt',{RM32,Reg32}),
- t(OS,'bt',{RM32,Imm8}),
- t(OS,'btc',{RM32,Reg32}),
- t(OS,'btc',{RM32,Imm8}),
- t(OS,'btr',{RM32,Reg32}),
- t(OS,'btr',{RM32,Imm8}),
- t(OS,'bts',{RM32,Reg32}),
- t(OS,'bts',{RM32,Imm8}),
- t(OS,'call',{Rel32}),
- t(OS,'call',{RM32}),
- t(OS,'cbw',{}),
- t(OS,'cdq',{}),
- t(OS,'clc',{}),
- t(OS,'cld',{}),
- t(OS,'cmc',{}),
- t(OS,'cmovcc',{CC,Reg32,RM32}),
- t(OS,'cmp',{eax,Imm32}),
- t(OS,'cmp',{RM32,Imm32}),
- t(OS,'cmp',{RM32,Imm8}),
- t(OS,'cmp',{RM32,Reg32}),
- t(OS,'cmp',{Reg32,RM32}),
- t(OS,'cwde',{}),
- t(OS,'dec',{RM32}),
- t(OS,'dec',{Reg32}),
- t(OS,'div',{RM32}),
- t(OS,'enter',{Imm16,{imm8,3}}),
- t(OS,'idiv',{RM32}),
- t(OS,'imul',{RM32}),
- t(OS,'imul',{Reg32,RM32}),
- t(OS,'imul',{Reg32,RM32,Imm8}),
- t(OS,'imul',{Reg32,RM32,Imm32}),
- t(OS,'inc',{RM32}),
- t(OS,'inc',{Reg32}),
- t(OS,'into',{}),
- t(OS,'jcc',{CC,Rel8}),
- t(OS,'jcc',{CC,Rel32}),
- t(OS,'jecxz',{Rel8}),
- t(OS,'jmp',{Rel8}),
- t(OS,'jmp',{Rel32}),
- t(OS,'jmp',{RM32}),
- t(OS,'lea',{Reg32,EA}),
- t(OS,'leave',{}),
- t(OS,'loop',{Rel8}),
- t(OS,'loope',{Rel8}),
- t(OS,'loopne',{Rel8}),
- t(OS,'mov',{RM8,Reg8}),
- t(OS,'mov',{RM16,Reg16}),
- t(OS,'mov',{RM32,Reg32}),
- t(OS,'mov',{Reg8,RM8}),
- t(OS,'mov',{Reg16,RM16}),
- t(OS,'mov',{Reg32,RM32}),
- t(OS,'mov',{al,Moffs8}),
- t(OS,'mov',{ax,Moffs16}),
- t(OS,'mov',{eax,Moffs32}),
- t(OS,'mov',{Moffs8,al}),
- t(OS,'mov',{Moffs16,ax}),
- t(OS,'mov',{Moffs32,eax}),
- t(OS,'mov',{Reg8,Imm8}),
- t(OS,'mov',{Reg16,Imm16}),
- t(OS,'mov',{Reg32,Imm32}),
- t(OS,'mov',{RM8,Imm8}),
- t(OS,'mov',{RM16,Imm16}),
- t(OS,'mov',{RM32,Imm32}),
- t(OS,'movsx',{Reg16,RM8}),
- t(OS,'movsx',{Reg32,RM8}),
- t(OS,'movsx',{Reg32,RM16}),
- t(OS,'movzx',{Reg16,RM8}),
- t(OS,'movzx',{Reg32,RM8}),
- t(OS,'movzx',{Reg32,RM16}),
- t(OS,'mul',{RM32}),
- t(OS,'neg',{RM32}),
- t(OS,'nop',{}),
- t(OS,'not',{RM32}),
- t(OS,'or',{eax,Imm32}),
- t(OS,'or',{RM32,Imm32}),
- t(OS,'or',{RM32,Imm8}),
- t(OS,'or',{RM32,Reg32}),
- t(OS,'or',{Reg32,RM32}),
- t(OS,'pop',{RM32}),
- t(OS,'pop',{Reg32}),
- t(OS,'push',{RM32}),
- t(OS,'push',{Reg32}),
- t(OS,'push',{Imm8}),
- t(OS,'push',{Imm32}),
- t(OS,'rcl',{RM32,1}),
- t(OS,'rcl',{RM32,cl}),
- t(OS,'rcl',{RM32,Imm8}),
- t(OS,'rcl',{RM16,Imm8}),
- t(OS,'rcr',{RM32,1}),
- t(OS,'rcr',{RM32,cl}),
- t(OS,'rcr',{RM32,Imm8}),
- t(OS,'rcr',{RM16,Imm8}),
- t(OS,'ret',{}),
- t(OS,'ret',{Imm16}),
- t(OS,'rol',{RM32,1}),
- t(OS,'rol',{RM32,cl}),
- t(OS,'rol',{RM32,Imm8}),
- t(OS,'rol',{RM16,Imm8}),
- t(OS,'ror',{RM32,1}),
- t(OS,'ror',{RM32,cl}),
- t(OS,'ror',{RM32,Imm8}),
- t(OS,'ror',{RM16,Imm8}),
- t(OS,'sar',{RM32,1}),
- t(OS,'sar',{RM32,cl}),
- t(OS,'sar',{RM32,Imm8}),
- t(OS,'sar',{RM16,Imm8}),
- t(OS,'sbb',{eax,Imm32}),
- t(OS,'sbb',{RM32,Imm32}),
- t(OS,'sbb',{RM32,Imm8}),
- t(OS,'sbb',{RM32,Reg32}),
- t(OS,'sbb',{Reg32,RM32}),
- t(OS,'setcc',{CC,RM8}),
- t(OS,'shl',{RM32,1}),
- t(OS,'shl',{RM32,cl}),
- t(OS,'shl',{RM32,Imm8}),
- t(OS,'shl',{RM16,Imm8}),
- t(OS,'shld',{RM32,Reg32,Imm8}),
- t(OS,'shld',{RM32,Reg32,cl}),
- t(OS,'shr',{RM32,1}),
- t(OS,'shr',{RM32,cl}),
- t(OS,'shr',{RM32,Imm8}),
- t(OS,'shr',{RM16,Imm8}),
- t(OS,'shrd',{RM32,Reg32,Imm8}),
- t(OS,'shrd',{RM32,Reg32,cl}),
- t(OS,'stc',{}),
- t(OS,'std',{}),
- t(OS,'sub',{eax,Imm32}),
- t(OS,'sub',{RM32,Imm32}),
- t(OS,'sub',{RM32,Imm8}),
- t(OS,'sub',{RM32,Reg32}),
- t(OS,'sub',{Reg32,RM32}),
- t(OS,'test',{al,Imm8}),
- t(OS,'test',{ax,Imm16}),
- t(OS,'test',{eax,Imm32}),
- t(OS,'test',{RM8,Imm8}),
- t(OS,'test',{RM16,Imm16}),
- t(OS,'test',{RM32,Imm32}),
- t(OS,'test',{RM32,Reg32}),
- t(OS,'xor',{eax,Imm32}),
- t(OS,'xor',{RM32,Imm32}),
- t(OS,'xor',{RM32,Imm8}),
- t(OS,'xor',{RM32,Reg32}),
- t(OS,'xor',{Reg32,RM32}),
- t(OS,'prefix_fs',{}), t(OS,'add',{{reg32,?EAX},{rm32,rm_mem(ea_disp32(16#20))}}),
- [].
-
-dotest() -> dotest1(group_leader()). % stdout == group_leader
-
-dotest(File) ->
- {ok,OS} = file:open(File, [write]),
- dotest1(OS),
- file:close(OS).
--endif.
diff --git a/lib/hipe/x86/hipe_x86_encode.txt b/lib/hipe/x86/hipe_x86_encode.txt
deleted file mode 100644
index eab732fb2d..0000000000
--- a/lib/hipe/x86/hipe_x86_encode.txt
+++ /dev/null
@@ -1,211 +0,0 @@
-hipe_x86_encode USAGE GUIDE
-Revision 0.4, 2001-10-09
-
-This document describes how to use the hipe_x86_encode.erl module.
-
-Preliminaries
--------------
-This is not a tutorial on the x86 architecture. The reader
-should be familiar with both the programming model and
-the general syntax of instructions and their operands.
-
-The hipe_x86_encode module follows the conventions in the
-"Intel Architecture Software Developer's Manual, Volume 2:
-Instruction Set Reference" document. In particular, the
-order of source and destination operands in instructions
-follows Intel's conventions: "add eax,edx" adds edx to eax.
-The GNU Assembler "gas" follows the so-called AT&T syntax
-which reverses the order of the source and destination operands.
-
-Basic Functionality
--------------------
-The hipe_x86_encode module implements the mapping from symbolic x86
-instructions to their binary representation, as lists of bytes.
-
-Instructions and operands have to match actual x86 instructions
-and operands exactly. The mapping from "abstract" instructions
-to correct x86 instructions has to be done before the instructions
-are passed to the hipe_x86_encode module. (In HiPE, this mapping
-is done by the hipe_x86_assemble module.)
-
-The hipe_x86_encode module handles arithmetic operations on 32-bit
-integers, data movement of 8, 16, and 32-bit words, and most
-control flow operations. A 32-bit address and operand size process
-mode is assumed, which is what Unix and Linux systems use.
-
-Operations and registers related to floating-point, MMX, SIMD, 3dnow!,
-or operating system control are not implemented. Segment registers
-are supported minimally: a 'prefix_fs' pseudo-instruction can be
-used to insert an FS segment register override prefix.
-
-Instruction Syntax
-------------------
-The function hipe_x86_encode:insn_encode/1 takes an instruction in
-symbolic form and translates it to its binary representation,
-as a list of bytes.
-
-Symbolic instructions are Erlang terms in the following syntax:
-
- Insn ::= {Op,Opnds}
- Op ::= (an Erlang atom)
- Opnds ::= {Opnd1,...,Opndn} (n >= 0)
- Opnd ::= eax | ax | al | 1 | cl
- | {imm32,Imm32} | {imm16,Imm16} | {imm8,Imm8}
- | {rm32,RM32} | {rm16,RM16} | {rm8,RM8}
- | {rel32,Rel32} | {rel8,Rel8}
- | {moffs32,Moffs32} | {moffs16,Moffs16} | {moffs8,Moffs8}
- | {cc,CC}
- | {reg32,Reg32} | {reg16,Reg16} | {reg8,Reg8}
- | {ea,EA}
- Imm32 ::= (a 32-bit integer; immediate value)
- Imm16 ::= (a 16-bit integer; immediate value)
- Imm8 ::= (an 8-bit integer; immediate value)
- Rel32 ::= (a 32-bit integer; jump offset)
- Rel8 ::= (an 8-bit integer; jump offset)
- Moffs32 ::= (a 32-bit integer; address of 32-bit word)
- Moffs16 ::= (a 32-bit integer; address of 16-bit word)
- Moffs8 ::= (a 32-bit integer; address of 8-bit word)
- CC ::= (a 4-bit condition code)
- Reg32 ::= (a 3-bit register number of a 32-bit register)
- Reg16 ::= (same as Reg32, but the register size is 16 bits)
- Reg8 ::= (a 3-bit register number of an 8-bit register)
- EA ::= (general operand; a memory cell)
- RM32 ::= (general operand; a 32-bit register or memory cell)
- RM16 ::= (same as RM32, but the operand size is 16 bits)
- RM8 ::= (general operand; an 8-bit register or memory cell)
-
-To construct these terms, the hipe_x86_encode module exports several
-helper functions:
-
-cc/1
- Converts an atom to a 4-bit condition code.
-
-al/0, cl/0, dl/0, bl/0, ah/0, ch/0, dh/0, bh/0
- Returns a 3-bit register number for an 8-bit register.
-
-eax/0, ecx/0, edx/0, ebx/0, esp/0, ebp/0, esi/0, edi/0
- Returns a 3-bit register number for a 32- or 16-bit register.
-
-A general operand can be a register or a memory operand.
-An x86 memory operand is expressed as an "effective address":
-
- Displacement(Base register,Index register,Scale)
-or
- [base register] + [(index register) * (scale)] + [displacement]
-
-where the base register is any of the 8 integer registers,
-the index register in any of the 8 integer registers except ESP,
-scale is 0, 1, 2, or 3 (multiply index with 1, 2, 4, or 8),
-and displacement is an 8- or 32-bit offset.
-Most components are optional.
-
-An effective address is constructed by calling one of the following
-nine functions:
-
-ea_base/1
- ea_base(Reg32), where Reg32 is not ESP or EBP,
- constructs the EA "(Reg32)", i.e. Reg32.
-ea_disp32/1
- ea_disp32(Disp32) construct the EA "Disp32"
-ea_disp32_base/2
- ea_disp32(Disp32, Reg32), where Reg32 is not ESP,
- constructs the EA "Disp32(Reg32)", i.e. Reg32+Disp32.
-ea_disp8_base/2
- This is like ea_disp32_base/2, except the displacement
- is 8 bits instead of 32 bits. The CPU will _sign-extend_
- the 8-bit displacement to 32 bits before using it.
-ea_disp32_sindex/1
- ea_disp32_sindex(Disp32) constructs the EA "Disp32",
- but uses a longer encoding than ea_disp32/1.
- Hint: Don't use this one.
-
-The last four forms use index registers with or without scaling
-factors and base registers, so-called "SIBs". To build these, call:
-
-sindex/2
- sindex(Scale, Index), where scale is 0, 1, 2, or 3, and
- Index is a 32-bit integer register except ESP, constructs
- part of a SIB representing "Index * 2^Scale".
-sib/1
- sib(Reg32) constructs a SIB containing only a base register
- and no scaled index, "(Reg32)", i.e. "Reg32".
-sib/2
- sib(Reg32, sindex(Scale, Index)) constructs a SIB
- "(Reg32,Index,Scale)", i.e. "Reg32 + (Index * 2^Scale)".
-
-ea_sib/1
- ea_sib(SIB), where SIB's base register is not EBP,
- constructs an EA which is that SIB, i.e. "(Base)" or
- "(Base,Index,Scale)".
-ea_disp32_sib/2
- ea_disp32_sib(Disp32, SIB) constructs the EA "Disp32(SIB)",
- i.e. "Base+Disp32" or "Base+(Index*2^Scale)+Disp32".
-ea_disp32_sindex/2
- ea_disp32_sindex(Disp32, Sindex) constructs the EA
- "Disp32(,Index,Scale)", i.e. "(Index*2^Scale)+Disp32".
-ea_disp8_sib/2
- This is just like ea_disp32_sib/2, except the displacement
- is 8 bits (with sign-extension).
-
-To construct a general operand, call one of these two functions:
-
-rm_reg/1
- rm_reg(Reg) constructs a general operand which is that register.
-rm_mem/1
- rm_mem(EA) constucts a general operand which is the memory
- cell addressed by EA.
-
-A symbolic instruction with name "Op" and the n operands "Opnd1"
-to "Opndn" is represented as the tuple
-
- {Op, {Opnd1, ..., Opndn}}
-
-Usage
------
-Once a symbolic instruction "Insn" has been constructed, it can be
-translated to binary by calling
-
- insn_encode(Insn)
-
-which returns a list of bytes.
-
-Since x86 instructions have varying size (as opposed to most
-RISC machines), there is also a function
-
- insn_sizeof(Insn)
-
-which returns the number of bytes the binary encoding will occupy.
-insn_sizeof(Insn) equals length(insn_encode(Insn)), but insn_sizeof
-is cheaper to compute. This is useful for two purposes: (1) when
-compiling to memory, one needs to know in advance how many bytes of
-memory to allocate for a piece of code, and (2) when computing the
-relative distance between a jump or call instruction and its target
-label.
-
-Examples
---------
-1. nop
-is constructed as
- {nop, {}}
-
-2. add eax,edx (eax := eax + edx)
-can be constructed as
- {add, {eax, {reg32, hipe_x86_encode:edx()}}}
-or as
- Reg32 = {reg32, hipe_x86_encode:eax()},
- RM32 = {rm32, hipe_x86_encode:rm_reg(hipe_x86_encode:edx())},
- {add, {Reg32, RM32}}
-
-3. mov edx,(eax) (edx := MEM[eax])
-is constructed as
- Reg32 = {reg32, hipe_x86_encode:edx()},
- RM32 = {rm32, hipe_x86_encode:rm_reg(hipe_x86_encode:eax())},
- {mov, {Reg32, RM32}}
-
-Addendum
---------
-The hipe_x86_encode.erl source code is the authoritative reference
-for the hipe_x86_encode module.
-
-Please report errors in either hipe_x86_encode.erl or this guide
-to mikpe@it.uu.se.
diff --git a/lib/hipe/x86/hipe_x86_frame.erl b/lib/hipe/x86/hipe_x86_frame.erl
deleted file mode 100644
index 558321d0c3..0000000000
--- a/lib/hipe/x86/hipe_x86_frame.erl
+++ /dev/null
@@ -1,713 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% x86 stack frame handling
-%%%
-%%% - map non-register temps to stack slots
-%%% - add explicit stack management code to prologue and epilogue,
-%%% and at calls and tailcalls
-%%%
-%%% TODO:
-%%% - Compute max stack in a pre-pass? (get rid of ref cell updates)
-%%% - Merge all_temps and defun_minframe to a single
-%%% pass, for compile-time efficiency reasons.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_FRAME, hipe_amd64_frame).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
--define(LEAF_WORDS, ?AMD64_LEAF_WORDS).
--else.
--define(HIPE_X86_FRAME, hipe_x86_frame).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_LIVENESS, hipe_x86_liveness).
--define(LEAF_WORDS, ?X86_LEAF_WORDS).
--endif.
-
--module(?HIPE_X86_FRAME).
--export([frame/2]).
--include("../x86/hipe_x86.hrl").
--include("../rtl/hipe_literals.hrl").
-
-frame(CFG0, _Options) ->
- Formals = fix_formals(hipe_x86_cfg:params(CFG0)),
- Temps0 = all_temps(CFG0, Formals),
- MinFrame = defun_minframe(CFG0),
- Temps = ensure_minframe(MinFrame, Temps0),
- Liveness = ?HIPE_X86_LIVENESS:analyse(CFG0),
- do_body(CFG0, Liveness, Formals, Temps).
-
-fix_formals(Formals) ->
- fix_formals(?HIPE_X86_REGISTERS:nr_args(), Formals).
-
-fix_formals(0, Rest) -> Rest;
-fix_formals(N, [_|Rest]) -> fix_formals(N-1, Rest);
-fix_formals(_, []) -> [].
-
-do_body(CFG0, Liveness, Formals, Temps) ->
- Context = mk_context(Liveness, Formals, Temps),
- CFG1 = do_blocks(CFG0, Context),
- do_prologue(CFG1, Context).
-
-do_blocks(CFG, Context) ->
- hipe_x86_cfg:map_bbs(fun(Lbl, BB) -> do_block(Lbl, BB, Context) end, CFG).
-
-do_block(Label, Block, Context) ->
- Liveness = context_liveness(Context),
- LiveOut = ?HIPE_X86_LIVENESS:liveout(Liveness, Label),
- Code = hipe_bb:code(Block),
- NewCode = do_block(Code, LiveOut, Context, context_framesize(Context), []),
- hipe_bb:code_update(Block, NewCode).
-
-do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) ->
- {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0),
- do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode));
-do_block([], _, Context, FPoff, RevCode) ->
- FPoff0 = context_framesize(Context),
- if FPoff =:= FPoff0 -> [];
- true -> exit({?MODULE,do_block,FPoff})
- end,
- lists:reverse(RevCode, []).
-
-do_insn(I, LiveOut, Context, FPoff) ->
- case I of
- #alu{} ->
- {[do_alu(I, Context, FPoff)], FPoff};
- #cmp{} ->
- {[do_cmp(I, Context, FPoff)], FPoff};
- #fp_unop{} ->
- {do_fp_unop(I, Context, FPoff), FPoff};
- #fp_binop{} ->
- {do_fp_binop(I, Context, FPoff), FPoff};
- #fmove{} ->
- {[do_fmove(I, Context, FPoff)], FPoff};
- #imul{} ->
- {[do_imul(I, Context, FPoff)], FPoff};
- #move{} ->
- {do_move(I, Context, FPoff), FPoff};
- #movsx{} ->
- {[do_movsx(I, Context, FPoff)], FPoff};
- #movzx{} ->
- {[do_movzx(I, Context, FPoff)], FPoff};
- #pseudo_call{} ->
- do_pseudo_call(I, LiveOut, Context, FPoff);
- #pseudo_spill_fmove{} ->
- {do_pseudo_spill_fmove(I, Context, FPoff), FPoff};
- #pseudo_spill_move{} ->
- {do_pseudo_spill_move(I, Context, FPoff), FPoff};
- #pseudo_tailcall{} ->
- {do_pseudo_tailcall(I, Context), context_framesize(Context)};
- #push{} ->
- {[do_push(I, Context, FPoff)], FPoff+word_size()};
- #ret{} ->
- {do_ret(I, Context, FPoff), context_framesize(Context)};
- #shift{} ->
- {[do_shift(I, Context, FPoff)], FPoff};
- #test{} ->
- {[do_test(I, Context, FPoff)], FPoff};
- _ -> % comment, jmp, label, pseudo_jcc, pseudo_tailcall_prepare
- {[I], FPoff}
- end.
-
-%%%
-%%% Convert any pseudo-temp operand in a binary (alu, cmp, move)
-%%% or unary (push) instruction to an explicit x86_mem operand.
-%%%
-
-do_alu(I, Context, FPoff) ->
- #alu{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I#alu{src=Src,dst=Dst}.
-
-do_cmp(I, Context, FPoff) ->
- #cmp{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I#cmp{src=Src,dst=Dst}.
-
-do_fp_unop(I, Context, FPoff) ->
- #fp_unop{arg=Arg0} = I,
- Arg = conv_opnd(Arg0, FPoff, Context),
- [I#fp_unop{arg=Arg}].
-
-do_fp_binop(I, Context, FPoff) ->
- #fp_binop{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- [I#fp_binop{src=Src,dst=Dst}].
-
-do_fmove(I0, Context, FPoff) ->
- #fmove{src=Src0,dst=Dst0} = I0,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I = I0#fmove{src=Src,dst=Dst},
- case Src =:= Dst of
- true -> []; % omit move-to-self
- false -> [I]
- end.
-
-do_pseudo_spill_fmove(I0, Context, FPoff) ->
- #pseudo_spill_fmove{src=Src0,temp=Temp0,dst=Dst0} = I0,
- Src = conv_opnd(Src0, FPoff, Context),
- Temp = conv_opnd(Temp0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- case Src =:= Dst of
- true -> []; % omit move-to-self
- false -> [#fmove{src=Src, dst=Temp}, #fmove{src=Temp, dst=Dst}]
- end.
-
-do_imul(I, Context, FPoff) ->
- #imul{src=Src0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- I#imul{src=Src}.
-
-do_move(I0, Context, FPoff) ->
- #move{src=Src0,dst=Dst0} = I0,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I = I0#move{src=Src,dst=Dst},
- case Src =:= Dst of
- true -> []; % omit move-to-self
- false -> [I]
- end.
-
-do_pseudo_spill_move(I0, Context, FPoff) ->
- #pseudo_spill_move{src=Src0,temp=Temp0,dst=Dst0} = I0,
- Src = conv_opnd(Src0, FPoff, Context),
- Temp = conv_opnd(Temp0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- case Src =:= Dst of
- true -> []; % omit move-to-self
- false -> [#move{src=Src, dst=Temp}, #move{src=Temp, dst=Dst}]
- end.
-
-do_movsx(I, Context, FPoff) ->
- #movsx{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I#movsx{src=Src,dst=Dst}.
-
-do_movzx(I, Context, FPoff) ->
- #movzx{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I#movzx{src=Src,dst=Dst}.
-
-do_push(I, Context, FPoff) ->
- #push{src=Src0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- I#push{src=Src}.
-
-do_shift(I, Context, FPoff) ->
- #shift{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I#shift{src=Src,dst=Dst}.
-
-do_test(I, Context, FPoff) ->
- #test{src=Src0,dst=Dst0} = I,
- Src = conv_opnd(Src0, FPoff, Context),
- Dst = conv_opnd(Dst0, FPoff, Context),
- I#test{src=Src,dst=Dst}.
-
-conv_opnd(Opnd, FPoff, Context) ->
- case opnd_is_pseudo(Opnd) of
- false ->
- Opnd;
- true ->
- conv_pseudo(Opnd, FPoff, Context)
- end.
-
-conv_pseudo(Temp, FPoff, Context) ->
- Off = FPoff + context_offset(Context, Temp),
- conv_pseudo(Temp, Off).
-
-conv_pseudo(Temp, Off) ->
- hipe_x86:mk_mem(mk_sp(), hipe_x86:mk_imm(Off), hipe_x86:temp_type(Temp)).
-
-%%%
-%%% Return - deallocate frame and emit 'ret $N' insn.
-%%%
-
-do_ret(_I, Context, FPoff) ->
- %% XXX: this conses up a new ret insn, ignoring the one rtl->x86 made
- adjust_sp(FPoff, [hipe_x86:mk_ret(word_size()*context_arity(Context))]).
-
-adjust_sp(N, Rest) ->
- if N =:= 0 ->
- Rest;
- true ->
- [hipe_x86:mk_alu('add', hipe_x86:mk_imm(N), mk_sp()) | Rest]
- end.
-
-%%%
-%%% Recursive calls.
-%%%
-
-do_pseudo_call(I, LiveOut, Context, FPoff0) ->
- #x86_sdesc{exnlab=ExnLab,arity=OrigArity} = hipe_x86:pseudo_call_sdesc(I),
- Fun0 = hipe_x86:pseudo_call_fun(I),
- Fun1 = conv_opnd(Fun0, FPoff0, Context),
- LiveTemps = [Temp || Temp <- LiveOut, temp_is_pseudo(Temp)],
- SDesc = mk_sdesc(ExnLab, Context, LiveTemps),
- ContLab = hipe_x86:pseudo_call_contlab(I),
- Linkage = hipe_x86:pseudo_call_linkage(I),
- CallCode = [hipe_x86:mk_pseudo_call(Fun1, SDesc, ContLab, Linkage)],
- %% +word_size() for our RA and +word_size() for callee's RA should
- %% it need to call inc_stack
- StkArity = erlang:max(0, OrigArity - ?HIPE_X86_REGISTERS:nr_args()),
- context_need_stack(Context, stack_need(FPoff0 + 2*word_size(), StkArity, Fun1)),
- ArgsBytes = word_size() * StkArity,
- {CallCode, FPoff0 - ArgsBytes}.
-
-stack_need(FPoff, StkArity, Fun) ->
- case Fun of
- #x86_prim{} -> FPoff;
- #x86_mfa{m=M,f=F,a=A} ->
- case erlang:is_builtin(M, F, A) of
- true -> FPoff;
- false -> stack_need_general(FPoff, StkArity)
- end;
- #x86_temp{} -> stack_need_general(FPoff, StkArity);
- #x86_mem{} -> stack_need_general(FPoff, StkArity)
- end.
-
-stack_need_general(FPoff, StkArity) ->
- erlang:max(FPoff, FPoff + (?LEAF_WORDS - 2 - StkArity) * word_size()).
-
-%%%
-%%% Create stack descriptors for call sites.
-%%%
-
-mk_sdesc(ExnLab, Context, Temps) -> % for normal calls
- Temps0 = only_tagged(Temps),
- Live = mk_live(Context, Temps0),
- Arity = context_arity(Context),
- FSize = context_framesize(Context),
- hipe_x86:mk_sdesc(ExnLab, FSize div word_size(), Arity,
- list_to_tuple(Live)).
-
-only_tagged(Temps)->
- [X || X <- Temps, hipe_x86:temp_type(X) =:= 'tagged'].
-
-mk_live(Context, Temps) ->
- lists:sort([temp_to_slot(Context, Temp) || Temp <- Temps]).
-
-temp_to_slot(Context, Temp) ->
- (context_framesize(Context) + context_offset(Context, Temp))
- div word_size().
-
-mk_minimal_sdesc(Context) -> % for inc_stack_0 calls
- hipe_x86:mk_sdesc([], 0, context_arity(Context), {}).
-
-%%%
-%%% Tailcalls.
-%%%
-
-do_pseudo_tailcall(I, Context) -> % always at FPoff=context_framesize(Context)
- Arity = context_arity(Context),
- Args = hipe_x86:pseudo_tailcall_stkargs(I) ++ [context_ra(Context)],
- Fun0 = hipe_x86:pseudo_tailcall_fun(I),
- {Insns, FPoff1, Fun1} = do_tailcall_args(Args, Context, Fun0),
- context_need_stack(Context, FPoff1),
- FPoff2 = FPoff1 + word_size()+word_size()*Arity - word_size()*length(Args),
- %% +word_size() for callee's inc_stack RA
- StkArity = length(hipe_x86:pseudo_tailcall_stkargs(I)),
- context_need_stack(Context, stack_need(FPoff2 + word_size(), StkArity, Fun1)),
- I2 = hipe_x86:mk_jmp_fun(Fun1, hipe_x86:pseudo_tailcall_linkage(I)),
- Insns ++ adjust_sp(FPoff2, [I2]).
-
-do_tailcall_args(Args, Context, Fun0) ->
- FPoff0 = context_framesize(Context),
- Arity = context_arity(Context),
- FrameTop = word_size() + word_size()*Arity,
- DangerOff = FrameTop - word_size()*length(Args),
- Moves = mk_moves(Args, FrameTop, []),
- {Stores, Simple, Conflict} =
- split_moves(Moves, Context, DangerOff, [], [], []),
- %% sanity check (shouldn't trigger any more)
- if DangerOff < -FPoff0 ->
- exit({?MODULE,do_tailcall_args,DangerOff,-FPoff0});
- true -> []
- end,
- FPoff1 = FPoff0,
- %%
- {Pushes, MoreSimple, FPoff2} = split_conflict(Conflict, FPoff1, [], []),
- %%
- {PushFun0, FPoff3, LoadFun1, Fun1} =
- case opnd_is_pseudo(Fun0) of
- false ->
- {[], FPoff2, [], Fun0};
- true ->
- Type = hipe_x86:temp_type(Fun0),
- Temp1 = mk_temp1(Type),
- Fun0Off = context_offset(Context, Fun0),
- MEM0 = conv_pseudo(Fun0, FPoff2 + Fun0Off),
- if Fun0Off >= DangerOff ->
- Fun1Off = hipe_x86:mk_imm(0),
- MEM1 = hipe_x86:mk_mem(mk_sp(), Fun1Off, Type),
- {[hipe_x86:mk_push(MEM0)],
- FPoff2 + word_size(),
- [hipe_x86:mk_move(MEM1, Temp1)],
- Temp1};
- true ->
- {[], FPoff2, [hipe_x86:mk_move(MEM0, Temp1)], Temp1}
- end
- end,
- %%
- RegTemp0 = ?HIPE_X86_REGISTERS:temp0(),
- TempReg =
- case hipe_x86:is_temp(Fun1) of
- true ->
- RegFun1 = hipe_x86:temp_reg(Fun1),
- if RegFun1 =/= RegTemp0 -> RegTemp0;
- true -> ?HIPE_X86_REGISTERS:temp1()
- end;
- false ->
- RegTemp0
- end,
- %%
- {Pushes ++ PushFun0 ++
- store_moves(Stores, FPoff3, LoadFun1 ++
- simple_moves(Simple, FPoff3, TempReg,
- simple_moves(MoreSimple, FPoff3, TempReg,
- []))),
- FPoff3, Fun1}.
-
-mk_moves([Arg|Args], Off, Moves) ->
- Off1 = Off - word_size(),
- mk_moves(Args, Off1, [{Arg,Off1}|Moves]);
-mk_moves([], _, Moves) ->
- Moves.
-
-split_moves([Move|Moves], Context, DangerOff, Stores, Simple, Conflict) ->
- {Src,DstOff} = Move,
- case src_is_pseudo(Src) of
- false ->
- split_moves(Moves, Context, DangerOff, [Move|Stores],
- Simple, Conflict);
- true ->
- SrcOff = context_offset(Context, Src),
- Type = typeof_src(Src),
- if SrcOff =:= DstOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, Conflict);
- SrcOff >= DangerOff ->
- split_moves(Moves, Context, DangerOff, Stores,
- Simple, [{SrcOff,DstOff,Type}|Conflict]);
- true ->
- split_moves(Moves, Context, DangerOff, Stores,
- [{SrcOff,DstOff,Type}|Simple], Conflict)
- end
- end;
-split_moves([], _, _, Stores, Simple, Conflict) ->
- {Stores, Simple, Conflict}.
-
-split_conflict([{SrcOff,DstOff,Type}|Conflict], FPoff, Pushes, Simple) ->
- Push = hipe_x86:mk_push(
- hipe_x86:mk_mem(mk_sp(), hipe_x86:mk_imm(FPoff+SrcOff), Type)),
- split_conflict(Conflict, FPoff+word_size(), [Push|Pushes],
- [{-(FPoff+word_size()),DstOff,Type}|Simple]);
-split_conflict([], FPoff, Pushes, Simple) ->
- {lists:reverse(Pushes), Simple, FPoff}.
-
-simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) ->
- Temp = hipe_x86:mk_temp(TempReg, Type),
- SP = mk_sp(),
- LoadOff = hipe_x86:mk_imm(FPoff+SrcOff),
- LD = hipe_x86:mk_move(hipe_x86:mk_mem(SP, LoadOff, Type), Temp),
- StoreOff = hipe_x86:mk_imm(FPoff+DstOff),
- ST = hipe_x86:mk_move(Temp, hipe_x86:mk_mem(SP, StoreOff, Type)),
- simple_moves(Moves, FPoff, TempReg, [LD, ST | Rest]);
-simple_moves([], _, _, Rest) ->
- Rest.
-
-store_moves([{Src,DstOff}|Moves], FPoff, Rest) ->
- Type = typeof_src(Src),
- SP = mk_sp(),
- StoreOff = hipe_x86:mk_imm(FPoff+DstOff),
- ST = hipe_x86:mk_move(Src, hipe_x86:mk_mem(SP, StoreOff, Type)),
- store_moves(Moves, FPoff, [ST | Rest]);
-store_moves([], _, Rest) ->
- Rest.
-
-%%%
-%%% Contexts
-%%%
-
--record(context, {liveness, framesize, arity, map, ra, ref_maxstack}).
-
-mk_context(Liveness, Formals, Temps) ->
- RA = hipe_x86:mk_new_temp('untagged'),
- {Map, MinOff} = mk_temp_map(Formals, RA, Temps),
- FrameSize = (-MinOff),
- RefMaxStack = hipe_bifs:ref(FrameSize),
- Context = #context{liveness=Liveness,
- framesize=FrameSize, arity=length(Formals),
- map=Map, ra=RA, ref_maxstack=RefMaxStack},
- Context.
-
-context_need_stack(#context{ref_maxstack=RM}, N) ->
- M = hipe_bifs:ref_get(RM),
- if N > M -> hipe_bifs:ref_set(RM, N);
- true -> []
- end.
-
-context_maxstack(#context{ref_maxstack=RM}) ->
- hipe_bifs:ref_get(RM).
-
-context_arity(#context{arity=Arity}) ->
- Arity.
-
-context_framesize(#context{framesize=FrameSize}) ->
- FrameSize.
-
-context_liveness(#context{liveness=Liveness}) ->
- Liveness.
-
-context_offset(#context{map=Map}, Temp) ->
- tmap_lookup(Map, Temp).
-
-context_ra(#context{ra=RA}) ->
- RA.
-
-mk_temp_map(Formals, RA, Temps) ->
- {Map, _} = enter_vars(Formals, word_size() * (length(Formals)+1),
- tmap_bind(tmap_empty(), RA, 0)),
- enter_vars(tset_to_list(Temps), 0, Map).
-
-enter_vars([V|Vs], PrevOff, Map) ->
- Off =
- case hipe_x86:temp_type(V) of
- 'double' -> PrevOff - float_size();
- _ -> PrevOff - word_size()
- end,
- enter_vars(Vs, Off, tmap_bind(Map, V, Off));
-enter_vars([], Off, Map) ->
- {Map, Off}.
-
-tmap_empty() ->
- gb_trees:empty().
-
-tmap_bind(Map, Key, Val) ->
- gb_trees:insert(Key, Val, Map).
-
-tmap_lookup(Map, Key) ->
- gb_trees:get(Key, Map).
-
-%%%
-%%% do_prologue: prepend stack frame allocation code.
-%%%
-%%% NewStart:
-%%% temp0 = sp - MaxStack
-%%% if( temp0 < SP_LIMIT(P) ) goto IncStack else goto AllocFrame
-%%% AllocFrame:
-%%% sp -= FrameSize
-%%% goto OldStart
-%%% OldStart:
-%%% ...
-%%% IncStack:
-%%% call inc_stack
-%%% goto NewStart
-
-do_prologue(CFG, Context) ->
- do_check_stack(do_alloc_frame(CFG, Context), Context).
-
-do_alloc_frame(CFG, Context) ->
- case context_framesize(Context) of
- 0 ->
- CFG;
- FrameSize ->
- OldStartLab = hipe_x86_cfg:start_label(CFG),
- AllocFrameLab = hipe_gensym:get_next_label(x86),
- SP = mk_sp(),
- AllocFrameCode =
- [hipe_x86:mk_alu('sub', hipe_x86:mk_imm(FrameSize), SP),
- hipe_x86:mk_jmp_label(OldStartLab)],
- CFG1 = hipe_x86_cfg:bb_add(CFG, AllocFrameLab,
- hipe_bb:mk_bb(AllocFrameCode)),
- hipe_x86_cfg:start_label_update(CFG1, AllocFrameLab)
- end.
-
-do_check_stack(CFG, Context) ->
- MaxStack = context_maxstack(Context),
- Arity = context_arity(Context),
- Guaranteed = erlang:max(0, (?LEAF_WORDS - 1 - Arity) * word_size()),
- if MaxStack =< Guaranteed ->
- %% io:format("~w: MaxStack ~w =< Guaranteed ~w :-)\n", [?MODULE,MaxStack,Guaranteed]),
- CFG;
- true ->
- %% io:format("~w: MaxStack ~w > Guaranteed ~w :-(\n", [?MODULE,MaxStack,Guaranteed]),
- AllocFrameLab = hipe_x86_cfg:start_label(CFG),
- NewStartLab = hipe_gensym:get_next_label(x86),
- IncStackLab = hipe_gensym:get_next_label(x86),
- %%
- Type = 'untagged',
- Preg = ?HIPE_X86_REGISTERS:proc_pointer(),
- Pbase = hipe_x86:mk_temp(Preg, Type),
- SP_LIMIT_OFF = hipe_x86:mk_imm(
- ?HIPE_X86_REGISTERS:sp_limit_offset()),
- Temp0 = mk_temp0(Type),
- SP = mk_sp(),
- NewStartCode =
- %% hopefully this lea is faster than the mov;sub it replaced
- [hipe_x86:mk_lea(
- hipe_x86:mk_mem(SP, hipe_x86:mk_imm(-MaxStack), 'untagged'),
- Temp0),
- hipe_x86:mk_cmp(
- hipe_x86:mk_mem(Pbase, SP_LIMIT_OFF, Type), Temp0),
- hipe_x86:mk_pseudo_jcc('b', IncStackLab, AllocFrameLab, 0.01)],
- IncStackCode =
- [hipe_x86:mk_call(hipe_x86:mk_prim('inc_stack_0'),
- mk_minimal_sdesc(Context), not_remote),
- hipe_x86:mk_jmp_label(NewStartLab)],
- %%
- CFG1 = hipe_x86_cfg:bb_add(CFG, NewStartLab,
- hipe_bb:mk_bb(NewStartCode)),
- CFG2 = hipe_x86_cfg:bb_add(CFG1, IncStackLab,
- hipe_bb:mk_bb(IncStackCode)),
- hipe_x86_cfg:start_label_update(CFG2, NewStartLab)
- end.
-
-%%% typeof_src -- what's src's type?
-
-typeof_src(Src) ->
- case Src of
- #x86_imm{} ->
- 'untagged';
- #x86_temp{} ->
- hipe_x86:temp_type(Src);
- #x86_mem{} ->
- hipe_x86:mem_type(Src)
- end.
-
-%%% Cons up an '%sp' Temp.
-
-mk_sp() ->
- hipe_x86:mk_temp(?HIPE_X86_REGISTERS:sp(), 'untagged').
-
-%%% Cons up a '%temp0' Temp.
-
-mk_temp0(Type) ->
- hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp0(), Type).
-
-%%% Cons up a '%temp1' Temp.
-
-mk_temp1(Type) ->
- hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp1(), Type).
-
-%%% Check if an operand is a pseudo-Temp.
-
-src_is_pseudo(Src) ->
- opnd_is_pseudo(Src).
-
-opnd_is_pseudo(Opnd) ->
- case hipe_x86:is_temp(Opnd) of
- true -> temp_is_pseudo(Opnd);
- false -> false
- end.
-
-temp_is_pseudo(Temp) ->
- case hipe_x86:is_temp(Temp) of
- true ->
- not(?HIPE_X86_REGISTERS:is_precoloured(hipe_x86:temp_reg(Temp)));
- false ->
- false
- end.
-
-
-%%%
-%%% Build the set of all temps used in a Defun's body.
-%%%
-
-all_temps(CFG, Formals) ->
- S0 = fold_insns(fun find_temps/2, tset_empty(), CFG),
- S1 = tset_del_list(S0, Formals),
- S2 = tset_filter(S1, fun(T) -> temp_is_pseudo(T) end),
- S2.
-
-find_temps(I, S0) ->
- S1 = tset_add_list(S0, hipe_x86_defuse:insn_def(I)),
- tset_add_list(S1, hipe_x86_defuse:insn_use(I)).
-
-fold_insns(Fun, InitAcc, CFG) ->
- hipe_x86_cfg:fold_bbs(
- fun(_, BB, Acc0) -> lists:foldl(Fun, Acc0, hipe_bb:code(BB)) end,
- InitAcc, CFG).
-
--compile({inline, [tset_empty/0, tset_size/1, tset_insert/2,
- tset_filter/2, tset_to_list/1]}).
-
-tset_empty() ->
- #{}.
-
-tset_size(S) ->
- map_size(S).
-
-tset_insert(S, T) ->
- S#{T => []}.
-
-tset_add_list(S, []) -> S;
-tset_add_list(S, [T|Ts]) ->
- tset_add_list(S#{T => []}, Ts).
-
-tset_del_list(S, []) -> S;
-tset_del_list(S, [T|Ts]) ->
- tset_del_list(maps:remove(T,S), Ts).
-
-tset_filter(S, F) ->
- maps:filter(fun(K, _V) -> F(K) end, S).
-
-tset_to_list(S) ->
- maps:keys(S).
-
-%%%
-%%% Compute minimum permissible frame size, ignoring spilled temps.
-%%% This is done to ensure that we won't have to adjust the frame size
-%%% in the middle of a tailcall.
-%%%
-
-defun_minframe(CFG) ->
- MaxTailArity = fold_insns(fun insn_mta/2, 0, CFG),
- MyArity = length(fix_formals(hipe_x86_cfg:params(CFG))),
- erlang:max(MaxTailArity - MyArity, 0).
-
-insn_mta(I, MTA) ->
- case I of
- #pseudo_tailcall{arity=Arity} ->
- erlang:max(MTA, Arity - ?HIPE_X86_REGISTERS:nr_args());
- _ -> MTA
- end.
-
-%%%
-%%% Ensure that we have enough temps to satisfy the minimum frame size,
-%%% if necessary by prepending unused dummy temps.
-%%%
-
-ensure_minframe(MinFrame, Temps) ->
- ensure_minframe(MinFrame, tset_size(Temps), Temps).
-
-ensure_minframe(MinFrame, Frame, Temps) ->
- if MinFrame > Frame ->
- Temp = hipe_x86:mk_new_temp('untagged'),
- ensure_minframe(MinFrame, Frame+1, tset_insert(Temps, Temp));
- true -> Temps
- end.
-
-word_size() ->
- ?HIPE_X86_REGISTERS:wordsize().
-
-float_size() ->
- ?HIPE_X86_REGISTERS:float_size().
diff --git a/lib/hipe/x86/hipe_x86_liveness.erl b/lib/hipe/x86/hipe_x86_liveness.erl
deleted file mode 100644
index 470501b46d..0000000000
--- a/lib/hipe/x86/hipe_x86_liveness.erl
+++ /dev/null
@@ -1,52 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% x86_liveness -- compute register liveness for x86 CFGs
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
--define(HIPE_X86_DEFUSE, hipe_amd64_defuse).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--else.
--define(HIPE_X86_LIVENESS, hipe_x86_liveness).
--define(HIPE_X86_DEFUSE, hipe_x86_defuse).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--endif.
-
--module(?HIPE_X86_LIVENESS).
-
--export([analyse/1]).
--export([liveout/2]).
--export([uses/1, defines/1]). % used in hipe_*_spill_restore modules
-
--include("../x86/hipe_x86.hrl"). % ../x86/ is needed when included in amd64
--include("../flow/liveness.inc").
-
-analyse(CFG) -> analyze(CFG).
-cfg_bb(CFG, L) -> hipe_x86_cfg:bb(CFG, L).
-cfg_postorder(CFG) -> hipe_x86_cfg:postorder(CFG).
-cfg_succ(CFG, L) -> hipe_x86_cfg:succ(CFG, L).
-uses(Insn) -> ?HIPE_X86_DEFUSE:insn_use(Insn).
-defines(Insn) -> ?HIPE_X86_DEFUSE:insn_def(Insn).
-liveout_no_succ() ->
- ordsets:from_list(lists:map(fun({Reg,Type}) ->
- hipe_x86:mk_temp(Reg, Type)
- end,
- ?HIPE_X86_REGISTERS:live_at_return())).
-
--ifdef(DEBUG_LIVENESS).
-cfg_labels(CFG) -> hipe_x86_cfg:labels(CFG).
-cfg_bb_add(CFG,L,NewBB) -> hipe_x86_cfg:bb_add(CFG,L,NewBB).
-mk_comment(Text) -> hipe_x86:mk_comment(Text).
--endif.
diff --git a/lib/hipe/x86/hipe_x86_main.erl b/lib/hipe/x86/hipe_x86_main.erl
deleted file mode 100644
index 7e9fd10e62..0000000000
--- a/lib/hipe/x86/hipe_x86_main.erl
+++ /dev/null
@@ -1,68 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_MAIN, hipe_amd64_main).
--define(RTL_TO_X86, rtl_to_amd64). % XXX: kill this crap
--define(HIPE_RTL_TO_X86, hipe_rtl_to_amd64).
--define(HIPE_X86_RA, hipe_amd64_ra).
--define(HIPE_X86_FRAME, hipe_amd64_frame).
--define(HIPE_X86_PP, hipe_amd64_pp).
--define(X86TAG, amd64). % XXX: kill this crap
--define(X86STR, "amd64").
--define(HIPE_X86_SPILL_RESTORE, hipe_amd64_spill_restore).
--else.
--define(HIPE_X86_MAIN, hipe_x86_main).
--define(RTL_TO_X86, rtl_to_x86). % XXX: kill this crap
--define(HIPE_RTL_TO_X86, hipe_rtl_to_x86).
--define(HIPE_X86_RA, hipe_x86_ra).
--define(HIPE_X86_FRAME, hipe_x86_frame).
--define(HIPE_X86_PP, hipe_x86_pp).
--define(X86TAG, x86). % XXX: kill this crap
--define(X86STR, "x86").
--define(HIPE_X86_SPILL_RESTORE, hipe_x86_spill_restore).
--endif.
-
--module(?HIPE_X86_MAIN).
--export([?RTL_TO_X86/3]). % XXX: change to 'from_rtl' to avoid $ARCH substring
-
--ifndef(DEBUG).
--define(DEBUG,1).
--endif.
--define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.
--include("../main/hipe.hrl").
-
-?RTL_TO_X86(MFA, RTL, Options) ->
- Translated = ?option_time(?HIPE_RTL_TO_X86:translate(RTL),
- "RTL-to-"?X86STR, Options),
- TransCFG = ?option_time(hipe_x86_cfg:init(Translated),
- ?X86STR" to cfg", Options),
- SpillRestCFG =
- case proplists:get_bool(caller_save_spill_restore, Options) of
- true ->
- ?option_time(?HIPE_X86_SPILL_RESTORE:spill_restore(TransCFG, Options),
- ?X86STR" spill restore", Options);
- false ->
- TransCFG
- end,
- AllocatedCFG = ?option_time(?HIPE_X86_RA:ra(SpillRestCFG, Options),
- ?X86STR" register allocation", Options),
- FramedCFG = ?option_time(?HIPE_X86_FRAME:frame(AllocatedCFG, Options),
- ?X86STR" frame", Options),
- Framed = ?option_time(hipe_x86_cfg:linearise(FramedCFG),
- ?X86STR" linearise", Options),
- Finalised = ?option_time(hipe_x86_postpass:postpass(Framed, Options),
- ?X86STR" finalise", Options),
- ?HIPE_X86_PP:optional_pp(Finalised, MFA, Options),
- {native, ?X86TAG, {unprofiled, Finalised}}.
diff --git a/lib/hipe/x86/hipe_x86_postpass.erl b/lib/hipe/x86/hipe_x86_postpass.erl
deleted file mode 100644
index 925054dd68..0000000000
--- a/lib/hipe/x86/hipe_x86_postpass.erl
+++ /dev/null
@@ -1,285 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%%----------------------------------------------------------------------
-%%% File : hipe_x86_postpass.erl
-%%% Author : Christoffer Vikström <chvi3471@student.uu.se>
-%%% Purpose : Contain postpass optimisations for x86-assembler code.
-%%% Created : 5 Aug 2003 by Christoffer Vikström <chvi3471@student.uu.se>
-%%%----------------------------------------------------------------------
-
--ifndef(HIPE_X86_POSTPASS).
--define(HIPE_X86_POSTPASS, hipe_x86_postpass).
--endif.
-
--module(?HIPE_X86_POSTPASS).
--export([postpass/2]).
--include("../x86/hipe_x86.hrl").
-
-%%>----------------------------------------------------------------------<
-% Procedure : postpass/2
-% Purpose : Function that performs a nr of postpass optimizations on
-% the hipe x86-assembler code before it is encoded and loaded.
-%%>----------------------------------------------------------------------<
-postpass(#defun{code=Code0}=Defun, Options) ->
- Code1 = pseudo_insn_expansion(Code0),
- Code2 = case proplists:get_bool(peephole, Options) of
- true -> peephole_optimization(Code1);
- false -> Code1
- end,
- Code3 = trivial_goto_elimination(Code2),
- Defun#defun{code=Code3}.
-
-
-%%>----------------------------------------------------------------------<
-% Procedure : peep/1
-% Purpose : Function that does peephole optimizations. It works by
-% moving a window over the code and looking at a sequence of
-% a few instructions. Replaces long sequences of instructions
-% with shorter ones and removes unnecesary ones.
-% Arguments : Insns - List of pseudo x86-assembler records.
-% Res - Returned list of pseudo x86-assembler records.
-% Kept reversed, until it is returned.
-% Return : An optimized list of pseudo x86-assembler records with
-% (hopefully) fewer or faster instructions.
-%%>----------------------------------------------------------------------<
-peephole_optimization(Insns) ->
- peep(Insns, [], []).
-
-
-%% MoveSelf related peep-opts
-%% ------------------------------
-peep([#fmove{src=Src, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, Res, [moveSelf1|Lst]);
-peep([I=#fmove{src=Src, dst=Dst},
- #fmove{src=Dst, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, [I|Res], [moveSelf2|Lst]);
-peep([#movsx{src=Src, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, Res, [moveSelf3|Lst]);
-peep([I=#movsx{src=Src, dst=Dst},
- #movsx{src=Dst, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, [I|Res], [moveSelf4|Lst]);
-peep([#movzx{src=Src, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, Res, [moveSelf5|Lst]);
-peep([I=#movzx{src=Src, dst=Dst},
- #movzx{src=Dst, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, [I|Res], [moveSelf6|Lst]);
-peep([#cmovcc{src=Src, dst=Src} | Insns], Res,Lst) ->
- peep(Insns, Res, [moveSelf7|Lst]);
-peep([I=#cmovcc{src=Src, dst=Dst},
- #cmovcc{src=Dst, dst=Src}|Insns], Res,Lst) ->
- peep(Insns, [I|Res], [moveSelf8|Lst]);
-peep([#move{src=#x86_temp{reg=X},
- dst=#x86_temp{reg=X}} | Insns], Res,Lst) ->
- peep(Insns, Res, [moveSelf9|Lst]);
-peep([I=#move{src=#x86_temp{reg=Src}, dst=#x86_temp{reg=Dst}},
- #move{src=#x86_temp{reg=Dst}, dst=#x86_temp{reg=Src}} | Insns], Res,Lst) ->
- peep(Insns, [I|Res], [moveSelf0|Lst]);
-
-
-%% ElimBinALMDouble
-%% ----------------
-peep([Move=#move{src=Src, dst=Dst}, Alu=#alu{src=Src, dst=Dst}|Insns], Res, Lst)
- when not is_record(Dst, x86_mem) ->
- peep([Alu#alu{src=Dst}|Insns], [Move|Res], [elimBinALMDouble|Lst]);
-
-
-%% ElimFBinDouble
-%% --------------
-peep([Move=#fmove{src=Src, dst=Dst},
- BinOp=#fp_binop{src=Src, dst=Dst}|Insns], Res, Lst) ->
- peep([BinOp#fp_binop{src=Dst}|Insns], [Move|Res], [elimFBinDouble|Lst]);
-
-
-%% CommuteBinALMD
-%% --------------
-peep([#move{src=Src1, dst=Dst},
- #alu{aluop=Op,src=Src2,dst=Dst}|Insns], Res, Lst)
- when (Src1 =:= #x86_imm{}) and (Src2 =/= #x86_imm{}) and
- ((Op =:= 'add') or (Op =:= 'and') or (Op =:= 'or') or (Op =:= 'xor')) ->
- peep(Insns, [#alu{aluop=Op,src=Src1,dst=Dst},
- #move{src=Src2, dst=Dst}|Res],
- [commuteBinALMD|Lst]);
-
-
-%% ElimCmp0
-%% --------
-peep([#cmp{src=#x86_imm{value=0}, dst=Dst=#x86_temp{}}|Insns],Res,Lst) ->
- %% TEST leaves the adjust flag undefined, whereas CMP sets it properly (in
- %% this case to 0). However, since HiPE does not use any instructions that
- %% read the adjust flag, we can do this transform safely.
- peep(Insns, [#test{src=Dst, dst=Dst} | Res], [elimCmp0_1|Lst]);
-peep([#cmp{src=Src=#x86_temp{}, dst=#x86_imm{value=0}},
- J=#jcc{cc=Cond}|Insns],Res,Lst)
- when Cond =:= 'e'; Cond =:= 'ne' -> % We're commuting the comparison
- peep(Insns, [J, #test{src=Src, dst=Src} | Res], [elimCmp0_2|Lst]);
-
-%% ElimCmpTest
-%% -----------
-peep([I|Insns],Res,Lst) when (I =:= #cmp{}) or (I =:= #test{}) ->
- case check(Insns) of
- #jcc{} ->
- peep(Insns, [I|Res], Lst);
- #jmp_fun{} ->
- peep(Insns, [I|Res], Lst);
- #jmp_label{} ->
- peep(Insns, [I|Res], Lst);
- #jmp_switch{} ->
- peep(Insns, [I|Res], Lst);
- #cmovcc{} ->
- peep(Insns, [I|Res], Lst);
- #ret{} ->
- peep(Insns, [I|Res], Lst);
- _ ->
- peep(Insns, Res, [elimCmpTest|Lst])
- end;
-
-
-%% ElimPushPop
-%% -----------
-peep([#push{src=Opr}, #pop{dst=Opr} | Insns], Res, Lst) ->
- peep(Insns, Res, [elimPushPop|Lst]);
-
-
-% %% ElimIFF
-% %% -------
-peep([#jcc{label=Lab}, I=#label{label=Lab}|Insns], Res, Lst) ->
- peep(Insns, [I, #jmp_label{label=Lab}|Res], [elimIFF|Lst]);
-
-
-%% ElimSet0
-%% --------
-peep([#move{src=#x86_imm{value=0},dst=Dst=#x86_temp{}}|Insns],Res,Lst) ->
- peep(Insns, [#alu{aluop='xor', src=Dst, dst=Dst}|Res], [elimSet0|Lst]);
-
-%% ElimMDPow2
-%% ----------
-peep([B = #alu{aluop=Op,src=#x86_imm{value=Val},dst=Dst}|Insns], Res, Lst) ->
- {IsLog2, Size, Sign} = log2(Val),
- case ((Op =:= imul) or (Op =:= idiv)) and IsLog2 of
- true ->
- Sh = case Sign of positive -> 'bsl'; negative -> 'bsr' end,
- peep(Insns,
- [#shift{shiftop=Sh, src=#x86_imm{value=Size}, dst=Dst}|Res],
- [elimMDPow2|Lst]);
- false ->
- peep(Insns, [B|Res], Lst)
- end;
-
-%% LeaToAdd
-%% This rule transforms lea into add when the destination is the same as one of
-%% the operands. Sound because lea is never used where the condition codes are
-%% live (and would be clobbered by add).
-%% ----------
-peep([#lea{mem=#x86_mem{base=#x86_temp{reg=DstR},off=Src},
- temp=Dst=#x86_temp{reg=DstR}}|Insns], Res, Lst) ->
- peep(Insns, [#alu{aluop='add',src=Src,dst=Dst}|Res], [leaToAdd|Lst]);
-peep([#lea{mem=#x86_mem{base=Src,off=#x86_temp{reg=DstR}},
- temp=Dst=#x86_temp{reg=DstR}}|Insns], Res, Lst) ->
- peep(Insns, [#alu{aluop='add',src=Src,dst=Dst}|Res], [leaToAdd|Lst]);
-
-%% SubToDec
-%% This rule turns "subl $1,Dst; jl Lab" into "decl Dst; jl Lab", which
-%% changes reduction counter tests to use decl instead of subl.
-%% However, on Athlon64 this leads to a small but measurable decrease
-%% in performance. The use of dec is also not recommended on P4, so
-%% this transformation is disabled.
-%% peep([#alu{aluop='sub',src=#x86_imm{value=1},dst=Dst},J=#jcc{cc='l'}|Insns], Res, Lst) ->
-%% peep(Insns, [J, #dec{dst=Dst} | Res], [subToDec|Lst]);
-
-%% Standard list recursion clause
-%% ------------------------------
-peep([I | Insns], Res, Lst) ->
- peep(Insns, [I|Res], Lst);
-peep([], Res, _Lst) ->
- lists:reverse(Res).
-
-%% Simple goto elimination
-%% -----------------------
-trivial_goto_elimination(Insns) -> goto_elim(Insns, []).
-
-goto_elim([#jmp_label{label=Label}, I = #label{label=Label}|Insns], Res) ->
- goto_elim([I|Insns], Res);
-goto_elim([#jcc{cc=CC, label=Label} = IJCC,
- #jmp_label{label=BranchTgt},
- #label{label=Label} = ILBL|Insns], Res) ->
- goto_elim([IJCC#jcc{cc=hipe_x86:neg_cc(CC), label=BranchTgt},
- ILBL|Insns], Res);
-goto_elim([I | Insns], Res) ->
- goto_elim(Insns, [I|Res]);
-goto_elim([], Res) ->
- lists:reverse(Res).
-
-
-%%>----------------------------------------------------------------------<
-%% Procedure : expand/1
-%% Purpose : Expands pseudo instructions.
-%% Arguments : Insns - An x86-instruction list.
-%% Return : An expanded instruction list.
-%% Notes :
-%%>----------------------------------------------------------------------<
-pseudo_insn_expansion(Insns) -> expand(Insns, []).
-expand([I|Tail], Res) ->
- case I of
- #pseudo_jcc{cc=Cc,true_label=TrueLab,false_label=FalseLab} ->
- expand(Tail, [hipe_x86:mk_jmp_label(FalseLab),
- hipe_x86:mk_jcc(Cc, TrueLab) | Res]);
- #pseudo_tailcall_prepare{} ->
- expand(Tail, Res);
- #pseudo_call{'fun'=Fun,sdesc=SDesc,contlab=ContLab,linkage=Linkage} ->
- expand(Tail, [hipe_x86:mk_jmp_label(ContLab),
- hipe_x86:mk_call(Fun, SDesc, Linkage) | Res]);
- _ ->
- expand(Tail, [I|Res])
- end;
-expand([], Res) -> lists:reverse(Res).
-
-%% Log2 function
-%% -------------
-%% Used by ElimMDPow2 clause of peep(..)
-log2(Nr) -> log2(Nr, 0).
-log2(0, _) -> {false, 0, positive};
-log2(Nr, I) ->
- case (Nr band 1) =:= 1 of
- true ->
- case Nr of
- 1 ->
- {true, I, positive};
- -1 ->
- {true, I, negative};
- _ ->
- {false, 0, positive}
- end;
- false ->
- log2((Nr bsr 1), I+1)
- end.
-
-%% Skips through all comments and move instructions and returns the next one
-%% -------------------------------------------------------------------------
-%% Used by ElimCmpTest above.
-check([I|Ins]) ->
- case I of
- #comment{} ->
- check(Ins);
- #move{} ->
- check(Ins);
- #fmove{} ->
- check(Ins);
- #movsx{} ->
- check(Ins);
- #movzx{} ->
- check(Ins);
- OtherI ->
- OtherI
- end.
diff --git a/lib/hipe/x86/hipe_x86_pp.erl b/lib/hipe/x86/hipe_x86_pp.erl
deleted file mode 100644
index 72d2fa80bf..0000000000
--- a/lib/hipe/x86/hipe_x86_pp.erl
+++ /dev/null
@@ -1,351 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% x86 pretty-printer
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_PP, hipe_amd64_pp).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--else.
--define(HIPE_X86_PP, hipe_x86_pp).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--endif.
-
--module(?HIPE_X86_PP).
--export([% pp/1, pp/2,
- pp_insn/1, optional_pp/3]).
--include("../x86/hipe_x86.hrl").
-
-optional_pp(Defun, MFA, Options) ->
- case proplists:get_value(pp_native, Options) of
- true ->
- pp(Defun);
- {only,Lst} when is_list(Lst) ->
- case lists:member(MFA, Lst) of
- true -> pp(Defun);
- false -> ok
- end;
- {only,MFA} ->
- pp(Defun);
- {file,FileName} ->
- {ok, File} = file:open(FileName, [write,append]),
- pp(File, Defun),
- ok = file:close(File);
- _ ->
- ok
- end.
-
-pp(Defun) ->
- pp(standard_io, Defun).
-
-pp(Dev, #defun{mfa={M,F,A}, code=Code, data=Data}) ->
- Fname = atom_to_list(M)++"_"++atom_to_list(F)++"_"++integer_to_list(A),
- io:format(Dev, "\t.text\n", []),
- io:format(Dev, "\t.align 4\n", []),
- io:format(Dev, "\t.global ~s\n", [Fname]),
- io:format(Dev, "~s:\n", [Fname]),
- pp_insns(Dev, Code, Fname),
- io:format(Dev, "\t.rodata\n", []),
- io:format(Dev, "\t.align 4\n", []),
- hipe_data_pp:pp(Dev, Data, x86, Fname),
- io:format(Dev, "\n", []).
-
-pp_insns(Dev, [I|Is], Fname) ->
- pp_insn(Dev, I, Fname),
- pp_insns(Dev, Is, Fname);
-pp_insns(_, [], _) ->
- ok.
-
-pp_insn(I) ->
- pp_insn(standard_io, I, "").
-
-pp_insn(Dev, I, Pre) ->
- case I of
- #alu{aluop=AluOp, src=Src, dst=Dst} ->
- io:format(Dev, "\t~s ", [alu_op_name(AluOp)]),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #call{'fun'=Fun, sdesc=SDesc, linkage=Linkage} ->
- io:format(Dev, "\tcall ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " #", []),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #cmovcc{cc=Cc, src=Src, dst=Dst} ->
- io:format(Dev, "\tcmov~s ", [cc_name(Cc)]),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #cmp{src=Src, dst=Dst} ->
- io:format(Dev, "\tcmp ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #comment{term=Term} ->
- io:format(Dev, "\t# ~p\n", [Term]);
- #imul{imm_opt=ImmOpt, src=Src, temp=Temp} ->
- io:format(Dev, "\timul ", []),
- case ImmOpt of
- [] -> ok;
- Imm ->
- pp_imm(Dev, Imm, true),
- io:format(Dev, ", ", [])
- end,
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Temp),
- io:format(Dev, "\n", []);
- #jcc{cc=Cc, label=Label} ->
- io:format(Dev, "\tj~s .~s_~w\n", [cc_name(Cc), Pre, Label]);
- #jmp_fun{'fun'=Fun, linkage=Linkage} ->
- io:format(Dev, "\tjmp ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " ~w\n", [Linkage]);
- #jmp_label{label=Label} ->
- io:format(Dev, "\tjmp .~s_~w\n", [Pre, Label]);
- #jmp_switch{temp=Temp, jtab=JTab, labels=Labels} ->
- io:format(Dev, "\tjmp *{constant,~w}(,", [JTab]),
- pp_temp(Dev, Temp),
- io:format(Dev, ",4) #", []),
- pp_labels(Dev, Labels, Pre),
- io:format(Dev, "\n", []);
- #label{label=Label} ->
- io:format(Dev, ".~s_~w:~n", [Pre, Label]);
- #lea{mem=Mem, temp=Temp} ->
- io:format(Dev, "\tlea ", []),
- pp_mem(Dev, Mem),
- io:format(Dev, ", ", []),
- pp_temp(Dev, Temp),
- io:format(Dev, "\n", []);
- #move{src=Src, dst=Dst} ->
- io:format(Dev, "\tmov ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #move64{} ->
- pp_move64(Dev, I);
- #movsx{src=Src, dst=Dst} ->
- io:format(Dev, "\tmovsx ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #movzx{src=Src, dst=Dst} ->
- io:format(Dev, "\tmovzx ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #pseudo_call{'fun'=Fun, sdesc=SDesc, contlab=ContLab, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_call ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " # contlab .~s_~w", [Pre, ContLab]),
- pp_sdesc(Dev, Pre, SDesc),
- io:format(Dev, " ~w\n", [Linkage]);
- #pseudo_jcc{cc=Cc, true_label=TrueLab, false_label=FalseLab, pred=Pred} ->
- io:format(Dev, "\tpseudo_j~s ", [cc_name(Cc)]),
- io:format(Dev, ".~s_~w # .~s_~w ~.2f\n",
- [Pre, TrueLab, Pre, FalseLab, Pred]);
- #pseudo_tailcall{'fun'=Fun, arity=Arity, stkargs=StkArgs, linkage=Linkage} ->
- io:format(Dev, "\tpseudo_tailcall ", []),
- pp_fun(Dev, Fun),
- io:format(Dev, " ~w (", [Arity]),
- pp_args(Dev, StkArgs),
- io:format(Dev, ") ~w\n", [Linkage]);
- #pseudo_tailcall_prepare{} ->
- io:format(Dev, "\tpseudo_tailcall_prepare\n", []);
- #push{src=Src} ->
- io:format(Dev, "\tpush ", []),
- pp_src(Dev, Src),
- io:format(Dev, "\n", []);
- #ret{npop=NPop} ->
- io:format(Dev, "\tret $~s\n", [to_hex(NPop)]);
- #shift{shiftop=ShiftOp, src=Src, dst=Dst} ->
- io:format(Dev, "\t~s ", [alu_op_name(ShiftOp)]),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #test{src=Src, dst=Dst} ->
- io:format(Dev, "\ttest ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- #fp_binop{src=Src, dst=Dst, op=Op} ->
- io:format(Dev, "\t~s ", [Op]),
- pp_dst(Dev, Dst),
- io:format(Dev, ", ", []),
- pp_src(Dev, Src),
- io:format(Dev, "\n", []);
- #fp_unop{arg=Arg, op=Op} ->
- io:format(Dev, "\t~s ", [Op]),
- case Arg of
- []->
- io:format(Dev, "\n", []);
- _ ->
- pp_args(Dev, [Arg]),
- io:format(Dev, "\n", [])
- end;
- #fmove{src=Src, dst=Dst} ->
- io:format(Dev, "\tfmove ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []);
- _ ->
- exit({?MODULE, pp_insn, {"unknown x86 instruction", I}})
- end.
-
--ifdef(HIPE_AMD64).
-pp_move64(Dev, I) ->
- #move64{imm=Src, dst=Dst} = I,
- io:format(Dev, "\tmov64 ", []),
- pp_src(Dev, Src),
- io:format(Dev, ", ", []),
- pp_dst(Dev, Dst),
- io:format(Dev, "\n", []).
--else.
-pp_move64(_Dev, I) -> exit({?MODULE, I}).
--endif.
-
-to_hex(N) ->
- io_lib:format("~.16x", [N, "0x"]).
-
-pp_sdesc(Dev, Pre, #x86_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live}) ->
- pp_sdesc_exnlab(Dev, Pre, ExnLab),
- io:format(Dev, " ~s ~w [", [to_hex(FSize), Arity]),
- pp_sdesc_live(Dev, Live),
- io:format(Dev, "]", []).
-
-pp_sdesc_exnlab(Dev, _, []) -> io:format(Dev, " []", []);
-pp_sdesc_exnlab(Dev, Pre, ExnLab) -> io:format(Dev, " .~s_~w", [Pre, ExnLab]).
-
-pp_sdesc_live(_, {}) -> ok;
-pp_sdesc_live(Dev, Live) -> pp_sdesc_live(Dev, Live, 1).
-
-pp_sdesc_live(Dev, Live, I) ->
- io:format(Dev, "~s", [to_hex(element(I, Live))]),
- if I < tuple_size(Live) ->
- io:format(Dev, ",", []),
- pp_sdesc_live(Dev, Live, I+1);
- true -> ok
- end.
-
-pp_labels(Dev, [Label|Labels], Pre) ->
- io:format(Dev, " .~s_~w", [Pre, Label]),
- pp_labels(Dev, Labels, Pre);
-pp_labels(_, [], _) ->
- ok.
-
-pp_fun(Dev, Fun) ->
- case Fun of
- #x86_mfa{m=M, f=F, a=A} ->
- io:format(Dev, "~w:~w/~w", [M, F, A]);
- #x86_prim{prim=Prim} ->
- io:format(Dev, "~w", [Prim]);
- _ -> % temp or mem
- io:format(Dev, "*", []),
- pp_dst(Dev, Fun)
- end.
-
-alu_op_name(Op) -> Op.
-
-cc_name(Cc) -> Cc.
-
-pp_hard_reg(Dev, Reg) ->
- io:format(Dev, "~s", [?HIPE_X86_REGISTERS:reg_name(Reg)]).
-
-type_tag('tagged') -> "t";
-type_tag('untagged') -> "u";
-type_tag('double') -> "d".
-
-pp_temp(Dev, #x86_temp{reg=Reg, type=Type}) ->
- case Type of
- double ->
- Tag = type_tag(Type),
- io:format(Dev, "~s~w", [Tag, Reg]);
- _ ->
- case ?HIPE_X86_REGISTERS:is_precoloured(Reg) of
- true ->
- pp_hard_reg(Dev, Reg);
- false ->
- Tag = type_tag(Type),
- io:format(Dev, "~s~w", [Tag, Reg])
- end
- end.
-
-pp_fpreg(Dev, #x86_fpreg{reg=Reg, pseudo=Pseudo})->
- case Pseudo of
- true -> io:format(Dev, "pseudo_fp(~w)", [Reg]);
- _ -> io:format(Dev, "st(~w)", [Reg])
- end.
-
-pp_imm(Dev, #x86_imm{value=Value}, Dollar) ->
- if Dollar =:= true -> io:format(Dev, [$$], []);
- true -> ok
- end,
- if is_integer(Value) -> io:format(Dev, "~s", [to_hex(Value)]);
- true -> io:format(Dev, "~w", [Value])
- end.
-
-pp_mem(Dev, #x86_mem{base=Base, off=Off}) ->
- pp_off(Dev, Off),
- case Base of
- [] ->
- ok;
- _ ->
- io:format(Dev, "(", []),
- pp_temp(Dev, Base),
- io:format(Dev, ")", [])
- end.
-
-pp_off(Dev, Off) ->
- pp_src(Dev, Off, false).
-
-pp_src(Dev, Src) ->
- pp_src(Dev, Src, true).
-
-pp_src(Dev, Src, Dollar) ->
- case Src of
- #x86_temp{} ->
- pp_temp(Dev, Src);
- #x86_imm{} ->
- pp_imm(Dev, Src, Dollar);
- #x86_mem{} ->
- pp_mem(Dev, Src);
- #x86_fpreg{} ->
- pp_fpreg(Dev, Src)
- end.
-
-pp_dst(Dev, Dst) ->
- pp_src(Dev, Dst).
-
-pp_args(Dev, [A|As]) ->
- pp_src(Dev, A),
- pp_comma_args(Dev, As);
-pp_args(_, []) ->
- ok.
-
-pp_comma_args(Dev, [A|As]) ->
- io:format(Dev, ", ", []),
- pp_src(Dev, A),
- pp_comma_args(Dev, As);
-pp_comma_args(_, []) ->
- ok.
diff --git a/lib/hipe/x86/hipe_x86_ra.erl b/lib/hipe/x86/hipe_x86_ra.erl
deleted file mode 100644
index f358306d49..0000000000
--- a/lib/hipe/x86/hipe_x86_ra.erl
+++ /dev/null
@@ -1,116 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_RA, hipe_amd64_ra).
--define(HIPE_X86_PP, hipe_amd64_pp).
--define(HIPE_X86_RA_LS, hipe_amd64_ra_ls).
--define(HIPE_X86_RA_NAIVE, hipe_amd64_ra_naive).
--define(HIPE_X86_RA_FINALISE, hipe_amd64_ra_finalise).
--define(HIPE_X86_SPECIFIC, hipe_amd64_specific).
--else.
--define(HIPE_X86_RA, hipe_x86_ra).
--define(HIPE_X86_PP, hipe_x86_pp).
--define(HIPE_X86_RA_LS, hipe_x86_ra_ls).
--define(HIPE_X86_RA_NAIVE, hipe_x86_ra_naive).
--define(HIPE_X86_RA_FINALISE, hipe_x86_ra_finalise).
--define(HIPE_X86_SPECIFIC, hipe_x86_specific).
--endif.
-
--module(?HIPE_X86_RA).
--export([ra/2]).
-
-%%-define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.
--include("../main/hipe.hrl").
-
--ifdef(HIPE_INSTRUMENT_COMPILER).
-code_size(CFG) ->
- hipe_x86_cfg:fold_bbs(fun(_, BB, Acc) -> Acc + length(hipe_bb:code(BB)) end,
- 0, CFG).
--endif. %% ifdef(HIPE_INSTRUMENT_COMPILER)
-
-ra(CFG0, Options) ->
- %% hipe_x86_cfg:pp(CFG0),
- Liveness0 = ?HIPE_X86_SPECIFIC:analyze(CFG0, no_context),
- {CFG1, Liveness, Coloring_fp, SpillIndex} = ra_fp(CFG0, Liveness0, Options),
- %% hipe_x86_cfg:pp(CFG1),
- ?start_ra_instrumentation(Options,
- code_size(CFG1),
- element(2,hipe_gensym:var_range(x86))),
- {CFG2, _, Coloring}
- = case proplists:get_value(regalloc, Options, coalescing) of
- coalescing ->
- ra(CFG1, Liveness, SpillIndex, Options, hipe_coalescing_regalloc);
- optimistic ->
- ra(CFG1, Liveness, SpillIndex, Options, hipe_optimistic_regalloc);
- graph_color ->
- ra(CFG1, Liveness, SpillIndex, Options, hipe_graph_coloring_regalloc);
- linear_scan ->
- ?HIPE_X86_RA_LS:ra(CFG1, Liveness, SpillIndex, Options);
- naive ->
- ?HIPE_X86_RA_NAIVE:ra(CFG1, Liveness, Coloring_fp, Options);
- _ ->
- exit({unknown_regalloc_compiler_option,
- proplists:get_value(regalloc,Options)})
- end,
- ?stop_ra_instrumentation(Options,
- code_size(CFG2),
- element(2,hipe_gensym:var_range(x86))),
- %% hipe_x86_cfg:pp(CFG2),
- ?HIPE_X86_RA_FINALISE:finalise(CFG2, Coloring, Coloring_fp, Options).
-
-ra(CFG, Liveness, SpillIndex, Options, RegAllocMod) ->
- hipe_regalloc_loop:ra(CFG, Liveness, SpillIndex, Options, RegAllocMod,
- ?HIPE_X86_SPECIFIC, no_context).
-
--ifdef(HIPE_AMD64).
-ra_fp(CFG, Liveness, Options) ->
- Regalloc0 = proplists:get_value(regalloc, Options),
- {Regalloc, TargetMod} =
- case proplists:get_bool(inline_fp, Options) and (Regalloc0 =/= naive) of
- false -> {naive, undefined};
- true ->
- case proplists:get_bool(x87, Options) of
- true -> {linear_scan, hipe_amd64_specific_x87};
- false -> {Regalloc0, hipe_amd64_specific_sse2}
- end
- end,
- case Regalloc of
- coalescing ->
- ra_fp(CFG, Liveness, Options, hipe_coalescing_regalloc, TargetMod);
- optimistic ->
- ra_fp(CFG, Liveness, Options, hipe_optimistic_regalloc, TargetMod);
- graph_color ->
- ra_fp(CFG, Liveness, Options, hipe_graph_coloring_regalloc, TargetMod);
- linear_scan -> hipe_amd64_ra_ls:ra_fp(CFG, Liveness, Options, TargetMod,
- no_context);
- naive -> {CFG,Liveness,[],0};
- _ ->
- exit({unknown_regalloc_compiler_option,
- proplists:get_value(regalloc,Options)})
- end.
-
-ra_fp(CFG, Liveness, Options, RegAllocMod, TargetMod) ->
- hipe_regalloc_loop:ra_fp(CFG, Liveness, Options, RegAllocMod, TargetMod,
- no_context).
--else.
-ra_fp(CFG, Liveness, Options) ->
- case proplists:get_bool(inline_fp, Options) of
- true ->
- hipe_x86_ra_ls:ra_fp(CFG, Liveness, Options, hipe_x86_specific_x87,
- no_context);
- false ->
- {CFG,Liveness,[],0}
- end.
--endif.
diff --git a/lib/hipe/x86/hipe_x86_ra_finalise.erl b/lib/hipe/x86/hipe_x86_ra_finalise.erl
deleted file mode 100644
index e8abe78e00..0000000000
--- a/lib/hipe/x86/hipe_x86_ra_finalise.erl
+++ /dev/null
@@ -1,335 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% - apply temp -> reg/spill map from RA
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_RA_FINALISE, hipe_amd64_ra_finalise).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_X87, hipe_amd64_x87).
--define(HIPE_X86_SSE2, hipe_amd64_sse2).
--define(IF_HAS_SSE2(Expr), Expr).
--else.
--define(HIPE_X86_RA_FINALISE, hipe_x86_ra_finalise).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_X87, hipe_x86_x87).
--define(IF_HAS_SSE2(Expr),).
--endif.
-
--module(?HIPE_X86_RA_FINALISE).
--export([finalise/4]).
--include("../x86/hipe_x86.hrl").
-
-finalise(CFG0, TempMap, FpMap, Options) ->
- CFG1 = finalise_ra(CFG0, TempMap, FpMap, Options),
- case proplists:get_bool(x87, Options) of
- true ->
- ?HIPE_X86_X87:map(CFG1);
- _ ->
- case
- proplists:get_bool(inline_fp, Options)
- and (proplists:get_value(regalloc, Options) =:= linear_scan)
- of
- %% Ugly, but required to avoid Dialyzer complaints about "Unknown
- %% function" hipe_x86_sse2:map/1
- ?IF_HAS_SSE2(true ->
- ?HIPE_X86_SSE2:map(CFG1);)
- false ->
- CFG1
- end
- end.
-
-%%%
-%%% Finalise the temp->reg/spill mapping.
-%%% (XXX: maybe this should be merged with the main pass,
-%%% but I just want this to work now)
-%%%
-
-finalise_ra(CFG, [], [], _Options) ->
- CFG;
-finalise_ra(CFG, TempMap, FpMap, Options) ->
- {_, SpillLimit} = hipe_gensym:var_range(x86),
- Map = mk_ra_map(TempMap, SpillLimit),
- FpMap0 = mk_ra_map_fp(FpMap, SpillLimit, Options),
- hipe_x86_cfg:map_bbs(fun(_Lbl, BB) -> ra_bb(BB, Map, FpMap0) end, CFG).
-
-ra_bb(BB, Map, FpMap) ->
- hipe_bb:code_update(BB, ra_code(hipe_bb:code(BB), Map, FpMap)).
-
-ra_code(Code, Map, FpMap) ->
- [ra_insn(I, Map, FpMap) || I <- Code].
-
-ra_insn(I, Map, FpMap) ->
- case I of
- #alu{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#alu{src=Src,dst=Dst};
- #call{} ->
- I;
- #cmovcc{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#cmovcc{src=Src,dst=Dst};
- #cmp{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#cmp{src=Src,dst=Dst};
- #comment{} ->
- I;
- #fmove{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map, FpMap),
- Dst = ra_opnd(Dst0, Map, FpMap),
- I#fmove{src=Src,dst=Dst};
- #fp_unop{arg=Arg0} ->
- Arg = ra_opnd(Arg0, Map, FpMap),
- I#fp_unop{arg=Arg};
- #fp_binop{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map, FpMap),
- Dst = ra_opnd(Dst0, Map, FpMap),
- I#fp_binop{src=Src,dst=Dst};
- #imul{src=Src0,temp=Temp0} ->
- Src = ra_opnd(Src0, Map),
- Temp = ra_temp(Temp0, Map),
- I#imul{src=Src,temp=Temp};
- #jcc{} ->
- I;
- #jmp_fun{'fun'=Fun0} ->
- Fun = ra_opnd(Fun0, Map),
- I#jmp_fun{'fun'=Fun};
- #jmp_label{} ->
- I;
- #jmp_switch{temp=Temp0,jtab=JTab0} ->
- Temp = ra_opnd(Temp0, Map),
- JTab = ra_opnd(JTab0, Map),
- I#jmp_switch{temp=Temp,jtab=JTab};
- #label{} ->
- I;
- #lea{mem=Mem0,temp=Temp0} ->
- Mem = ra_mem(Mem0, Map),
- Temp = ra_temp(Temp0, Map),
- I#lea{mem=Mem,temp=Temp};
- #move{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#move{src=Src,dst=Dst};
- #move64{dst=Dst0} ->
- Dst = ra_opnd(Dst0, Map),
- I#move64{dst=Dst};
- #movsx{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#movsx{src=Src,dst=Dst};
- #movzx{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#movzx{src=Src,dst=Dst};
- #pseudo_call{'fun'=Fun0} ->
- Fun = ra_opnd(Fun0, Map),
- I#pseudo_call{'fun'=Fun};
- #pseudo_jcc{} ->
- I;
- #pseudo_spill_fmove{src=Src0, temp=Temp0, dst=Dst0} ->
- Src = ra_opnd(Src0, Map, FpMap),
- Temp = ra_opnd(Temp0, Map, FpMap),
- Dst = ra_opnd(Dst0, Map, FpMap),
- I#pseudo_spill_fmove{src=Src, temp=Temp, dst=Dst};
- #pseudo_spill_move{src=Src0, temp=Temp0, dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Temp = ra_opnd(Temp0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#pseudo_spill_move{src=Src, temp=Temp, dst=Dst};
- #pseudo_tailcall{'fun'=Fun0,stkargs=StkArgs0} ->
- Fun = ra_opnd(Fun0, Map),
- StkArgs = ra_args(StkArgs0, Map),
- I#pseudo_tailcall{'fun'=Fun,stkargs=StkArgs};
- #pseudo_tailcall_prepare{} ->
- I;
- #push{src=Src0} ->
- Src = ra_opnd(Src0, Map),
- I#push{src=Src};
- #ret{} ->
- I;
- #shift{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#shift{src=Src,dst=Dst};
- #test{src=Src0,dst=Dst0} ->
- Src = ra_opnd(Src0, Map),
- Dst = ra_opnd(Dst0, Map),
- I#test{src=Src,dst=Dst};
- _ ->
- exit({?MODULE,ra_insn,I})
- end.
-
-ra_args(Args, Map) ->
- [ra_opnd(Opnd, Map) || Opnd <- Args].
-
-ra_opnd(Opnd, Map) ->
- ra_opnd(Opnd, Map, gb_trees:empty()).
-ra_opnd(Opnd, Map, FpMap) ->
- case Opnd of
- #x86_temp{} -> ra_temp(Opnd, Map, FpMap);
- #x86_mem{} -> ra_mem(Opnd, Map);
- _ -> Opnd
- end.
-
-ra_mem(Mem, Map) ->
- #x86_mem{base=Base0,off=Off0} = Mem,
- Base = ra_opnd(Base0, Map),
- Off = ra_opnd(Off0, Map),
- Mem#x86_mem{base=Base,off=Off}.
-
-ra_temp(Temp, Map) ->
- ra_temp(Temp, Map, gb_trees:empty()).
-
-ra_temp(Temp, Map, FpMap) ->
- Reg = hipe_x86:temp_reg(Temp),
- case hipe_x86:temp_type(Temp) of
- double ->
- ra_temp_double(Temp, Reg, FpMap);
- _->
- case ?HIPE_X86_REGISTERS:is_precoloured(Reg) of
- true ->
- Temp;
- _ ->
- case gb_trees:lookup(Reg, Map) of
- {value,NewReg} -> Temp#x86_temp{reg=NewReg};
- _ -> Temp
- end
- end
- end.
-
--ifdef(HIPE_AMD64).
-ra_temp_double(Temp, Reg, FpMap) ->
- case hipe_amd64_registers:is_precoloured_sse2(Reg) of
- true ->
- Temp;
- _ ->
- case gb_trees:lookup(Reg, FpMap) of
- {value,NewReg} -> Temp#x86_temp{reg=NewReg};
- _ -> Temp
- end
- end.
--else.
-ra_temp_double(Temp, Reg, FpMap) ->
- case gb_trees:lookup(Reg, FpMap) of
- {value,NewReg} ->
- case hipe_x86_registers:is_precoloured_x87(NewReg) of
- true -> hipe_x86:mk_fpreg(NewReg);
- false ->
- Temp#x86_temp{reg=NewReg}
- end;
- _ ->
- Temp
- end.
--endif.
-
-mk_ra_map(TempMap, SpillLimit) ->
- %% Build a partial map from pseudo to reg or spill.
- %% Spills are represented as pseudos with indices above SpillLimit.
- %% (I'd prefer to use negative indices, but that breaks
- %% ?HIPE_X86_REGISTERS:is_precoloured/1.)
- %% The frame mapping proper is unchanged, since spills look just like
- %% ordinary (un-allocated) pseudos.
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit,
- is_precoloured),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- TempMap).
-
-conv_ra_maplet({From,To}, SpillLimit, IsPrecoloured)
- when is_integer(From), From =< SpillLimit ->
- %% From should be a pseudo, or a hard reg mapped to itself.
- case ?HIPE_X86_REGISTERS:IsPrecoloured(From) of
- false -> ok;
- _ -> To = {reg, From}, ok
- end,
- %% end of From check
- case To of
- {reg, NewReg} when is_integer(NewReg) ->
- %% NewReg should be a hard reg, or a pseudo mapped
- %% to itself (formals are handled this way).
- true = (?HIPE_X86_REGISTERS:IsPrecoloured(NewReg) orelse From =:= NewReg),
- {From, NewReg};
- {spill, SpillIndex} when is_integer(SpillIndex), SpillIndex >= 0 ->
- ToTempNum = SpillLimit+SpillIndex+1,
- MaxTempNum = hipe_gensym:get_var(x86),
- if MaxTempNum >= ToTempNum -> ok;
- true -> hipe_gensym:set_var(x86, ToTempNum)
- end,
- {From, ToTempNum}
- end.
-
-mk_ra_map_x87(FpMap, SpillLimit) ->
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit,
- is_precoloured_x87),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- FpMap).
-
--ifdef(HIPE_AMD64).
-mk_ra_map_sse2(FpMap, SpillLimit) ->
- lists:foldl(fun(MapLet, Map) ->
- {Key,Val} = conv_ra_maplet(MapLet, SpillLimit,
- is_precoloured_sse2),
- gb_trees:insert(Key, Val, Map)
- end,
- gb_trees:empty(),
- FpMap).
-
-mk_ra_map_fp(FpMap, SpillLimit, Options) ->
- case proplists:get_bool(x87, Options) of
- true -> mk_ra_map_x87(FpMap, SpillLimit);
- false -> mk_ra_map_sse2(FpMap, SpillLimit)
- end.
--else.
-mk_ra_map_fp(FpMap, SpillLimit, _Options) ->
- mk_ra_map_x87(FpMap, SpillLimit).
--endif.
-
--ifdef(notdef).
-conv_ra_maplet_fp(MapLet = {From,To}, SpillLimit) ->
- %% From should be a pseudo
- if is_integer(From), From =< SpillLimit -> [];
- true -> exit({?MODULE,conv_ra_maplet_fp,MapLet})
- end,
- %% end of From check
- case To of
- {reg, NewReg} ->
- case hipe_x86_registers:is_precoloured_x87(NewReg) of
- true-> [];
- false -> exit({?MODULE,conv_ra_maplet_fp,MapLet})
- end,
- %% end of NewReg check.
- {From, NewReg};
- {spill, SpillIndex} ->
- %% SpillIndex should be >= 0.
- if is_integer(SpillIndex), SpillIndex >= 0 -> [];
- true -> exit({?MODULE,conv_ra_maplet_fp,MapLet})
- end,
- %% end of SpillIndex check
- ToTempNum = SpillLimit+SpillIndex+1,
- MaxTempNum = hipe_gensym:get_var(x86),
- if MaxTempNum >= ToTempNum -> [];
- true -> hipe_gensym:set_var(x86, ToTempNum)
- end,
- {From, ToTempNum};
- _ -> exit({?MODULE,conv_ra_maplet_fp,MapLet})
- end.
--endif.
diff --git a/lib/hipe/x86/hipe_x86_ra_ls.erl b/lib/hipe/x86/hipe_x86_ra_ls.erl
deleted file mode 100644
index 581abd299d..0000000000
--- a/lib/hipe/x86/hipe_x86_ra_ls.erl
+++ /dev/null
@@ -1,104 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% Linear Scan register allocator for x86
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_RA_LS, hipe_amd64_ra_ls).
--define(HIPE_X86_PP, hipe_amd64_pp).
--define(HIPE_X86_RA_POSTCONDITIONS, hipe_amd64_ra_postconditions).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_SPECIFIC, hipe_amd64_specific).
--else.
--define(HIPE_X86_RA_LS, hipe_x86_ra_ls).
--define(HIPE_X86_PP, hipe_x86_pp).
--define(HIPE_X86_RA_POSTCONDITIONS, hipe_x86_ra_postconditions).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_SPECIFIC, hipe_x86_specific).
--endif.
-
--module(?HIPE_X86_RA_LS).
--export([ra/4,ra_fp/5]).
--define(HIPE_INSTRUMENT_COMPILER, true). %% Turn on instrumentation.
--include("../main/hipe.hrl").
-
-ra(CFG, Liveness, SpillIndex, Options) ->
- SpillLimit = ?HIPE_X86_SPECIFIC:number_of_temporaries(
- CFG, no_context),
- ?inc_counter(bbs_counter, length(hipe_x86_cfg:labels(CFG))),
- alloc(CFG, Liveness, SpillIndex, SpillLimit, Options).
-
-ra_fp(CFG, Liveness, Options, TargetMod, TargetCtx) ->
- ?inc_counter(ra_calls_counter,1),
- %% ?inc_counter(ra_caller_saves_counter,count_caller_saves(CFG)),
- SpillIndex = 0,
- SpillLimit = TargetMod:number_of_temporaries(CFG, TargetCtx),
- ?inc_counter(bbs_counter, length(hipe_x86_cfg:labels(CFG))),
-
- ?inc_counter(ra_iteration_counter,1),
- %% ?HIPE_X86_PP:pp(Defun),
-
- {Coloring,NewSpillIndex} =
- regalloc(CFG, Liveness,
- TargetMod:allocatable('linearscan', TargetCtx),
- [hipe_x86_cfg:start_label(CFG)],
- SpillIndex, SpillLimit, Options,
- TargetMod, TargetCtx),
-
- {NewCFG, _DidSpill} =
- TargetMod:check_and_rewrite(CFG, Coloring, 'linearscan', TargetCtx),
- TempMap = hipe_temp_map:cols2tuple(Coloring, TargetMod, TargetCtx),
- {TempMap2, NewSpillIndex2} =
- hipe_spillmin:stackalloc(CFG, Liveness, [], SpillIndex, Options,
- TargetMod, TargetCtx, TempMap),
- Coloring2 =
- hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), TempMap2),
- ?add_spills(Options, NewSpillIndex),
- {NewCFG, Liveness, Coloring2, NewSpillIndex2}.
-
-alloc(CFG, Liveness, SpillIndex, SpillLimit, Options) ->
- ?inc_counter(ra_iteration_counter,1),
- %% ?HIPE_X86_PP:pp(Defun),
- {Coloring, NewSpillIndex} =
- regalloc(
- CFG, Liveness,
- ?HIPE_X86_REGISTERS:allocatable()--
- [?HIPE_X86_REGISTERS:temp1(),
- ?HIPE_X86_REGISTERS:temp0()],
- [hipe_x86_cfg:start_label(CFG)],
- SpillIndex, SpillLimit, Options,
- ?HIPE_X86_SPECIFIC, no_context),
- {NewCFG, _DidSpill} =
- ?HIPE_X86_RA_POSTCONDITIONS:check_and_rewrite(
- CFG, Coloring, 'linearscan'),
- %% ?HIPE_X86_PP:pp(NewDefun),
- TempMap = hipe_temp_map:cols2tuple(Coloring, ?HIPE_X86_SPECIFIC, no_context),
- {TempMap2,NewSpillIndex2} =
- hipe_spillmin:stackalloc(CFG, Liveness, [], SpillIndex, Options,
- ?HIPE_X86_SPECIFIC, no_context, TempMap),
- Coloring2 =
- hipe_spillmin:mapmerge(hipe_temp_map:to_substlist(TempMap), TempMap2),
- case proplists:get_bool(verbose_spills, Options) of
- true ->
- ?msg("Stack slot size: ~p~n",[NewSpillIndex2-SpillIndex]);
- false ->
- ok
- end,
- ?add_spills(Options, NewSpillIndex),
- {NewCFG, Liveness, Coloring2}.
-
-regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex, DontSpill, Options,
- TgtMod, TgtCtx) ->
- hipe_ls_regalloc:regalloc(CFG, Liveness, PhysRegs, Entrypoints, SpillIndex,
- DontSpill, Options, TgtMod, TgtCtx).
diff --git a/lib/hipe/x86/hipe_x86_ra_naive.erl b/lib/hipe/x86/hipe_x86_ra_naive.erl
deleted file mode 100644
index f96c662d18..0000000000
--- a/lib/hipe/x86/hipe_x86_ra_naive.erl
+++ /dev/null
@@ -1,412 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% simple local x86 regalloc
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_RA_NAIVE, hipe_amd64_ra_naive).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_SPECIFIC_FP, hipe_amd64_specific_sse2).
--define(ECX, rcx).
--else.
--define(HIPE_X86_RA_NAIVE, hipe_x86_ra_naive).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_SPECIFIC_FP, hipe_x86_specific_x87).
--define(ECX, ecx).
--endif.
-
--module(?HIPE_X86_RA_NAIVE).
--export([ra/4]).
-
--include("../x86/hipe_x86.hrl").
--define(HIPE_INSTRUMENT_COMPILER, true). % enable instrumentation
--include("../main/hipe.hrl").
-
-ra(CFG0, Liveness, Coloring_fp, Options) ->
- CFG = hipe_x86_cfg:map_bbs(fun do_bb/2, CFG0),
- NofSpilledFloats = count_non_float_spills(Coloring_fp),
- NofFloats = length(Coloring_fp),
- ?add_spills(Options, hipe_gensym:get_var(x86) -
- ?HIPE_X86_REGISTERS:first_virtual()-
- NofSpilledFloats -
- NofFloats),
- TempMap = [],
- {CFG, Liveness,
- TempMap}.
-
-do_bb(_Lbl, BB) ->
- hipe_bb:code_update(BB, do_insns(hipe_bb:code(BB))).
-
-count_non_float_spills(Coloring_fp) ->
- count_non_float_spills(Coloring_fp, 0).
-
-count_non_float_spills([{_,To}|Tail], Num) ->
- case ?HIPE_X86_SPECIFIC_FP:is_precoloured(To, no_context) of
- true ->
- count_non_float_spills(Tail, Num);
- false ->
- count_non_float_spills(Tail, Num+1)
- end;
-count_non_float_spills([], Num) ->
- Num.
-
-do_insns([I|Insns]) ->
- do_insn(I) ++ do_insns(Insns);
-do_insns([]) ->
- [].
-
-do_insn(I) -> % Insn -> Insn list
- case I of
- #alu{} ->
- do_alu(I);
- #cmp{} ->
- do_cmp(I);
- #imul{} ->
- do_imul(I);
- #jmp_switch{} ->
- do_jmp_switch(I);
- #lea{} ->
- do_lea(I);
- #move{} ->
- do_move(I);
- #move64{} ->
- do_move64(I);
- #movzx{} ->
- do_movx(I);
- #movsx{} ->
- do_movx(I);
- #fmove{} ->
- do_fmove(I);
- #fp_unop{} ->
- do_fp_unop(I);
- #fp_binop{} ->
- do_fp_binop(I);
- #shift{} ->
- do_shift(I);
- #test{} ->
- do_test(I);
- #label{} ->
- [I];
- #pseudo_jcc{} ->
- [I];
- #pseudo_call{} ->
- [I];
- #ret{} ->
- [I];
- #pseudo_tailcall_prepare{} ->
- [I];
- #pseudo_tailcall{} ->
- [I];
- #push{} ->
- [I];
- #jmp_label{} ->
- [I];
- #comment{} ->
- [I];
- _ ->
- io:format("Unknown Instruction = ~w\n", [I]),
- exit({?MODULE, unknown_instruction, I})
- end.
-
-%%% Fix an alu op.
-
-do_alu(I) ->
- #alu{src=Src0,dst=Dst0} = I,
- {FixSrc,Src,FixDst,Dst} = do_binary(Src0, Dst0),
- FixSrc ++ FixDst ++ [I#alu{src=Src,dst=Dst}].
-
-%%% Fix a cmp op.
-
-do_cmp(I) ->
- #cmp{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
- FixSrc ++ FixDst ++ [I#cmp{src=Src,dst=Dst}].
-
-%%% Fix an imul op.
-
-do_imul(I) ->
- #imul{imm_opt=ImmOpt,src=Src0,temp=Temp0} = I,
- {FixSrc,Src} = fix_src_operand(Src0), % may use temp0
- {FixTempSrc,Temp,FixTempDst} =
- case temp_is_pseudo(Temp0) of
- false ->
- {[], Temp0, []};
- true ->
- Reg = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp1(), 'untagged'),
- {case ImmOpt of
- [] -> [hipe_x86:mk_move(Temp0, Reg)]; % temp *= src
- _ -> [] % temp = src * imm
- end,
- Reg,
- [hipe_x86:mk_move(Reg, Temp0)]}
- end,
- FixSrc ++ FixTempSrc ++ [I#imul{src=Src,temp=Temp}] ++ FixTempDst.
-
-%%% Fix a jmp_switch op.
-
--ifdef(HIPE_AMD64).
-do_jmp_switch(I) ->
- #jmp_switch{temp=Temp, jtab=Tab} = I,
- case temp_is_pseudo(Temp) of
- false ->
- case temp_is_pseudo(Tab) of
- false ->
- [I];
- true ->
- Reg = hipe_x86:mk_temp(hipe_amd64_registers:temp0(), 'untagged'),
- [hipe_x86:mk_move(Temp, Reg), I#jmp_switch{jtab=Reg}]
- end;
- true ->
- Reg = hipe_x86:mk_temp(hipe_amd64_registers:temp1(), 'untagged'),
- case temp_is_pseudo(Tab) of
- false ->
- [hipe_x86:mk_move(Temp, Reg), I#jmp_switch{temp=Reg}];
- true ->
- Reg2 = hipe_x86:mk_temp(hipe_amd64_registers:temp0(), 'untagged'),
- [hipe_x86:mk_move(Temp, Reg),
- hipe_x86:mk_move(Tab, Reg2),
- I#jmp_switch{temp=Reg, jtab=Reg2}]
- end
- end.
--else.
-do_jmp_switch(I) ->
- #jmp_switch{temp=Temp} = I,
- case temp_is_pseudo(Temp) of
- false ->
- [I];
- true ->
- Reg = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp0(), 'untagged'),
- [hipe_x86:mk_move(Temp, Reg), I#jmp_switch{temp=Reg}]
- end.
--endif.
-
-%%% Fix a lea op.
-
-do_lea(I) ->
- #lea{temp=Temp} = I,
- case temp_is_pseudo(Temp) of
- false ->
- [I];
- true ->
- Reg = hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp0(), 'untagged'),
- [I#lea{temp=Reg}, hipe_x86:mk_move(Reg, Temp)]
- end.
-
-%%% Fix a move op.
-
-do_move(I) ->
- #move{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
- FixSrc ++ FixDst ++ [I#move{src=Src,dst=Dst}].
-
--ifdef(HIPE_AMD64).
-do_move64(I) ->
- #move64{dst=Dst} = I,
- case is_mem_opnd(Dst) of
- false ->
- [I];
- true ->
- Reg = hipe_amd64_registers:temp1(),
- NewDst = clone(Dst, Reg),
- [I#move64{dst=NewDst}, hipe_x86:mk_move(NewDst, Dst)]
- end.
--else.
-do_move64(I) -> exit({?MODULE, I}).
--endif.
-
-do_movx(I) ->
- {{FixSrc, Src}, {FixDst, Dst}} =
- case I of
- #movsx{src=Src0,dst=Dst0} ->
- {fix_src_operand(Src0), fix_dst_operand(Dst0)};
- #movzx{src=Src0,dst=Dst0} ->
- {fix_src_operand(Src0), fix_dst_operand(Dst0)}
- end,
- Reg = ?HIPE_X86_REGISTERS:temp0(),
- Dst2 = clone(Dst, Reg),
- I2 = case is_mem_opnd(Dst) of
- true ->
- Reg = ?HIPE_X86_REGISTERS:temp0(),
- Dst2 = clone(Dst, Reg),
- case I of
- #movsx{} ->
- [hipe_x86:mk_movsx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)];
- #movzx{} ->
- [hipe_x86:mk_movzx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)]
- end;
- false ->
- case I of
- #movsx{} ->
- [hipe_x86:mk_movsx(Src, Dst)];
- #movzx{} ->
- [hipe_x86:mk_movzx(Src, Dst)]
- end
- end,
- FixSrc ++ FixDst ++ I2.
-
-
-%%% Fix a fmove op.
-%% conv_to_float
-do_fmove(I=#fmove{src=#x86_temp{type=untagged},
- dst=#x86_temp{type=double}}) ->
- #fmove{src=Src0,dst=Dst0} = I,
- Src = clone(Src0, ?HIPE_X86_REGISTERS:temp0()),
- Dst = clone(Dst0, ?HIPE_X86_REGISTERS:temp1()),
- [hipe_x86:mk_move(Src0, Src),
- I#fmove{src=Src, dst=Dst},
- hipe_x86:mk_fmove(Dst, Dst0)];
-%% fmove
-do_fmove(I) ->
- #fmove{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
- FixSrc ++ FixDst ++ [I#fmove{src=Src,dst=Dst}].
-
-do_fp_unop(I) ->
- #fp_unop{arg=Arg} = I,
- case is_mem_opnd(Arg) of
- false ->
- [I];
- true ->
- Reg = ?HIPE_X86_REGISTERS:temp1(),
- NewArg = clone(Arg, Reg),
- [hipe_x86:mk_fmove(Arg, NewArg),
- I#fp_unop{arg=NewArg},
- hipe_x86:mk_fmove(NewArg, Arg)]
- end.
-
-do_fp_binop(I) ->
- #fp_binop{src=Src0, dst=Dst0} = I,
- {FixSrc, Src} = fix_src_operand(Src0),
- {FixDst, Dst} = fix_dst_operand(Dst0),
- Reg = ?HIPE_X86_REGISTERS:temp1(),
- Dst2 = clone(Dst, Reg),
- FixSrc ++ FixDst ++ [hipe_x86:mk_fmove(Dst, Dst2),
- I#fp_binop{src=Src, dst=Dst2},
- hipe_x86:mk_fmove(Dst2, Dst)].
-
-do_shift(I) ->
- #shift{src=Src0,dst=Dst0} = I,
- {FixDst, Dst} = fix_dst_operand(Dst0),
- Reg = ?HIPE_X86_REGISTERS:?ECX(),
- case Src0 of
- #x86_imm{} ->
- FixDst ++ [I#shift{dst=Dst}];
- #x86_temp{reg=Reg} ->
- FixDst ++ [I#shift{dst=Dst}]
- end.
-
-do_test(I) ->
- #test{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, FixDst, Dst} = do_binary(Src0, Dst0),
- FixSrc ++ FixDst ++ [I#test{src=Src,dst=Dst}].
-
-%%% Fix the operands of a binary op.
-%%% 1. remove pseudos from any explicit memory operands
-%%% 2. if both operands are (implicit or explicit) memory operands,
-%%% move src to a reg and use reg as src in the original insn
-
-do_binary(Src0, Dst0) ->
- {FixSrc, Src} = fix_src_operand(Src0),
- {FixDst, Dst} = fix_dst_operand(Dst0),
- {FixSrc3, Src3} =
- case is_mem_opnd(Src) of
- false ->
- {FixSrc, Src};
- true ->
- case is_mem_opnd(Dst) of
- false ->
- {FixSrc, Src};
- true ->
- Reg = ?HIPE_X86_REGISTERS:temp0(),
- Src2 = clone(Src, Reg),
- FixSrc2 = FixSrc ++ [mk_move(Src, Src2)],
- {FixSrc2, Src2}
- end
- end,
- {FixSrc3, Src3, FixDst, Dst}.
-
-%%% Fix any x86_mem operand to not refer to any pseudos.
-%%% The fixup may use additional instructions and registers.
-%%% 'src' operands may clobber '%temp0'.
-%%% 'dst' operands may clobber '%temp1'.
-
-fix_src_operand(Opnd) ->
- fix_mem_operand(Opnd, ?HIPE_X86_REGISTERS:temp0()).
-
-fix_dst_operand(Opnd) ->
- fix_mem_operand(Opnd, ?HIPE_X86_REGISTERS:temp1()).
-
-fix_mem_operand(Opnd, Reg) -> % -> {[fixupcode], newop}
- case Opnd of
- #x86_mem{base=Base,off=Off} ->
- case is_mem_opnd(Base) of
- false ->
- case src_is_pseudo(Off) of
- false ->
- {[], Opnd};
- true -> % pseudo(reg)
- Temp = clone(Off, Reg),
- {[hipe_x86:mk_move(Off, Temp)],
- Opnd#x86_mem{off=Temp}}
- end;
- true ->
- Temp = clone(Base, Reg),
- case src_is_pseudo(Off) of
- false -> % imm/reg(pseudo)
- {[hipe_x86:mk_move(Base, Temp)],
- Opnd#x86_mem{base=Temp}};
- true -> % pseudo1(pseudo0)
- {[hipe_x86:mk_move(Base, Temp),
- hipe_x86:mk_alu('add', Off, Temp)],
- Opnd#x86_mem{base=Temp, off=hipe_x86:mk_imm(0)}}
- end
- end;
- _ ->
- {[], Opnd}
- end.
-
-%%% Check if an operand denotes a memory cell (mem or pseudo).
-
-is_mem_opnd(Opnd) ->
- case Opnd of
- #x86_mem{} -> true;
- #x86_temp{} -> temp_is_pseudo(Opnd);
- _ -> false
- end.
-
-%%% Check if an operand is a pseudo-Temp.
-
-src_is_pseudo(Src) ->
- case hipe_x86:is_temp(Src) of
- true -> temp_is_pseudo(Src);
- false -> false
- end.
-
-temp_is_pseudo(Temp) ->
- not(?HIPE_X86_REGISTERS:is_precoloured(hipe_x86:temp_reg(Temp))).
-
-%%% Make Reg a clone of Dst (attach Dst's type to Reg).
-
-clone(Dst, Reg) ->
- Type =
- case Dst of
- #x86_mem{} -> hipe_x86:mem_type(Dst);
- #x86_temp{} -> hipe_x86:temp_type(Dst)
- end,
- hipe_x86:mk_temp(Reg, Type).
-
-mk_move(Src, Dst=#x86_temp{type=double}) ->
- hipe_x86:mk_fmove(Src, Dst);
-mk_move(Src, Dst) ->
- hipe_x86:mk_move(Src, Dst).
diff --git a/lib/hipe/x86/hipe_x86_ra_postconditions.erl b/lib/hipe/x86/hipe_x86_ra_postconditions.erl
deleted file mode 100644
index db6391d5c1..0000000000
--- a/lib/hipe/x86/hipe_x86_ra_postconditions.erl
+++ /dev/null
@@ -1,474 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_RA_POSTCONDITIONS, hipe_amd64_ra_postconditions).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_SPECIFIC, hipe_amd64_specific).
--define(ECX, rcx).
--else.
--define(HIPE_X86_RA_POSTCONDITIONS, hipe_x86_ra_postconditions).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_SPECIFIC, hipe_x86_specific).
--define(ECX, ecx).
--endif.
-
--module(?HIPE_X86_RA_POSTCONDITIONS).
-
--export([check_and_rewrite/3]).
-
--include("../x86/hipe_x86.hrl").
--define(HIPE_INSTRUMENT_COMPILER, true).
--include("../main/hipe.hrl").
--define(count_temp(T), ?cons_counter(counter_mfa_mem_temps, T)).
-
-check_and_rewrite(CFG, Coloring, Strategy) ->
- %% io:format("Converting\n"),
- TempMap = hipe_temp_map:cols2tuple(Coloring, ?HIPE_X86_SPECIFIC, no_context),
- %% io:format("Rewriting\n"),
- do_bbs(hipe_x86_cfg:labels(CFG), TempMap, Strategy, CFG, false).
-
-do_bbs([], _, _, CFG, DidSpill) -> {CFG, DidSpill};
-do_bbs([Lbl|Lbls], TempMap, Strategy, CFG0, DidSpill0) ->
- Code0 = hipe_bb:code(BB = hipe_x86_cfg:bb(CFG0, Lbl)),
- {Code, DidSpill} = do_insns(Code0, TempMap, Strategy, [], DidSpill0),
- CFG = hipe_x86_cfg:bb_add(CFG0, Lbl, hipe_bb:code_update(BB, Code)),
- do_bbs(Lbls, TempMap, Strategy, CFG, DidSpill).
-
-do_insns([I|Insns], TempMap, Strategy, Accum, DidSpill0) ->
- {NewIs, DidSpill1} = do_insn(I, TempMap, Strategy),
- do_insns(Insns, TempMap, Strategy, lists:reverse(NewIs, Accum), DidSpill0 or DidSpill1);
-do_insns([], _TempMap, _Strategy, Accum, DidSpill) ->
- {lists:reverse(Accum), DidSpill}.
-
-do_insn(I, TempMap, Strategy) -> % Insn -> {Insn list, DidSpill}
- case I of
- #alu{} ->
- do_alu(I, TempMap, Strategy);
- #cmp{} ->
- do_cmp(I, TempMap, Strategy);
- #imul{} ->
- do_imul(I, TempMap, Strategy);
- #jmp_switch{} ->
- do_jmp_switch(I, TempMap, Strategy);
- #lea{} ->
- do_lea(I, TempMap, Strategy);
- #move{} ->
- do_move(I, TempMap, Strategy);
- #move64{} ->
- do_move64(I, TempMap, Strategy);
- #movsx{} ->
- do_movx(I, TempMap, Strategy);
- #movzx{} ->
- do_movx(I, TempMap, Strategy);
- #fmove{} ->
- do_fmove(I, TempMap, Strategy);
- #pseudo_spill_move{} ->
- do_pseudo_spill_move(I, TempMap, Strategy);
- #shift{} ->
- do_shift(I, TempMap, Strategy);
- #test{} ->
- do_test(I, TempMap, Strategy);
- _ ->
- %% comment, jmp*, label, pseudo_call, pseudo_jcc, pseudo_tailcall,
- %% pseudo_tailcall_prepare, push, ret
- {[I], false}
- end.
-
-%%% Fix an alu op.
-
-do_alu(I, TempMap, Strategy) ->
- #alu{src=Src0,dst=Dst0} = I,
- {FixSrc,Src,FixDst,Dst,DidSpill} =
- do_binary(Src0, Dst0, TempMap, Strategy),
- {FixSrc ++ FixDst ++ [I#alu{src=Src,dst=Dst}], DidSpill}.
-
-%%% Fix a cmp op.
-
-do_cmp(I, TempMap, Strategy) ->
- #cmp{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, FixDst, Dst, DidSpill} =
- do_binary(Src0, Dst0, TempMap, Strategy),
- {FixSrc ++ FixDst ++ [I#cmp{src=Src,dst=Dst}], DidSpill}.
-
-%%% Fix an imul op.
-
-do_imul(I, TempMap, Strategy) ->
- #imul{imm_opt=ImmOpt,src=Src0,temp=Temp0} = I,
- {FixSrc,Src,DidSpill1} = fix_src_operand(Src0, TempMap, Strategy), % temp1
- {FixTempSrc,Temp,FixTempDst,DidSpill2} =
- case is_spilled(Temp0, TempMap) of
- false ->
- {[], Temp0, [], false};
- true ->
- Reg = spill_temp0('untagged', Strategy),
- {case ImmOpt of
- [] -> [hipe_x86:mk_move(Temp0, Reg)]; % temp *= src
- _ -> [] % temp = src * imm
- end,
- Reg,
- [hipe_x86:mk_move(Reg, Temp0)],
- true}
- end,
- {FixSrc ++ FixTempSrc ++ [I#imul{src=Src,temp=Temp}] ++ FixTempDst,
- DidSpill1 or DidSpill2}.
-
-%%% Fix a jmp_switch op.
-
--ifdef(HIPE_AMD64).
-do_jmp_switch(I, TempMap, Strategy) ->
- #jmp_switch{temp=Temp, jtab=Tab} = I,
- case is_spilled(Temp, TempMap) of
- false ->
- case is_spilled(Tab, TempMap) of
- false ->
- {[I], false};
- true ->
- NewTab = spill_temp('untagged', Strategy),
- {[hipe_x86:mk_move(Tab, NewTab), I#jmp_switch{jtab=Tab}],
- true}
- end;
- true ->
- case is_spilled(Tab, TempMap) of
- false ->
- NewTmp = spill_temp('untagged', Strategy),
- {[hipe_x86:mk_move(Temp, NewTmp), I#jmp_switch{temp=NewTmp}],
- true};
- true ->
- NewTmp = spill_temp('untagged', Strategy),
- NewTab = spill_temp0('untagged', Strategy),
- {[hipe_x86:mk_move(Temp, NewTmp),
- hipe_x86:mk_move(Tab, NewTab),
- I#jmp_switch{temp=NewTmp, jtab=NewTab}],
- true}
- end
- end.
--else. % not AMD64
-do_jmp_switch(I, TempMap, Strategy) ->
- #jmp_switch{temp=Temp} = I,
- case is_spilled(Temp, TempMap) of
- false ->
- {[I], false};
- true ->
- NewTmp = spill_temp('untagged', Strategy),
- {[hipe_x86:mk_move(Temp, NewTmp), I#jmp_switch{temp=NewTmp}],
- true}
- end.
--endif. % not AMD64
-
-%%% Fix a lea op.
-
-do_lea(I, TempMap, Strategy) ->
- #lea{mem=Mem0,temp=Temp0} = I,
- {FixMem, Mem, DidSpill1} = fix_mem_operand(Mem0, TempMap, temp1(Strategy)),
- case Mem of
- #x86_mem{base=Base, off=#x86_imm{value=0}} ->
- %% We've decayed into a move due to both operands being memory (there's an
- %% 'add' in FixMem).
- {FixMem ++ [hipe_x86:mk_move(Base, Temp0)], DidSpill1};
- #x86_mem{} ->
- {StoreTemp, Temp, DidSpill2} =
- case is_mem_opnd(Temp0, TempMap) of
- false -> {[], Temp0, false};
- true ->
- Temp1 = clone2(Temp0, temp0(Strategy)),
- {[hipe_x86:mk_move(Temp1, Temp0)], Temp1, true}
- end,
- {FixMem ++ [I#lea{mem=Mem,temp=Temp} | StoreTemp], DidSpill1 or DidSpill2}
- end.
-
-%%% Fix a move op.
-
-do_move(I, TempMap, Strategy) ->
- #move{src=Src0,dst=Dst0} = I,
- case
- is_record(Src0, x86_temp) andalso is_record(Dst0, x86_temp)
- andalso is_spilled(Src0, TempMap) andalso is_spilled(Dst0, TempMap)
- of
- true ->
- Tmp = clone(Src0, Strategy),
- {[hipe_x86:mk_pseudo_spill_move(Src0, Tmp, Dst0)], true};
- false ->
- {FixSrc, Src, FixDst, Dst, DidSpill} =
- do_check_byte_move(Src0, Dst0, TempMap, Strategy),
- {FixSrc ++ FixDst ++ [I#move{src=Src,dst=Dst}],
- DidSpill}
- end.
-
--ifdef(HIPE_AMD64).
-
-%%% AMD64 has no issues with byte moves.
-do_check_byte_move(Src0, Dst0, TempMap, Strategy) ->
- do_binary(Src0, Dst0, TempMap, Strategy).
-
--else. % not AMD64
-
-%%% x86 can only do byte moves to a subset of the integer registers.
-do_check_byte_move(Src0, Dst0, TempMap, Strategy) ->
- case Dst0 of
- #x86_mem{type=byte} ->
- do_byte_move(Src0, Dst0, TempMap, Strategy);
- _ ->
- do_binary(Src0, Dst0, TempMap, Strategy)
- end.
-
-do_byte_move(Src0, Dst0, TempMap, Strategy) ->
- {FixSrc, Src, DidSpill1} = fix_src_operand(Src0, TempMap, Strategy),
- {FixDst, Dst, DidSpill2} = fix_dst_operand(Dst0, TempMap, Strategy),
- Reg = hipe_x86_registers:eax(),
- {FixSrc3, Src3} = % XXX: this just checks Src, the result is known!
- case Src of
- #x86_imm{} ->
- {FixSrc, Src};
- #x86_temp{reg=Reg} -> % small moves must start from reg 1->4
- {FixSrc, Src} % so variable sources are always put in eax
- end,
- {FixSrc3, Src3, FixDst, Dst,
- DidSpill2 or DidSpill1}.
-
--endif. % not AMD64
-
-%%% Fix a move64 op.
-
-do_move64(I, TempMap, Strategy) ->
- #move64{dst=Dst} = I,
- case is_spilled(Dst, TempMap) of
- false ->
- {[I], false};
- true ->
- Reg = clone(Dst, Strategy),
- {[I#move64{dst=Reg}, hipe_x86:mk_move(Reg, Dst)], true}
- end.
-
-%%% Fix a movx op.
-
-do_movx(I, TempMap, Strategy) ->
- {{FixSrc, Src, DidSpill1}, {FixDst, Dst, DidSpill2}} =
- case I of
- #movsx{src=Src0,dst=Dst0} ->
- {fix_src_operand(Src0, TempMap, Strategy),
- fix_dst_operand(Dst0, TempMap, Strategy)};
- #movzx{src=Src0,dst=Dst0} ->
- {fix_src_operand(Src0, TempMap, Strategy),
- fix_dst_operand(Dst0, TempMap, Strategy)}
- end,
- {I3, DidSpill3} =
- case is_spilled(Dst, TempMap) of
- false ->
- I2 = case I of
- #movsx{} ->
- [hipe_x86:mk_movsx(Src, Dst)];
- #movzx{} ->
- [hipe_x86:mk_movzx(Src, Dst)]
- end,
- {I2, false};
- true ->
- Dst2 = clone(Dst, Strategy),
- I2 =
- case I of
- #movsx{} ->
- [hipe_x86:mk_movsx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)];
- #movzx{} ->
- [hipe_x86:mk_movzx(Src, Dst2), hipe_x86:mk_move(Dst2, Dst)]
- end,
- {I2, true}
- end,
- {FixSrc++FixDst++I3,
- DidSpill3 or DidSpill2 or DidSpill1}.
-
-%%% Fix an fmove op.
-
-do_fmove(I, TempMap, Strategy) ->
- #fmove{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, DidSpill1} = fix_src_operand(Src0, TempMap, Strategy),
- {FixDst, Dst, DidSpill2} = fix_dst_operand(Dst0, TempMap, Strategy),
- %% fmoves from memory position to memory position is handled
- %% by the f.p. register allocator.
- {FixSrc ++ FixDst ++ [I#fmove{src=Src,dst=Dst}],
- DidSpill1 or DidSpill2}.
-
-%%% Fix an pseudo_spill_move op.
-
-do_pseudo_spill_move(I = #pseudo_spill_move{temp=Temp}, TempMap, _Strategy) ->
- %% Temp is above the low water mark and must not have been spilled
- false = is_spilled(Temp, TempMap),
- {[I], false}. % nothing to do
-
-%%% Fix a shift operation.
-%%% 1. remove pseudos from any explicit memory operands
-%%% 2. if the source is a register or memory position
-%%% make sure to move it to %ecx
-
-do_shift(I, TempMap, Strategy) ->
- #shift{src=Src0,dst=Dst0} = I,
- {FixDst, Dst, DidSpill} = fix_dst_operand(Dst0, TempMap, Strategy),
- Reg = ?HIPE_X86_REGISTERS:?ECX(),
- case Src0 of
- #x86_imm{} ->
- {FixDst ++ [I#shift{dst=Dst}], DidSpill};
- #x86_temp{reg=Reg} ->
- {FixDst ++ [I#shift{dst=Dst}], DidSpill}
- end.
-
-%%% Fix a test op.
-
-do_test(I, TempMap, Strategy) ->
- #test{src=Src0,dst=Dst0} = I,
- {FixSrc, Src, FixDst, Dst, DidSpill} =
- do_binary(Src0, Dst0, TempMap, Strategy),
- {FixSrc ++ FixDst ++ [I#test{src=Src,dst=Dst}], DidSpill}.
-
-%%% Fix the operands of a binary op.
-%%% 1. remove pseudos from any explicit memory operands
-%%% 2. if both operands are (implicit or explicit) memory operands,
-%%% move src to a reg and use reg as src in the original insn
-
-do_binary(Src0, Dst0, TempMap, Strategy) ->
- {FixSrc, Src, DidSpill1} = fix_src_operand(Src0, TempMap, Strategy),
- {FixDst, Dst, DidSpill2} = fix_dst_operand(Dst0, TempMap, Strategy),
- {FixSrc3, Src3, DidSpill3} =
- case is_mem_opnd(Src, TempMap) of
- false ->
- {FixSrc, Src, false};
- true ->
- case is_mem_opnd(Dst, TempMap) of
- false ->
- {FixSrc, Src, false};
- true ->
- Src2 = clone(Src, Strategy),
- FixSrc2 = FixSrc ++ [hipe_x86:mk_move(Src, Src2)],
- {FixSrc2, Src2, true}
- end
- end,
- {FixSrc3, Src3, FixDst, Dst,
- DidSpill3 or DidSpill2 or DidSpill1}.
-
-%%% Fix any x86_mem operand to not refer to any spilled temps.
-
-fix_src_operand(Opnd, TmpMap, Strategy) ->
- fix_mem_operand(Opnd, TmpMap, temp1(Strategy)).
-
-temp1('normal') -> [];
-temp1('linearscan') -> ?HIPE_X86_REGISTERS:temp1().
-
-fix_dst_operand(Opnd, TempMap, Strategy) ->
- fix_mem_operand(Opnd, TempMap, temp0(Strategy)).
-
-temp0('normal') -> [];
-temp0('linearscan') -> ?HIPE_X86_REGISTERS:temp0().
-
-fix_mem_operand(Opnd, TempMap, RegOpt) -> % -> {[fixupcode], newop, DidSpill}
- case Opnd of
- #x86_mem{base=Base,off=Off} ->
- case is_mem_opnd(Base, TempMap) of
- false ->
- case is_mem_opnd(Off, TempMap) of
- false ->
- {[], Opnd, false};
- true ->
- Temp = clone2(Off, RegOpt),
- {[hipe_x86:mk_move(Off, Temp)],
- Opnd#x86_mem{off=Temp},
- true}
- end;
- true ->
- Temp = clone2(Base, RegOpt),
- case is_mem_opnd(Off, TempMap) of
- false -> % imm/reg(pseudo)
- {[hipe_x86:mk_move(Base, Temp)],
- Opnd#x86_mem{base=Temp},
- true};
- true -> % pseudo(pseudo)
- {[hipe_x86:mk_move(Base, Temp),
- hipe_x86:mk_alu('add', Off, Temp)],
- Opnd#x86_mem{base=Temp, off=hipe_x86:mk_imm(0)},
- true}
- end
- end;
- _ ->
- {[], Opnd, false}
- end.
-
-%%% Check if an operand denotes a memory cell (mem or pseudo).
-
-is_mem_opnd(Opnd, TempMap) ->
- R =
- case Opnd of
- #x86_mem{} -> true;
- #x86_temp{} ->
- Reg = hipe_x86:temp_reg(Opnd),
- case hipe_x86:temp_is_allocatable(Opnd) of
- true ->
- case
- hipe_temp_map:is_spilled(Reg, TempMap) of
- true ->
- ?count_temp(Reg),
- true;
- false -> false
- end;
- false -> true
- end;
- _ -> false
- end,
- %% io:format("Op ~w mem: ~w\n",[Opnd,R]),
- R.
-
-%%% Check if an operand is a spilled Temp.
-
-is_spilled(Temp, TempMap) ->
- case hipe_x86:temp_is_allocatable(Temp) of
- true ->
- Reg = hipe_x86:temp_reg(Temp),
- case hipe_temp_map:is_spilled(Reg, TempMap) of
- true ->
- ?count_temp(Reg),
- true;
- false ->
- false
- end;
- false -> true
- end.
-
-%%% Make Reg a clone of Dst (attach Dst's type to Reg).
-
-clone(Dst, Strategy) ->
- Type =
- case Dst of
- #x86_mem{} -> hipe_x86:mem_type(Dst);
- #x86_temp{} -> hipe_x86:temp_type(Dst)
- end,
- spill_temp(Type, Strategy).
-
-spill_temp0(Type, 'normal') when Type =/= double ->
- hipe_x86:mk_new_temp(Type);
-spill_temp0(Type, 'linearscan') when Type =/= double ->
- hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp0(), Type).
-
-spill_temp(Type, 'normal') when Type =/= double ->
- hipe_x86:mk_new_temp(Type);
-spill_temp(Type, 'linearscan') when Type =/= double ->
- hipe_x86:mk_temp(?HIPE_X86_REGISTERS:temp1(), Type).
-
-%%% Make a certain reg into a clone of Dst
-
-clone2(Dst, RegOpt) ->
- Type =
- case Dst of
- #x86_mem{} -> hipe_x86:mem_type(Dst);
- #x86_temp{} -> hipe_x86:temp_type(Dst)
- end,
- case RegOpt of
- [] when Type =/= double -> hipe_x86:mk_new_temp(Type);
- Reg -> hipe_x86:mk_temp(Reg, Type)
- end.
diff --git a/lib/hipe/x86/hipe_x86_registers.erl b/lib/hipe/x86/hipe_x86_registers.erl
deleted file mode 100644
index dbff68ad28..0000000000
--- a/lib/hipe/x86/hipe_x86_registers.erl
+++ /dev/null
@@ -1,249 +0,0 @@
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% TODO:
-%%% - Do we need a pseudo reg for the condition codes?
-
--module(hipe_x86_registers).
-
--export([reg_name/1,
- first_virtual/0,
- is_precoloured/1,
- is_precoloured_x87/1,
- all_precoloured/0,
- eax/0,
- ecx/0,
- temp0/0,
- temp1/0,
- sp/0,
- proc_pointer/0,
- heap_limit/0,
- fcalls/0,
- proc_offset/1,
- sp_limit_offset/0,
- is_fixed/1,
- %% fixed/0,
- allocatable/0,
- allocatable_x87/0,
- nr_args/0,
- arg/1,
- is_arg/1,
- args/1,
- nr_rets/0,
- ret/1,
- call_clobbered/0,
- tailcall_clobbered/0,
- live_at_return/0,
- float_size/0,
- wordsize/0,
- alignment/0]).
-
--include("../rtl/hipe_literals.hrl").
-
--ifdef(X86_HP_IN_ESI).
--export([heap_pointer/0]).
--endif.
-
--define(EAX, 0).
--define(ECX, 1).
--define(EDX, 2).
--define(EBX, 3).
--define(ESP, 4).
--define(EBP, 5).
--define(ESI, 6).
--define(EDI, 7).
--define(FCALLS, 8). % proc field alias
--define(HEAP_LIMIT, 9). % proc field alias
--define(LAST_PRECOLOURED, 9).
-
--define(ARG0, ?EAX).
--define(ARG1, ?EDX).
--define(ARG2, ?ECX).
--define(ARG3, ?EBX).
--define(ARG4, ?EDI).
-
--define(RET0, ?EAX).
--define(RET1, ?EDX).
--define(RET2, ?ECX).
--define(RET3, ?EBX).
--define(RET4, ?EDI).
-
--define(TEMP0, ?EBX). % XXX: was EAX
--define(TEMP1, ?EDI). % XXX: was EDX then EDI
-
--define(PROC_POINTER, ?EBP).
-
-reg_name(R) ->
- case R of
- ?EAX -> "%eax";
- ?ECX -> "%ecx";
- ?EDX -> "%edx";
- ?EBX -> "%ebx";
- ?ESP -> "%esp";
- ?EBP -> "%ebp";
- ?ESI -> "%esi";
- ?EDI -> "%edi";
- ?FCALLS -> "%fcalls";
- ?HEAP_LIMIT -> "%hplim";
- Other -> "%r" ++ integer_to_list(Other)
- end.
-
-first_virtual() -> ?LAST_PRECOLOURED + 1.
-
-is_precoloured(X) -> X =< ?LAST_PRECOLOURED.
-
-is_precoloured_x87(X) -> X =< 6.
-
-all_precoloured() ->
- [?EAX,
- ?ECX,
- ?EDX,
- ?EBX,
- ?ESP,
- ?EBP,
- ?ESI,
- ?EDI,
- ?FCALLS,
- ?HEAP_LIMIT].
-
-eax() -> ?EAX.
-ecx() -> ?ECX.
-temp0() -> ?TEMP0.
-temp1() -> ?TEMP1.
-sp() -> ?ESP.
-proc_pointer() -> ?PROC_POINTER.
-fcalls() -> ?FCALLS.
-heap_limit() -> ?HEAP_LIMIT.
-
--ifdef(X86_HP_IN_ESI).
--define(ESI_IS_FIXED,1).
--define(HEAP_POINTER, ?ESI).
-heap_pointer() -> ?HEAP_POINTER.
-is_heap_pointer(?HEAP_POINTER) -> true;
-is_heap_pointer(_) -> false.
--define(LIST_HP_FIXED,[?HEAP_POINTER]).
--define(LIST_HP_LIVE_AT_RETURN,[{?HEAP_POINTER,untagged}]).
--else.
-is_heap_pointer(_) -> false.
--define(LIST_HP_FIXED,[]).
--define(LIST_HP_LIVE_AT_RETURN,[]).
--endif.
-
--ifdef(ESI_IS_FIXED).
--define(LIST_ESI_ALLOCATABLE,[]).
--define(LIST_ESI_CALL_CLOBBERED,[]).
--else.
--define(LIST_ESI_ALLOCATABLE,[?ESI]).
--define(LIST_ESI_CALL_CLOBBERED,[{?ESI,tagged},{?ESI,untagged}]).
--endif.
-
-proc_offset(?FCALLS) -> ?P_FCALLS;
-proc_offset(?HEAP_LIMIT) -> ?P_HP_LIMIT;
-proc_offset(_) -> false.
-
-sp_limit_offset() -> ?P_NSP_LIMIT.
-
-is_fixed(?ESP) -> true;
-is_fixed(?PROC_POINTER) -> true;
-is_fixed(?FCALLS) -> true;
-is_fixed(?HEAP_LIMIT) -> true;
-is_fixed(R) -> is_heap_pointer(R).
-
-%% fixed() ->
-%% [?ESP, ?PROC_POINTER, ?FCALLS, ?HEAP_LIMIT | ?LIST_HP_FIXED].
-
-allocatable() ->
- [?EDX, ?ECX, ?EBX, ?EAX, ?EDI| ?LIST_ESI_ALLOCATABLE].
-
-allocatable_x87() ->
- [0,1,2,3,4,5,6].
-
-nr_args() -> ?X86_NR_ARG_REGS.
-
-arg(N) ->
- if N < ?X86_NR_ARG_REGS ->
- case N of
- 0 -> ?ARG0;
- 1 -> ?ARG1;
- 2 -> ?ARG2;
- 3 -> ?ARG3;
- 4 -> ?ARG4;
- _ -> exit({?MODULE, arg, N})
- end;
- true ->
- exit({?MODULE, arg, N})
- end.
-
-is_arg(R) ->
- case R of
- ?ARG0 -> ?X86_NR_ARG_REGS > 0;
- ?ARG1 -> ?X86_NR_ARG_REGS > 1;
- ?ARG2 -> ?X86_NR_ARG_REGS > 2;
- ?ARG3 -> ?X86_NR_ARG_REGS > 3;
- ?ARG4 -> ?X86_NR_ARG_REGS > 4;
- _ -> false
- end.
-
-args(Arity) when is_integer(Arity), Arity >= 0 ->
- N = erlang:min(Arity, ?X86_NR_ARG_REGS),
- args(N-1, []).
-
-args(I, Rest) when I < 0 -> Rest;
-args(I, Rest) -> args(I-1, [arg(I) | Rest]).
-
-nr_rets() -> ?X86_NR_RET_REGS.
-
-ret(N) ->
- if N < ?X86_NR_RET_REGS ->
- case N of
- 0 -> ?RET0;
- 1 -> ?RET1;
- 2 -> ?RET2;
- 3 -> ?RET3;
- 4 -> ?RET4;
- _ -> exit({?MODULE, ret, N})
- end;
- true ->
- exit({?MODULE, ret, N})
- end.
-
-%% Note: the fact that (allocatable() UNION allocatable_x87()) is a subset of
-%% call_clobbered() is hard-coded in hipe_x86_defuse:insn_defs_all/1
-call_clobbered() ->
- [{?EAX,tagged},{?EAX,untagged}, % does the RA strip the type or not?
- {?EDX,tagged},{?EDX,untagged},
- {?ECX,tagged},{?ECX,untagged},
- {?EBX,tagged},{?EBX,untagged},
- {?EDI,tagged},{?EDI,untagged}
- | ?LIST_ESI_CALL_CLOBBERED] ++ all_x87_pseudos().
-
-tailcall_clobbered() -> % tailcall crapola needs two temps
- [{?TEMP0,tagged},{?TEMP0,untagged},
- {?TEMP1,tagged},{?TEMP1,untagged}] ++ all_x87_pseudos().
-
-all_x87_pseudos() ->
- [{0,double}, {1,double}, {2,double}, {3,double},
- {4,double}, {5,double}, {6,double}].
-
-live_at_return() ->
- [{?ESP,untagged}
- ,{?PROC_POINTER,untagged}
- ,{?FCALLS,untagged}
- ,{?HEAP_LIMIT,untagged}
- | ?LIST_HP_LIVE_AT_RETURN
- ].
-
-alignment() -> 4.
-
-float_size() -> 8.
-
-wordsize() -> 4.
diff --git a/lib/hipe/x86/hipe_x86_spill_restore.erl b/lib/hipe/x86/hipe_x86_spill_restore.erl
deleted file mode 100644
index 90edef31f3..0000000000
--- a/lib/hipe/x86/hipe_x86_spill_restore.erl
+++ /dev/null
@@ -1,334 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% ====================================================================
-%% Authors : Dogan Yazar and Erdem Aksu (KT2 project of 2008)
-%% ====================================================================
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_SPILL_RESTORE, hipe_amd64_spill_restore).
--define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(X86STR, "amd64").
--else.
--define(HIPE_X86_SPILL_RESTORE, hipe_x86_spill_restore).
--define(HIPE_X86_LIVENESS, hipe_x86_liveness).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(X86STR, "x86").
--endif.
-
--module(?HIPE_X86_SPILL_RESTORE).
-
--export([spill_restore/2]).
-
-%% controls which set library is used to keep temp variables.
--define(SET_MODULE, ordsets).
-
-%% Turn on instrumentation.
--define(HIPE_INSTRUMENT_COMPILER, true).
-
--include("../main/hipe.hrl").
--include("../x86/hipe_x86.hrl"). % Added for the definition of #pseudo_call{}
--include("../flow/cfg.hrl"). % Added for the definition of #cfg{}
-
-%% Main function
-spill_restore(CFG0, Options) ->
- CFG1 = ?option_time(firstPass(CFG0), ?X86STR" First Pass", Options),
- ?option_time(secondPass(CFG1), ?X86STR" Second Pass", Options).
-
-%% Performs the first pass of the algorithm.
-%% By working bottom up, introduce the pseudo_spills.
-firstPass(CFG0) ->
- %% get the labels bottom up
- Labels = hipe_x86_cfg:postorder(CFG0),
- Liveness = ?HIPE_X86_LIVENESS:analyse(CFG0),
- %% spill around the function will be introduced below the move
- %% formals, so get all labels except it.
- LabelsExceptMoveFormals = lists:sublist(Labels, length(Labels)-1),
- %% all work is done by the helper function firstPassHelper
- %% saveTree keeps the all newly introduced spills. Keys are the labels.
- {CFG1, SaveTree} = firstPassHelper(LabelsExceptMoveFormals, Liveness, CFG0),
- case hipe_x86_cfg:reverse_postorder(CFG0) of
- [Label1, Label2|_] ->
- SaveTreeElement = saveTreeLookup(Label2, SaveTree),
- %% FilteredSaveTreeElement is the to be spilled temps around the
- %% function call. They are spilled just before move formals.
- FilteredSaveTreeElement = [T || T <- SaveTreeElement, temp_is_pseudo(T)],
- Block = hipe_x86_cfg:bb(CFG1, Label1),
- Code = hipe_bb:code(Block),
- %% The following statements are tedious but work ok.
- %% Put spills between move formals and the jump code.
- %% This disgusting thing is done because spills should be
- %% introduced after move formals.
- %% Another solution may be to introduce another block.
- MoveCodes = lists:sublist(Code, length(Code)-1),
- JumpCode = lists:last(Code),
- hipe_x86_cfg:bb_add(CFG1, Label1, hipe_bb:mk_bb(MoveCodes ++ [hipe_x86:mk_pseudo_spill(FilteredSaveTreeElement), JumpCode]));
- _ ->
- CFG1
- end.
-
-%% helper function of firstPass
-
-%% processes all labels recursively and decides the spills to be put.
-%% spills are introduced before each function call (pseudo_call) as well as
-%% global spill is found
-firstPassHelper(Labels, Liveness, CFG) ->
- firstPassHelper(Labels, Liveness, CFG, gb_trees:empty()).
-
-firstPassHelper([Label|Labels], Liveness, CFG, SaveTree) ->
- LiveOut = from_list(?HIPE_X86_LIVENESS:liveout(Liveness, Label)),
- Block = hipe_x86_cfg:bb(CFG, Label),
- Code = hipe_bb:code(Block),
- Succ = hipe_x86_cfg:succ(CFG, Label),
- IntersectedSaveList = findIntersectedSaveList(Succ,SaveTree),
- %% call firstPassDoBlock which will give the updated block
- %% code(including spills) as well as Intersected Save List which
- %% should be passed above blocks
- {_,NewIntersectedList,NewCode} =
- firstPassDoBlock(Code, LiveOut,IntersectedSaveList),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- NewCFG = hipe_x86_cfg:bb_add(CFG, Label, NewBlock),
- SizeOfSet = setSize(NewIntersectedList),
- %% if the Intersected Save List is not empty, insert it in the save tree.
- if SizeOfSet =/= 0 ->
- UpdatedSaveTree = gb_trees:insert(Label, NewIntersectedList, SaveTree),
- firstPassHelper(Labels, Liveness, NewCFG, UpdatedSaveTree);
- true ->
- firstPassHelper(Labels, Liveness, NewCFG, SaveTree)
- end;
-firstPassHelper([], _, CFG, SaveTree) ->
- {CFG, SaveTree}.
-
-%% handle each instruction in the block bottom up
-firstPassDoBlock(Insts, LiveOut, IntersectedSaveList) ->
- lists:foldr(fun firstPassDoInsn/2, {LiveOut,IntersectedSaveList,[]}, Insts).
-
-firstPassDoInsn(I, {LiveOut,IntersectedSaveList,PrevInsts}) ->
- case I of
- #pseudo_call{} ->
- do_pseudo_call(I, {LiveOut,IntersectedSaveList,PrevInsts});
- _ -> % other instructions
- DefinedList = from_list( ?HIPE_X86_LIVENESS:defines(I)),
- UsedList = from_list(?HIPE_X86_LIVENESS:uses(I)),
- NewLiveOut = subtract(union(LiveOut, UsedList), DefinedList),
- NewIntersectedSaveList = subtract(IntersectedSaveList, DefinedList),
- {NewLiveOut, NewIntersectedSaveList, [I|PrevInsts]}
- end.
-
-do_pseudo_call(I, {LiveOut,IntersectedSaveList,PrevInsts}) ->
- LiveTemps = [Temp || Temp <- to_list(LiveOut), temp_is_pseudo(Temp)],
- NewIntersectedSaveList = union(IntersectedSaveList, LiveOut),
- {LiveOut, NewIntersectedSaveList, [hipe_x86:mk_pseudo_spill(LiveTemps), I | PrevInsts]}.
-
-findIntersectedSaveList(LabelList, SaveTree) ->
- findIntersectedSaveList([saveTreeLookup(Label,SaveTree) || Label <- LabelList]).
-
-findIntersectedSaveList([]) ->
- [];
-findIntersectedSaveList([List1]) ->
- List1;
-findIntersectedSaveList([List1,List2|Rest]) ->
- findIntersectedSaveList([intersection(List1, List2)|Rest]).
-
-saveTreeLookup(Label, SaveTree) ->
- case gb_trees:lookup(Label, SaveTree) of
- {value, SaveList} ->
- SaveList;
- _ ->
- []
- end.
-
-%% Performs the second pass of the algorithm.
-%% It basically eliminates the unnecessary spills and introduces restores.
-%% Works top down
-secondPass(CFG0) ->
- Labels = hipe_x86_cfg:reverse_postorder(CFG0),
- Liveness = ?HIPE_X86_LIVENESS:analyse(CFG0),
- secondPassHelper(Labels,Liveness,CFG0).
-
-%% helper function of secondPass.
-
-%% recursively handle all labels given.
-secondPassHelper(Labels, Liveness, CFG) ->
- secondPassHelper(Labels, Liveness, CFG, gb_trees:empty(), CFG).
-
-%% AccumulatedCFG stands for the CFG that has restore edges incrementally.
-%% UnmodifiedCFG is the CFG created after first pass.
-
-%% AccumulatedSaveTree is used to eliminate the unnecessary saves. The
-%% saves (spills) in above blocks are traversed down (if still live
-%% and not redefined) and redundant saves are eliminated in the lower
-%% blocks.
-%% For memory efficiency, it may be better not to maintain the
-%% AccumulatedSaveTree but traverse the tree recursively and pass the
-%% save lists to the childs individually.
-%% But current approach may be faster even though it needs bigger memory.
-
-secondPassHelper([Label|RestOfLabels], Liveness,
- AccumulatedCFG, AccumulatedSaveTree, UnmodifiedCFG) ->
- LiveOut = ?HIPE_X86_LIVENESS:liveout(Liveness, Label),
- Block = hipe_x86_cfg:bb(AccumulatedCFG, Label),
- Code = hipe_bb:code(Block),
-
- %% UnmodifiedCFG is needed for getting the correct predecessors.
- %% (i.e. not to get the restore edge blocks)
- PredList = hipe_x86_cfg:pred(UnmodifiedCFG, Label),
- %% find the spills coming from all the parents by intersecting
- InitialAccumulatedSaveList =
- findIntersectedSaveList(PredList, AccumulatedSaveTree),
- AccumulatedSaveList =
- keepLiveVarsInAccumSaveList(InitialAccumulatedSaveList, LiveOut),
-
- {NewCode, CFGUpdateWithRestores, NewAccumulatedSaveList} =
- secondPassDoBlock(Label, Code, AccumulatedCFG, AccumulatedSaveList),
-
- UpdatedAccumulatedSaveTree =
- gb_trees:insert(Label, NewAccumulatedSaveList, AccumulatedSaveTree),
- NewBlock = hipe_bb:code_update(Block, NewCode),
- NewCFG = hipe_x86_cfg:bb_add(CFGUpdateWithRestores, Label, NewBlock),
- secondPassHelper(RestOfLabels, Liveness, NewCFG,
- UpdatedAccumulatedSaveTree, UnmodifiedCFG);
-secondPassHelper([], _, AccumulatedCFG, _, _) ->
- AccumulatedCFG.
-
-secondPassDoBlock(CurrentLabel, Insts, CFG, AccumulatedSaveList) ->
- {NewAccumulatedSaveList,NewInsts,_,_,CFGUpdateWithRestores} =
- lists:foldl(fun secondPassDoInsn/2, {AccumulatedSaveList,[],[],CurrentLabel,CFG}, Insts),
- {NewInsts, CFGUpdateWithRestores, NewAccumulatedSaveList}.
-
-secondPassDoInsn(I, {AccumulatedSaveList,PrevInsts,SpillList,CurrentLabel,CFG}) ->
- case I of
- #pseudo_spill{} ->
- %% spill variables that are not accumulated from top down
- %% (which are not already saved)
- VariablesAlreadySaved = [X || {X,_} <- to_list(AccumulatedSaveList)],
- VariablesToBeSpilled = I#pseudo_spill.args -- VariablesAlreadySaved,
- NewSpillList = [{Temp, hipe_x86:mk_new_temp(Temp#x86_temp.type)} || Temp <- VariablesToBeSpilled],
- %% update accumulated saved list by adding the newly spilled variables.
- NewAccumulatedSaveList = union(AccumulatedSaveList, from_list(NewSpillList)),
- {NewAccumulatedSaveList, PrevInsts ++ secondPassDoPseudoSpill(NewSpillList), NewSpillList, CurrentLabel, CFG};
- #pseudo_call{} ->
- {CFGUpdateWithRestores, NewPseudoCall} =
- secondPassDoPseudoCall(I, AccumulatedSaveList, CFG),
- %% spill list is emptied after use
- {AccumulatedSaveList, PrevInsts ++ [NewPseudoCall], CurrentLabel, [], CFGUpdateWithRestores};
- _ ->
- %% remove the defined variables from the accumulated save
- %% list since they need to be saved again in later occasions.
- DefinedList = from_list(?HIPE_X86_LIVENESS:defines(I)),
- NewAccumulatedSaveList = removeRedefVarsFromAccumSaveList(AccumulatedSaveList, DefinedList),
- {NewAccumulatedSaveList, PrevInsts ++ [I], SpillList, CurrentLabel, CFG}
- end.
-
-%% remove dead vars from accumulated save list so that they are not restored.
-keepLiveVarsInAccumSaveList([], _) ->
- [];
-keepLiveVarsInAccumSaveList([{Var,Temp}|Rest], DefinedList) ->
- IsDefined = is_element(Var, DefinedList),
- case IsDefined of
- true -> [{Var,Temp}|keepLiveVarsInAccumSaveList(Rest, DefinedList)];
- false -> keepLiveVarsInAccumSaveList(Rest, DefinedList)
- end.
-
-%% remove the redefined variables from accumulated save list since
-%% they are changed.
-removeRedefVarsFromAccumSaveList([], _) ->
- [];
-removeRedefVarsFromAccumSaveList([{Var,Temp}|Rest], DefinedList) ->
- IsDefined = is_element(Var, DefinedList),
- case IsDefined of
- true -> removeRedefVarsFromAccumSaveList(Rest, DefinedList);
- false -> [{Var,Temp}|removeRedefVarsFromAccumSaveList(Rest, DefinedList)]
- end.
-
-%% convert pseudo_spills to move instructions.
-secondPassDoPseudoSpill(SpillList) ->
- lists:foldl(fun convertPseudoSpillToMov/2, [], SpillList).
-
-%% if there are variables to be restored, then call addRestoreBlockToEdge to
-%% place them in a new block on the edge of the blocks.
-secondPassDoPseudoCall(I, RestoreList, CFG) ->
- ContLabel = I#pseudo_call.contlab,
- SizeOfSet = setSize(RestoreList),
- if SizeOfSet =/= 0 ->
- addRestoreBlockToEdge(I, ContLabel, CFG, RestoreList);
- true ->
- {CFG, I}
- end.
-
-%% prepares the moves for the spills.
-convertPseudoSpillToMov({Temp, NewTemp}, OtherMoves) ->
- OtherMoves ++ [mkMove(Temp, NewTemp)].
-
-%% prepares the moves for the restores.
-%% Called by addRestoreBlockToEdge while introducing the restores.
-convertPseudoRestoreToMov({Temp, NewTemp}, OtherMoves) ->
- OtherMoves ++ [mkMove(NewTemp, Temp)].
-
-%% makes the move record, special care is taken for doubles.
-mkMove(NewTemp,Temp) ->
- if Temp#x86_temp.type =:= 'double' ->
- hipe_x86:mk_fmove(NewTemp, Temp);
- true ->
- hipe_x86:mk_move(NewTemp, Temp)
- end.
-
-%% adds a new block (on the edge) that includes introduced restore moves.
-addRestoreBlockToEdge(PseudoCall, ContLabel, CFG, TempArgsList) ->
- NextLabel = hipe_gensym:get_next_label(x86),
- NewCode = lists:foldl(fun convertPseudoRestoreToMov/2, [], TempArgsList) ++ [hipe_x86:mk_jmp_label(ContLabel)],
- NewBlock = hipe_bb:mk_bb(NewCode),
- NewPseudoCall = redirect_pseudo_call(PseudoCall, ContLabel, NextLabel),
- NewCFG = hipe_x86_cfg:bb_add(CFG, NextLabel, NewBlock),
- {NewCFG, NewPseudoCall}.
-
-%% used instead of hipe_x86_cfg:redirect_jmp since it does not handle
-%% pseudo_call calls.
-redirect_pseudo_call(I = #pseudo_call{contlab=ContLabel}, Old, New) ->
- case Old =:= ContLabel of
- true -> I#pseudo_call{contlab=New};
- false -> I
- end.
-
-temp_is_pseudo(Temp) ->
- case hipe_x86:is_temp(Temp) of
- true -> not(?HIPE_X86_REGISTERS:is_precoloured(hipe_x86:temp_reg(Temp)));
- false -> false
- end.
-
-%%---------------------------------------------------------------------
-%% Set operations where the module name is an easily changeable macro
-%%---------------------------------------------------------------------
-
-union(Set1, Set2) ->
- ?SET_MODULE:union(Set1, Set2).
-
-setSize(Set) ->
- ?SET_MODULE:size(Set).
-
-from_list(List) ->
- ?SET_MODULE:from_list(List).
-
-to_list(Set) ->
- ?SET_MODULE:to_list(Set).
-
-subtract(Set1, Set2) ->
- ?SET_MODULE:subtract(Set1, Set2).
-
-intersection(Set1, Set2) ->
- ?SET_MODULE:intersection(Set1, Set2).
-
-is_element(Element, Set) ->
- ?SET_MODULE:is_element(Element, Set).
diff --git a/lib/hipe/x86/hipe_x86_subst.erl b/lib/hipe/x86/hipe_x86_subst.erl
deleted file mode 100644
index 7db3b23d92..0000000000
--- a/lib/hipe/x86/hipe_x86_subst.erl
+++ /dev/null
@@ -1,112 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_SUBST, hipe_amd64_subst).
--else.
--define(HIPE_X86_SUBST, hipe_x86_subst).
--endif.
-
--module(?HIPE_X86_SUBST).
--export([insn_temps/2, insn_lbls/2]).
--include("../x86/hipe_x86.hrl").
-
-%% These should be moved to hipe_x86 and exported
--type temp() :: #x86_temp{}.
--type oper() :: temp() | #x86_imm{} | #x86_mem{}.
--type mfarec() :: #x86_mfa{}.
--type prim() :: #x86_prim{}.
--type funv() :: mfarec() | prim() | temp().
--type label() :: non_neg_integer().
--type insn() :: tuple(). % for now
-
--type subst_fun() :: fun((temp()) -> temp()).
-
-%% @doc Maps over the temporaries in an instruction
--spec insn_temps(subst_fun(), insn()) -> insn().
-insn_temps(SubstTemp, I) ->
- O = fun(O) -> oper_temps(SubstTemp, O) end,
- case I of
- #alu {src=S, dst=D} -> I#alu {src=O(S), dst=O(D)};
- #cmovcc {src=S, dst=D} -> I#cmovcc {src=O(S), dst=O(D)};
- #cmp {src=S, dst=D} -> I#cmp {src=O(S), dst=O(D)};
- #fmove {src=S, dst=D} -> I#fmove {src=O(S), dst=O(D)};
- #fp_binop{src=S, dst=D} -> I#fp_binop{src=O(S), dst=O(D)};
- #imul {src=S, temp=T} -> I#imul {src=O(S), temp=O(T)};
- #lea {mem=M, temp=T} -> I#lea {mem=O(M), temp=O(T)};
- #move {src=S, dst=D} -> I#move {src=O(S), dst=O(D)};
- #movsx {src=S, dst=D} -> I#movsx {src=O(S), dst=O(D)};
- #movzx {src=S, dst=D} -> I#movzx {src=O(S), dst=O(D)};
- #shift {src=S, dst=D} -> I#shift {src=O(S), dst=O(D)};
- #test {src=S, dst=D} -> I#test {src=O(S), dst=O(D)};
- #fp_unop{arg=[]} -> I;
- #fp_unop{arg=A} -> I#fp_unop{arg=O(A)};
- #move64 {dst=D} -> I#move64 {dst=O(D)};
- #push {src=S} -> I#push {src=O(S)};
- #pop {dst=D} -> I#pop {dst=O(D)};
- #jmp_switch{temp=T, jtab=J} ->
- I#jmp_switch{temp=O(T), jtab=jtab_temps(SubstTemp, J)};
- #pseudo_call{'fun'=F} ->
- I#pseudo_call{'fun'=funv_temps(SubstTemp, F)};
- #pseudo_spill_fmove{src=S, temp=T, dst=D} ->
- I#pseudo_spill_fmove{src=O(S), temp=O(T), dst=O(D)};
- #pseudo_spill_move{src=S, temp=T, dst=D} ->
- I#pseudo_spill_move{src=O(S), temp=O(T), dst=O(D)};
- #pseudo_tailcall{'fun'=F, stkargs=Stk} ->
- I#pseudo_tailcall{'fun'=funv_temps(SubstTemp, F),
- stkargs=lists:map(O, Stk)};
- #comment{} -> I;
- #jmp_label{} -> I;
- #pseudo_tailcall_prepare{} -> I;
- #pseudo_jcc{} -> I;
- #ret{} -> I
- end.
-
--spec oper_temps(subst_fun(), oper()) -> oper().
-oper_temps(_SubstTemp, I=#x86_imm{}) -> I;
-oper_temps(SubstTemp, T=#x86_temp{}) -> SubstTemp(T);
-oper_temps(SubstTemp, M=#x86_mem{base=Base,off=Off}) ->
- M#x86_mem{base=oper_temps(SubstTemp, Base),
- off =oper_temps(SubstTemp, Off)}.
-
--spec funv_temps(subst_fun(), funv()) -> funv().
-funv_temps(_SubstTemp, MFA=#x86_mfa{}) -> MFA;
-funv_temps(_SubstTemp, P=#x86_prim{}) -> P;
-funv_temps(SubstTemp, T=#x86_temp{}) -> SubstTemp(T).
-
-%% TODO: Undo this ifdeffery at the source (make jtab an #x86_imm{} on x86)
--ifdef(HIPE_AMD64).
-jtab_temps(SubstTemp, T=#x86_temp{}) -> SubstTemp(T).
--else.
-jtab_temps(_SubstTemp, DataLbl) when is_integer(DataLbl) -> DataLbl.
--endif.
-
--type lbl_subst_fun() :: fun((label()) -> label()).
-
-%% @doc Maps over the branch targets in an instruction
--spec insn_lbls(lbl_subst_fun(), insn()) -> insn().
-insn_lbls(SubstLbl, I) ->
- case I of
- #jmp_label{label=Label} ->
- I#jmp_label{label=SubstLbl(Label)};
- #pseudo_call{sdesc=Sdesc, contlab=Contlab} ->
- I#pseudo_call{sdesc=sdesc_lbls(SubstLbl, Sdesc),
- contlab=SubstLbl(Contlab)};
- #pseudo_jcc{true_label=T, false_label=F} ->
- I#pseudo_jcc{true_label=SubstLbl(T), false_label=SubstLbl(F)}
- end.
-
-sdesc_lbls(_SubstLbl, Sdesc=#x86_sdesc{exnlab=[]}) -> Sdesc;
-sdesc_lbls(SubstLbl, Sdesc=#x86_sdesc{exnlab=Exnlab}) ->
- Sdesc#x86_sdesc{exnlab=SubstLbl(Exnlab)}.
diff --git a/lib/hipe/x86/hipe_x86_x87.erl b/lib/hipe/x86/hipe_x86_x87.erl
deleted file mode 100644
index 85268ab85a..0000000000
--- a/lib/hipe/x86/hipe_x86_x87.erl
+++ /dev/null
@@ -1,629 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% Floating point handling.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_X87, hipe_amd64_x87).
--define(HIPE_X86_DEFUSE, hipe_amd64_defuse).
--define(HIPE_X86_LIVENESS, hipe_amd64_liveness).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--else.
--define(HIPE_X86_X87, hipe_x86_x87).
--define(HIPE_X86_DEFUSE, hipe_x86_defuse).
--define(HIPE_X86_LIVENESS, hipe_x86_liveness).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--endif.
-
--module(?HIPE_X86_X87).
-
--export([map/1]).
-
--include("../x86/hipe_x86.hrl").
--include("../main/hipe.hrl").
-
-%%----------------------------------------------------------------------
-
-map(CFG0) ->
- %% hipe_x86_cfg:pp(CFG0),
- Liveness = ?HIPE_X86_LIVENESS:analyse(CFG0),
- StartLabel = hipe_x86_cfg:start_label(CFG0),
- {CFG1,_} = do_blocks([], [StartLabel], CFG0, Liveness, [], gb_trees:empty()),
- CFG1.
-
-do_blocks(Pred, [Lbl|Lbls], CFG, Liveness, Map, BlockMap) ->
- case gb_trees:lookup(Lbl, BlockMap) of
- none ->
- %% This block has not been visited.
- Block = hipe_x86_cfg:bb(CFG, Lbl),
- Succ = hipe_x86_cfg:succ(CFG, Lbl),
- NewBlockMap = gb_trees:insert(Lbl, Map, BlockMap),
- LiveOut = [X || X <- ?HIPE_X86_LIVENESS:liveout(Liveness, Lbl),
- is_fp(X)],
- Code = hipe_bb:code(Block),
- ReverseCode = lists:reverse(Code),
- {NewCode0, NewMap, NewBlockMap1, Dirty} =
- do_block(ReverseCode, LiveOut, Map, NewBlockMap),
- NewCFG1 =
- case Dirty of
- true ->
- NewBlock = hipe_bb:code_update(Block, NewCode0),
- hipe_x86_cfg:bb_add(CFG, Lbl, NewBlock);
- _ ->
- CFG
- end,
- {NewCFG3, NewBlockMap2} =
- do_blocks(Lbl, Succ, NewCFG1, Liveness, NewMap, NewBlockMap1),
- do_blocks(Pred, Lbls, NewCFG3, Liveness, Map, NewBlockMap2);
- {value, fail} ->
- %% Don't have to follow this trace any longer.
- do_blocks(Pred,Lbls, CFG, Liveness, Map, BlockMap);
- {value, ExistingMap} ->
- %% This block belongs to a trace already handled.
- %% The Map coming in must be identical to the one used
- %% when the block was processed.
- if ExistingMap =:= Map ->
- do_blocks(Pred, Lbls, CFG, Liveness, Map, BlockMap);
- true ->
- NewCFG = do_shuffle(Pred, Lbl, CFG, Map, ExistingMap),
- do_blocks(Pred, Lbls, NewCFG, Liveness, Map, BlockMap)
- end
- end;
-do_blocks(_Pred, [], CFG, _Liveness, _Map, BlockMap) ->
- {CFG, BlockMap}.
-
-do_block(Ins, LiveOut, Map, BlockMap) ->
- do_block(Ins, LiveOut, Map, BlockMap, false).
-
-do_block([I|Is], LiveOut, Map, BlockMap, Dirty) ->
- case handle_insn(I) of
- false ->
- {NewCode, NewMap, NewBlockMap, NewDirty} =
- do_block(Is, LiveOut, Map, BlockMap, Dirty),
- {NewCode++[I], NewMap, NewBlockMap, NewDirty};
- true ->
- Def = ordsets:from_list(?HIPE_X86_DEFUSE:insn_def(I)),
- Use = ordsets:from_list(?HIPE_X86_DEFUSE:insn_use(I)),
- NewLiveOut =
- ordsets:filter(fun(X) -> is_fp(X) end,
- ordsets:union(ordsets:subtract(LiveOut, Def), Use)),
- {NewCode, NewMap, NewBlockMap, NewDirty} =
- do_block(Is, NewLiveOut, Map, BlockMap, Dirty),
- {NewI, NewMap1, NewBlockMap1} =
- do_insn(I, LiveOut, NewMap, NewBlockMap),
- NewDirty1 =
- if NewDirty =:= true -> true;
- NewI =:= [I] -> false;
- true -> true
- end,
- {NewCode++NewI, NewMap1, NewBlockMap1, NewDirty1}
- end;
-do_block([], LiveOut, Map, BlockMap, Dirty) ->
- case [X || X <- Map, not lists:member(X, LiveOut)] of
- [] ->
- {[], Map, BlockMap, Dirty};
- Pop ->
- {PopIns, NewMap} = pop_dead(Pop, Map),
- {PopIns, NewMap, BlockMap, true}
- end.
-
-do_shuffle(Pred, Lbl, CFG, OldMap, NewMap) ->
- %% First make sure both maps have the same members.
- Push = NewMap -- OldMap,
- Pop = OldMap -- NewMap,
- {PopInsn, OldMap0} = pop_dead(Pop, OldMap),
- {PushInsn, OldMap1} =
- case Push of
- []-> {[], OldMap0};
- _-> push_list(lists:reverse(Push), OldMap0)
- end,
- Code =
- if OldMap1 =:= NewMap ->
- %% It was enough to push and pop.
- PopInsn ++ PushInsn ++ [hipe_x86:mk_jmp_label(Lbl)];
- true ->
- %% Shuffle the positions so the maps match
- Cycles = find_swap_cycles(OldMap1, NewMap),
- SwitchInsns = do_switching(Cycles),
- PopInsn ++ PushInsn ++ SwitchInsns ++ [hipe_x86:mk_jmp_label(Lbl)]
- end,
- %% Update the CFG.
- NewLabel = hipe_gensym:get_next_label(x86),
- NewCFG1 = hipe_x86_cfg:bb_add(CFG, NewLabel, hipe_bb:mk_bb(Code)),
- OldPred = hipe_x86_cfg:bb(NewCFG1, Pred),
- PredCode = hipe_bb:code(OldPred),
- NewLast = redirect(lists:last(PredCode), Lbl,NewLabel),
- NewPredCode = butlast(PredCode) ++ [NewLast],
- NewPredBB = hipe_bb:code_update(OldPred, NewPredCode),
- hipe_x86_cfg:bb_add(NewCFG1, Pred, NewPredBB).
-
-find_swap_cycles(OldMap, NewMap) ->
- Moves = [get_pos(X, NewMap, 1) || X <- OldMap],
- find_swap_cycles(OldMap, Moves, lists:seq(1, length(OldMap)), []).
-
-find_swap_cycles(OldMap, Moves, NotHandled, Cycles) ->
- if NotHandled =:= [] -> Cycles;
- true ->
- Cycle = find_cycle(Moves, [hd(NotHandled)]),
- NewNotHandled = NotHandled -- Cycle,
- case lists:member(1, Cycle) of
- true ->
- %% The cycle that contains the first element on the stack
- %% must be processed last.
- NewCycle = format_cycle(Cycle),
- find_swap_cycles(OldMap, Moves, NewNotHandled, Cycles ++ [NewCycle]);
- _ ->
- NewCycle = format_cycle(Cycle),
- find_swap_cycles(OldMap, Moves, NewNotHandled, [NewCycle|Cycles])
- end
- end.
-
-find_cycle(Moves, Cycle) ->
- To = lists:nth(lists:last(Cycle), Moves),
- if To =:= hd(Cycle) -> Cycle;
- true -> find_cycle(Moves, Cycle ++ [To])
- end.
-
-format_cycle(C) ->
- %% The position numbers start with 1 - should start with 0.
- %% If position 0 is in the cycle it will be permuted until
- %% the 0 is first and then remove it.
- %% Otherwise the first element is also added last.
- NewCycle = [X - 1 || X <- C],
- case lists:member(0, NewCycle) of
- true -> format_cycle(NewCycle, []);
- _ -> NewCycle ++ [hd(NewCycle)]
- end.
-
-format_cycle([H|T], NewCycle) ->
- case H of
- 0 -> T ++ NewCycle;
- _ -> format_cycle(T, NewCycle ++ [H])
- end.
-
-do_switching(Cycles) ->
- do_switching(Cycles, []).
-
-do_switching([C|Cycles], Insns) ->
- NewInsns = Insns ++ [hipe_x86:mk_fp_unop(fxch, mk_st(X)) || X <- C],
- do_switching(Cycles, NewInsns);
-do_switching([], Insns) ->
- Insns.
-
-redirect(Insn, OldLbl, NewLbl) ->
- case Insn of
- #pseudo_call{contlab = ContLab, sdesc = SDesc} ->
- #x86_sdesc{exnlab = ExnLab} = SDesc,
- if ContLab =:= OldLbl ->
- Insn#pseudo_call{contlab = NewLbl};
- ExnLab =:= OldLbl ->
- Insn#pseudo_call{sdesc = SDesc#x86_sdesc{exnlab = NewLbl}}
- end;
- _ ->
- hipe_x86_cfg:redirect_jmp(Insn, OldLbl, NewLbl)
- end.
-
-do_insn(I, LiveOut, Map, BlockMap) ->
- case I of
- #pseudo_call{'fun' = Fun, contlab = ContLab} ->
- case Fun of
- %% We don't want to spill anything if an exception has been thrown.
- {_, 'handle_fp_exception'} ->
- NewBlockMap =
- case gb_trees:lookup(ContLab, BlockMap) of
- {value, fail} ->
- BlockMap;
- {value, _} ->
- gb_trees:update(ContLab, fail, BlockMap);
- none ->
- gb_trees:insert(ContLab, fail, BlockMap)
- end,
- {[I], [], NewBlockMap};
- _ ->
- {pop_all(Map)++[I],[],BlockMap}
- end;
- #fp_unop{op = 'fwait'} ->
- Store = pseudo_pop(Map),
- {Store ++ [I], Map, BlockMap};
- #fp_unop{} ->
- {NewI, NewMap} = do_fp_unop(I, LiveOut, Map),
- {NewI, NewMap, BlockMap};
- #fp_binop{} ->
- {NewI, NewMap} = do_fp_binop(I, LiveOut, Map),
- {NewI, NewMap, BlockMap};
- #fmove{src = Src, dst = Dst} ->
- if Src =:= Dst ->
- %% Don't need to keep this instruction!
- %% However, we may need to pop from the stack.
- case is_liveOut(Src, LiveOut) of
- true->
- {[], Map, BlockMap};
- false ->
- {SwitchInsn, NewMap0} = switch_first(Dst, Map),
- NewMap = pop(NewMap0),
- {SwitchInsn++pop_insn(), NewMap, BlockMap}
- end;
- true ->
- {NewI, NewMap} = do_fmove(Src, Dst, LiveOut, Map),
- {NewI, NewMap, BlockMap}
- end;
- _ ->
- {[I], Map, BlockMap}
- end.
-
-do_fmove(Src, Dst = #x86_mem{}, LiveOut, Map) ->
- %% Storing a float from the stack into memory.
- {SwitchInsn, NewMap0} = switch_first(Src, Map),
- case is_liveOut(Src, LiveOut) of
- true ->
- {SwitchInsn ++ [hipe_x86:mk_fp_unop(fst, Dst)], NewMap0};
- _ ->
- NewMap1 = pop(NewMap0),
- {SwitchInsn ++ [hipe_x86:mk_fp_unop(fstp, Dst)], NewMap1}
- end;
-do_fmove(Src = #x86_mem{}, Dst, _LiveOut, Map) ->
- %% Pushing a float into the stack.
- case in_map(Dst, Map) of
- true -> ?EXIT({loadingExistingFpVariable,{Src,Dst}});
- _ -> ok
- end,
- {PushOp, [_|NewMap0]} = push(Src, Map),
- %% We want Dst in the map rather than Src.
- NewMap = [Dst|NewMap0],
- {PushOp, NewMap};
-do_fmove(Src, Dst, LiveOut, Map) ->
- %% Copying a float that either is spilled or is on the fp stack,
- %% or converting a fixnum in a temp to a float on the fp stack.
- case in_map(Dst, Map) of
- true -> ?EXIT({copyingToExistingFpVariable,{Src,Dst}});
- _ -> ok
- end,
- IsConv =
- case Src of
- #x86_temp{type = Type} -> Type =/= 'double';
- _ -> false
- end,
- case IsConv of
- true ->
- do_conv(Src, Dst, Map);
- _ ->
- %% Copying.
- case {is_liveOut(Src, LiveOut), in_map(Src, Map)} of
- {false, true} ->
- %% Just remap Dst to Src
- {Head, [_|T]} = lists:splitwith(fun(X) -> X =/= Src end, Map),
- {[], Head ++ [Dst|T]};
- _ ->
- {PushOp, [_|NewMap0]} = push(Src, Map),
- %% We want Dst in the map rather than Src.
- NewMap = [Dst|NewMap0],
- {PushOp, NewMap}
- end
- end.
-
-do_conv(Src = #x86_temp{reg = Reg}, Dst, Map) ->
- %% Converting. Src must not be a register, so we
- %% might have to put it into memory in between.
- {Move, NewSrc} =
- case ?HIPE_X86_REGISTERS:is_precoloured(Reg) of
- true ->
- Temp = hipe_x86:mk_new_temp('untagged'),
- {[hipe_x86:mk_move(Src,Temp)], Temp};
- _ ->
- {[], Src}
- end,
- {PushOp, [_|NewMap0]} = push(NewSrc, Map),
- %% We want Dst in the map rather than NewSrc.
- NewMap = [Dst|NewMap0],
- case length(PushOp) of
- 1 -> %% No popping of memory object on fpstack
- {Move ++ [hipe_x86:mk_fp_unop(fild, NewSrc)], NewMap};
- _ -> %% H contains pop instructions. Must be kept!
- Head = butlast(PushOp),
- {Move ++ Head ++ [hipe_x86:mk_fp_unop(fild, NewSrc)], NewMap}
- end.
-
-do_fp_unop(I = #fp_unop{arg = Arg, op = fchs}, Liveout, Map) ->
- %% This is fchs, the only operation without a
- %% popping version. Needs special handling.
- case is_liveOut(Arg, Liveout) of
- true ->
- {SwitchIns, NewMap} = switch_first(Arg, Map),
- {SwitchIns ++ [I#fp_unop{arg = []}], NewMap};
- false ->
- %% Don't need to keep this instruction!
- %% However, we may need to pop Src from the stack.
- case in_map(Arg, Map) of
- true ->
- {SwitchInsn, NewMap0} = switch_first(Arg, Map),
- NewMap = pop(NewMap0),
- {SwitchInsn ++ pop_insn(), NewMap};
- _ ->
- {[],Map}
- end
- end.
-
-do_fp_binop(#fp_binop{src = Src, dst = Dst, op = Op}, LiveOut, Map) ->
- case {is_liveOut(Src, LiveOut), is_liveOut(Dst, LiveOut)} of
- {true, true} ->
- keep_both(Op, Src, Dst, Map);
- {true, false} ->
- keep_src(Op, Src, Dst, Map);
- {false, true} ->
- keep_dst(Op, Src, Dst, Map);
- {false, false} ->
- %% Both Dst and Src are popped.
- keep_none(Op, Src, Dst, Map)
- end.
-
-keep_both(Op, Src, Dst, Map) ->
- %% Keep both Dst and Src if it is there.
- {SwitchInsn, NewMap} = switch_first(Dst, Map),
- NewSrc = get_new_opnd(Src, NewMap),
- Insn = format_fp_binop(Op, NewSrc, mk_st(0)),
- {SwitchInsn++Insn, NewMap}.
-
-keep_src(Op, Src, Dst, Map) ->
- %% Pop Dst but keep Src in stack if it is there.
- {SwitchInsn, NewMap0} = switch_first(Dst, Map),
- NewSrc = get_new_opnd(Src, NewMap0),
- NewMap = pop(NewMap0),
- Insn = format_fp_binop(Op, NewSrc, mk_st(0)),
- {SwitchInsn ++ Insn ++ pop_insn(), NewMap}.
-
-keep_dst(Op, Src, Dst, Map) ->
- %% Keep Dst but pop Src.
- %% Dst must be in stack.
- DstInMap = in_map(Dst, Map),
- SrcInMap = in_map(Src, Map),
- case SrcInMap of
- true ->
- case DstInMap of
- true ->
- %% Src must be popped. If Dst is on top of the stack we can
- %% alter the operation rather than shuffle the stack.
- {SwitchInsn, Insn, NewMap} =
- if hd(Map) =:= Dst ->
- NewOp = mk_op_pop(reverse_op(Op)),
- NewDst = get_new_opnd(Src, Map),
- TmpMap = lists:map(fun(X) ->
- if X =:= Src -> Dst; true -> X end
- end, Map),
- {[], format_fp_binop(NewOp, mk_st(0), NewDst), pop(TmpMap)};
- true ->
- {SwitchInsn1, NewMap0} = switch_first(Src, Map),
- NewDst = get_new_opnd(Dst,NewMap0),
- NewOp = mk_op_pop(Op),
- {SwitchInsn1,format_fp_binop(NewOp, mk_st(0), NewDst), pop(NewMap0)}
- end,
- {SwitchInsn ++ Insn, NewMap};
- _ ->
- %% Src is on the stack, but Dst isn't. Use memory command to avoid
- %% unnecessary loading instructions.
- {SwitchInsn, NewMap0} = switch_first(Src, Map),
- NewOp = reverse_op(Op),
- NewMap = [Dst] ++ tl(NewMap0),
- Insn = format_fp_binop(NewOp, Dst, mk_st(0)),
- {SwitchInsn ++ Insn, NewMap}
- end;
- _ ->
- %% Src isn't in the map so it doesn't have to be popped.
- {SwitchInsn, NewMap} = switch_first(Dst, Map),
- {SwitchInsn ++ [#fp_unop{arg = Src, op = Op}], NewMap}
- end.
-
-keep_none(Op, Src, Dst, Map) ->
- %% Dst must be on stack.
- {PushInsn, NewMap0} =
- case in_map(Dst, Map) of
- true -> {[], Map};
- _ -> push(Dst, Map)
- end,
- case in_map(Src, NewMap0) of
- true ->
- %% Src must be popped.
- {SwitchInsn1, NewMap1} = switch_first(Src, NewMap0),
- NewOp = mk_op_pop(Op),
- NewDst = get_new_opnd(Dst,NewMap1),
- NewMap2 = pop(NewMap1),
- %% Then Dst has to be popped.
- {PopInsn, NewMap} = pop_member(Dst, NewMap2),
- Insn = format_fp_binop(NewOp, mk_st(0), NewDst),
- {PushInsn ++ SwitchInsn1 ++ Insn ++ PopInsn, NewMap};
- _ ->
- %% Src isn't in the map so it doesn't have to be popped.
- {SwitchInsn, NewMap1} = switch_first(Dst, NewMap0),
- NewMap = pop(NewMap1),
- {SwitchInsn ++ [#fp_unop{arg = Src, op = Op}] ++ pop_insn(), NewMap}
- end.
-
-format_fp_binop(Op, Src = #x86_temp{}, Dst = #x86_fpreg{reg = Reg}) ->
- %% Handle that st(0) is sometimes implicit.
- if Reg =:= 0 -> [hipe_x86:mk_fp_unop(Op, Src)];
- true -> [hipe_x86:mk_fp_binop(Op, Src, Dst)]
- end;
-format_fp_binop(Op, Src, Dst) ->
- [hipe_x86:mk_fp_binop(Op, Src, Dst)].
-
-in_map(X, Map) ->
- lists:member(X, Map).
-
-push_list(L, Map) ->
- push_list(L, Map, []).
-push_list([H|T], Map, Acc) ->
- {Insn, NewMap} = push(H,Map),
- push_list(T, NewMap, Acc++Insn);
-push_list([], Map, Acc) ->
- {Acc, Map}.
-
-push(X, Map0) ->
- {PopInsn, Map} =
- if length(Map0) > 7 -> pop_a_temp(Map0);
- true -> {[], Map0}
- end,
- NewX = get_new_opnd(X,Map),
- NewMap = [X | Map],
- PushOp = [hipe_x86:mk_fp_unop(fld, NewX)],
- {PopInsn ++ PushOp, NewMap}.
-
-pop([_|Map]) ->
- Map.
-
-pop_insn() ->
- [hipe_x86:mk_fp_unop('fstp',mk_st(0))].
-
-pop_dead(Dead, Map) ->
- Dead0 = [X || X <- Map, lists:member(X,Dead)],
- pop_dead(Dead0, Map, []).
-
-pop_dead([D|Dead], Map, Code) ->
- {I, NewMap0} = switch_first(D, Map),
- NewMap = pop(NewMap0),
- Store = case D of
- #x86_temp{} -> [hipe_x86:mk_fp_unop('fstp', D)];
- _ -> pop_insn()
- end,
- pop_dead(Dead, NewMap, Code++I++Store);
-pop_dead([], Map, Code) ->
- {Code,Map}.
-
-pop_all(Map) ->
- {Code, _} = pop_dead(Map, Map),
- Code.
-
-pop_member(Member, Map) ->
- {Head,[_|T]} = lists:splitwith(fun(X)-> X =/= Member end, Map),
- {[hipe_x86:mk_fp_unop('fstp', mk_st(get_pos(Member, Map, 0)))],
- Head++T}.
-
-pop_a_temp(Map) ->
- Temp = find_a_temp(Map),
- {SwitchInsn, NewMap0} = switch_first(Temp, Map),
- NewMap = pop(NewMap0),
- {SwitchInsn ++ [hipe_x86:mk_fp_unop('fstp', Temp)], NewMap}.
-
-find_a_temp([H = #x86_temp{}|_]) ->
- H;
-find_a_temp([_|T]) ->
- find_a_temp(T);
-find_a_temp([]) ->
- ?EXIT({noTempOnFPStack,{}}).
-
-switch_first(X, Map = [H|_]) ->
- Pos = get_pos(X, Map, 0),
- case Pos of
- 0 ->
- {[], Map};
- notFound ->
- push(X, Map);
- _ ->
- {[_|Head], [_|Tail]} = lists:splitwith(fun(Y)-> Y =/= X end, Map),
- NewMap = [X|Head] ++ [H|Tail],
- Ins = hipe_x86:mk_fp_unop(fxch, mk_st(Pos)),
- {[Ins], NewMap}
- end;
-switch_first(X, Map) ->
- push(X, Map).
-
-get_pos(X, [H|T], Pos) ->
- if X =:= H -> Pos;
- true -> get_pos(X, T, Pos+1)
- end;
-get_pos(_, [], _) ->
- notFound.
-
-get_new_opnd(X, Map) ->
- I = get_pos(X, Map, 0),
- case I of
- notFound ->
- %% The operand is probably a spilled float.
- X;
- _ ->
- mk_st(I)
- end.
-
-is_fp(#x86_fpreg{}) ->
- true;
-is_fp(#x86_mem{type = Type}) ->
- Type =:= 'double';
-is_fp(#x86_temp{type = Type}) ->
- Type =:= 'double'.
-
-handle_insn(I) ->
- case I of
- #fmove{} -> true;
- #fp_unop{} -> true;
- #fp_binop{} -> true;
- #pseudo_call{} ->true;
- %% #ret{} -> true;
- _ -> false
- end.
-
-is_liveOut(X, LiveOut) ->
- ordsets:is_element(X, LiveOut).
-
-mk_st(X) ->
- hipe_x86:mk_fpreg(X, false).
-
-reverse_op(Op) ->
- case Op of
- 'fsub' -> 'fsubr';
- 'fdiv' -> 'fdivr';
- 'fsubr'-> 'fsub';
- 'fdivr' -> 'fdiv';
- _ -> Op
- end.
-
-mk_op_pop(Op) ->
- case Op of
- 'fadd'-> 'faddp';
- 'fdiv' -> 'fdivp';
- 'fdivr' -> 'fdivrp';
- 'fmul' -> 'fmulp';
- 'fsub' -> 'fsubp';
- 'fsubr' -> 'fsubrp';
- _ -> ?EXIT({operandHasNoPopVariant,{Op}})
- end.
-
-butlast([X|Xs]) -> butlast(Xs,X).
-
-butlast([],_) -> [];
-butlast([X|Xs],Y) -> [Y|butlast(Xs,X)].
-
-%%pp_insn(Op, Src, Dst) ->
-%% pp([hipe_x86:mk_fp_binop(Op, Src, Dst)]).
-
-%%pp([I|Ins]) ->
-%% hipe_x86_pp:pp_insn(I),
-%% pp(Ins);
-%%pp([]) ->
-%% [].
-
-pseudo_pop(Map) when length(Map) > 0 ->
- Dst = hipe_x86:mk_new_temp('double'),
- pseudo_pop(Dst, length(Map), []);
-pseudo_pop(_) ->
- [].
-
-pseudo_pop(Dst, St, Acc) when St > 1 ->
- %% Store all members of the stack to a single temporary to force
- %% any floating point overflow exceptions to occur even though we
- %% don't have overflow for the extended double precision in the x87.
- pseudo_pop(Dst, St-1,
- [hipe_x86:mk_fp_unop('fxch', mk_st(St-1)),
- hipe_x86:mk_fp_unop('fst', Dst),
- hipe_x86:mk_fp_unop('fxch', mk_st(St-1))
- |Acc]);
-pseudo_pop(Dst, _St, Acc) ->
- [hipe_x86:mk_fp_unop('fst', Dst)|Acc].