From patchwork Fri Sep 27 18:15:11 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chung-Ju Wu X-Patchwork-Id: 278663 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 6E8112C00B9 for ; Sat, 28 Sep 2013 04:15:31 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:references :in-reply-to:content-type; q=dns; s=default; b=o99kK+PiRuhvgUwRd rH9MUb8b2+z6MHbJCXSIhtesb1QuupVKQ0i4O6sFWVE7Pa7M/FvJvD/Zu4gntPau GnIFL5/nZ6ADZygNd1VM/qbMRiOIc0Xe+IKrJeV+J8Dw3aeH4rWBIEXOiCVZCAfC qzbDK4iGVBykRs4oO/NrQtVlIA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:references :in-reply-to:content-type; s=default; bh=q46ufRDzMpUKKFw26C4wIn+ Aobw=; b=JvgodgpXCT238lU9+l1k9T7LCntCO/6emdLB0rC7kpCM5a42F0QbJQ2 lISuU53Wnr1vwY6uE+qfy29lBHykpDKNdbjonO8gx0LIQmi4iTXpKNjFntEs8VUy jnjXqRMVVBJ7Ws+wrTzQQOwUwnmFrMmE4UBsIDf42VgcF9MHjKZk= Received: (qmail 25983 invoked by alias); 27 Sep 2013 18:15:22 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 25972 invoked by uid 89); 27 Sep 2013 18:15:22 -0000 Received: from mail-pa0-f46.google.com (HELO mail-pa0-f46.google.com) (209.85.220.46) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 27 Sep 2013 18:15:22 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.2 required=5.0 tests=ALL_TRUSTED, AWL, BAYES_80, FREEMAIL_FROM autolearn=no version=3.3.2 X-HELO: mail-pa0-f46.google.com Received: by mail-pa0-f46.google.com with SMTP id fa1so3109889pad.19 for ; Fri, 27 Sep 2013 11:15:14 -0700 (PDT) X-Received: by 10.68.249.229 with SMTP id yx5mr9030508pbc.12.1380305714666; Fri, 27 Sep 2013 11:15:14 -0700 (PDT) Received: from Wu-Chung-Jude-MacBook-Air.local (123-194-206-10.dynamic.kbronet.com.tw. [123.194.206.10]) by mx.google.com with ESMTPSA id xn12sm14166528pac.12.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 27 Sep 2013 11:15:14 -0700 (PDT) Message-ID: <5245CB2F.1070604@gmail.com> Date: Sat, 28 Sep 2013 02:15:11 +0800 From: Chung-Ju Wu User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/20130801 Thunderbird/17.0.8 MIME-Version: 1.0 To: gcc-patches , rdsandiford@googlemail.com Subject: Re: [PATCH 2/6] Andes nds32: machine description of nds32 porting (3). References: <51EFF82C.5050501@gmail.com> <51F0F38C.2020802@gmail.com> <522CA277.2040806@gmail.com> <87ob7ujrxe.fsf@talisman.default> In-Reply-To: <87ob7ujrxe.fsf@talisman.default> X-IsSubscribed: yes On 9/15/13 6:33 PM, Richard Sandiford wrote: > Some comments about the final part: > Thank you so much. The followings are our revisions for final part. > Chung-Ju Wu writes: >> +(define_constraint "Ibms" >> + "The immediate value with power of 2" >> + (and (match_code "const_int") >> + (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M) >> + && (floor_log2 (ival) < 8) >> + && (ival > 0) >> + && (ival == (1 << floor_log2 (ival)))"))) > > I think the last three lines are equivalent to: > > IN_RANGE (exact_log2 (ival), 0, 7) > Modify it accordingly. >> +(define_constraint "Ifex" >> + "The immediate value with power of 2 minus 1" >> + (and (match_code "const_int") >> + (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M) >> + && (ival < 256) >> + && (ival > 0) >> + && (floor_log2 (ival + 1) - 1 < 8) >> + && ((ival + 1) == (1 << floor_log2 (ival + 1)))"))) > > And here: > > IN_RANGE (exact_log2 (ival + 1), 1, 8) > Modify it accordingly. >> +#ifndef nds32_OPTS_H >> +#define nds32_OPTS_H > > Very minor, but the mixture of case looks odd. > Fix it accordingly. >> +;; ------------------------------------------------------------- >> +;; Boolean DImode instructions. >> +;; ------------------------------------------------------------- >> + >> +;; Boolean and,ior,xor insns. >> + >> +;; 'and' operation. >> + >> +(define_expand "anddi3" >> + [(set (match_operand:DI 0 "register_operand" "") >> + (and:DI (match_operand:DI 1 "register_operand" "") >> + (match_operand:DI 2 "register_operand" "")))] >> + "" >> + "" >> +) >> + >> +; Use '#' to split instruction. >> +(define_insn "*anddi3_insn" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (and:DI (match_operand:DI 1 "register_operand" " %0, r") >> + (match_operand:DI 2 "register_operand" " r, r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> +; Use '#' to split instruction. >> +; The zero extend of operand 2 clears the high word of the output operand. >> +(define_insn_and_split "*anddi_zesidi_di" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (and:DI (zero_extend:DI (match_operand:SI 2 "register_operand" " r, r")) >> + (match_operand:DI 1 "register_operand" " 0, r")))] >> + "" >> + "#" >> + "reload_completed" >> + [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2))) >> + (set (match_dup 3) (const_int 0))] >> +{ >> + operands[3] = gen_highpart (SImode, operands[0]); >> + operands[0] = gen_lowpart (SImode, operands[0]); >> + operands[1] = gen_lowpart (SImode, operands[1]); >> +} >> + [(set_attr "length" "8")]) >> + >> +; Use '#' to split instruction. >> +(define_insn "*anddi_sesidi_di" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (and:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")) >> + (match_operand:DI 1 "register_operand" " 0, r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> + >> +;; 'ior' operation. >> + >> +(define_expand "iordi3" >> + [(set (match_operand:DI 0 "register_operand" "") >> + (ior:DI (match_operand:DI 1 "register_operand" "") >> + (match_operand:DI 2 "register_operand" "")))] >> + "" >> + "" >> +) >> + >> +; Use '#' to split instruction. >> +(define_insn "*iordi3_insn" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (ior:DI (match_operand:DI 1 "register_operand" " %0, r") >> + (match_operand:DI 2 "register_operand" " r, r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> +; Use '#' to split instruction. >> +(define_insn "*iordi_zesidi_di" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (ior:DI (zero_extend:DI (match_operand:SI 2 "register_operand" " r, r")) >> + (match_operand:DI 1 "register_operand" " 0, ?r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> +; Use '#' to split instruction. >> +(define_insn "*iordi_sesidi_di" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (ior:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")) >> + (match_operand:DI 1 "register_operand" " 0, r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> + >> +;; 'xor' operation. >> + >> +(define_expand "xordi3" >> + [(set (match_operand:DI 0 "register_operand" "") >> + (xor:DI (match_operand:DI 1 "register_operand" "") >> + (match_operand:DI 2 "register_operand" "")))] >> + "" >> + "" >> +) >> + >> +; Use '#' to split instruction. >> +(define_insn "*xordi3_insn" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (xor:DI (match_operand:DI 1 "register_operand" " %0, r") >> + (match_operand:DI 2 "register_operand" " r, r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> +; Use '#' to split instruction. >> +(define_insn "*xordi_zesidi_di" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (xor:DI (zero_extend:DI (match_operand:SI 2 "register_operand" " r, r")) >> + (match_operand:DI 1 "register_operand" " 0, ?r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> +; Use '#' to split instruction. >> +(define_insn "*xordi_sesidi_di" >> + [(set (match_operand:DI 0 "register_operand" "=&r, &r") >> + (xor:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")) >> + (match_operand:DI 1 "register_operand" " 0, r")))] >> + "" >> + "#" >> + [(set_attr "length" "8")]) >> + >> + >> +;; Split up double word logical operations. >> + >> +;; Split up simple DImode logical operations. Simply perform the logical >> +;; operation on the upper and lower halves of the registers. >> +(define_split >> + [(set (match_operand:DI 0 "register_operand" "") >> + (match_operator:DI 6 "nds32_logical_binary_operator" >> + [(match_operand:DI 1 "register_operand" "") >> + (match_operand:DI 2 "register_operand" "")]))] >> + "reload_completed" >> + [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)])) >> + (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))] >> +{ >> + /* Note that operands[0], operands[1], >> + and operands[2] will be assigned new rtx, >> + so be careful of the order when using them. */ >> + >> + operands[3] = gen_highpart (SImode, operands[0]); >> + operands[0] = gen_lowpart (SImode, operands[0]); >> + >> + operands[4] = gen_highpart (SImode, operands[1]); >> + operands[1] = gen_lowpart (SImode, operands[1]); >> + >> + operands[5] = gen_highpart (SImode, operands[2]); >> + operands[2] = gen_lowpart (SImode, operands[2]); >> +}) > > In the past it was good practice to define multiword operations like > these so that they could be seen as simple binary operations during > early rtl optimisation. That shouldn't be necessary now that we have > gimple-level optimisation though. Instead, splitting from the outset > allows the rtl passes to see and optimise the individual word operations. > > If you don't define the patterns, the generic code will split the > operation in the same way. You should then get the zero_extend > optimisation above for free. You should also get better code for > cases where operand 2 is constant. > > So in theory it should be better to remove these patterns. > These patterns are legacy code migrated from arm porting. Under some experiments and testing results, indeed it is better to remove these patterns in practice on current gcc trunk. Thanks for the explanation. I remove them as you suggested. >> +;; Interrupt Instructions. >> + >> +(define_insn "unspec_volatile_setgie_en" >> + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_EN)] >> + "" >> + "setgie.e" >> + [(set_attr "type" "misc")] >> +) >> + >> +(define_insn "unspec_volatile_setgie_dis" >> + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_DIS)] >> + "" >> + "setgie.d" >> + [(set_attr "type" "misc")] >> +) > > Ah, following up from my comment in part 1 about plain [(unspec ...)] > (as opposed to [(set ... (unspec ...))]) insns being dangerous: it looks > like the intrinsics are all unspec_volatile instead, which is good. > Maybe it'd be worth changing the .c comment to say unspec_volatile instead. > Modify it accordingly in nds32.c file. >> +;; Load Multiple Insns. >> +;; >> +;; opernads[0] is the first of the consecutive registers. > > Typo: operands > Fix it accordingly. >> +misr-vector-size= >> +Target Report RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE) >> +Specify the size of each vector for interrupt handler. The valid value is 4 or 16. > > Maybe: > > Specify the size of each interrupt vector, which must be 4 or 16. > Modify it accordingly. >> +mcache-block-size= >> +Target Report RejectNegative Joined UInteger Var(nds32_cache_block_size) Init(NDS32_DEFAULT_CACHE_BLOCK_SIZE) >> +Specify the size of each cache block. The size is the power of 2 in bytes. The valid value is: 4, 8, 16, 32, 64, 128, 256, or 512. > > And here: > > Specify the size of each cache block, which must be a power of 2 between 4 and 512. > Modify it accordingly. >> +march= >> +Target RejectNegative Joined Enum(nds32_arch_type) Var(nds32_arch_option) Init(ARCH_V3) >> +Specify the name of the target architecture. The valid value is: v2, v3, or v3m. > > "The valid value..." part shouldn't be needed, since the general options > machinery will print out the enum values. > Modify it accordingly. >> +mforce-fp-as-gp >> +Target Report RejectNegative Mask(FORCE_FP_AS_GP) >> +Prevent $fp being allocated during register allocation so that compiler is able to force using $fp to access static and global variables for code-size reduction. Then compiler will use special directives and code generation to guide linker doing fp-as-gp optimization (NOTE: This is link time optimization so make sure you pass '--relax' option to linker at linking stage). > > This seems a bit long for help text. Also, it might be better to drop > the RejectNegative, so that "-mforce-fp-as-gp -mno-force-fp-as-gp" works. > (This is sometimes useful when dealing with badly-written makefiles.) > Thanks for the suggestion. Modify it accordingly. >> +mex9 >> +Target Report RejectNegative Mask(EX9) >> +Use special directives to guide linker doing ex9 optimization (NOTE: This is link time optimization so make sure you pass '--relax' and '--mex9' option to linker at linking stage). > > The driver ought to pass down -mex9 as --mex9 instead, via LINK_SPEC, > so that the user doesn't have to. Maybe it should pass down --relax too, > if that makes sense. I.e. something like: > > %{mex9: --mex9} > > or (if there are no drawbacks to making -mex9 imply --relax): > > %{mex9: --relax --mex9} > In the revised patch we add a new option -mrelax. Also, --relax should be passed to linker if -mforce-fp-as-gp is used. So we modify LINK_SPEC like this: #define LINK_SPEC \ " %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ " %{mrelax|mforce-fp-as-gp|mex9:--relax}" \ " %{mex9:--mex9}" >> +mno-ctor-dtor >> +Target Report RejectNegative >> +Disable constructor/destructor feature. > > How is this option used? > It effects how we link crt stuff. Refer to nds32.h: /* The option -mno-ctor-dtor can disable constructor/destructor feature by applying different crt stuff. In the convention, crt0.o is the startup file without constructor/destructor; crt1.o, crti.o, crtbegin.o, crtend.o, and crtn.o are the startup files with constructor/destructor. Note that crt0.o, crt1.o, crti.o, and crtn.o are provided by newlib/mculib/glibc/ublic, while crtbegin.o and crtend.o are currently provided by GCC for nds32 target. For nds32 target so far: If -mno-ctor-dtor, we are going to link "crt0.o [user objects]". If general cases, we are going to link "crt1.o crtbegin1.o [user objects] crtend1.o". */ #define STARTFILE_SPEC \ " %{!mno-ctor-dtor:crt1.o%s;:crt0.o%s}" \ " %{!mno-ctor-dtor:crtbegin1.o%s}" #define ENDFILE_SPEC \ " %{!mno-ctor-dtor:crtend1.o%s}" >> +;; Merge single move to sign_extend load. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (match_operand:SI 1 "register_operand" "")) >> + (set (match_operand:SI 2 "register_operand" "") >> + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand")))))] >> + "peep2_reg_dead_p (2, operands[0])" >> + [(set (match_dup 2) >> + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3)))))] >> +) >> + >> +;; Merge single move to zero_extend load. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (match_operand:SI 1 "register_operand" "")) >> + (set (match_operand:SI 2 "register_operand" "") >> + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand")))))] >> + "peep2_reg_dead_p (2, operands[0])" >> + [(set (match_dup 2) >> + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3)))))] >> +) >> + >> +;; Merge single move to load. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (match_operand:SI 1 "register_operand" "")) >> + (set (match_operand:QIHISI 2 "register_operand" "") >> + (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand"))))] >> + "peep2_reg_dead_p (2, operands[0])" >> + [(set (match_dup 2) >> + (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3))))] >> +) >> + >> +;; Merge single move to store. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (match_operand:SI 1 "register_operand" "")) >> + (set (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand"))) >> + (match_operand:QIHISI 2 "register_operand" ""))] >> + "peep2_reg_dead_p (2, operands[0])" >> + [(set (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3))) >> + (match_dup 2))] >> +) > > It looks like these peepholes are working around the fact that the move, > sign_extend and zero_extend alternatives are split across several patterns. > Hopefully they won't be needed if each operation has a single define_insn > that lists all the alternatives. > Yes. With your previous comments of using single define_insn for each operation. These peepholes can be removed. Thanks so much. >> +;; Merge single addi to sign_extend load. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (plus:SI (match_operand:SI 1 "register_operand" "") >> + (match_operand:SI 4 "immediate_operand" ""))) >> + (set (match_operand:SI 2 "register_operand" "") >> + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand")))))] >> + "peep2_reg_dead_p (2, operands[0]) >> + && CONST_INT_P (operands[4]) >> + && CONST_INT_P (operands[3]) >> + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) >> + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" >> + [(set (match_dup 2) >> + (sign_extend:SI (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3)))))] >> +{ >> + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), >> + SImode); >> +}) >> + >> +;; Merge single addi to zero_extend load. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (plus:SI (match_operand:SI 1 "register_operand" "") >> + (match_operand:SI 4 "immediate_operand" ""))) >> + (set (match_operand:SI 2 "register_operand" "") >> + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand")))))] >> + "peep2_reg_dead_p (2, operands[0]) >> + && CONST_INT_P (operands[4]) >> + && CONST_INT_P (operands[3]) >> + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) >> + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" >> + [(set (match_dup 2) >> + (zero_extend:SI (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3)))))] >> +{ >> + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), >> + SImode); >> +}) >> + >> +;; Merge single addi to load. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (plus:SI (match_operand:SI 1 "register_operand" "") >> + (match_operand:SI 4 "immediate_operand" ""))) >> + (set (match_operand:QIHISI 2 "register_operand" "") >> + (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand"))))] >> + "peep2_reg_dead_p (2, operands[0]) >> + && CONST_INT_P (operands[4]) >> + && CONST_INT_P (operands[3]) >> + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) >> + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" >> + [(set (match_dup 2) >> + (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3))))] >> +{ >> + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), >> + SImode); >> +}) >> + >> +;; Merge single addi to store. >> +(define_peephole2 >> + [(set (match_operand:SI 0 "register_operand" "") >> + (plus:SI (match_operand:SI 1 "register_operand" "") >> + (match_operand:SI 4 "immediate_operand" ""))) >> + (set (mem:QIHISI (plus:SI (match_dup 0) >> + (match_operand:SI 3 "immediate_operand"))) >> + (match_operand:QIHISI 2 "register_operand" ""))] >> + "peep2_reg_dead_p (2, operands[0]) >> + && CONST_INT_P (operands[4]) >> + && CONST_INT_P (operands[3]) >> + && ((INTVAL (operands[3]) + INTVAL (operands[4])) % == 0) >> + && satisfies_constraint_Is15 (GEN_INT (trunc_int_for_mode (INTVAL (operands[3]) + INTVAL (operands[4]), SImode)))" >> + [(set (mem:QIHISI (plus:SI (match_dup 1) >> + (match_dup 3))) >> + (match_dup 2))] >> +{ >> + operands[3] = gen_int_mode (INTVAL(operands[3]) + INTVAL(operands[4]), >> + SImode); >> +}) > > TBH I'm suprised these are necessary. They seem to be doing a simple > forward-propagation of the addition, which is something that the post-reload > optimisers ought to be able to do already. Could you double-check whether > these still trigger? It'd be interesting to know why if so. > These are legacy implementation of define_peephole2 patterns. It is now difficult to reproduce the bad cases that they intended to solve. So I decide to remove these patterns. >> +;; Reg, subreg(reg) or const_int. >> +(define_predicate "nds32_reg_or_int_operand" >> + (ior (match_operand 0 "immediate_operand") >> + (match_operand 0 "register_operand")) >> +{ >> + if (GET_CODE (op) == SUBREG) >> + op = SUBREG_REG (op); >> + >> + if (REG_P (op)) >> + return true; >> + >> + if (GET_CODE (op) == CONST_INT) >> + return true; >> + return false; >> +}) >> + >> +(define_predicate "nds32_nonmemory_nonsymbol_operand" >> + (match_operand 0 "nonmemory_operand") >> +{ >> + switch (GET_CODE (op)) >> + { >> + case SYMBOL_REF: >> + case LABEL_REF: >> + case CONST: >> + return false; >> + default: >> + return true; >> + } >> +}) > > Following up from my other comment yesterday, I'm not sure about the > difference between these two. Is there something that one of the > predicates is trying to reject but the other isn't? I suppose > "nds32_nonmemory_nonsymbol_operand" could be used in a floating-point > context to allow floating-point constants, but its only use was with SImode. > > You also have: > > (define_predicate "nds32_reg_constant_operand" > (ior (match_operand 0 "register_operand") > (match_operand 0 "const_int_operand"))) > > which looks like the natural definition of "nds32_reg_or_int_operand". > Would it be possible to just keep that predicate (with whichever name > seems best) and remove the two quoted above? > Sorry to make you confused. It is caused by that I didn't properly merge predicate functions from different engineers. It is definitely better to just keep nds32_reg_constant_operand predicate. >> +(define_predicate "nds32_rimm15s_operand" >> + (match_operand 0 "general_operand") >> +{ >> + if (GET_CODE (op) == SUBREG) >> + op = SUBREG_REG (op); >> + if (GET_CODE (op) == REG) >> + return true; >> + if (GET_CODE (op) != CONST_INT) >> + return false; >> + >> + return satisfies_constraint_Is15 (op); >> +}) > > Maybe: > > (ior (match_operand 0 "register_operand") > (and (match_operand 0 "const_int_operand") > (match_test "satisfies_constraint_Is15 (op)"))) > > In general, defining predicates in terms of other predicates should > lead to better insn-recog.c code (although I'm sure there are exceptions). > Thanks for the suggestion. Modify it accordingly. >> +(define_predicate "nds32_imm5u_operand" >> + (match_operand 0 "immediate_operand") >> +{ >> + return satisfies_constraint_Iu05 (op); >> +}) > > Using const_int_operand would be tighter than immediate_operand. > Modify it accordingly. >> +(define_special_predicate "nds32_load_multiple_operation" >> + (match_code "parallel") >> +{ >> + HOST_WIDE_INT count; >> + int dest_regno; >> + rtx src_addr; >> + >> + int i; >> + rtx elt; >> + >> + /* Get the counts of elements in the parallel rtx. */ >> + count = XVECLEN (op, 0); >> + >> + /* Pick up the first element. */ >> + elt = XVECEXP (op, 0, 0); >> + >> + /* Perform some quick check for the first element in the parallel rtx. */ >> + if (GET_CODE (elt) != SET >> + || count <= 1 >> + || count > 8 >> + || GET_CODE (SET_DEST (elt)) != REG >> + || GET_CODE (SET_SRC (elt)) != MEM) >> + return false; >> + >> + dest_regno = REGNO (SET_DEST (elt)); >> + src_addr = XEXP (SET_SRC (elt), 0); >> + >> + /* Perform detail check for each element. */ >> + for (i = 0; i < count; i++) >> + { >> + elt = XVECEXP (op, 0, i); >> + >> + /* Refer to nds32.multiple.md for more information >> + about following checking. */ >> + if (GET_CODE (elt) != SET >> + || GET_CODE (SET_DEST (elt)) != REG >> + || GET_MODE (SET_DEST (elt)) != SImode >> + || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i) >> + || GET_CODE (SET_SRC (elt)) != MEM >> + || GET_MODE (SET_SRC (elt)) != SImode >> + || (GET_CODE (src_addr) != REG && GET_CODE (src_addr) != PLUS)) >> + return false; >> + } >> + >> + return true; >> +}) >> + >> +(define_special_predicate "nds32_store_multiple_operation" >> + (match_code "parallel") >> +{ >> + HOST_WIDE_INT count; >> + int src_regno; >> + rtx dest_addr; >> + >> + int i; >> + rtx elt; >> + >> + /* Get the counts of elements in the parallel rtx. */ >> + count = XVECLEN (op, 0); >> + >> + /* Pick up the first element. */ >> + elt = XVECEXP (op, 0, 0); >> + >> + /* Perform some quick check for the first element in the parallel rtx. */ >> + if (GET_CODE (elt) != SET >> + || count <= 1 >> + || count > 8 >> + || GET_CODE (SET_SRC (elt)) != REG >> + || GET_CODE (SET_DEST (elt)) != MEM) >> + return false; >> + >> + src_regno = REGNO (SET_SRC (elt)); >> + dest_addr = XEXP (SET_DEST (elt), 0); >> + >> + /* Perform detail check for each element. */ >> + for (i = 0; i < count; i++) >> + { >> + elt = XVECEXP (op, 0, i); >> + >> + /* Refer to nds32.multiple.md for more information >> + about following checking. */ >> + if (GET_CODE (elt) != SET >> + || GET_CODE (SET_SRC (elt)) != REG >> + || GET_MODE (SET_SRC (elt)) != SImode >> + || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i) >> + || GET_CODE (SET_DEST (elt)) != MEM >> + || GET_MODE (SET_DEST (elt)) != SImode >> + || (GET_CODE (dest_addr) != REG && GET_CODE (dest_addr) != PLUS)) >> + return false; >> + } >> + >> + return true; >> +}) > > These are basically the same, but with SET_SRC and SET_DEST swapped. > It'd be good to have a single nds32.c function that handles both, > with a parameter to choose between loads and stores. > Thanks for the comment. I define a new extern function nds32_valid_multiple_load_store() for these two predicates. > Those are all the comments I had. Like I say, it seems very clean overall. > > Thanks, > Richard > A revised patch for other md files is attached. I would like to thank you again for your review. It makes our nds32 port implementation much cleaner and better. We will keep refining our nds32 initial patch whenever others give us comments. Hopefully this nds32 port can be approved soon so that we can commit it into trunk and other developers are able to get this port easily. :) Best regards, jasonwucj diff --git gcc/config/nds32/constants.md gcc/config/nds32/constants.md new file mode 100644 index 0000000..af51117 --- /dev/null +++ gcc/config/nds32/constants.md @@ -0,0 +1,55 @@ +;; Constant defintions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + + +;; Register numbers. +(define_constants + [(R8_REGNUM 8) + (TA_REGNUM 15) + (FP_REGNUM 28) + (GP_REGNUM 29) + (LP_REGNUM 30) + (SP_REGNUM 31) + ]) + + +;; The unpec operation index. +(define_c_enum "unspec_element" [ + UNSPEC_STACK_PUSH_MULTIPLE + UNSPEC_STACK_POP_MULTIPLE + UNSPEC_STACK_V3PUSH + UNSPEC_STACK_V3POP + UNSPEC_FUNC_RETURN +]) + + +;; The unspec_volatile operation index. +(define_c_enum "unspec_volatile_element" [ + UNSPEC_VOLATILE_ISYNC + UNSPEC_VOLATILE_ISB + UNSPEC_VOLATILE_MFSR + UNSPEC_VOLATILE_MFUSR + UNSPEC_VOLATILE_MTSR + UNSPEC_VOLATILE_MTUSR + UNSPEC_VOLATILE_SETGIE_EN + UNSPEC_VOLATILE_SETGIE_DIS +]) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/constraints.md gcc/config/nds32/constraints.md new file mode 100644 index 0000000..4b9db23 --- /dev/null +++ gcc/config/nds32/constraints.md @@ -0,0 +1,260 @@ +;; Constraint definitions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; Check 16.8.7 Defining Machine-Specific Constraints for detail. + +;; NO contrains can be prefixed with: E F V X g i m n o p r s +;; Machine-dependent integer: I J K L M N O P +;; Machine-dependent floating: G H + + +(define_register_constraint "w" "(TARGET_ISA_V3 || TARGET_ISA_V3M) ? LOW_REGS : NO_REGS" + "LOW register class $r0 ~ $r7 constraint for V3/V3M ISA") + +(define_register_constraint "l" "LOW_REGS" + "LOW register class $r0 ~ $r7") + +(define_register_constraint "d" "MIDDLE_REGS" + "MIDDLE register class $r0 ~ $r11, $r16 ~ $r19") + +(define_register_constraint "h" "HIGH_REGS" + "HIGH register class $r12 ~ $r14, $r20 ~ $r31") + + +(define_register_constraint "t" "R15_TA_REG" + "Temporary Assist register $ta (i.e. $r15)") + +(define_register_constraint "k" "STACK_REG" + "Stack register $sp") + + +(define_constraint "Iu03" + "Unsigned immediate 3-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 3) && ival >= 0"))) + +(define_constraint "In03" + "Negative immediate 3-bit value in the range of -7 to 0" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, -7, 0)"))) + +(define_constraint "Iu04" + "Unsigned immediate 4-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 4) && ival >= 0"))) + +(define_constraint "Is05" + "Signed immediate 5-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 4) && ival >= -(1 << 4)"))) + +(define_constraint "Iu05" + "Unsigned immediate 5-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 5) && ival >= 0"))) + +(define_constraint "In05" + "Negative immediate 5-bit value in the range of -31 to 0" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, -31, 0)"))) + +;; Ip05 is special and dedicated for v3 movpi45 instruction. +;; movpi45 has imm5u field but the range is 16 ~ 47. +(define_constraint "Ip05" + "Unsigned immediate 5-bit value for movpi45 instruction with range 16-47" + (and (match_code "const_int") + (match_test "ival < ((1 << 5) + 16) + && ival >= (0 + 16) + && (TARGET_ISA_V3 || TARGET_ISA_V3M)"))) + +(define_constraint "Iu06" + "Unsigned immediate 6-bit value constraint for addri36.sp instruction" + (and (match_code "const_int") + (match_test "ival < (1 << 6) + && ival >= 0 + && (ival % 4 == 0) + && (TARGET_ISA_V3 || TARGET_ISA_V3M)"))) + +(define_constraint "Iu08" + "Unsigned immediate 8-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 8) && ival >= 0"))) + +(define_constraint "Iu09" + "Unsigned immediate 9-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 9) && ival >= 0"))) + + +(define_constraint "Is10" + "Signed immediate 10-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 9) && ival >= -(1 << 9)"))) + +(define_constraint "Is11" + "Signed immediate 11-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 10) && ival >= -(1 << 10)"))) + + +(define_constraint "Is15" + "Signed immediate 15-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 14) && ival >= -(1 << 14)"))) + +(define_constraint "Iu15" + "Unsigned immediate 15-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 15) && ival >= 0"))) + + +;; Ic15 is special and dedicated for performance extension +;; 'bclr' (single-bit-clear) instruction. +;; It is used in andsi3 pattern and recognized for the immediate +;; which is NOT in the range of imm15u but OK for 'bclr' instruction. +;; (If the immediate value IS in the range of imm15u, +;; we can directly use 'andi' instruction.) +(define_constraint "Ic15" + "A constant which is not in the range of imm15u but ok for bclr instruction" + (and (match_code "const_int") + (match_test "(ival & 0xffff8000) && nds32_can_use_bclr_p (ival)"))) + +;; Ie15 is special and dedicated for performance extension +;; 'bset' (single-bit-set) instruction. +;; It is used in iorsi3 pattern and recognized for the immediate +;; which is NOT in the range of imm15u but OK for 'bset' instruction. +;; (If the immediate value IS in the range of imm15u, +;; we can directly use 'ori' instruction.) +(define_constraint "Ie15" + "A constant which is not in the range of imm15u but ok for bset instruction" + (and (match_code "const_int") + (match_test "(ival & 0xffff8000) && nds32_can_use_bset_p (ival)"))) + +;; It15 is special and dedicated for performance extension +;; 'btgl' (single-bit-toggle) instruction. +;; It is used in xorsi3 pattern and recognized for the immediate +;; which is NOT in the range of imm15u but OK for 'btgl' instruction. +;; (If the immediate value IS in the range of imm15u, +;; we can directly use 'xori' instruction.) +(define_constraint "It15" + "A constant which is not in the range of imm15u but ok for btgl instruction" + (and (match_code "const_int") + (match_test "(ival & 0xffff8000) && nds32_can_use_btgl_p (ival)"))) + + +;; Ii15 is special and dedicated for v3 isa +;; 'bitci' (bit-clear-immediate) instruction. +;; It is used in andsi3 pattern and recognized for the immediate whose +;; (~ival) value is in the range of imm15u and OK for 'bitci' instruction. +;; For example, 'andi $r0,$r0,0xfffffffc' can be presented +; with 'bitci $r0,$r0,3'. +(define_constraint "Ii15" + "A constant whose compliment value is in the range of imm15u + and ok for bitci instruction" + (and (match_code "const_int") + (match_test "nds32_can_use_bitci_p (ival)"))) + + +(define_constraint "Is16" + "Signed immediate 16-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 15) && ival >= -(1 << 15)"))) + +(define_constraint "Is17" + "Signed immediate 17-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 16) && ival >= -(1 << 16)"))) + + +(define_constraint "Is19" + "Signed immediate 19-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 18) && ival >= -(1 << 18)"))) + + +(define_constraint "Is20" + "Signed immediate 20-bit value" + (and (match_code "const_int") + (match_test "ival < (1 << 19) && ival >= -(1 << 19)"))) + + +(define_constraint "Ispl" + "The immediate value that need to be split" + (and (match_code "const_int") + (match_test "(ival & 0xfff) != 0"))) + +(define_constraint "Ihig" + "The immediate value that can be simply set high 20-bit" + (and (match_code "const_int") + (match_test "(ival != 0) && ((ival & 0xfff) == 0)"))) + + +(define_constraint "Izeb" + "The immediate value 0xff" + (and (match_code "const_int") + (match_test "(ival == 0xff)"))) + +(define_constraint "Izeh" + "The immediate value 0xffff" + (and (match_code "const_int") + (match_test "(ival == 0xffff)"))) + +(define_constraint "Ixls" + "The immediate value 0x01" + (and (match_code "const_int") + (match_test "TARGET_PERF_EXT && (ival == 0x1)"))) + +(define_constraint "Ix11" + "The immediate value 0x7ff" + (and (match_code "const_int") + (match_test "TARGET_PERF_EXT && (ival == 0x7ff)"))) + +(define_constraint "Ibms" + "The immediate value with power of 2" + (and (match_code "const_int") + (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M) + && (IN_RANGE (exact_log2 (ival), 0, 7))"))) + +(define_constraint "Ifex" + "The immediate value with power of 2 minus 1" + (and (match_code "const_int") + (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M) + && (IN_RANGE (exact_log2 (ival + 1), 1, 8))"))) + + +(define_memory_constraint "U33" + "Memory constraint for 333 format" + (and (match_code "mem") + (match_test "nds32_mem_format (op) == ADDRESS_LO_REG_IMM3U"))) + +(define_memory_constraint "U45" + "Memory constraint for 45 format" + (and (match_code "mem") + (match_test "(nds32_mem_format (op) == ADDRESS_REG) + && (GET_MODE (op) == SImode)"))) + +(define_memory_constraint "U37" + "Memory constraint for 37 format" + (and (match_code "mem") + (match_test "(nds32_mem_format (op) == ADDRESS_SP_IMM7U + || nds32_mem_format (op) == ADDRESS_FP_IMM7U) + && (GET_MODE (op) == SImode)"))) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/iterators.md gcc/config/nds32/iterators.md new file mode 100644 index 0000000..6ec5196 --- /dev/null +++ gcc/config/nds32/iterators.md @@ -0,0 +1,55 @@ +;; Code and mode itertator and attribute definitions +;; of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;---------------------------------------------------------------------------- +;; Mode iterators. +;;---------------------------------------------------------------------------- + +;; A list of integer modes that are up to one word long. +(define_mode_iterator QIHISI [QI HI SI]) + +;; A list of integer modes that are up to one half-word long. +(define_mode_iterator QIHI [QI HI]) + +;; A list of the modes that are up to double-word long. +(define_mode_iterator DIDF [DI DF]) + + +;;---------------------------------------------------------------------------- +;; Mode attributes. +;;---------------------------------------------------------------------------- + +(define_mode_attr size [(QI "b") (HI "h") (SI "w")]) + +(define_mode_attr byte [(QI "1") (HI "2") (SI "4")]) + + +;;---------------------------------------------------------------------------- +;; Code iterators. +;;---------------------------------------------------------------------------- + + +;;---------------------------------------------------------------------------- +;; Code attributes. +;;---------------------------------------------------------------------------- + + +;;---------------------------------------------------------------------------- diff --git gcc/config/nds32/nds32-doubleword.md gcc/config/nds32/nds32-doubleword.md new file mode 100644 index 0000000..d02c042 --- /dev/null +++ gcc/config/nds32/nds32-doubleword.md @@ -0,0 +1,245 @@ +;; DImode/DFmode patterns description of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + + +;; ------------------------------------------------------------- +;; Move DImode/DFmode instructions. +;; ------------------------------------------------------------- + + +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" +{ + /* Need to force register if mem <- !reg. */ + if (GET_CODE (operands[0]) == MEM && !REG_P (operands[1])) + operands[1] = force_reg (DImode, operands[1]); +}) + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" +{ + /* Need to force register if mem <- !reg. */ + if (GET_CODE (operands[0]) == MEM && !REG_P (operands[1])) + operands[1] = force_reg (DFmode, operands[1]); +}) + + +(define_insn "move_" + [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, m") + (match_operand:DIDF 1 "general_operand" " r, i, m, r"))] + "" +{ + rtx addr; + rtx otherops[5]; + + switch (which_alternative) + { + case 0: + return "movd44\t%0, %1"; + + case 1: + /* reg <- const_int, we ask gcc to split instruction. */ + return "#"; + + case 2: + /* Refer to nds32_legitimate_address_p() in nds32.c, + we only allow "reg", "symbol_ref", "const", and "reg + const_int" + as address rtx for DImode/DFmode memory access. */ + addr = XEXP (operands[1], 0); + + otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + otherops[2] = addr; + + if (REG_P (addr)) + { + /* (reg) <- (mem (reg)) */ + output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops); + } + else if (GET_CODE (addr) == PLUS) + { + /* (reg) <- (mem (plus (reg) (const_int))) */ + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (REG_P (op0)) + { + otherops[2] = op0; + otherops[3] = op1; + otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode); + } + else + { + otherops[2] = op1; + otherops[3] = op0; + otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode); + } + + /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */ + if (REGNO (otherops[0]) != REGNO (otherops[2])) + { + output_asm_insn ("lwi\t%0, [%2 + (%3)]", otherops); + output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops); + } + else + { + output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops); + output_asm_insn ("lwi\t%0,[ %2 + (%3)]", otherops); + } + } + else + { + /* (reg) <- (mem (symbol_ref ...)) + (reg) <- (mem (const ...)) */ + output_asm_insn ("lwi.gp\t%0, [ + %2]", otherops); + output_asm_insn ("lwi.gp\t%1, [ + %2 + 4]", otherops); + } + + /* We have already used output_asm_insn() by ourself, + so return an empty string. */ + return ""; + + case 3: + /* Refer to nds32_legitimate_address_p() in nds32.c, + we only allow "reg", "symbol_ref", "const", and "reg + const_int" + as address rtx for DImode/DFmode memory access. */ + addr = XEXP (operands[0], 0); + + otherops[0] = gen_rtx_REG (SImode, REGNO (operands[1])); + otherops[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + otherops[2] = addr; + + if (REG_P (addr)) + { + /* (mem (reg)) <- (reg) */ + output_asm_insn ("smw.bi\t%0, [%2], %1, 0", otherops); + } + else if (GET_CODE (addr) == PLUS) + { + /* (mem (plus (reg) (const_int))) <- (reg) */ + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (REG_P (op0)) + { + otherops[2] = op0; + otherops[3] = op1; + otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode); + } + else + { + otherops[2] = op1; + otherops[3] = op0; + otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode); + } + + /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */ + if (REGNO (otherops[0]) != REGNO (otherops[2])) + { + output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops); + output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops); + } + else + { + output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops); + output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops); + } + } + else + { + /* (mem (symbol_ref ...)) <- (reg) + (mem (const ...)) <- (reg) */ + output_asm_insn ("swi.gp\t%0, [ + %2]", otherops); + output_asm_insn ("swi.gp\t%1, [ + %2 + 4]", otherops); + } + + /* We have already used output_asm_insn() by ourself, + so return an empty string. */ + return ""; + + default: + gcc_unreachable (); + } +} + [(set_attr "type" "move,move,move,move") + (set_attr "length" " 4, 16, 8, 8")]) + +(define_split + [(set (match_operand:DIDF 0 "register_operand" "") + (match_operand:DIDF 1 "const_double_operand" ""))] + "reload_completed" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] +{ + /* Construct lowpart rtx. */ + operands[2] = gen_lowpart (SImode, operands[0]); + operands[3] = gen_lowpart (SImode, operands[1]); + + /* Construct highpart rtx. */ + /* Note that operands[1] can be VOIDmode constant, + so we need to use gen_highpart_mode(). + Refer to gcc/emit-rtl.c for more information. */ + operands[4] = gen_highpart (SImode, operands[0]); + operands[5] = gen_highpart_mode (SImode, + GET_MODE (operands[0]), operands[1]); +}) + +;; There is 'movd44' instruction for DImode/DFmode movement under V3/V3M ISA. +;; We only need to split it under V2 ISA or none-16-bit code generation. +(define_split + [(set (match_operand:DIDF 0 "register_operand" "") + (match_operand:DIDF 1 "register_operand" ""))] + "reload_completed + && (TARGET_ISA_V2 || !TARGET_16_BIT)" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] +{ + operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = gen_highpart (SImode, operands[1]); + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + + /* Handle a partial overlap. */ + if (rtx_equal_p (operands[0], operands[3])) + { + rtx tmp0 = operands[0]; + rtx tmp1 = operands[1]; + + operands[0] = operands[2]; + operands[1] = operands[3]; + operands[2] = tmp0; + operands[3] = tmp1; + } +}) + +;; ------------------------------------------------------------- +;; Boolean DImode instructions. +;; ------------------------------------------------------------- + +;; Nowadays, the generic code is supposed to split the DImode +;; boolean operations and have good code generation. +;; Unless we find out some bad cases, there is no need to +;; define DImode boolean operations by ourself. + +;; ------------------------------------------------------------- diff --git gcc/config/nds32/nds32-intrinsic.md gcc/config/nds32/nds32-intrinsic.md new file mode 100644 index 0000000..4ee2d85 --- /dev/null +++ gcc/config/nds32/nds32-intrinsic.md @@ -0,0 +1,97 @@ +;; Intrinsic patterns description of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; ------------------------------------------------------------------------ + +;; Register Transfer. + +(define_insn "unspec_volatile_mfsr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MFSR))] + "" + "mfsr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +(define_insn "unspec_volatile_mfusr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MFUSR))] + "" + "mfusr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +(define_insn "unspec_volatile_mtsr" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTSR)] + "" + "mtsr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +(define_insn "unspec_volatile_mtusr" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTUSR)] + "" + "mtusr\t%0, %V1" + [(set_attr "type" "misc") + (set_attr "length" "4")] +) + +;; ------------------------------------------------------------------------ + +;; Interrupt Instructions. + +(define_insn "unspec_volatile_setgie_en" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_EN)] + "" + "setgie.e" + [(set_attr "type" "misc")] +) + +(define_insn "unspec_volatile_setgie_dis" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETGIE_DIS)] + "" + "setgie.d" + [(set_attr "type" "misc")] +) + +;; ------------------------------------------------------------------------ + +;; Cache Synchronization Instructions + +(define_insn "unspec_volatile_isync" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_ISYNC)] + "" + "isync\t%0" + [(set_attr "type" "misc")] +) + +(define_insn "unspec_volatile_isb" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_ISB)] + "" + "isb" + [(set_attr "type" "misc")] +) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/nds32-modes.def gcc/config/nds32/nds32-modes.def new file mode 100644 index 0000000..9d32ada --- /dev/null +++ gcc/config/nds32/nds32-modes.def @@ -0,0 +1,21 @@ +/* Extra machine modes of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +/* So far, there is no need to define any modes for nds32 target. */ diff --git gcc/config/nds32/nds32-multiple.md gcc/config/nds32/nds32-multiple.md new file mode 100644 index 0000000..da89a49 --- /dev/null +++ gcc/config/nds32/nds32-multiple.md @@ -0,0 +1,410 @@ +;; Load/Store Multiple patterns description of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation.for NDS32. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + + +;; Load Multiple Insns. +;; +;; operands[0] is the first of the consecutive registers. +;; operands[1] is the first memory location. +;; operands[2] is the number of consecutive registers. + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" +{ + int maximum; + + /* Because reduced-set regsiters has few registers + (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot + be used for register allocation), + using 8 registers for load_multiple may easily consume all of them. + It makes register allocation/spilling hard to work. + So we only allow maximum=4 registers for load_multiple + under reduced-set registers. */ + if (TARGET_REDUCED_REGS) + maximum = 4; + else + maximum = 8; + + /* Here are the conditions that must be all passed, + otherwise we have to FAIL this rtx generation: + 1. The number of consecutive registers must be integer. + 2. Maximum 4 or 8 registers for lmw.bi instruction + (based on this nds32-multiple.md design). + 3. Minimum 2 registers for lmw.bi instruction + (based on this nds32-multiple.md design). + 4. operands[0] must be register for sure. + 5. operands[1] must be memory for sure. + 6. Do not cross $r15 register because it is not allocatable. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > maximum + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != REG + || GET_CODE (operands[1]) != MEM + || REGNO (operands[0]) + INTVAL (operands[2]) > TA_REGNUM) + FAIL; + + /* For (mem addr), we force_reg on addr here, + so that nds32_expand_load_multiple can easily use it. */ + operands[3] = nds32_expand_load_multiple (REGNO (operands[0]), + INTVAL (operands[2]), + force_reg (SImode, + XEXP (operands[1], 0)), + operands[1]); +}) + +;; Ordinary Load Multiple. + +(define_insn "*lmwsi8" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28))))])] + "(XVECLEN (operands[0], 0) == 8)" + "lmw.bi\t%2, [%1], %9, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi7" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24))))])] + "(XVECLEN (operands[0], 0) == 7)" + "lmw.bi\t%2, [%1], %8, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi6" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20))))])] + "(XVECLEN (operands[0], 0) == 6)" + "lmw.bi\t%2, [%1], %7, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi5" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16))))])] + "(XVECLEN (operands[0], 0) == 5)" + "lmw.bi\t%2, [%1], %6, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi4" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12))))])] + "(XVECLEN (operands[0], 0) == 4)" + "lmw.bi\t%2, [%1], %5, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi3" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8))))])] + "(XVECLEN (operands[0], 0) == 3)" + "lmw.bi\t%2, [%1], %4, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi2" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4))))])] + "(XVECLEN (operands[0], 0) == 2)" + "lmw.bi\t%2, [%1], %3, 0x0" + [(set_attr "type" "load") + (set_attr "length" "4")] +) + + +;; Store Multiple Insns. +;; +;; operands[0] is the first memory location. +;; opernads[1] is the first of the consecutive registers. +;; operands[2] is the number of consecutive registers. + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" +{ + int maximum; + + /* Because reduced-set regsiters has few registers + (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot + be used for register allocation), + using 8 registers for store_multiple may easily consume all of them. + It makes register allocation/spilling hard to work. + So we only allow maximum=4 registers for store_multiple + under reduced-set registers. */ + if (TARGET_REDUCED_REGS) + maximum = 4; + else + maximum = 8; + + /* Here are the conditions that must be all passed, + otherwise we have to FAIL this rtx generation: + 1. The number of consecutive registers must be integer. + 2. Maximum 4 or 8 registers for smw.bi instruction + (based on this nds32-multiple.md design). + 3. Minimum 2 registers for smw.bi instruction + (based on this nds32-multiple.md design). + 4. operands[0] must be memory for sure. + 5. operands[1] must be register for sure. + 6. Do not cross $r15 register because it is not allocatable. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > maximum + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != REG + || REGNO (operands[1]) + INTVAL (operands[2]) > TA_REGNUM) + FAIL; + + /* For (mem addr), we force_reg on addr here, + so that nds32_expand_store_multiple can easily use it. */ + operands[3] = nds32_expand_store_multiple (REGNO (operands[1]), + INTVAL (operands[2]), + force_reg (SImode, + XEXP (operands[0], 0)), + operands[0]); +}) + +;; Ordinary Store Multiple. + +(define_insn "*stmsi8" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 8)" + "smw.bi\t%2, [%1], %9, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi7" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 7)" + "smw.bi\t%2, [%1], %8, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi6" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 6)" + "smw.bi\t%2, [%1], %7, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi5" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 5)" + "smw.bi\t%2, [%1], %6, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi4" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 4)" + "smw.bi\t%2, [%1], %5, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi3" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 3)" + "smw.bi\t%2, [%1], %4, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +(define_insn "*stmsi2" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 2)" + "smw.bi\t%2, [%1], %3, 0x0" + [(set_attr "type" "store") + (set_attr "length" "4")] +) + +;; Move a block of memory if it is word aligned and MORE than 2 words long. +;; We could let this apply for blocks of less than this, but it clobbers so +;; many registers that there is then probably a better way. +;; +;; operands[0] is the destination block of memory. +;; operands[1] is the source block of memory. +;; operands[2] is the number of bytes to move. +;; operands[3] is the known shared alignment. + +(define_expand "movmemqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")] + "" +{ + if (nds32_expand_movmemqi (operands[0], + operands[1], + operands[2], + operands[3])) + DONE; + + FAIL; +}) + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/nds32-opts.h gcc/config/nds32/nds32-opts.h new file mode 100644 index 0000000..b38672f --- /dev/null +++ gcc/config/nds32/nds32-opts.h @@ -0,0 +1,35 @@ +/* Definitions for option handling of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#ifndef NDS32_OPTS_H +#define NDS32_OPTS_H + +#define NDS32_DEFAULT_CACHE_BLOCK_SIZE 16 +#define NDS32_DEFAULT_ISR_VECTOR_SIZE (TARGET_ISA_V3 ? 4 : 16) + +/* The various ANDES ISA. */ +enum nds32_arch_type +{ + ARCH_V2, + ARCH_V3, + ARCH_V3M +}; + +#endif diff --git gcc/config/nds32/nds32-peephole2.md gcc/config/nds32/nds32-peephole2.md new file mode 100644 index 0000000..dbe2d6c --- /dev/null +++ gcc/config/nds32/nds32-peephole2.md @@ -0,0 +1,25 @@ +;; define_peephole2 optimization patterns of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + + +;; Use define_peephole and define_peephole2 to handle possible +;; target-specific optimization in this file. + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/nds32-protos.h gcc/config/nds32/nds32-protos.h new file mode 100644 index 0000000..243d9ee --- /dev/null +++ gcc/config/nds32/nds32-protos.h @@ -0,0 +1,119 @@ +/* Prototypes for exported functions of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + + +/* ------------------------------------------------------------------------ */ + +/* Defining Data Structures for Per-function Information. */ + +extern void nds32_init_expanders (void); + + +/* Register Usage. */ + +/* -- How Values Fit in Registers. */ + +extern int nds32_hard_regno_nregs (int, enum machine_mode); +extern int nds32_hard_regno_mode_ok (int, enum machine_mode); + + +/* Register Classes. */ + +extern enum reg_class nds32_regno_reg_class (int); + + +/* Stack Layout and Calling Conventions. */ + +/* -- Basic Stack Layout. */ + +extern rtx nds32_return_addr_rtx (int, rtx); + +/* -- Eliminating Frame Pointer and Arg Pointer. */ + +extern HOST_WIDE_INT nds32_initial_elimination_offset (unsigned int, + unsigned int); + +/* -- Passing Arguments in Registers. */ + +extern void nds32_init_cumulative_args (CUMULATIVE_ARGS *, + tree, rtx, tree, int); + +/* -- Function Entry and Exit. */ + +extern void nds32_expand_prologue (void); +extern void nds32_expand_epilogue (void); +extern void nds32_expand_prologue_v3push (void); +extern void nds32_expand_epilogue_v3pop (void); + +/* ------------------------------------------------------------------------ */ + +/* Auxiliary functions for auxiliary macros in nds32.h. */ + +extern bool nds32_ls_333_p (rtx, rtx, rtx, enum machine_mode); + +/* Auxiliary functions for expanding rtl used in nds32-multiple.md. */ + +extern rtx nds32_expand_load_multiple (int, int, rtx, rtx); +extern rtx nds32_expand_store_multiple (int, int, rtx, rtx); +extern int nds32_expand_movmemqi (rtx, rtx, rtx, rtx); + +/* Auxiliary functions for multiple load/store predicate checking. */ + +extern bool nds32_valid_multiple_load_store (rtx, bool); + +/* Auxiliary functions for bit operation detection. */ + +extern int nds32_can_use_bclr_p (int); +extern int nds32_can_use_bset_p (int); +extern int nds32_can_use_btgl_p (int); + +extern int nds32_can_use_bitci_p (int); + +/* Auxiliary function for 'Computing the Length of an Insn'. */ + +extern int nds32_adjust_insn_length (rtx, int); + +/* Auxiliary functions for FP_AS_GP detection. */ + +extern bool nds32_symbol_load_store_p (rtx); +extern int nds32_fp_as_gp_check_available (void); + +/* Auxiliary functions for jump table generation. */ + +extern const char *nds32_output_casesi_pc_relative (rtx *); +extern const char *nds32_output_casesi (rtx *); + +/* Auxiliary functions to identify 16 bit addresing mode. */ + +extern enum nds32_16bit_address_type nds32_mem_format (rtx); + +/* Auxiliary functions to output assembly code. */ + +extern const char *nds32_output_16bit_store (rtx *, int); +extern const char *nds32_output_16bit_load (rtx *, int); +extern const char *nds32_output_32bit_store (rtx *, int); +extern const char *nds32_output_32bit_load (rtx *, int); +extern const char *nds32_output_32bit_load_s (rtx *, int); + +/* Auxiliary functions to decide output alignment or not. */ + +extern int nds32_target_alignment (rtx); + +/* ------------------------------------------------------------------------ */ diff --git gcc/config/nds32/nds32.opt gcc/config/nds32/nds32.opt new file mode 100644 index 0000000..9849aa5 --- /dev/null +++ gcc/config/nds32/nds32.opt @@ -0,0 +1,102 @@ +; Options of Andes NDS32 cpu for GNU compiler +; Copyright (C) 2012-2013 Free Software Foundation, Inc. +; Contributed by Andes Technology Corporation. +; +; This file is part of GCC. +; +; GCC is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License as published +; by the Free Software Foundation; either version 3, or (at your +; option) any later version. +; +; GCC is distributed in the hope that it will be useful, but WITHOUT +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +; License for more details. +; +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING3. If not see +; . + +HeaderInclude +config/nds32/nds32-opts.h + +mbig-endian +Target Report RejectNegative Negative(mlittle-endian) Mask(BIG_ENDIAN) +Generate code in big-endian mode. + +mlittle-endian +Target Report RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN) +Generate code in little-endian mode. + +mreduced-regs +Target Report RejectNegative Negative(mfull-regs) Mask(REDUCED_REGS) +Use reduced-set registers for register allocation. + +mfull-regs +Target Report RejectNegative Negative(mreduced-regs) InverseMask(REDUCED_REGS) +Use full-set registers for register allocation. + +mcmov +Target Report Mask(CMOV) +Generate conditional move instructions. + +mperf-ext +Target Report Mask(PERF_EXT) +Generate performance extension instructions. + +mv3push +Target Report Mask(V3PUSH) +Generate v3 push25/pop25 instructions. + +m16-bit +Target Report Mask(16_BIT) +Generate 16-bit instructions. + +mgp-direct +Target Report Mask(GP_DIRECT) +Generate GP base instructions directly. + +misr-vector-size= +Target Report RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE) +Specify the size of each interrupt vector, which must be 4 or 16. + +mcache-block-size= +Target Report RejectNegative Joined UInteger Var(nds32_cache_block_size) Init(NDS32_DEFAULT_CACHE_BLOCK_SIZE) +Specify the size of each cache block, which must be a power of 2 between 4 and 512. + +march= +Target RejectNegative Joined Enum(nds32_arch_type) Var(nds32_arch_option) Init(ARCH_V3) +Specify the name of the target architecture. + +Enum +Name(nds32_arch_type) Type(enum nds32_arch_type) + +EnumValue +Enum(nds32_arch_type) String(v2) Value(ARCH_V2) + +EnumValue +Enum(nds32_arch_type) String(v3) Value(ARCH_V3) + +EnumValue +Enum(nds32_arch_type) String(v3m) Value(ARCH_V3M) + +mforce-fp-as-gp +Target Report Mask(FORCE_FP_AS_GP) +Prevent $fp being allocated during register allocation so that compiler is able to force performing fp-as-gp optimization. + +mforbid-fp-as-gp +Target Report Mask(FORBID_FP_AS_GP) +Forbid using $fp to access static and global variables. This option strictly forbids fp-as-gp optimization regardless of '-mforce-fp-as-gp'. + +mex9 +Target Report Mask(EX9) +Use special directives to guide linker doing ex9 optimization. + +mctor-dtor +Target Report +Enable constructor/destructor feature. + +mrelax +Target Report +Guide linker to relax instructions. diff --git gcc/config/nds32/nds32_intrinsic.h gcc/config/nds32/nds32_intrinsic.h new file mode 100644 index 0000000..33064a9 --- /dev/null +++ gcc/config/nds32/nds32_intrinsic.h @@ -0,0 +1,37 @@ +/* Intrinsic definitions of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _NDS32_INTRINSIC_H +#define _NDS32_INTRINSIC_H + +enum nds32_intrinsic_registers +{ + __NDS32_REG_PSW__ = 1024, + __NDS32_REG_IPSW__, + __NDS32_REG_ITYPE__, + __NDS32_REG_IPC__ +}; + +#endif /* nds32_intrinsic.h */ diff --git gcc/config/nds32/pipelines.md gcc/config/nds32/pipelines.md new file mode 100644 index 0000000..9c8c56b --- /dev/null +++ gcc/config/nds32/pipelines.md @@ -0,0 +1,29 @@ +;; Pipeline descriptions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +(define_automaton "nds32_machine") + +(define_cpu_unit "general_unit" "nds32_machine") + +(define_insn_reservation "simple_insn" 1 + (eq_attr "type" "unknown,load,store,move,alu,compare,branch,call,misc") + "general_unit") + +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/predicates.md gcc/config/nds32/predicates.md new file mode 100644 index 0000000..a995e45 --- /dev/null +++ gcc/config/nds32/predicates.md @@ -0,0 +1,65 @@ +;; Predicate definitions of Andes NDS32 cpu for GNU compiler +;; Copyright (C) 2012-2013 Free Software Foundation, Inc. +;; Contributed by Andes Technology Corporation. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. +;; +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +(define_predicate "nds32_equality_comparison_operator" + (match_code "eq,ne")) + +(define_predicate "nds32_greater_less_comparison_operator" + (match_code "gt,ge,lt,le")) + +(define_special_predicate "nds32_logical_binary_operator" + (match_code "and,ior,xor")) + +(define_predicate "nds32_symbolic_operand" + (match_code "const,symbol_ref,label_ref")) + +(define_predicate "nds32_nonsymbolic_operand" + (and (match_operand 0 "general_operand") + (not (match_code "high,const,symbol_ref,label_ref")))) + +(define_predicate "nds32_reg_constant_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "const_int_operand"))) + +(define_predicate "nds32_rimm15s_operand" + (ior (match_operand 0 "register_operand") + (and (match_operand 0 "const_int_operand") + (match_test "satisfies_constraint_Is15 (op)")))) + +(define_predicate "nds32_imm5u_operand" + (and (match_operand 0 "const_int_operand") + (match_test "satisfies_constraint_Iu05 (op)"))) + +(define_special_predicate "nds32_load_multiple_operation" + (match_code "parallel") +{ + /* To verify 'load' operation, pass 'true' for the second argument. + See the implementation in nds32.c for details. */ + return nds32_valid_multiple_load_store (op, true); +}) + +(define_special_predicate "nds32_store_multiple_operation" + (match_code "parallel") +{ + /* To verify 'store' operation, pass 'false' for the second argument. + See the implementation in nds32.c for details. */ + return nds32_valid_multiple_load_store (op, false); +}) +;; ------------------------------------------------------------------------ diff --git gcc/config/nds32/t-mlibs gcc/config/nds32/t-mlibs new file mode 100644 index 0000000..c66ed54 --- /dev/null +++ gcc/config/nds32/t-mlibs @@ -0,0 +1,30 @@ +# The multilib settings of Andes NDS32 cpu for GNU compiler +# Copyright (C) 2012-2013 Free Software Foundation, Inc. +# Contributed by Andes Technology Corporation. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 3, or (at your +# option) any later version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# We need to build following multilibs: +# -mlittle-endian +# -mbig-endian +# +# We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the +# driver program which options are defaults for this target and thus +# do not need to be handled specially. +MULTILIB_OPTIONS = mlittle-endian/mbig-endian mgp-direct/mno-gp-direct + +# ------------------------------------------------------------------------