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