1// Copyright 2022 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// This file contains rules used by the laterLower pass. 6 7// Simplify ISEL x $0 z into ISELZ 8(ISEL [a] x (MOVDconst [0]) z) => (ISELZ [a] x z) 9// Simplify ISEL $0 y z into ISELZ by inverting comparison and reversing arguments. 10(ISEL [a] (MOVDconst [0]) y z) => (ISELZ [a^0x4] y z) 11 12// SETBC, SETBCR is supported on ISA 3.1(Power10) and newer, use ISELZ for 13// older targets 14(SETBC [2] cmp) && buildcfg.GOPPC64 <= 9 => (ISELZ [2] (MOVDconst [1]) cmp) 15(SETBCR [2] cmp) && buildcfg.GOPPC64 <= 9 => (ISELZ [6] (MOVDconst [1]) cmp) 16(SETBC [0] cmp) && buildcfg.GOPPC64 <= 9 => (ISELZ [0] (MOVDconst [1]) cmp) 17(SETBCR [0] cmp) && buildcfg.GOPPC64 <= 9 => (ISELZ [4] (MOVDconst [1]) cmp) 18(SETBC [1] cmp) && buildcfg.GOPPC64 <= 9 => (ISELZ [1] (MOVDconst [1]) cmp) 19(SETBCR [1] cmp) && buildcfg.GOPPC64 <= 9 => (ISELZ [5] (MOVDconst [1]) cmp) 20 21// The upper bits of the smaller than register values is undefined. Take advantage of that. 22(AND <t> x:(MOVDconst [m]) n) && t.Size() <= 2 => (ANDconst [int64(int16(m))] n) 23 24// Convert simple bit masks to an equivalent rldic[lr] if possible. 25(AND x:(MOVDconst [m]) n) && isPPC64ValidShiftMask(m) => (RLDICL [encodePPC64RotateMask(0,m,64)] n) 26(AND x:(MOVDconst [m]) n) && m != 0 && isPPC64ValidShiftMask(^m) => (RLDICR [encodePPC64RotateMask(0,m,64)] n) 27 28// If the RLDICL does not rotate its value, a shifted value can be merged. 29(RLDICL [em] x:(SRDconst [s] a)) && (em&0xFF0000) == 0 => (RLDICL [mergePPC64RLDICLandSRDconst(em, s)] a) 30 31// Convert rotated 32 bit masks on 32 bit values into rlwinm. In general, this leaves the upper 32 bits in an undefined state. 32(AND <t> x:(MOVDconst [m]) n) && t.Size() == 4 && isPPC64WordRotateMask(m) => (RLWINM [encodePPC64RotateMask(0,m,32)] n) 33 34// When PCRel is supported, paddi can add a 34b signed constant in one instruction. 35(ADD (MOVDconst [m]) x) && supportsPPC64PCRel() && (m<<30)>>30 == m => (ADDconst [m] x) 36 37 38// Where possible and practical, generate CC opcodes. Due to the structure of the rules, there are limits to how 39// a Value can be rewritten which make it impossible to correctly rewrite sibling Value users. To workaround this 40// case, candidates for CC opcodes are converted in two steps: 41// 1. Convert all (x (Op ...) ...) into (x (Select0 (OpCC ...) ...). See convertPPC64OpToOpCC for more 42// detail on how and why this is done there. 43// 2. Rewrite (CMPconst [0] (Select0 (OpCC ...))) into (Select1 (OpCC...)) 44// Note: to minimize potentially expensive regeneration of CC opcodes during the flagalloc pass, only rewrite if 45// both ops are in the same block. 46(CMPconst [0] z:((ADD|AND|ANDN|OR|SUB|NOR|XOR) x y)) && v.Block == z.Block => (CMPconst [0] convertPPC64OpToOpCC(z)) 47(CMPconst [0] z:((NEG|CNTLZD|RLDICL) x)) && v.Block == z.Block => (CMPconst [0] convertPPC64OpToOpCC(z)) 48// Note: ADDCCconst only assembles to 1 instruction for int16 constants. 49(CMPconst [0] z:(ADDconst [c] x)) && int64(int16(c)) == c && v.Block == z.Block => (CMPconst [0] convertPPC64OpToOpCC(z)) 50(CMPconst [0] z:(ANDconst [c] x)) && int64(uint16(c)) == c && v.Block == z.Block => (CMPconst [0] convertPPC64OpToOpCC(z)) 51// And finally, fixup the flag user. 52(CMPconst <t> [0] (Select0 z:((ADD|AND|ANDN|OR|SUB|NOR|XOR)CC x y))) => (Select1 <t> z) 53(CMPconst <t> [0] (Select0 z:((ADDCCconst|ANDCCconst|NEGCC|CNTLZDCC|RLDICLCC) y))) => (Select1 <t> z) 54 55// After trying to convert ANDconst to ANDCCconst above, if the CC result is not needed, try to avoid using 56// ANDconst which clobbers CC. 57(ANDconst [m] x) && isPPC64ValidShiftMask(m) => (RLDICL [encodePPC64RotateMask(0,m,64)] x) 58 59// Likewise, trying converting RLDICLCC back to ANDCCconst as it is faster. 60(RLDICLCC [a] x) && convertPPC64RldiclAndccconst(a) != 0 => (ANDCCconst [convertPPC64RldiclAndccconst(a)] x) 61