• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "cast_opt.h"
17 #include "irmap.h"
18 #include "mir_builder.h"
19 #include "constantfold.h"
20 
21 namespace maple {
22 // This is not safe because handlefunction may ignore necessary implicit intTrunc, so we skip it now.
23 static constexpr bool mapleSimplifyZextU32 = false;
24 
GetCastKindByTwoType(PrimType fromType,PrimType toType)25 CastKind GetCastKindByTwoType(PrimType fromType, PrimType toType)
26 {
27     // This is a workaround, we don't optimize `cvt u1 xx <expr>` because it will be converted to
28     // `ne u1 xx (<expr>, constval xx 0)`. There is no `cvt u1 xx <expr>` in the future.
29     if (toType == PTY_u1 && fromType != PTY_u1) {
30         return CAST_unknown;
31     }
32     const uint32 fromTypeBitSize = GetPrimTypeActualBitSize(fromType);
33     const uint32 toTypeBitSize = GetPrimTypeActualBitSize(toType);
34     // Both integer, ptr/ref/a64/u64... are also integer
35     if (IsPrimitiveInteger(fromType) && IsPrimitiveInteger(toType)) {
36         if (toTypeBitSize == fromTypeBitSize) {
37             return CAST_retype;
38         } else if (toTypeBitSize < fromTypeBitSize) {
39             return CAST_intTrunc;
40         } else {
41             return IsSignedInteger(fromType) ? CAST_sext : CAST_zext;
42         }
43     }
44     // Both fp
45     if (IsPrimitiveFloat(fromType) && IsPrimitiveFloat(toType)) {
46         if (toTypeBitSize == fromTypeBitSize) {
47             return CAST_retype;
48         } else if (toTypeBitSize < fromTypeBitSize) {
49             return CAST_fpTrunc;
50         } else {
51             return CAST_fpExt;
52         }
53     }
54     // int2fp
55     if (IsPrimitiveInteger(fromType) && IsPrimitiveFloat(toType)) {
56         return CAST_int2fp;
57     }
58     // fp2int
59     if (IsPrimitiveFloat(fromType) && IsPrimitiveInteger(toType)) {
60         return CAST_fp2int;
61     }
62     return CAST_unknown;
63 }
64 
CreateMapleExprByCastKind(MIRBuilder & mirBuilder,CastKind castKind,PrimType srcType,PrimType dstType,BaseNode * opnd,TyIdx dstTyIdx)65 BaseNode *MapleCastOpt::CreateMapleExprByCastKind(MIRBuilder &mirBuilder, CastKind castKind, PrimType srcType,
66                                                   PrimType dstType, BaseNode *opnd, TyIdx dstTyIdx)
67 {
68     if (castKind == CAST_zext) {
69         return mirBuilder.CreateExprExtractbits(OP_zext, dstType, 0, GetPrimTypeActualBitSize(srcType), opnd);
70     } else if (castKind == CAST_sext) {
71         return mirBuilder.CreateExprExtractbits(OP_sext, dstType, 0, GetPrimTypeActualBitSize(srcType), opnd);
72     } else if (castKind == CAST_retype && srcType == opnd->GetPrimType()) {
73         // If srcType is different from opnd->primType, we should create cvt instead of retype.
74         // Because CGFunc::SelectRetype always use opnd->primType as srcType.
75         CHECK_FATAL(dstTyIdx != 0u, "must specify valid tyIdx for retype");
76         MIRType *dstMIRType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(dstTyIdx);
77         return mirBuilder.CreateExprRetype(*dstMIRType, srcType, opnd);
78     } else {
79         return mirBuilder.CreateExprTypeCvt(OP_cvt, dstType, srcType, *opnd);
80     }
81 }
82 
83 // This interface is conservative, which means that some op are explicit type cast but
84 // the interface returns false.
IsExplicitCastOp(Opcode op)85 bool CastOpt::IsExplicitCastOp(Opcode op)
86 {
87     if (op == OP_retype || op == OP_cvt || op == OP_zext || op == OP_sext) {
88         return true;
89     }
90     return false;
91 }
92 
93 // This interface is conservative, which means that some op are implicit type cast but
94 // the interface returns false.
IsImplicitCastOp(Opcode op)95 bool CastOpt::IsImplicitCastOp(Opcode op)
96 {
97     if (op == OP_iread || op == OP_regread || op == OP_dread) {
98         return true;
99     }
100     return false;
101 }
102 
IsCompareOp(Opcode op)103 bool CastOpt::IsCompareOp(Opcode op)
104 {
105     if (op == OP_eq || op == OP_ne || op == OP_ge || op == OP_gt || op == OP_le || op == OP_lt) {
106         return true;
107     }
108     return false;
109 }
110 
TransformCvtU1ToNe(MIRBuilder & mirBuilder,const TypeCvtNode * cvtExpr)111 BaseNode *MapleCastOpt::TransformCvtU1ToNe(MIRBuilder &mirBuilder, const TypeCvtNode *cvtExpr)
112 {
113     PrimType fromType = cvtExpr->FromType();
114     auto *fromMIRType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(fromType));
115     // We use u8 instead of u1 because codegen can't recognize u1
116     auto *toMIRType = GlobalTables::GetTypeTable().GetUInt8();
117     auto *zero = GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, *fromMIRType);
118     auto *converted = mirBuilder.CreateExprCompare(OP_ne, *toMIRType, *fromMIRType, cvtExpr->Opnd(0),
119                                                    mirBuilder.CreateConstval(zero));
120     return converted;
121 }
122 
SimplifyCastSingle(MIRBuilder & mirBuilder,const BaseNodeCastInfo & castInfo)123 BaseNode *MapleCastOpt::SimplifyCastSingle(MIRBuilder &mirBuilder, const BaseNodeCastInfo &castInfo)
124 {
125     if (castInfo.IsInvalid()) {
126         return nullptr;
127     }
128     auto *castExpr = static_cast<BaseNode *>(castInfo.expr);
129     auto *opnd = castExpr->Opnd(0);
130     Opcode op = castExpr->GetOpCode();
131     Opcode opndOp = opnd->GetOpCode();
132     // cast to integer + compare  ==>  compare
133     if (IsPrimitiveInteger(castInfo.dstType) && IsCompareOp(opndOp)) {
134         // exclude the following castExpr:
135         //   sext xx 1 <expr>
136         bool excluded = (op == OP_sext && static_cast<ExtractbitsNode *>(castExpr)->GetBitsSize() == 1);
137         if (!excluded) {
138             opnd->SetPrimType(castExpr->GetPrimType());
139             return opnd;
140         }
141     }
142     // cast + const  ==>  const
143     if (castInfo.kind != CAST_retype && opndOp == OP_constval) {
144         ConstantFold cf(*theMIRModule);
145         MIRConst *cst = cf.FoldTypeCvtMIRConst(*static_cast<ConstvalNode *>(opnd)->GetConstVal(), castInfo.srcType,
146                                                castInfo.dstType);
147         if (cst != nullptr) {
148             return mirBuilder.CreateConstval(cst);
149         }
150     }
151     if (mapleSimplifyZextU32) {
152         // zextTo32 + read  ==>  read 32
153         if (castInfo.kind == CAST_zext && (opndOp == OP_iread || opndOp == OP_regread || opndOp == OP_dread)) {
154             uint32 dstSize = GetPrimTypeActualBitSize(castInfo.dstType);
155             if (dstSize == k32BitSize && IsUnsignedInteger(castInfo.dstType) &&
156                 IsUnsignedInteger(opnd->GetPrimType()) &&
157                 GetPrimTypeActualBitSize(castInfo.srcType) == GetPrimTypeActualBitSize(opnd->GetPrimType())) {
158                 opnd->SetPrimType(castInfo.dstType);
159                 return opnd;
160             }
161         }
162     }
163     if (castInfo.dstType == opnd->GetPrimType() &&
164         GetPrimTypeActualBitSize(castInfo.srcType) >= GetPrimTypeActualBitSize(opnd->GetPrimType())) {
165         return opnd;
166     }
167     return nullptr;
168 }
169 }  // namespace maple
170