diff --git a/BUILD.gn b/BUILD.gn index 40e691379fdb548eb9a6292775b15262bfa1c51d..50821caea157b36852805040e664cdc9b3afc605 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -20,6 +20,10 @@ group("irbuild") { deps = [ "${MAPLEALL_ROOT}:irbuild" ] } +group("mplverf") { + deps = [ "${MAPLEALL_ROOT}:mplverf" ] +} + group("hir2mpl") { deps = [ "${HIR2MPL_ROOT}:hir2mpl" ] } diff --git a/Makefile b/Makefile index e3a7e3bc88374fd545074c6ad755af9a98538cf7..f74a3cde8601c0ddea310a03f1168c342fa6d57a 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,10 @@ irbuild: install_patch mpldbg: $(call build_gn, $(GN_OPTIONS), mpldbg) +.PHONY: mplverf +mplverf: install_patch + $(call build_gn, $(GN_OPTIONS), mplverf) + .PHONY: ast2mpl ast2mpl: $(call build_gn, $(GN_OPTIONS), ast2mpl) @@ -137,7 +141,7 @@ java-core-def: install $(MAKE) gen-def OPT=$(OPT) DEBUG=$(DEBUG) .PHONY: install -install: maple dex2mpl_install irbuild hir2mpl +install: maple dex2mpl_install irbuild hir2mpl mplverf $(shell mkdir -p $(INSTALL_DIR)/ops/linker/; \ rsync -a -L $(MRT_ROOT)/maplert/linker/maplelld.so.lds $(INSTALL_DIR)/ops/linker/; \ rsync -a -L $(MAPLE_ROOT)/build/java2d8 $(INSTALL_DIR)/bin; \ diff --git a/src/mapleall/BUILD.gn b/src/mapleall/BUILD.gn index 73605d9877d2425298c4152e1e56be1145fb713c..dee546447246a76756a15f944f2124b37dfa1a51 100644 --- a/src/mapleall/BUILD.gn +++ b/src/mapleall/BUILD.gn @@ -121,3 +121,7 @@ group("irbuild") { group("maplegen") { deps = [ "${MAPLEALL_ROOT}/maple_be:maplegen" ] } + +group("mplverf") { + deps = [ "${MAPLEALL_ROOT}/maple_ir:mplverf" ] +} diff --git a/src/mapleall/maple_ir/BUILD.gn b/src/mapleall/maple_ir/BUILD.gn index 79155184d4f909a4ad848b8a783c71f17953a0fe..0b797ce04c89617f66eced456e0d144dd08262f7 100755 --- a/src/mapleall/maple_ir/BUILD.gn +++ b/src/mapleall/maple_ir/BUILD.gn @@ -107,3 +107,17 @@ executable("mpldbg") { "${THIRD_PARTY_ROOT}/bounds_checking_function:libHWSecureC", ] } + +src_mplverf = [ "src/mpl_verify.cpp" ] + +executable("mplverf") { + sources = src_mplverf + include_dirs = include_directories + deps = [ + ":libmplir", + "${MAPLEALL_ROOT}/mempool:libmempool", + "${MAPLEALL_ROOT}/mpl2mpl:libmpl2mpl", + "${THIRD_PARTY_ROOT}/bounds_checking_function:libHWSecureC", + "${MAPLEALL_ROOT}/maple_driver:libmaple_driver", + ] +} diff --git a/src/mapleall/maple_ir/CMakeLists.txt b/src/mapleall/maple_ir/CMakeLists.txt index 24d556a4e6767de9a4f1c0a5ad40b85fe1265310..8da1c6037ed2d4dda720262dc5a95c8b6a1156f5 100755 --- a/src/mapleall/maple_ir/CMakeLists.txt +++ b/src/mapleall/maple_ir/CMakeLists.txt @@ -65,6 +65,8 @@ set(src_irbuild "src/driver.cpp") set(src_mpldbg "src/mpl_dbg.cpp") +set(src_mplverf "src/mpl_verify.cpp") + set(deps_libmplir libdriver_option libmplphase @@ -113,3 +115,12 @@ set_target_properties(mpldbg PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${MAPLE_BUILD_OUTPUT}/bin" ) +#mplverf +add_executable(mplverf "${src_mplverf}") +set_target_properties(mplverf PROPERTIES + COMPILE_FLAGS "" + INCLUDE_DIRECTORIES "${inc_libmplir}" + LINK_LIBRARIES "${deps_irbuild}" + RUNTIME_OUTPUT_DIRECTORY "${MAPLE_BUILD_OUTPUT}/bin" +) + diff --git a/src/mapleall/maple_ir/src/mir_nodes.cpp b/src/mapleall/maple_ir/src/mir_nodes.cpp index 7a03023d8561fdb8f4ec9c78a7b808a8b74e3a5b..12d5128afdf8c5feb3fad3dd1f72a7e82d947ba0 100644 --- a/src/mapleall/maple_ir/src/mir_nodes.cpp +++ b/src/mapleall/maple_ir/src/mir_nodes.cpp @@ -1612,6 +1612,101 @@ void AsmNode::Dump(int32 indent) const { LogInfo::MapleLogger() << " }\n"; } +/* Start of primtype verification for Maple IR nodes. + + General rules: + + 1. For binary operations, the types of the two operands must be compatible. + + 2. In checking type compatibility, other than identical types, the types in + each of the following group are compatible with each other: + [i32, u32, ptr, ref, a32] + [i64, u64, ptr, ref, a64] + + 3. dynany is compatiable with any dyn* type. + + 4. u1, i8, u8, i16, u16 must not be types of arithmetic operations, because + many machines do not provide instructions for such types as they lack such + register sizes. Similarly, these types must not be used as result types for + any read instructions: dread/iread/regread. + + 5. When an opcode only specifies one type (which is called the result type), + it expects both operands and results to be of this same type. Thus, the + types among the operands and this result type must be compatible. + + 6. When an opcode specifies two types, the additional (second) type is + the operand type. The types of the operands and the operand type must be + compatible. + + 7. The opcodes addrof, addroflabel, addroffunc and iaddrof form addresses. + Thus, their result type must be in [ptr,ref,a32,a64]. + + 8. The opcodes bnot, extractbits, sext, zext, lnot must have result type in + [i32, u32, i64, u64]. + + 9. The opcodes abs, neg must have result type in + [i32, u32, i64, u64, f32, f64]. + + 10. The opcodes recip, sqrt must have result type in [f32, f64]. + + 11. The opcodes ceil, floor, round, trunc must have result-type in + [i32, u32, i64, u64] and operand-type in [f32, f64]. + + 12. The opcodes add, div, sub, mpy, max, min must have result-type in + [i32, u32, i64, u64, f32, f64]. + + 13. The opcodes eq, ge, gt, le, lt, ne must have result-type in + any signed or unsigned integer type; they also specifies operand-type, and + this operand-type and the types of their two operands must be compatible. + + 14. The opcodes ashr, band, bior, bxor, depositbits, land, lior, lshr, shl, + rem must have result-type in [i32, u32, i64, u64]. + + 15. select's result-type and the types of its second and third operands must + be compatible; its first operand must be of integer type. + + 16. array's result-type must be in [ptr,ref,a32,a64]; the type of must + also be in [ptr,ref,a32,a64]; the types of the rest of the operands must be in + [i32, u32, i64, u64]. + + 17. The operand of brfalse, trfalse must be of integer type. + + 18. The operand of switch, rangegoto must be in [i32, u32, i64, u64]. +*/ + +inline bool ExcludeSmallIntTypeVerify(const BaseNode &opnd) { + switch (opnd.GetPrimType()) { + case PTY_u1: + case PTY_i8: + case PTY_u8: + case PTY_i16: + case PTY_u16: + return false; + default: + break; + } + return true; +} + +inline bool ArithTypeVerify(const BaseNode &opnd) { + bool verifyResult = ExcludeSmallIntTypeVerify(opnd); + if (!verifyResult) { + LogInfo::MapleLogger() << "\n#Error:u1,i8,u8,i16,u16 should not be used as types of arithmetic operations\n"; + opnd.Dump(); + } + return verifyResult; +} + +inline bool ReadTypeVerify(const BaseNode &opnd) { + bool verifyResult = ExcludeSmallIntTypeVerify(opnd); + if (!verifyResult) { + LogInfo::MapleLogger() + << "\n#Error:u1,i8,u8,i16,u16 should not be used as result types for dread/iread/regread/ireadoff/ireadfpoff\n"; + opnd.Dump(); + } + return verifyResult; +} + inline bool IntTypeVerify(PrimType pTyp) { return pTyp == PTY_i32 || pTyp == PTY_u32 || pTyp == PTY_i64 || pTyp == PTY_u64; } @@ -1670,7 +1765,7 @@ inline bool BinaryTypeVerify(PrimType pType) { } inline bool BinaryGenericVerify(const BaseNode &bOpnd0, const BaseNode &bOpnd1) { - return bOpnd0.Verify() && bOpnd1.Verify(); + return bOpnd0.Verify() && bOpnd1.Verify() && ArithTypeVerify(bOpnd0) && ArithTypeVerify(bOpnd1); } inline bool CompareTypeVerify(PrimType pType) { @@ -1870,7 +1965,10 @@ bool UnaryNode::Verify() const { } else if (GetOpCode() == OP_recip || GetOpCode() == OP_sqrt) { resTypeVerf = UnaryTypeVerify2(GetPrimType()); } - + bool opndTypeVerf = true; + if (op != OP_lnot) { + opndTypeVerf = ArithTypeVerify(*uOpnd); + } // When an opcode only specifies one type, check for compatibility // between the operands and the result-type. bool compVerf = true; @@ -1879,7 +1977,7 @@ bool UnaryNode::Verify() const { compVerf = CompatibleTypeVerify(*uOpnd, *this); } bool opndExprVerf = uOpnd->Verify(); - return resTypeVerf && compVerf && opndExprVerf; + return resTypeVerf && opndTypeVerf && compVerf && opndExprVerf; } bool TypeCvtNode::Verify() const { @@ -2130,7 +2228,7 @@ bool IntrinsicopNode::VerifyJArrayLength(VerifyResult &verifyResult) const { bool IreadNode::Verify() const { bool addrExprVerf = Opnd(0)->Verify(); - bool pTypeVerf = true; + bool pTypeVerf = ReadTypeVerify(*this); bool structVerf = true; if (GetTypeKind(tyIdx) != kTypePointer) { LogInfo::MapleLogger() << "\n#Error: must be a pointer type\n"; @@ -2171,7 +2269,7 @@ bool IreadNode::Verify() const { } bool RegreadNode::Verify() const { - return true; + return ReadTypeVerify(*this); } bool IreadoffNode::Verify() const { @@ -2184,6 +2282,7 @@ bool IreadFPoffNode::Verify() const { bool ExtractbitsNode::Verify() const { bool opndExprVerf = Opnd(0)->Verify(); + bool opndTypeVerf = ArithTypeVerify(*Opnd(0)); bool compVerf = CompatibleTypeVerify(*Opnd(0), *this); bool resTypeVerf = UnaryTypeVerify0(GetPrimType()); constexpr int numBitsInByte = 8; @@ -2192,7 +2291,7 @@ bool ExtractbitsNode::Verify() const { LogInfo::MapleLogger() << "\n#Error: The operand of extractbits must be large enough to contain the specified bitfield\n"; } - return opndExprVerf && compVerf && resTypeVerf && opnd0SizeVerf; + return opndExprVerf && opndTypeVerf && compVerf && resTypeVerf && opnd0SizeVerf; } bool BinaryNode::Verify() const { @@ -2317,6 +2416,7 @@ bool AddrofNode::Verify() const { bool pTypeVerf = true; bool structVerf = IsStructureVerify(fieldID, GetStIdx()); if (GetOpCode() == OP_dread) { + pTypeVerf = ReadTypeVerify(*this); if (fieldID == 0 && IsStructureTypeKind(GetTypeKind(GetStIdx()))) { if (GetPrimType() != PTY_agg) { pTypeVerf = false; @@ -2433,12 +2533,13 @@ bool RangeGotoNode::Verify() const { } bool BlockNode::Verify() const { + bool passing = true; for (auto &stmt : GetStmtNodes()) { if (!stmt.Verify()) { - return false; + passing = false; } } - return true; + return passing; } bool BlockNode::Verify(VerifyResult &verifyResult) const { diff --git a/src/mapleall/maple_ir/src/mpl_verify.cpp b/src/mapleall/maple_ir/src/mpl_verify.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58444df6230ac4e779d4472eb3bc5d92f7e74685 --- /dev/null +++ b/src/mapleall/maple_ir/src/mpl_verify.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co., Ltd. All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include +#include + +#include "bin_mplt.h" +#include "mir_function.h" +#include "mir_parser.h" +#include "opcode_info.h" +#include "triple.h" + +using namespace maple; + +static bool dumpit; + +static bool VerifyModule(MIRModule *module) { + bool res = true; + for (MIRFunction *curfunc : module->GetFunctionList()) { + BlockNode *block = curfunc->GetBody(); + module->SetCurFunction(curfunc); + if (dumpit) { + curfunc->Dump(false); + } + if (!block) { + continue; + } + if (!block->Verify()) { + res = false; + } + } + return res; +} + +static void Usage(const char *pgm) { + INFO(kLncInfo, "usage: %s [--dump]\n", pgm); +} + +int main(int argc, const char *argv[]) { + if (argc < 2) { + Usage(argv[0]); + return 1; + } + + const char *mirInfile = nullptr; + for (int i = 1; i < argc; ++i) { + if (!strncmp(argv[i], "--dump", 6)) { + dumpit = true; + } else if (argv[i][0] != '-') { + mirInfile = argv[i]; + } + } + + if (!mirInfile) { + Usage(argv[0]); + return 1; + } + Triple::GetTriple().Init(); + std::string filename(mirInfile); + std::string::size_type lastdot = filename.find_last_of("."); + bool isbpl = filename.compare(lastdot, std::string::npos, ".bpl") == 0; + + MIRModule *theModule = new MIRModule(mirInfile); + theMIRModule = theModule; + if (!isbpl) { + maple::MIRParser theparser(*theModule); + if (!theparser.ParseMIR()) { + theparser.EmitError(filename); + return 1; + } + } + else { + BinaryMplImport binMplt(*theModule); + binMplt.SetImported(false); + if (!binMplt.Import(filename, true)) { + FATAL(kLncFatal, "cannot open .bpl file: %s", mirInfile); + return 1; + } + } + if (!VerifyModule(theModule)) { + return 1; + } + return 0; +}