From 1b1e81f847a651bef0fff52d4dc5d09d9e521bcc Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Fri, 26 Jun 2015 14:00:56 +0000 Subject: [PATCH] [AArch64][2/2] Implement -fpic for -mcmodel=small 2015-06-26 Jiong Wang gcc/ * config/aarch64/aarch64-protos.h (aarch64_symbol_type): New type SYMBOL_SMALL_GOT_28K. * config/aarch64/aarch64.md: (ldr_got_small_): Support new GOT relocation modifiers. (unspec): New enum "UNSPEC_GOTMALLPIC28K. (ldr_got_small_28k_): New. (ldr_got_small_28k_sidi): New. * config/aarch64/iterators.md (got_modifier): New mode iterator. * config/aarch64/aarch64-otps.h (aarch64_code_model): New model. * config/aarch64/aarch64.c (aarch64_load_symref_appropriately): Support SYMBOL_SMALL_GOT_28K. (aarch64_rtx_costs): Add costs for new instruction sequences. (initialize_aarch64_code_model): Initialize new model. (aarch64_classify_symbol): Recognize new model and new symbol classification. (aarch64_asm_preferred_eh_data_format): Support new model. (aarch64_load_symref_appropriately): Generate new instruction sequences for -fpic. (TARGET_USE_PSEUDO_PIC_REG): New definition. (aarch64_use_pseudo_pic_reg): New function. gcc/testsuite/ * gcc.target/aarch64/pic-small.c: New testcase. From-SVN: r225017 --- gcc/ChangeLog | 22 +++++ gcc/config/aarch64/aarch64-opts.h | 3 + gcc/config/aarch64/aarch64-protos.h | 8 ++ gcc/config/aarch64/aarch64.c | 86 +++++++++++++++++++- gcc/config/aarch64/aarch64.md | 24 ++++++ gcc/config/aarch64/iterators.md | 4 + gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.target/aarch64/pic-small.c | 26 ++++++ 8 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/pic-small.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e1827899a46..bf2d02c8c3c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -67,6 +67,28 @@ (AARCH64_FUSE_ADRP_LDR): Likewise. (AARCH64_FUSE_CMP_BRANCH): Likewise. +2015-06-26 Jiong Wang + + * config/aarch64/aarch64-protos.h (aarch64_symbol_type): New type + SYMBOL_SMALL_GOT_28K. + * config/aarch64/aarch64.md: (ldr_got_small_): Support new GOT + relocation modifiers. + (unspec): New enum "UNSPEC_GOTMALLPIC28K. + (ldr_got_small_28k_): New. + (ldr_got_small_28k_sidi): New. + * config/aarch64/iterators.md (got_modifier): New mode iterator. + * config/aarch64/aarch64-otps.h (aarch64_code_model): New model. + * config/aarch64/aarch64.c (aarch64_load_symref_appropriately): Support + SYMBOL_SMALL_GOT_28K. + (aarch64_rtx_costs): Add costs for new instruction sequences. + (initialize_aarch64_code_model): Initialize new model. + (aarch64_classify_symbol): Recognize new model and new symbol classification. + (aarch64_asm_preferred_eh_data_format): Support new model. + (aarch64_load_symref_appropriately): Generate new instruction + sequences for -fpic. + (TARGET_USE_PSEUDO_PIC_REG): New definition. + (aarch64_use_pseudo_pic_reg): New function. + 2015-06-26 Jiong Wang * config/aarch64/aarch64-protos.h (aarch64_symbol_type): Rename diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h index ea64cf4a1e7..24bfd9fd150 100644 --- a/gcc/config/aarch64/aarch64-opts.h +++ b/gcc/config/aarch64/aarch64-opts.h @@ -56,6 +56,9 @@ enum aarch64_code_model { /* Static code, data and GOT/PLT fit within a 4GB region. The default PIC code model. */ AARCH64_CMODEL_SMALL_PIC, + /* -fpic for small memory model. + GOT size to 28KiB (4K*8-4K) or 3580 entries. */ + AARCH64_CMODEL_SMALL_SPIC, /* No assumptions about addresses of code and data. The PIC variant is not yet implemented. */ AARCH64_CMODEL_LARGE diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 4522f9c4b2f..2c623cc145c 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -62,6 +62,13 @@ enum aarch64_symbol_context This corresponds to the small PIC model of the compiler. + SYMBOL_SMALL_GOT_28K: Similar to SYMBOL_SMALL_GOT_4G, but used for symbol + restricted within 28K GOT table size. + + ldr reg, [gp, #:gotpage_lo15:sym] + + This corresponds to -fpic model for small memory model of the compiler. + SYMBOL_SMALL_TLSGD SYMBOL_SMALL_TLSDESC SYMBOL_SMALL_GOTTPREL @@ -95,6 +102,7 @@ enum aarch64_symbol_context enum aarch64_symbol_type { SYMBOL_SMALL_ABSOLUTE, + SYMBOL_SMALL_GOT_28K, SYMBOL_SMALL_GOT_4G, SYMBOL_SMALL_TLSGD, SYMBOL_SMALL_TLSDESC, diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 8533e1d2f7f..a11d8568e31 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -846,6 +846,66 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, emit_insn (gen_rtx_SET (dest, imm)); return; + case SYMBOL_SMALL_GOT_28K: + { + machine_mode mode = GET_MODE (dest); + rtx gp_rtx = pic_offset_table_rtx; + + /* NOTE: pic_offset_table_rtx can be NULL_RTX, because we can reach + here before rtl expand. Tree IVOPT will generate rtl pattern to + decide rtx costs, in which case pic_offset_table_rtx is not + initialized. For that case no need to generate the first adrp + instruction as the the final cost for global variable access is + one instruction. */ + if (gp_rtx != NULL) + { + /* -fpic for -mcmodel=small allow 32K GOT table size (but we are + using the page base as GOT base, the first page may be wasted, + in the worst scenario, there is only 28K space for GOT). + + The generate instruction sequence for accessing global variable + is: + + ldr reg, [pic_offset_table_rtx, #:gotpage_lo15:sym] + + Only one instruction needed. But we must initialize + pic_offset_table_rtx properly. We generate initialize insn for + every global access, and allow CSE to remove all redundant. + + The final instruction sequences will look like the following + for multiply global variables access. + + adrp pic_offset_table_rtx, _GLOBAL_OFFSET_TABLE_ + + ldr reg, [pic_offset_table_rtx, #:gotpage_lo15:sym1] + ldr reg, [pic_offset_table_rtx, #:gotpage_lo15:sym2] + ldr reg, [pic_offset_table_rtx, #:gotpage_lo15:sym3] + ... */ + + rtx s = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + crtl->uses_pic_offset_table = 1; + emit_move_insn (gp_rtx, gen_rtx_HIGH (Pmode, s)); + + if (mode != GET_MODE (gp_rtx)) + gp_rtx = simplify_gen_subreg (mode, gp_rtx, GET_MODE (gp_rtx), 0); + } + + if (mode == ptr_mode) + { + if (mode == DImode) + emit_insn (gen_ldr_got_small_28k_di (dest, gp_rtx, imm)); + else + emit_insn (gen_ldr_got_small_28k_si (dest, gp_rtx, imm)); + } + else + { + gcc_assert (mode == Pmode); + emit_insn (gen_ldr_got_small_28k_sidi (dest, gp_rtx, imm)); + } + + return; + } + case SYMBOL_SMALL_GOT_4G: { /* In ILP32, the mode of dest can be either SImode or DImode, @@ -1498,6 +1558,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) case SYMBOL_SMALL_TLSGD: case SYMBOL_SMALL_TLSDESC: case SYMBOL_SMALL_GOTTPREL: + case SYMBOL_SMALL_GOT_28K: case SYMBOL_SMALL_GOT_4G: case SYMBOL_TINY_GOT: if (offset != const0_rtx) @@ -6441,7 +6502,8 @@ cost_plus: case SYMBOL_REF: - if (aarch64_cmodel == AARCH64_CMODEL_LARGE) + if (aarch64_cmodel == AARCH64_CMODEL_LARGE + || aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC) { /* LDR. */ if (speed) @@ -7295,7 +7357,9 @@ initialize_aarch64_code_model (void) aarch64_cmodel = AARCH64_CMODEL_TINY_PIC; break; case AARCH64_CMODEL_SMALL: - aarch64_cmodel = AARCH64_CMODEL_SMALL_PIC; + aarch64_cmodel = (flag_pic == 2 + ? AARCH64_CMODEL_SMALL_PIC + : AARCH64_CMODEL_SMALL_SPIC); break; case AARCH64_CMODEL_LARGE: sorry ("code model %qs with -f%s", "large", @@ -7376,6 +7440,7 @@ aarch64_classify_symbol (rtx x, rtx offset, case AARCH64_CMODEL_TINY: return SYMBOL_TINY_ABSOLUTE; + case AARCH64_CMODEL_SMALL_SPIC: case AARCH64_CMODEL_SMALL_PIC: case AARCH64_CMODEL_SMALL: return SYMBOL_SMALL_ABSOLUTE; @@ -7423,9 +7488,11 @@ aarch64_classify_symbol (rtx x, rtx offset, return SYMBOL_TINY_GOT; return SYMBOL_TINY_ABSOLUTE; + case AARCH64_CMODEL_SMALL_SPIC: case AARCH64_CMODEL_SMALL_PIC: if (!aarch64_symbol_binds_local_p (x)) - return SYMBOL_SMALL_GOT_4G; + return (aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC + ? SYMBOL_SMALL_GOT_28K : SYMBOL_SMALL_GOT_4G); return SYMBOL_SMALL_ABSOLUTE; default: @@ -9299,6 +9366,7 @@ aarch64_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global) case AARCH64_CMODEL_TINY_PIC: case AARCH64_CMODEL_SMALL: case AARCH64_CMODEL_SMALL_PIC: + case AARCH64_CMODEL_SMALL_SPIC: /* text+got+data < 4Gb. 4-byte signed relocs are sufficient for everything. */ type = DW_EH_PE_sdata4; @@ -11594,6 +11662,15 @@ aarch64_gen_adjusted_ldpstp (rtx *operands, bool load, return true; } +/* Return 1 if pseudo register should be created and used to hold + GOT address for PIC code. */ + +bool +aarch64_use_pseudo_pic_reg (void) +{ + return aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC; +} + #undef TARGET_ADDRESS_COST #define TARGET_ADDRESS_COST aarch64_address_cost @@ -11872,6 +11949,9 @@ aarch64_gen_adjusted_ldpstp (rtx *operands, bool load, #undef TARGET_SCHED_FUSION_PRIORITY #define TARGET_SCHED_FUSION_PRIORITY aarch64_sched_fusion_priority +#undef TARGET_USE_PSEUDO_PIC_REG +#define TARGET_USE_PSEUDO_PIC_REG aarch64_use_pseudo_pic_reg + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-aarch64.h" diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index dbc4d1fbfee..a1722684bc5 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -87,6 +87,7 @@ UNSPEC_FRINTX UNSPEC_FRINTZ UNSPEC_GOTSMALLPIC + UNSPEC_GOTSMALLPIC28K UNSPEC_GOTSMALLTLS UNSPEC_GOTTINYPIC UNSPEC_LD1 @@ -4360,6 +4361,29 @@ [(set_attr "type" "load1")] ) +(define_insn "ldr_got_small_28k_" + [(set (match_operand:PTR 0 "register_operand" "=r") + (unspec:PTR [(mem:PTR (lo_sum:PTR + (match_operand:PTR 1 "register_operand" "r") + (match_operand:PTR 2 "aarch64_valid_symref" "S")))] + UNSPEC_GOTSMALLPIC28K))] + "" + "ldr\\t%0, [%1, #::%a2]" + [(set_attr "type" "load1")] +) + +(define_insn "ldr_got_small_28k_sidi" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (unspec:SI [(mem:SI (lo_sum:DI + (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "aarch64_valid_symref" "S")))] + UNSPEC_GOTSMALLPIC28K)))] + "TARGET_ILP32" + "ldr\\t%w0, [%1, #:gotpage_lo14:%a2]" + [(set_attr "type" "load1")] +) + (define_insn "ldr_got_tiny" [(set (match_operand:DI 0 "register_operand" "=r") (unspec:DI [(match_operand:DI 1 "aarch64_valid_symref" "S")] diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 498358a6354..b19d3d743a7 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -657,6 +657,10 @@ (define_mode_attr insn_count [(OI "8") (CI "12") (XI "16")]) +;; -fpic small model GOT reloc modifers: gotpage_lo15/lo14 for ILP64/32. +;; No need of iterator for -fPIC as it use got_lo12 for both modes. +(define_mode_attr got_modifier [(SI "gotpage_lo14") (DI "gotpage_lo15")]) + ;; ------------------------------------------------------------------- ;; Code Iterators ;; ------------------------------------------------------------------- diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 55fa18f1dc4..610650edef7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2015-06-26 Jiong Wang + + * gcc.target/aarch64/pic-small.c: New testcase. + 2015-06-26 Richard Biener * gcc.dg/tree-ssa/forwprop-25.c: Adjust. diff --git a/gcc/testsuite/gcc.target/aarch64/pic-small.c b/gcc/testsuite/gcc.target/aarch64/pic-small.c new file mode 100644 index 00000000000..874f81b830b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pic-small.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fpic -fno-inline --save-temps" } */ + +void abort (); +int global_a; + +int +initialize (void) +{ + global_a = 0x10; + return global_a - 1; +} + +int +main (int argc, char **argv) +{ + int a = initialize (); + + if (a != global_a - 1) + abort (); + + return 0; +} + +/* { dg-final { scan-assembler-times "adrp\tx\[0-9\]+, _GLOBAL_OFFSET_TABLE" 2 } } */ +/* { dg-final { cleanup-saved-temps } } */ -- 2.30.2