From 38f31687815ca01c8851a8322e67e75e2afce1ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 9 Jul 2005 11:28:23 -0700 Subject: [PATCH] alpha.c (emit_insxl, [...]): New functions. * config/alpha/alpha.c (emit_insxl, alpha_expand_compare_and_swap_12, alpha_split_compare_and_swap_12, alpha_expand_lock_test_and_set_12, alpha_split_lock_test_and_set_12): New functions. * config/alpha/alpha-protos.h: Update. * config/alpha/alpha.md (UNSPEC_MB, UNSPEC_ATOMIC, UNSPEC_CMPXCHG, UNSPEC_XCHG): Rename from UNSPECV_FOO. * config/alpha/sync.md (I12MODE): New. (memory_barrier, mb_internal): Use unspec instead of unspec_volatile. (sync_): Likewise. (sync_nand): Likewise. (sync_old_): Likewise. (sync_new_): Likewise. (sync_old_nand, sync_new_nand): Likewise. (sync_compare_and_swap): Likewise. (sync_lock_test_and_set): Likewise. (sync_compare_and_swap): New. (sync_compare_and_swap_1): New. (sync_lock_test_and_set): New. (sync_lock_test_and_set_1): New. * lib/target-supports.exp (check_effective_target_sync_char_short): Add alpha. From-SVN: r101833 --- gcc/ChangeLog | 25 +++- gcc/config/alpha/alpha-protos.h | 6 + gcc/config/alpha/alpha.c | 163 ++++++++++++++++++++++++++ gcc/config/alpha/alpha.md | 14 ++- gcc/config/alpha/sync.md | 108 +++++++++++++---- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/lib/target-supports.exp | 1 + 7 files changed, 294 insertions(+), 28 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index abaa36d0ee22..f6a729a96950 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,9 +1,30 @@ +2005-07-09 Richard Henderson + + * config/alpha/alpha.c (emit_insxl, alpha_expand_compare_and_swap_12, + alpha_split_compare_and_swap_12, alpha_expand_lock_test_and_set_12, + alpha_split_lock_test_and_set_12): New functions. + * config/alpha/alpha-protos.h: Update. + * config/alpha/alpha.md (UNSPEC_MB, UNSPEC_ATOMIC, + UNSPEC_CMPXCHG, UNSPEC_XCHG): Rename from UNSPECV_FOO. + * config/alpha/sync.md (I12MODE): New. + (memory_barrier, mb_internal): Use unspec instead of unspec_volatile. + (sync_): Likewise. + (sync_nand): Likewise. + (sync_old_): Likewise. + (sync_new_): Likewise. + (sync_old_nand, sync_new_nand): Likewise. + (sync_compare_and_swap): Likewise. + (sync_lock_test_and_set): Likewise. + (sync_compare_and_swap): New. + (sync_compare_and_swap_1): New. + (sync_lock_test_and_set): New. + (sync_lock_test_and_set_1): New. + 2005-07-09 Diego Novillo PR 21356 PR 22332 - * passes.c (execute_todo): Cleanup the CFG before updating - SSA. + * passes.c (execute_todo): Cleanup the CFG before updating SSA. 2005-07-09 Jakub Jelinek diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index d854e35ca411..5dd57343c582 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -103,7 +103,13 @@ extern void alpha_emit_xfloating_arith (enum rtx_code, rtx[]); extern void alpha_emit_xfloating_cvt (enum rtx_code, rtx[]); extern void alpha_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx); extern void alpha_split_compare_and_swap (rtx, rtx, rtx, rtx, rtx); +extern void alpha_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx); +extern void alpha_split_compare_and_swap_12 (enum machine_mode, rtx, rtx, + rtx, rtx, rtx, rtx, rtx); extern void alpha_split_lock_test_and_set (rtx, rtx, rtx, rtx); +extern void alpha_expand_lock_test_and_set_12 (rtx, rtx, rtx); +extern void alpha_split_lock_test_and_set_12 (enum machine_mode, rtx, rtx, + rtx, rtx, rtx); #endif extern rtx alpha_need_linkage (const char *, int); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 3eaf15999570..5d8f72df2b10 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -4453,6 +4453,34 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val) emit_insn (fn (res, mem, val)); } +/* A subroutine of the atomic operation splitters. Emit an insxl + instruction in MODE. */ + +static rtx +emit_insxl (enum machine_mode mode, rtx op1, rtx op2) +{ + rtx ret = gen_reg_rtx (DImode); + rtx (*fn) (rtx, rtx, rtx); + + if (WORDS_BIG_ENDIAN) + { + if (mode == QImode) + fn = gen_insbl_be; + else + fn = gen_inswl_be; + } + else + { + if (mode == QImode) + fn = gen_insbl_le; + else + fn = gen_inswl_le; + } + emit_insn (fn (ret, op1, op2)); + + return ret; +} + /* Expand an an atomic fetch-and-operate pattern. CODE is the binary operation to perform. MEM is the memory on which to operate. VAL is the second operand of the binary operator. BEFORE and AFTER are optional locations to @@ -4530,6 +4558,79 @@ alpha_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval, emit_label (XEXP (label2, 0)); } +void +alpha_expand_compare_and_swap_12 (rtx dst, rtx mem, rtx oldval, rtx newval) +{ + enum machine_mode mode = GET_MODE (mem); + rtx addr, align, wdst; + rtx (*fn5) (rtx, rtx, rtx, rtx, rtx); + + addr = force_reg (DImode, XEXP (mem, 0)); + align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8), + NULL_RTX, 1, OPTAB_DIRECT); + + oldval = convert_modes (DImode, mode, oldval, 1); + newval = emit_insxl (mode, newval, addr); + + wdst = gen_reg_rtx (DImode); + if (mode == QImode) + fn5 = gen_sync_compare_and_swapqi_1; + else + fn5 = gen_sync_compare_and_swaphi_1; + emit_insn (fn5 (wdst, addr, oldval, newval, align)); + + emit_move_insn (dst, gen_lowpart (mode, wdst)); +} + +void +alpha_split_compare_and_swap_12 (enum machine_mode mode, rtx dest, rtx addr, + rtx oldval, rtx newval, rtx align, + rtx scratch, rtx cond) +{ + rtx label1, label2, mem, width, mask, x; + + mem = gen_rtx_MEM (DImode, align); + MEM_VOLATILE_P (mem) = 1; + + emit_insn (gen_memory_barrier ()); + label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + emit_label (XEXP (label1, 0)); + + emit_load_locked (DImode, scratch, mem); + + width = GEN_INT (GET_MODE_BITSIZE (mode)); + mask = GEN_INT (mode == QImode ? 0xff : 0xffff); + if (WORDS_BIG_ENDIAN) + emit_insn (gen_extxl_be (dest, scratch, width, addr)); + else + emit_insn (gen_extxl_le (dest, scratch, width, addr)); + + if (oldval == const0_rtx) + x = gen_rtx_NE (DImode, dest, const0_rtx); + else + { + x = gen_rtx_EQ (DImode, dest, oldval); + emit_insn (gen_rtx_SET (VOIDmode, cond, x)); + x = gen_rtx_EQ (DImode, cond, const0_rtx); + } + emit_unlikely_jump (x, label2); + + if (WORDS_BIG_ENDIAN) + emit_insn (gen_mskxl_be (scratch, scratch, mask, addr)); + else + emit_insn (gen_mskxl_le (scratch, scratch, mask, addr)); + emit_insn (gen_iordi3 (scratch, scratch, newval)); + + emit_store_conditional (DImode, scratch, mem, scratch); + + x = gen_rtx_EQ (DImode, scratch, const0_rtx); + emit_unlikely_jump (x, label1); + + emit_insn (gen_memory_barrier ()); + emit_label (XEXP (label2, 0)); +} + /* Expand an atomic exchange operation. */ void @@ -4550,6 +4651,68 @@ alpha_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch) x = gen_rtx_EQ (DImode, cond, const0_rtx); emit_unlikely_jump (x, label); } + +void +alpha_expand_lock_test_and_set_12 (rtx dst, rtx mem, rtx val) +{ + enum machine_mode mode = GET_MODE (mem); + rtx addr, align, wdst; + rtx (*fn4) (rtx, rtx, rtx, rtx); + + /* Force the address into a register. */ + addr = force_reg (DImode, XEXP (mem, 0)); + + /* Align it to a multiple of 8. */ + align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8), + NULL_RTX, 1, OPTAB_DIRECT); + + /* Insert val into the correct byte location within the word. */ + val = emit_insxl (mode, val, addr); + + wdst = gen_reg_rtx (DImode); + if (mode == QImode) + fn4 = gen_sync_lock_test_and_setqi_1; + else + fn4 = gen_sync_lock_test_and_sethi_1; + emit_insn (fn4 (wdst, addr, val, align)); + + emit_move_insn (dst, gen_lowpart (mode, wdst)); +} + +void +alpha_split_lock_test_and_set_12 (enum machine_mode mode, rtx dest, rtx addr, + rtx val, rtx align, rtx scratch) +{ + rtx label, mem, width, mask, x; + + mem = gen_rtx_MEM (DImode, align); + MEM_VOLATILE_P (mem) = 1; + + emit_insn (gen_memory_barrier ()); + label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); + emit_label (XEXP (label, 0)); + + emit_load_locked (DImode, scratch, mem); + + width = GEN_INT (GET_MODE_BITSIZE (mode)); + mask = GEN_INT (mode == QImode ? 0xff : 0xffff); + if (WORDS_BIG_ENDIAN) + { + emit_insn (gen_extxl_be (dest, scratch, width, addr)); + emit_insn (gen_mskxl_be (scratch, scratch, mask, addr)); + } + else + { + emit_insn (gen_extxl_le (dest, scratch, width, addr)); + emit_insn (gen_mskxl_le (scratch, scratch, mask, addr)); + } + emit_insn (gen_iordi3 (scratch, scratch, val)); + + emit_store_conditional (DImode, scratch, mem, scratch); + + x = gen_rtx_EQ (DImode, scratch, const0_rtx); + emit_unlikely_jump (x, label); +} /* Adjust the cost of a scheduling dependency. Return the new cost of a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index 35cc320ea840..d9f9e09e8087 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -56,6 +56,12 @@ (UNSPEC_IMPLVER 25) (UNSPEC_PERR 26) (UNSPEC_COPYSIGN 27) + + ;; Atomic operations + (UNSPEC_MB 28) + (UNSPEC_ATOMIC 31) + (UNSPEC_CMPXCHG 32) + (UNSPEC_XCHG 33) ]) ;; UNSPEC_VOLATILE: @@ -76,12 +82,8 @@ (UNSPECV_SET_TP 12) (UNSPECV_RPCC 13) (UNSPECV_SETJMPR_ER 14) ; builtin_setjmp_receiver fragment - (UNSPECV_MB 15) - (UNSPECV_LL 16) ; load-locked - (UNSPECV_SC 17) ; store-conditional - (UNSPECV_ATOMIC 18) - (UNSPECV_CMPXCHG 19) - (UNSPECV_XCHG 20) + (UNSPECV_LL 15) ; load-locked + (UNSPECV_SC 16) ; store-conditional ]) ;; Where necessary, the suffixes _le and _be are used to distinguish between diff --git a/gcc/config/alpha/sync.md b/gcc/config/alpha/sync.md index e913627e1515..1c34ce54b1c3 100644 --- a/gcc/config/alpha/sync.md +++ b/gcc/config/alpha/sync.md @@ -19,6 +19,7 @@ ;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. +(define_mode_macro I12MODE [QI HI]) (define_mode_macro I48MODE [SI DI]) (define_mode_attr modesuffix [(SI "l") (DI "q")]) @@ -34,7 +35,7 @@ (define_expand "memory_barrier" [(set (mem:BLK (match_dup 0)) - (unspec_volatile:BLK [(mem:BLK (match_dup 0))] UNSPECV_MB))] + (unspec:BLK [(mem:BLK (match_dup 0))] UNSPEC_MB))] "" { operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (DImode)); @@ -43,7 +44,7 @@ (define_insn "*mb_internal" [(set (match_operand:BLK 0 "" "") - (unspec_volatile:BLK [(match_operand:BLK 1 "" "")] UNSPECV_MB))] + (unspec:BLK [(match_operand:BLK 1 "" "")] UNSPEC_MB))] "" "mb" [(set_attr "type" "mb")]) @@ -75,10 +76,10 @@ (define_insn_and_split "sync_" [(set (match_operand:I48MODE 0 "memory_operand" "+m") - (unspec_volatile:I48MODE + (unspec:I48MODE [(FETCHOP:I48MODE (match_dup 0) (match_operand:I48MODE 1 "" ""))] - UNSPECV_ATOMIC)) + UNSPEC_ATOMIC)) (clobber (match_scratch:I48MODE 2 "=&r"))] "" "#" @@ -93,10 +94,10 @@ (define_insn_and_split "sync_nand" [(set (match_operand:I48MODE 0 "memory_operand" "+m") - (unspec_volatile:I48MODE + (unspec:I48MODE [(and:I48MODE (not:I48MODE (match_dup 0)) (match_operand:I48MODE 1 "register_operand" "r"))] - UNSPECV_ATOMIC)) + UNSPEC_ATOMIC)) (clobber (match_scratch:I48MODE 2 "=&r"))] "" "#" @@ -113,10 +114,10 @@ [(set (match_operand:I48MODE 0 "register_operand" "=&r") (match_operand:I48MODE 1 "memory_operand" "+m")) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(FETCHOP:I48MODE (match_dup 1) (match_operand:I48MODE 2 "" ""))] - UNSPECV_ATOMIC)) + UNSPEC_ATOMIC)) (clobber (match_scratch:I48MODE 3 "=&r"))] "" "#" @@ -133,10 +134,10 @@ [(set (match_operand:I48MODE 0 "register_operand" "=&r") (match_operand:I48MODE 1 "memory_operand" "+m")) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(and:I48MODE (not:I48MODE (match_dup 1)) (match_operand:I48MODE 2 "register_operand" "r"))] - UNSPECV_ATOMIC)) + UNSPEC_ATOMIC)) (clobber (match_scratch:I48MODE 3 "=&r"))] "" "#" @@ -155,9 +156,9 @@ (match_operand:I48MODE 1 "memory_operand" "+m") (match_operand:I48MODE 2 "" ""))) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(FETCHOP:I48MODE (match_dup 1) (match_dup 2))] - UNSPECV_ATOMIC)) + UNSPEC_ATOMIC)) (clobber (match_scratch:I48MODE 3 "=&r"))] "" "#" @@ -176,9 +177,9 @@ (not:I48MODE (match_operand:I48MODE 1 "memory_operand" "+m")) (match_operand:I48MODE 2 "register_operand" "r"))) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(and:I48MODE (not:I48MODE (match_dup 1)) (match_dup 2))] - UNSPECV_ATOMIC)) + UNSPEC_ATOMIC)) (clobber (match_scratch:I48MODE 3 "=&r"))] "" "#" @@ -191,15 +192,51 @@ } [(set_attr "type" "multi")]) +(define_expand "sync_compare_and_swap" + [(match_operand:I12MODE 0 "register_operand" "") + (match_operand:I12MODE 1 "memory_operand" "") + (match_operand:I12MODE 2 "register_operand" "") + (match_operand:I12MODE 3 "add_operand" "")] + "" +{ + alpha_expand_compare_and_swap_12 (operands[0], operands[1], + operands[2], operands[3]); + DONE; +}) + +(define_insn_and_split "sync_compare_and_swap_1" + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (zero_extend:DI + (mem:I12MODE (match_operand:DI 1 "register_operand" "r,r")))) + (set (mem:I12MODE (match_dup 1)) + (unspec:I12MODE + [(match_operand:DI 2 "reg_or_8bit_operand" "J,rI") + (match_operand:DI 3 "register_operand" "r,r") + (match_operand:DI 4 "register_operand" "r,r")] + UNSPEC_CMPXCHG)) + (clobber (match_scratch:DI 5 "=&r,&r")) + (clobber (match_scratch:DI 6 "=X,&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_compare_and_swap_12 (mode, operands[0], operands[1], + operands[2], operands[3], operands[4], + operands[5], operands[6]); + DONE; +} + [(set_attr "type" "multi")]) + (define_expand "sync_compare_and_swap" [(parallel [(set (match_operand:I48MODE 0 "register_operand" "") (match_operand:I48MODE 1 "memory_operand" "")) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(match_operand:I48MODE 2 "reg_or_8bit_operand" "") (match_operand:I48MODE 3 "add_operand" "rKL")] - UNSPECV_CMPXCHG)) + UNSPEC_CMPXCHG)) (clobber (match_scratch:I48MODE 4 "=&r"))])] "" { @@ -211,10 +248,10 @@ [(set (match_operand:I48MODE 0 "register_operand" "=&r") (match_operand:I48MODE 1 "memory_operand" "+m")) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(match_operand:DI 2 "reg_or_8bit_operand" "rI") (match_operand:I48MODE 3 "add_operand" "rKL")] - UNSPECV_CMPXCHG)) + UNSPEC_CMPXCHG)) (clobber (match_scratch:I48MODE 4 "=&r"))] "" "#" @@ -227,13 +264,44 @@ } [(set_attr "type" "multi")]) +(define_expand "sync_lock_test_and_set" + [(match_operand:I12MODE 0 "register_operand" "") + (match_operand:I12MODE 1 "memory_operand" "") + (match_operand:I12MODE 2 "register_operand" "")] + "" +{ + alpha_expand_lock_test_and_set_12 (operands[0], operands[1], operands[2]); + DONE; +}) + +(define_insn_and_split "sync_lock_test_and_set_1" + [(set (match_operand:DI 0 "register_operand" "=&r") + (zero_extend:DI + (mem:I12MODE (match_operand:DI 1 "register_operand" "r")))) + (set (mem:I12MODE (match_dup 1)) + (unspec:I12MODE + [(match_operand:DI 2 "reg_or_8bit_operand" "rI") + (match_operand:DI 3 "register_operand" "r")] + UNSPEC_XCHG)) + (clobber (match_scratch:DI 4 "=&r"))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + alpha_split_lock_test_and_set_12 (mode, operands[0], operands[1], + operands[2], operands[3], operands[4]); + DONE; +} + [(set_attr "type" "multi")]) + (define_insn_and_split "sync_lock_test_and_set" [(set (match_operand:I48MODE 0 "register_operand" "=&r") (match_operand:I48MODE 1 "memory_operand" "+m")) (set (match_dup 1) - (unspec_volatile:I48MODE + (unspec:I48MODE [(match_operand:I48MODE 2 "add_operand" "rKL")] - UNSPECV_XCHG)) + UNSPEC_XCHG)) (clobber (match_scratch:I48MODE 3 "=&r"))] "" "#" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7717a13dd19c..9a982a7fa8b4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-07-09 Richard Henderson + + * lib/target-supports.exp (check_effective_target_sync_char_short): + Add alpha. + 2005-07-09 Thomas Koenig PR libfortran/22217 diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 7605114a7223..14426ec82c34 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -1122,6 +1122,7 @@ proc check_effective_target_sync_char_short { } { if { [istarget ia64-*-*] || [istarget i?86-*-*] || [istarget x86_64-*-*] + || [istarget alpha*-*-*] || [istarget powerpc*-*-*] } { set et_sync_char_short_saved 1 }