From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2049) id 96B803856279; Thu, 5 May 2022 12:09:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 96B803856279 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Matthew Malcomson To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ARM/heads/morello)] aarch64: Hybrid support for non-TLS CADI symbols X-Act-Checkin: gcc X-Git-Author: Richard Sandiford X-Git-Refname: refs/vendors/ARM/heads/morello X-Git-Oldrev: c675754a1788ddd741fb310d8d7ee612b95264f5 X-Git-Newrev: c29d908fa60c52faf58f946fcbb2b1f98a83da6b Message-Id: <20220505120908.96B803856279@sourceware.org> Date: Thu, 5 May 2022 12:09:08 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 May 2022 12:09:08 -0000 https://gcc.gnu.org/g:c29d908fa60c52faf58f946fcbb2b1f98a83da6b commit c29d908fa60c52faf58f946fcbb2b1f98a83da6b Author: Richard Sandiford Date: Wed Apr 13 10:05:22 2022 +0100 aarch64: Hybrid support for non-TLS CADI symbols I think this patch contains the minimum changes needed to code-generate an existing non-TLS CAP_ADDR_EXPR for hybrid code. Any non-TLS CADI symbolic constant needs to be forced into a .data.rel.ro(.local) .capinit slot and then be loaded from there. Diff: --- gcc/config/aarch64/aarch64.c | 19 +++++++---- gcc/explow.c | 9 +++-- gcc/expr.c | 38 +++++++++++++++++----- .../aarch64/morello/hybrid-addr-expr-1.c | 20 ++++++++++++ .../aarch64/morello/hybrid-addr-expr-2.c | 21 ++++++++++++ .../aarch64/morello/hybrid-addr-expr-3.c | 21 ++++++++++++ .../aarch64/morello/hybrid-addr-expr-4.c | 21 ++++++++++++ .../aarch64/morello/hybrid-addr-expr-5.c | 21 ++++++++++++ .../aarch64/morello/hybrid-addr-expr-6.c | 21 ++++++++++++ .../aarch64/morello/hybrid-addr-expr-7.c | 23 +++++++++++++ .../aarch64/morello/hybrid-addr-expr-8.c | 22 +++++++++++++ 11 files changed, 219 insertions(+), 17 deletions(-) diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index b503e5dfd65..b5bc8949b2c 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -5537,11 +5537,12 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) } sty = aarch64_classify_symbol (base, const_offset); + scalar_addr_mode mem_mode = TARGET_ILP32 ? ptr_mode : addr_mode; switch (sty) { case SYMBOL_FORCE_TO_MEM: if (const_offset != 0 - && targetm.cannot_force_const_mem (addr_mode, imm)) + && targetm.cannot_force_const_mem (mem_mode, imm)) { gcc_assert (can_create_pseudo_p ()); base = aarch64_force_temporary (addr_mode, dest, base); @@ -5550,7 +5551,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) return; } - mem = force_const_mem (ptr_mode, imm); + mem = force_const_mem (mem_mode, imm); if (TARGET_CAPABILITY_PURE && SYMBOL_REF_P (base)) { /* Mark the symbol created by `force_const_mem` as one into the @@ -5570,7 +5571,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) we need to expand the literal pool access carefully. This is something that needs to be done in a number of places, so could well live as a separate function. */ - if (!memory_operand (mem, ptr_mode)) + if (!memory_operand (mem, mem_mode)) { gcc_assert (can_create_pseudo_p ()); if (TARGET_CAPABILITY_PURE && SYMBOL_REF_P (base)) @@ -5605,10 +5606,10 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) if (ptr_mode != Pmode) base = convert_memory_address (Pmode, base); } - mem = gen_rtx_MEM (ptr_mode, base); + mem = gen_rtx_MEM (mem_mode, base); } - if (addr_mode != ptr_mode) + if (addr_mode != mem_mode) mem = gen_rtx_ZERO_EXTEND (addr_mode, mem); emit_insn (gen_rtx_SET (dest, mem)); @@ -9366,7 +9367,7 @@ aarch64_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) else /* Avoid generating a 64-bit relocation in ILP32; leave to aarch64_expand_mov_immediate to handle it properly. */ - return mode != ptr_mode; + return TARGET_ILP32 && mode != ptr_mode; } return aarch64_tls_referenced_p (x); @@ -17110,6 +17111,12 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) if (aarch64_sym_indirectly_accessed_p (x)) return aarch64_classify_capability_symbol (x, offset); + /* In hybrid mode, the only way of loading a constant capability is + to force it into a (.data.rel.ro*) constant pool entry. Unlike + for pure capabilities, the GOT option is not available. */ + if (CAPABILITY_MODE_P (GET_MODE (x)) && !CAPABILITY_MODE_P (Pmode)) + return SYMBOL_FORCE_TO_MEM; + /* -mpc-relative-literal-loads tells us to assume that all (function) constant pool entries will be within the range of PC-relative LDR, which means that they must also be in range of ADR. */ diff --git a/gcc/explow.c b/gcc/explow.c index 00e89e32689..e58e5923f2a 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -363,11 +363,16 @@ convert_memory_address_addr_space_1 (scalar_addr_mode to_mode ATTRIBUTE_UNUSED, /* If X already has the right mode, just return it. */ if (GET_MODE (x) == to_mode) return x; - /* We can't convert a mode to a capability mode. + /* Non-capability symbolic constants can be re-expressed as capability + constants simply by (recursively) changing the mode. However, + we can't convert an arbitrary runtime value to a capability mode. Even if the from_mode was a capability mode there is no general way to handle that since we don't know what the extra bits contain in each case (they're not just simply bits ...). */ - gcc_assert (! CAPABILITY_MODE_P (to_mode)); + gcc_assert (! CAPABILITY_MODE_P (to_mode) + || GET_CODE (x) == LABEL_REF + || GET_CODE (x) == SYMBOL_REF + || GET_CODE (x) == CONST); pointer_mode = unqualified_pointer_mode (as); address_mode = unqualified_address_mode (as); diff --git a/gcc/expr.c b/gcc/expr.c index d48dfc6bccf..5fe7e9781f7 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8178,12 +8178,14 @@ expand_expr_constant (tree exp, int defer, enum expand_modifier modifier) return mem; } -/* A subroutine of expand_expr_addr_expr. Evaluate the address of EXP. - The TARGET, TMODE and MODIFIER arguments are as for expand_expr. */ +/* A subroutine of expand_expr_addr_expr. Evaluate the address of EXP + using code ADDR_CODE. The TARGET, TMODE and MODIFIER arguments are + as for expand_expr. */ static rtx -expand_expr_addr_expr_1 (tree exp, rtx target, scalar_addr_mode tmode, - enum expand_modifier modifier, addr_space_t as) +expand_expr_addr_expr_1 (tree_code addr_code, tree exp, rtx target, + scalar_addr_mode tmode, + enum expand_modifier modifier, addr_space_t as) { rtx result, subtarget; tree inner, offset; @@ -8191,6 +8193,11 @@ expand_expr_addr_expr_1 (tree exp, rtx target, scalar_addr_mode tmode, int unsignedp, reversep, volatilep = 0; machine_mode mode1; + /* Detect if we're creating a capability pointer in an environment + where that isn't the default behavior. */ + bool force_capability = (addr_code == CAP_ADDR_EXPR + && !CAPABILITY_MODE_P (Pmode)); + /* If we are taking the address of a constant and are at the top level, we have to use output_constant_def since we can't call force_const_mem at top level. */ @@ -8256,7 +8263,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, scalar_addr_mode tmode, the initializers aren't gimplified. */ if (COMPOUND_LITERAL_EXPR_DECL (exp) && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp))) - return expand_expr_addr_expr_1 (COMPOUND_LITERAL_EXPR_DECL (exp), + return expand_expr_addr_expr_1 (addr_code, + COMPOUND_LITERAL_EXPR_DECL (exp), target, tmode, modifier, as); /* FALLTHRU */ default: @@ -8271,8 +8279,13 @@ expand_expr_addr_expr_1 (tree exp, rtx target, scalar_addr_mode tmode, || TREE_CODE (exp) == CONSTRUCTOR || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR) { + /* If we want a capability pointer, and if normal pointers are + not capabilities, try harder to preserve the structure of + the original address. In particular, don't try to rewrite + the address to use (Pmode) section anchors. */ result = expand_expr (exp, target, tmode, modifier == EXPAND_INITIALIZER + || force_capability ? EXPAND_INITIALIZER : EXPAND_CONST_ADDRESS); /* If the DECL isn't in memory, then the DECL wasn't properly @@ -8282,6 +8295,11 @@ expand_expr_addr_expr_1 (tree exp, rtx target, scalar_addr_mode tmode, gcc_assert (MEM_P (result)); result = XEXP (result, 0); + /* Convert a non-capability constant address to a capability + while we still have its original form. */ + if (force_capability) + result = convert_memory_address_addr_space (tmode, result, as); + /* ??? Is this needed anymore? */ if (DECL_P (exp)) TREE_USED (exp) = 1; @@ -8317,7 +8335,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, scalar_addr_mode tmode, SET_TYPE_ALIGN (TREE_TYPE (inner), TYPE_ALIGN (TREE_TYPE (exp))); TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1; } - result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier, as); + result = expand_expr_addr_expr_1 (addr_code, inner, subtarget, tmode, + modifier, as); if (offset) { @@ -8393,8 +8412,8 @@ expand_expr_addr_expr (tree exp, rtx target, machine_mode tmode, ? pointer_mode : address_mode); - result = expand_expr_addr_expr_1 (TREE_OPERAND (exp, 0), target, - new_tmode, modifier, as); + result = expand_expr_addr_expr_1 (TREE_CODE (exp), TREE_OPERAND (exp, 0), + target, new_tmode, modifier, as); /* Despite expand_expr claims concerning ignoring TMODE when not strictly convenient, stuff breaks if we don't honor it. Note @@ -10600,7 +10619,8 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, gracefully. */ addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); scalar_addr_mode address_mode = unqualified_address_mode (as); - op0 = expand_expr_addr_expr_1 (exp, NULL_RTX, address_mode, + op0 = expand_expr_addr_expr_1 (unqualified_addr_expr (), exp, + NULL_RTX, address_mode, EXPAND_NORMAL, as); op0 = memory_address_addr_space (mode, op0, as); temp = gen_rtx_MEM (mode, op0); diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-1.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-1.c new file mode 100644 index 00000000000..175471ef26f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-1.c @@ -0,0 +1,20 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=tiny -fno-PIC -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** ldr c0, \.LC0 +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro\.local,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-2.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-2.c new file mode 100644 index 00000000000..b1a724f2158 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-2.c @@ -0,0 +1,21 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=tiny -fPIC -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** ldr c0, \.LC0 +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\tldr\tc0, \.LC0\n\tret\n} } } */ +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-3.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-3.c new file mode 100644 index 00000000000..512c517c8c4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-3.c @@ -0,0 +1,21 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=small -fno-PIC -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** adrp (x[0-9]+), \.LC0 +** ldr c0, \[\1, #:lo12:\.LC0\] +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro\.local,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-4.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-4.c new file mode 100644 index 00000000000..9f6ab6a54ce --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-4.c @@ -0,0 +1,21 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=small -fPIC -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** adrp (x[0-9]+), \.LC0 +** ldr c0, \[\1, #:lo12:\.LC0\] +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-5.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-5.c new file mode 100644 index 00000000000..53368e6dfab --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-5.c @@ -0,0 +1,21 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=small -fno-PIC -mpc-relative-literal-loads -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** adrp (x[0-9]+), \.LC0 +** ldr c0, \[\1, #:lo12:\.LC0\] +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro\.local,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-6.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-6.c new file mode 100644 index 00000000000..7ed909424db --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-6.c @@ -0,0 +1,21 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=small -fPIC -mpc-relative-literal-loads -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** adrp (x[0-9]+), \.LC0 +** ldr c0, \[\1, #:lo12:\.LC0\] +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-7.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-7.c new file mode 100644 index 00000000000..89ba1759861 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-7.c @@ -0,0 +1,23 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=large -fno-PIC -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** adrp (x[0-9]+), \.LC1 +** ldr (x[0-9]+), \[\1, #:lo12:\.LC1\] +** ldr c0, \[\2\] +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.size\t\.LC1, 8\n\.LC1:\n\t\.xword\t\.LC0\n} } } */ +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro\.local,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-8.c b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-8.c new file mode 100644 index 00000000000..ef2129371c1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/morello/hybrid-addr-expr-8.c @@ -0,0 +1,22 @@ +/* { dg-do assemble } */ +/* { dg-additional-options "-mcmodel=large -fno-PIC -mpc-relative-literal-loads -fgimple -g0 -save-temps" } */ +/* { dg-final { check-function-bodies "**" "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-mabi=purecap" "-mfake-capability" } { "" } } */ + +/* +** foo: +** ldr (x[0-9]+), \.LC1 +** ldr c0, \[\1\] +** ret +*/ +int x; +__GIMPLE int *__capability foo() { + int *__capability res; + + res = __CAP_ADDR x; + return res; +} + +/* { dg-final { scan-assembler {\t\.size\t\.LC1, 8\n\.LC1:\n\t\.xword\t\.LC0\n} } } */ +/* { dg-final { scan-assembler {\t\.section\t\.data\.rel\.ro\.local,"aw"\n\t\.align\t4\n\t\.type\t\.LC0, %object\n} } } */ +/* { dg-final { scan-assembler {\t\.size\t\.LC0, 16\n\.LC0:\n\t\.capinit\tx\n} } } */