From: Ilya Leoshkevich Date: Thu, 26 Nov 2020 01:16:17 +0000 (+0100) Subject: IBM Z: Use llihf and oilf to load large immediates into GPRs X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9776b4653bc4f8b568ea49fea4a7d7460e58b68a;p=gcc.git IBM Z: Use llihf and oilf to load large immediates into GPRs Currently GCC loads large immediates into GPRs from the literal pool, which is not as efficient as loading two halves with llihf and oilf. gcc/ChangeLog: 2020-11-30 Ilya Leoshkevich * config/s390/s390-protos.h (s390_const_int_pool_entry_p): New function. * config/s390/s390.c (s390_const_int_pool_entry_p): New function. * config/s390/s390.md: Add define_peephole2 that produces llihf and oilf. gcc/testsuite/ChangeLog: 2020-11-30 Ilya Leoshkevich * gcc.target/s390/load-imm64-1.c: New test. * gcc.target/s390/load-imm64-2.c: New test. --- diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index ad2f7f77c18..eb10c3f4bbb 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -135,6 +135,7 @@ extern void s390_split_access_reg (rtx, rtx *, rtx *); extern void print_operand_address (FILE *, rtx); extern void print_operand (FILE *, rtx, int); extern void s390_output_pool_entry (rtx, machine_mode, unsigned int); +extern bool s390_const_int_pool_entry_p (rtx, HOST_WIDE_INT *); extern int s390_label_align (rtx_insn *); extern int s390_agen_dep_p (rtx_insn *, rtx_insn *); extern rtx_insn *s390_load_got (void); diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 02f18366aa1..fb48102559d 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -9400,6 +9400,37 @@ s390_output_pool_entry (rtx exp, machine_mode mode, unsigned int align) } } +/* Return true if MEM refers to an integer constant in the literal pool. If + VAL is not nullptr, then also fill it with the constant's value. */ + +bool +s390_const_int_pool_entry_p (rtx mem, HOST_WIDE_INT *val) +{ + /* Try to match the following: + - (mem (unspec [(symbol_ref) (reg)] UNSPEC_LTREF)). + - (mem (symbol_ref)). */ + + if (!MEM_P (mem)) + return false; + + rtx addr = XEXP (mem, 0); + rtx sym; + if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_LTREF) + sym = XVECEXP (addr, 0, 0); + else + sym = addr; + + if (!SYMBOL_REF_P (sym) || !CONSTANT_POOL_ADDRESS_P (sym)) + return false; + + rtx val_rtx = get_pool_constant (sym); + if (!CONST_INT_P (val_rtx)) + return false; + + if (val != nullptr) + *val = INTVAL (val_rtx); + return true; +} /* Return an RTL expression representing the value of the return address for the frame COUNT steps up from the current frame. FRAME is the diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 910415a5974..d4cfbdf6732 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -2116,6 +2116,29 @@ [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))] "") +; Split loading of 64-bit constants into GPRs into llihf + oilf - +; counterintuitively, using oilf is faster than iilf. oilf clobbers +; cc, so cc must be dead. +(define_peephole2 + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "memory_operand" ""))] + "TARGET_64BIT + && TARGET_EXTIMM + && GENERAL_REG_P (operands[0]) + && s390_const_int_pool_entry_p (operands[1], nullptr) + && peep2_reg_dead_p (1, gen_rtx_REG (CCmode, CC_REGNUM))" + [(set (match_dup 0) (match_dup 2)) + (parallel + [(set (match_dup 0) (ior:DI (match_dup 0) (match_dup 3))) + (clobber (reg:CC CC_REGNUM))])] +{ + HOST_WIDE_INT val; + bool ok = s390_const_int_pool_entry_p (operands[1], &val); + gcc_assert (ok); + operands[2] = GEN_INT (val & 0xFFFFFFFF00000000ULL); + operands[3] = GEN_INT (val & 0x00000000FFFFFFFFULL); +}) + ; ; movsi instruction pattern(s). ; diff --git a/gcc/testsuite/gcc.target/s390/load-imm64-1.c b/gcc/testsuite/gcc.target/s390/load-imm64-1.c new file mode 100644 index 00000000000..03d17f59096 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/load-imm64-1.c @@ -0,0 +1,14 @@ +/* Test that large 64-bit constants are loaded with llihf + oilf when lgrl is + not available. */ + +/* { dg-do compile } */ +/* { dg-options "-O3 -march=z9-109" } */ + +unsigned long +magic (void) +{ + return 0x3f08c5392f756cd; +} + +/* { dg-final { scan-assembler-times {\n\tllihf\t} 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times {\n\toilf\t} 1 { target lp64 } } } */ diff --git a/gcc/testsuite/gcc.target/s390/load-imm64-2.c b/gcc/testsuite/gcc.target/s390/load-imm64-2.c new file mode 100644 index 00000000000..ee0ff3b0a91 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/load-imm64-2.c @@ -0,0 +1,14 @@ +/* Test that large 64-bit constants are loaded with llihf + oilf when lgrl is + available. */ + +/* { dg-do compile } */ +/* { dg-options "-O3 -march=z10" } */ + +unsigned long +magic (void) +{ + return 0x3f08c5392f756cd; +} + +/* { dg-final { scan-assembler-times {\n\tllihf\t} 1 { target lp64 } } } */ +/* { dg-final { scan-assembler-times {\n\toilf\t} 1 { target lp64 } } } */