From patchwork Sun Oct 21 21:44:38 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Uros Bizjak X-Patchwork-Id: 193060 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]) by ozlabs.org (Postfix) with SMTP id 0B4B22C0089 for ; Mon, 22 Oct 2012 08:44:50 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1351460691; h=Comment: DomainKey-Signature:Received:Received:Received:Received: MIME-Version:Received:Received:Date:Message-ID:Subject:From:To: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=Iwpav3l xpSIpZQcA00T27LpQsU4=; b=KnPGZEXAE+EXvwFayeJxG06VM+XpS7zuR3X3S6B nxOzajrcIsEgV0dsZw6Bshna1op54XWOlJD58lb5EZCjBVdzHCDWw2h+r0ejPO7N Hzn4YWMpxZLywdZ6TVQ70vODzATa607a5BUQAARUVTDRJqtUFY0cd2zDpX0LBREk bnwo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:MIME-Version:Received:Received:Date:Message-ID:Subject:From:To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=gdEQE92W05fk2QInLJmY9i2KMgeyqAXAMjYfnf5japXjJq4phz6RrrwJfXUi9s e6xB0GLUFzYYK4LTHgCpxtnSFf+BUNHs3wFnzp/Pj12MasEvs6zS2YMcbmce5/LE stD0cYJKakkA9UwM9Mya0KZ+0xV3yA8aum3KTNuipCC/8=; Received: (qmail 27902 invoked by alias); 21 Oct 2012 21:44:46 -0000 Received: (qmail 27893 invoked by uid 22791); 21 Oct 2012 21:44:45 -0000 X-SWARE-Spam-Status: No, hits=-4.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, TW_ZJ X-Spam-Check-By: sourceware.org Received: from mail-pa0-f47.google.com (HELO mail-pa0-f47.google.com) (209.85.220.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 21 Oct 2012 21:44:39 +0000 Received: by mail-pa0-f47.google.com with SMTP id fa11so1388364pad.20 for ; Sun, 21 Oct 2012 14:44:38 -0700 (PDT) MIME-Version: 1.0 Received: by 10.68.197.71 with SMTP id is7mr24570666pbc.79.1350855878356; Sun, 21 Oct 2012 14:44:38 -0700 (PDT) Received: by 10.66.246.232 with HTTP; Sun, 21 Oct 2012 14:44:38 -0700 (PDT) Date: Sun, 21 Oct 2012 23:44:38 +0200 Message-ID: Subject: [PATCH, i386]: Fix length attribute calculation for LEA and addr32 addresses From: Uros Bizjak To: gcc-patches@gcc.gnu.org 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 Hello! Attached patch fixes length attribute calculation for LEA insn and addr32 addresses: - REX prefix was computed in a wrong way for zero-extended LEA instructions. Addresses with SUBREG, ZERO_EXTEND and AND result in SImode target register without REX prefix. - addr32 handling was wrong for length calculation. We have to look at the mode of base or index _register_ of decomposed address, since addr32 prefix is emitted only when registers are used in the address. Note, that we never emit addr32 prefix for LEA insns. 2012-10-21 Uros Bizjak * config/i386/i386-protos.h (memory_address_length): Add new bool argument. Update all uses. * config/i386/i386.c (memory_address_length): If not LEA insn, then add length of addr32 prefix based on mode of base or index register. (ix86_attr_length_address_default) : Do not handle SImode addresses here. Update call to memory_address_length. (ix86_print_address_operand): Use SImode_address_operand predicate. * config/i386/predicates.md (SImode_address_operand): New. * config/i386/i386.md (lea): Use SImode_address_operand to calculate "mode" attribute. Use SImode_address_operand predicate instead of open-coding accepted RTX codes. Patch was bootstrapped and regression tested on x86_64-pc-linux-gnu {,-m32}, also tested with lots of asm code eyeballing. Patch was committed to mainline SVN, in a couple of days, it will also be committed to 4.7 branch. Uros. Index: i386-protos.h =================================================================== --- i386-protos.h (revision 192655) +++ i386-protos.h (working copy) @@ -282,7 +282,7 @@ struct ix86_address }; extern int ix86_decompose_address (rtx, struct ix86_address *); -extern int memory_address_length (rtx addr); +extern int memory_address_length (rtx, bool); extern void x86_output_aligned_bss (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int); extern void x86_elf_aligned_common (FILE *, const char *, Index: i386.c =================================================================== --- i386.c (revision 192655) +++ i386.c (working copy) @@ -14979,22 +14979,27 @@ ix86_print_operand_address (FILE *file, rtx addr) else { /* Print SImode register names to force addr32 prefix. */ - if (GET_CODE (addr) == SUBREG) + if (SImode_address_operand (addr, VOIDmode)) { +#ifdef ENABLE_CHECKING gcc_assert (TARGET_64BIT); - gcc_assert (GET_MODE (addr) == SImode); - gcc_assert (GET_MODE (SUBREG_REG (addr)) == DImode); + switch (GET_CODE (addr)) + { + case SUBREG: + gcc_assert (GET_MODE (addr) == SImode); + gcc_assert (GET_MODE (SUBREG_REG (addr)) == DImode); + break; + case ZERO_EXTEND: + case AND: + gcc_assert (GET_MODE (addr) == DImode); + break; + default: + gcc_unreachable (); + } +#endif gcc_assert (!code); code = 'l'; } - else if (GET_CODE (addr) == ZERO_EXTEND - || GET_CODE (addr) == AND) - { - gcc_assert (TARGET_64BIT); - gcc_assert (GET_MODE (addr) == DImode); - gcc_assert (!code); - code = 'l'; - } if (ASSEMBLER_DIALECT == ASM_ATT) { @@ -23752,14 +23757,14 @@ assign_386_stack_local (enum machine_mode mode, en /* Calculate the length of the memory address in the instruction encoding. Includes addr32 prefix, does not include the one-byte modrm, opcode, - or other prefixes. */ + or other prefixes. We never generate addr32 prefix for LEA insn. */ int -memory_address_length (rtx addr) +memory_address_length (rtx addr, bool lea) { struct ix86_address parts; rtx base, index, disp; - int len; + int len = 0; int ok; if (GET_CODE (addr) == PRE_DEC @@ -23780,10 +23785,6 @@ int index = parts.index; disp = parts.disp; - /* Add length of addr32 prefix. */ - len = (GET_CODE (addr) == ZERO_EXTEND - || GET_CODE (addr) == AND); - /* Rule of thumb: - esp as the base always wants an index, - ebp as the base always wants a displacement, @@ -23796,13 +23797,13 @@ int /* esp (for its index) and ebp (for its displacement) need the two-byte modrm form. Similarly for r12 and r13 in 64-bit code. */ - if (REG_P (addr) - && (addr == arg_pointer_rtx - || addr == frame_pointer_rtx - || REGNO (addr) == SP_REG - || REGNO (addr) == BP_REG - || REGNO (addr) == R12_REG - || REGNO (addr) == R13_REG)) + if (REG_P (base) + && (base == arg_pointer_rtx + || base == frame_pointer_rtx + || REGNO (base) == SP_REG + || REGNO (base) == BP_REG + || REGNO (base) == R12_REG + || REGNO (base) == R13_REG)) len = 1; } @@ -23870,6 +23871,12 @@ int break; } + /* If this is not LEA instruction, add the length of addr32 prefix. */ + if (TARGET_64BIT && !lea + && ((base && GET_MODE (base) == SImode) + || (index && GET_MODE (index) == SImode))) + len += 1; + return len; } @@ -23947,15 +23954,8 @@ ix86_attr_length_address_default (rtx insn) gcc_assert (GET_CODE (set) == SET); addr = SET_SRC (set); - if (TARGET_64BIT && get_attr_mode (insn) == MODE_SI) - { - if (GET_CODE (addr) == ZERO_EXTEND) - addr = XEXP (addr, 0); - if (GET_CODE (addr) == SUBREG) - addr = SUBREG_REG (addr); - } - return memory_address_length (addr); + return memory_address_length (addr, true); } extract_insn_cached (insn); @@ -23977,7 +23977,7 @@ ix86_attr_length_address_default (rtx insn) if (*constraints == 'X') continue; } - return memory_address_length (XEXP (recog_data.operand[i], 0)); + return memory_address_length (XEXP (recog_data.operand[i], 0), false); } return 0; } Index: i386.md =================================================================== --- i386.md (revision 192655) +++ i386.md (working copy) @@ -5494,18 +5494,9 @@ { rtx addr = operands[1]; - if (GET_CODE (addr) == SUBREG) + if (SImode_address_operand (addr, VOIDmode)) { gcc_assert (TARGET_64BIT); - gcc_assert (mode == SImode); - gcc_assert (GET_MODE (SUBREG_REG (addr)) == DImode); - return "lea{l}\t{%E1, %0|%0, %E1}"; - } - else if (GET_CODE (addr) == ZERO_EXTEND - || GET_CODE (addr) == AND) - { - gcc_assert (TARGET_64BIT); - gcc_assert (mode == DImode); return "lea{l}\t{%E1, %k0|%k0, %E1}"; } else @@ -5526,15 +5517,18 @@ /* Emit all operations in SImode for zero-extended addresses. Recall that x86_64 inheretly zero-extends SImode operations to DImode. */ - if (GET_CODE (operands[1]) == ZERO_EXTEND - || GET_CODE (operands[1]) == AND) + if (SImode_address_operand (operands[1], VOIDmode)) mode = SImode; ix86_split_lea_for_addr (curr_insn, operands, mode); DONE; } [(set_attr "type" "lea") - (set_attr "mode" "")]) + (set (attr "mode") + (if_then_else + (match_operand 1 "SImode_address_operand") + (const_string "SI") + (const_string "")))]) ;; Add instructions @@ -17832,7 +17826,7 @@ [(set_attr "type" "sse") (set_attr "atom_sse_attr" "prefetch") (set (attr "length_address") - (symbol_ref "memory_address_length (operands[0])")) + (symbol_ref "memory_address_length (operands[0], false)")) (set_attr "memory" "none")]) (define_insn "*prefetch_3dnow" @@ -17848,7 +17842,7 @@ } [(set_attr "type" "mmx") (set (attr "length_address") - (symbol_ref "memory_address_length (operands[0])")) + (symbol_ref "memory_address_length (operands[0], false)")) (set_attr "memory" "none")]) (define_expand "stack_protect_set" Index: predicates.md =================================================================== --- predicates.md (revision 192655) +++ predicates.md (working copy) @@ -813,6 +813,10 @@ return parts.seg == SEG_DEFAULT; }) +;; Return true for RTX codes that force SImode address. +(define_predicate "SImode_address_operand" + (match_code "subreg,zero_extend,and")) + ;; Return true if op if a valid base register, displacement or ;; sum of base register and displacement for VSIB addressing. (define_predicate "vsib_address_operand" @@ -982,7 +986,7 @@ ;; by the modRM array. (define_predicate "long_memory_operand" (and (match_operand 0 "memory_operand") - (match_test "memory_address_length (op)"))) + (match_test "memory_address_length (op, false)"))) ;; Return true if OP is a comparison operator that can be issued by fcmov. (define_predicate "fcmov_comparison_operator"