| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package rewriteppc64latelower |
| |
| import ( |
| "cmd/compile/internal/ssa" |
| "cmd/compile/internal/ssa/ssaop" |
| "cmd/compile/internal/types" |
| ) |
| |
| // Convert a PPC64 opcode from the Op to OpCC form. This converts (op x y) |
| // to (Select0 (opCC x y)) without having to explicitly fixup every user |
| // of op. |
| // |
| // E.g consider the case: |
| // a = (ADD x y) |
| // b = (CMPconst [0] a) |
| // c = (OR a z) |
| // |
| // A rule like (CMPconst [0] (ADD x y)) => (CMPconst [0] (Select0 (ADDCC x y))) |
| // would produce: |
| // a = (ADD x y) |
| // a' = (ADDCC x y) |
| // a” = (Select0 a') |
| // b = (CMPconst [0] a”) |
| // c = (OR a z) |
| // |
| // which makes it impossible to rewrite the second user. Instead the result |
| // of this conversion is: |
| // a' = (ADDCC x y) |
| // a = (Select0 a') |
| // b = (CMPconst [0] a) |
| // c = (OR a z) |
| // |
| // Which makes it trivial to rewrite b using a lowering rule. |
| func convertPPC64OpToOpCC(op *ssa.Value) *ssa.Value { |
| ccOpMap := map[ssaop.Op]ssaop.Op{ |
| ssaop.OpPPC64ADD: ssaop.OpPPC64ADDCC, |
| ssaop.OpPPC64ADDconst: ssaop.OpPPC64ADDCCconst, |
| ssaop.OpPPC64AND: ssaop.OpPPC64ANDCC, |
| ssaop.OpPPC64ANDN: ssaop.OpPPC64ANDNCC, |
| ssaop.OpPPC64ANDconst: ssaop.OpPPC64ANDCCconst, |
| ssaop.OpPPC64CNTLZD: ssaop.OpPPC64CNTLZDCC, |
| ssaop.OpPPC64MULHDU: ssaop.OpPPC64MULHDUCC, |
| ssaop.OpPPC64NEG: ssaop.OpPPC64NEGCC, |
| ssaop.OpPPC64NOR: ssaop.OpPPC64NORCC, |
| ssaop.OpPPC64OR: ssaop.OpPPC64ORCC, |
| ssaop.OpPPC64RLDICL: ssaop.OpPPC64RLDICLCC, |
| ssaop.OpPPC64SUB: ssaop.OpPPC64SUBCC, |
| ssaop.OpPPC64XOR: ssaop.OpPPC64XORCC, |
| } |
| b := op.Block |
| opCC := b.NewValue0I(op.Pos, ccOpMap[op.Op], types.NewTuple(op.Type, types.TypeFlags), op.AuxInt) |
| opCC.AddArgs(op.Args...) |
| op.Reset(ssaop.OpSelect0) |
| op.AddArgs(opCC) |
| return op |
| } |
| |
| // Try converting a RLDICL to ANDCC. If successful, return the mask otherwise 0. |
| func convertPPC64RldiclAndccconst(sauxint int64) int64 { |
| r, _, _, mask := ssa.DecodePPC64RotateMask(sauxint) |
| if r != 0 || mask&0xFFFF != mask { |
| return 0 |
| } |
| return int64(mask) |
| } |
| |
| // Merge (RLDICL [encoded] (SRDconst [s] x)) into (RLDICL [new_encoded] x) |
| // SRDconst on PPC64 is an extended mnemonic of RLDICL. If the input to an |
| // RLDICL is an SRDconst, and the RLDICL does not rotate its value, the two |
| // operations can be combined. This functions assumes the two opcodes can |
| // be merged, and returns an encoded rotate+mask value of the combined RLDICL. |
| func mergePPC64RLDICLandSRDconst(encoded, s int64) int64 { |
| mb := s |
| r := 64 - s |
| // A larger mb is a smaller mask. |
| if (encoded>>8)&0xFF < mb { |
| encoded = (encoded &^ 0xFF00) | mb<<8 |
| } |
| // The rotate is expected to be 0. |
| if (encoded & 0xFF0000) != 0 { |
| panic("non-zero rotate") |
| } |
| return encoded | r<<16 |
| } |